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-2002
16  *
17  * Max Levenkov
18  *
19  * Fido:     2:5000/117
20  * Internet: sackett@mail.ru
21  * Novosibirsk, West Siberia, Russia
22  *
23  * This file is part of HPT.
24  *
25  * HPT is free software; you can redistribute it and/or modify it
26  * under the terms of the GNU General Public License as published by the
27  * Free Software Foundation; either version 2, or (at your option) any
28  * later version.
29  *
30  * HPT is distributed in the hope that it will be useful, but
31  * WITHOUT ANY WARRANTY; without even the implied warranty of
32  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
33  * General Public License for more details.
34  *
35  * You should have received a copy of the GNU General Public License
36  * along with HPT; see the file COPYING.  If not, write to the Free
37  * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
38  *****************************************************************************
39  * $Id$
40  */
41 #include <string.h>
42 #include <stdlib.h>
43 #include <errno.h>
44 #include <ctype.h>
45 #include <sys/types.h>
46 #include <sys/stat.h>
47 
48 /* compiler.h */
49 #include <huskylib/compiler.h>
50 
51 
52 #if (defined(__EMX__) || defined(__MINGW32__)) && defined(__NT__)
53   /* we can't include windows.h for prevent compiler errors ... */
54 /*#  include <windows.h>*/
55 #  define CharToOem CharToOemA
56 #endif
57 
58 #ifdef HAS_UNISTD_H
59 #include <unistd.h>
60 #endif
61 
62 #ifdef HAS_IO_H
63 #include <io.h>
64 #endif
65 
66 #if defined(__OS2__)
67 #include <os2.h>
68 #endif
69 
70 #ifdef HAS_DOS_H
71 #include <dos.h>
72 #endif
73 
74 #if  defined(__NT__)
75 /* we can't include windows.h for several reasons ... */
76 #define GetFileAttributes GetFileAttributesA
77 #endif
78 
79 /* huskylib */
80 #include <huskylib/huskylib.h>
81 #include <huskylib/cvtdate.h>
82 #include <huskylib/dirlayer.h>
83 
84 /* smapi */
85 #include <smapi/msgapi.h>
86 
87 /* fidoconf */
88 #include <fidoconf/fidoconf.h>
89 #include <fidoconf/common.h>
90 #include <huskylib/dirlayer.h>
91 #include <huskylib/xstr.h>
92 #include <fidoconf/afixcmd.h>
93 #include <huskylib/temp.h>
94 #include <huskylib/recode.h>
95 #include <fidoconf/stat.h>
96 #include <areafix/areafix.h>
97 #include <areafix/query.h>
98 
99 #if defined(A_HIDDEN) && !defined(_A_HIDDEN)
100 #define _A_HIDDEN A_HIDDEN
101 #endif
102 
103 #ifdef USE_HPTZIP
104 #   include <hptzip/hptzip.h>
105 #endif
106 
107 /* hpt */
108 #include <pkt.h>
109 #include <scan.h>
110 #include <toss.h>
111 #include <global.h>
112 #include <seenby.h>
113 #include <dupe.h>
114 #include <version.h>
115 #include <scanarea.h>
116 #include <fcommon.h>
117 #include <hpt.h>
118 #ifdef DO_PERL
119 #include <hptperl.h>
120 #endif
121 
122 
123 #if defined(__MINGW32__) || (defined(__WATCOMC__) && (__WATCOMC__ < 1100))
124 #define NOSLASHES
125 #endif
126 
127 #ifdef DO_PERL
128 extern int perl_setattr; /* perl.c */
129 #endif
130 
131 
132 extern s_message **msgToSysop;
133 int save_err;
134 
135 static ULONG nopenpkt, maxopenpkt;
136 
137 s_statToss statToss;
138 int forwardPkt(const char *fileName, s_pktHeader *header, e_tossSecurity sec);
139 int processDir(char *directory, e_tossSecurity sec);
140 void makeMsgToSysop(char *areaName, hs_addr fromAddr, ps_addr uplinkAddr);
141 static void setmaxopen(void);
142 
143 char *(BadmailReasonString[BM_MAXERROR+1]) = {
144 /* 0*/"No reason",
145 /* 1*/"System not allowed to create new area",
146 /* 2*/"Sender not allowed to post in this area (access group)",
147 /* 3*/"Sender not allowed to post in this area (access level)",
148 /* 4*/"Sender not allowed to post in this area (access import)",
149 /* 5*/"Sender not active for this area",
150 /* 6*/"Rejected by perl filter",
151 /* 7*/"MSGAPI error",
152 /* 8*/"Can't create echoarea with forbidden symbols in areatag",
153 /* 9*/"Sender not found in config file",
154 /*10*/"Can't open config file",
155 /*11*/"No downlinks for passthrough area",
156 /*12*/"Length of CONFERENCE name is more than 60 symbols",
157 /*13*/"Area killed (unsubscribed)",
158 /*14*/"New area refused by NewAreaRefuseFile",
159 /*15*/"Wrong link to autocreate from (area requested from other link)",
160 /*16*/"Area is paused (unsubscribed at uplink)",
161 /*17*/"No valid areatag is given in the message",
162 /*18*/"Can't create subdirectories for echobase",
163 /*19*/"Mail considered to be too old",
164 /*20*/"Mail considered to be too new"
165 };
166 
167 
get_filename(char * pathname)168 static char *get_filename(char *pathname)
169 {
170     char *ptr = NULL;
171 
172     if (pathname == NULL || !(*pathname))
173         return pathname;
174 
175     ptr = pathname + strlen(pathname) - 1;
176 
177     while (*ptr != '/' && *ptr != '\\' && *ptr != ':' && ptr != pathname)
178         ptr--;
179 
180     if (*ptr == '/' || *ptr == '\\' || *ptr == ':')
181         ptr++;
182 
183     return ptr;
184 }
185 
186 
187 /* return value: 1 if success, 0 if fail */
putMsgInArea(s_area * echo,s_message * msg,int strip,dword forceattr)188 int putMsgInArea(s_area *echo, s_message *msg, int strip, dword forceattr)
189 {
190     char *ctrlBuff = NULL, *textStart = NULL, *textWithoutArea = NULL;
191     UINT textLength = (UINT) msg->textLength;
192     /* HAREA harea = NULL; */
193     HMSG  hmsg;
194     XMSG  xmsg;
195     char /**slash,*/ *p, *q, *tiny;
196     int rc = 0;
197     int recode = 1;
198 
199     if (echo->msgbType==MSGTYPE_PASSTHROUGH) {
200         w_log(LL_ERR, "Can't put message to passthrough area %s!", echo->areaName);
201         return rc;
202     }
203 
204     if (!msg->netMail) {
205 	msg->destAddr.zone  = echo->useAka->zone;
206 	msg->destAddr.net   = echo->useAka->net;
207 	msg->destAddr.node  = echo->useAka->node;
208 	msg->destAddr.point = echo->useAka->point;
209     }
210 #ifdef DO_PERL
211     switch( perl_putmsg(echo, msg) ) {
212         case 0 : return 1;
213         case 2 : recode = 0;
214         default: textLength = (UINT)msg->textLength;
215     }
216 #endif
217 
218     if (maxopenpkt == 0) setmaxopen();
219 
220     if (echo->harea == NULL) {
221     w_log( LL_SRCLINE, "%s:%d opening %s", __FILE__, __LINE__,echo->fileName);
222 	echo->harea = MsgOpenArea((UCHAR *) echo->fileName, MSGAREA_CRIFNEC,
223 			(word)(echo->msgbType | (msg->netMail ? 0 : MSGTYPE_ECHO)));
224 	if (echo->harea) nopenpkt+=3;
225     }
226     if (echo->harea != NULL) {
227     w_log( LL_SRCLINE, "%s:%d creating msg", __FILE__, __LINE__);
228 	hmsg = MsgOpenMsg(getHAREA(echo->harea), MOPEN_CREATE, 0);
229 	if (hmsg != NULL) {
230 
231 	    /*  recode from TransportCharset to internal Charset */
232 	    if ((config->recodeMsgBase) && (recode && config->intab != NULL)) {
233 		if ((msg->recode & REC_HDR)==0) {
234 		    recodeToInternalCharset((char*)msg->fromUserName);
235 		    recodeToInternalCharset((char*)msg->toUserName);
236 		    recodeToInternalCharset((char*)msg->subjectLine);
237 		    msg->recode |= REC_HDR;
238 		}
239 		if ((msg->recode & REC_TXT)==0) {
240 		    recodeToInternalCharset((char*)msg->text);
241 		    msg->recode |= REC_TXT;
242 		}
243 	    }
244 
245 	    textWithoutArea = msg->text;
246 
247 	    if ((strip==1) && (strncmp(msg->text, "AREA:", 5) == 0)) {
248 		/*  jump over AREA:xxxxx\r */
249 		while (*(textWithoutArea) != '\r') textWithoutArea++;
250 		textWithoutArea++;
251 		textLength -= (size_t) (textWithoutArea - msg->text);
252 	    }
253 	    if (echo->killSB) {
254 		tiny = strrstr(textWithoutArea, " * Origin:");
255 		if (tiny == NULL) tiny = textWithoutArea;
256 		if (NULL != (p = strstr(tiny, "\rSEEN-BY: "))) {
257 		    p[1]='\0';
258 		    textLength = (size_t) (p - textWithoutArea + 1);
259 		}
260 	    } else if (echo->tinySB) {
261 		tiny = strrstr(textWithoutArea, " * Origin:");
262 		if (tiny == NULL) tiny = textWithoutArea;
263 		if (NULL != (p = strstr(tiny, "\rSEEN-BY: "))) {
264 		    p++;
265 		    if (NULL != (q = strstr(p,"\001PATH: "))) {
266 			/*  memmove(p,q,strlen(q)+1); */
267 			memmove(p,q,textLength-(size_t)(q-textWithoutArea)+1);
268 			textLength -= (size_t) (q - p);
269 		    } else {
270 			p[0]='\0';
271 			textLength = (size_t) (p - textWithoutArea);
272 		    }
273 		}
274 	    }
275 	    ctrlBuff = (char *) CopyToControlBuf((UCHAR *) textWithoutArea,
276 						 (UCHAR **)&textStart,
277 						 &textLength);
278 	    /*  textStart is a pointer to the first non-kludge line */
279 	    xmsg = createXMSG(config,msg, NULL, forceattr,tossDir);
280         w_log( LL_SRCLINE, "%s:%d writing msg", __FILE__, __LINE__);
281 	    if (MsgWriteMsg(hmsg, 0, &xmsg, (byte *) textStart, (dword)
282 			    textLength, (dword) textLength,
283 			    (dword)strlen(ctrlBuff), (byte*)ctrlBuff)!=0)
284 		w_log(LL_ERR, "Could not write msg in %s! Check the wholeness of messagebase, please.", echo->fileName);
285 	    else rc = 1; /*  normal exit */
286 
287         w_log( LL_SRCLINE, "%s:%d closing msg", __FILE__, __LINE__);
288 	    if (MsgCloseMsg(hmsg)!=0) {
289 		w_log(LL_ERR, "Could not close msg in %s!", echo->fileName);
290 		rc = 0;
291 	    }
292 	    nfree(ctrlBuff);
293 
294 	} else w_log(LL_ERR, "Could not create new msg in %s!", echo->fileName);
295 	/* endif */
296 	if (nopenpkt>=maxopenpkt-12) {
297         w_log( LL_SRCLINE, "%s:%d closing %s", __FILE__, __LINE__,echo->fileName);
298 	    MsgCloseArea(getHAREA(echo->harea));
299 	    echo->harea = NULL;
300 	    nopenpkt-=3;
301 	}
302     } else w_log(LL_ERR, "Could not open/create EchoArea %s!", echo->fileName);
303     /* endif */
304     w_log( LL_SRCLINE, "%s:%d end rc=%d", __FILE__, __LINE__,rc);
305     return rc;
306 }
307 
closeOpenedPkt(void)308 void closeOpenedPkt(void) {
309     unsigned int i;
310 
311     for (i=0; i<config->linkCount; i++)
312 	if (config->links[i]->pkt) {
313 	    if (closeCreatedPkt(config->links[i]->pkt))
314 		w_log(LL_ERR,"can't close pkt: %s", config->links[i]->pktFile);
315 	    config->links[i]->pkt = NULL;
316 	    nopenpkt--;
317 	}
318     for (i=0; i<config->echoAreaCount; i++)
319 	if (getHAREA(config->echoAreas[i].harea)) {
320         w_log( LL_SRCLINE, "%s:%d closing %s", __FILE__, __LINE__,config->echoAreas[i].fileName);
321 	    MsgCloseArea(getHAREA(config->echoAreas[i].harea));
322 	    config->echoAreas[i].harea = NULL;
323 	    nopenpkt-=3;
324 	}
325     for (i=0; i<config->netMailAreaCount; i++)
326 	if (getHAREA(config->netMailAreas[i].harea)) {
327         w_log( LL_SRCLINE, "%s:%d closing %s", __FILE__, __LINE__,config->netMailAreas[i].fileName);
328 	    MsgCloseArea(getHAREA(config->netMailAreas[i].harea));
329 	    config->netMailAreas[i].harea = NULL;
330 	    nopenpkt-=3;
331     }
332     for (i=0; i<config->localAreaCount; i++)
333     {
334         if (getHAREA(config->localAreas[i].harea)) {
335             w_log( LL_SRCLINE, "%s:%d closing %s", __FILE__, __LINE__,config->localAreas[i].fileName);
336             MsgCloseArea(getHAREA(config->localAreas[i].harea));
337             config->localAreas[i].harea = NULL;
338             nopenpkt-=3;
339         }
340     }
341     if (getHAREA(config->badArea.harea)) {
342         w_log( LL_SRCLINE, "%s:%d closing %s", __FILE__, __LINE__,config->badArea.fileName);
343         MsgCloseArea(getHAREA(config->badArea.harea));
344         config->badArea.harea = NULL;
345         nopenpkt-=3;
346     }
347     if (getHAREA(config->dupeArea.harea)) {
348         w_log( LL_SRCLINE, "%s:%d closing %s", __FILE__, __LINE__,config->dupeArea.fileName);
349         MsgCloseArea(getHAREA(config->dupeArea.harea));
350         config->dupeArea.harea = NULL;
351         nopenpkt-=3;
352     }
353 }
354 
forwardToLinks(s_message * msg,s_area * echo,s_arealink ** newLinks,s_seenBy ** seenBys,UINT * seenByCount,s_seenBy ** path,UINT * pathCount)355 void forwardToLinks(s_message *msg, s_area *echo, s_arealink **newLinks,
356 		    s_seenBy **seenBys, UINT *seenByCount,
357 		    s_seenBy **path, UINT *pathCount) {
358     unsigned  int i, rc=0;
359     ULONG len;
360     FILE *f=NULL;
361     s_pktHeader header;
362     char *start = NULL, *text = NULL, *seenByText = NULL, *pathText = NULL;
363     char *debug=NULL;
364 
365     if (newLinks[0] == NULL) return;
366 
367     if (echo->debug) {
368 	xstrscat(&debug, config->logFileDir,
369 		 (echo->DOSFile) ? "common" : echo->areaName,
370 		 ".dbg", NULLP);
371 
372 	if (config->areasFileNameCase == eLower)
373 	    debug = strLower(debug);
374 	else
375 	    debug = strUpper(debug);
376 
377 	if ((f=fopen(debug,"a"))==NULL) {
378 	    w_log(LL_ERR,"can't open file: %s",debug);
379 	}else w_log(LL_FILE,"toss.c:forwardToLinks(): opened %s (\"a\" mode)",debug);
380 	nfree(debug);
381     }
382 
383     if (echo->sbstripCount > 0)    /* strip SEEN-BYs */
384     {
385         stripSeenByArray(seenBys, seenByCount, echo->sbstrip, echo->sbstripCount);
386     }
387 
388     for (i=0; i<config->addToSeenCount; i++) {
389         (*seenByCount)++;
390         (*seenBys) = (s_seenBy*) safe_realloc(*seenBys,sizeof(s_seenBy)*(*seenByCount));
391         (*seenBys)[*seenByCount-1].net = (UINT16) config->addToSeen[i].net;
392         (*seenBys)[*seenByCount-1].node = (UINT16) config->addToSeen[i].node;
393     }
394     for (i=0; i<echo->sbaddCount; i++) {
395         (*seenByCount)++;
396         (*seenBys) = (s_seenBy*) safe_realloc(*seenBys,sizeof(s_seenBy)*(*seenByCount));
397         (*seenBys)[*seenByCount-1].net = (UINT16) echo->sbadd[i].net;
398         (*seenBys)[*seenByCount-1].node = (UINT16) echo->sbadd[i].node;
399     }
400 
401     /*  add our aka to seen-by (zonegating link must strip our aka) */
402     if (echo->useAka->point==0) {
403 
404 	for (i=0; i < *seenByCount; i++) {
405 	    if ((*seenBys)[i].net == echo->useAka->net &&
406 		(*seenBys)[i].node == echo->useAka->node) break;
407 	}
408 
409 	if (*seenByCount==i) {
410 	    (*seenBys) = (s_seenBy*)
411 		safe_realloc((*seenBys), sizeof(s_seenBy) * (*seenByCount+1));
412 	    (*seenBys)[*seenByCount].net = (UINT16) echo->useAka->net;
413 	    (*seenBys)[*seenByCount].node = (UINT16) echo->useAka->node;
414 	    (*seenByCount)++;
415 	}
416     }
417 
418     /*  add seenBy for newLinks */
419     for (i=0; i<echo->downlinkCount; i++) {
420 
421         /*  no link at this index -> break */
422         if (newLinks[i] == NULL) break;
423         /*  don't include points in SEEN-BYs */
424         if (newLinks[i]->link->hisAka.point != 0) continue;
425         /*  fix for IgnoreSeen & -sbign */
426         if (newLinks[i]->link->sb == 1) continue;
427 
428         (*seenBys) = (s_seenBy*) safe_realloc((*seenBys), sizeof(s_seenBy) * (*seenByCount+1));
429         (*seenBys)[*seenByCount].net = (UINT16) newLinks[i]->link->hisAka.net;
430         (*seenBys)[*seenByCount].node = (UINT16) newLinks[i]->link->hisAka.node;
431         (*seenByCount)++;
432     }
433 
434     sortSeenBys((*seenBys), *seenByCount);
435 
436 #ifdef DEBUG_HPT
437     for (i=0; i< *seenByCount;i++) printf("%u/%u ", (*seenBys)[i].net, (*seenBys)[i].node);
438 #endif
439 
440     if (*pathCount > 0) {
441         if (((*path)[*pathCount-1].net != echo->useAka->net) ||
442             ((*path)[*pathCount-1].node != echo->useAka->node)) {
443             /*  add our aka to path */
444             (*path) = (s_seenBy*) safe_realloc((*path), sizeof(s_seenBy) * (*pathCount+1));
445             (*path)[*pathCount].net = (UINT16) echo->useAka->net;
446             (*path)[*pathCount].node = (UINT16) echo->useAka->node;
447             (*pathCount)++;
448         }
449     } else {
450         (*pathCount) = 0;
451         (*path) = (s_seenBy*) safe_realloc((*path),sizeof(s_seenBy));
452         (*path)[*pathCount].net = (UINT16) echo->useAka->net;
453         (*path)[*pathCount].node = (UINT16) echo->useAka->node;
454         (*pathCount) = 1;
455     }
456 
457 #ifdef DEBUG_HPT
458     for (i=0; i< *pathCount;i++) printf("%u/%u ", (*path)[i].net, (*path)[i].node);
459 #endif
460 
461     text = strrstr(msg->text, " * Origin:"); /*  jump over Origin */
462     if (text) { /*  origin was found */
463         start = strrchr(text, ')');
464         if (start) start++; /*  normal origin */
465         else {
466             start = text; /*  broken origin */
467             while(*start && *start!='\r') start++;
468         }
469         *start='\0';
470     } else { /*  no Origin found */
471         text = msg->text;
472         start = strstr(text, "\rSEEN-BY: ");
473         if (start == NULL) start = strstr(text, "SEEN-BY: ");
474         if (start) *start='\0';
475         /*  find start of PATH in Msg */
476         start = strstr(text, "\001PATH: ");
477         if (start) *start='\0';
478         else start = text+strlen(text);
479     }
480     msg->textLength = (size_t) (start - msg->text);
481 
482 	/*  create new seenByText */
483     seenByText = createControlText(*seenBys, *seenByCount, "SEEN-BY: ");
484     pathText   = createControlText(*path, *pathCount, "\001PATH: ");
485     xstrscat(&msg->text, "\r", seenByText, pathText, NULLP);
486     msg->textLength += 1 + strlen(seenByText) + strlen(pathText);
487     nfree(seenByText);
488     nfree(pathText);
489 
490     if (echo->debug) {
491 	debug = (char *) GetCtrlToken((byte *)msg->text, (byte *)"MSGID");
492 	if (f && debug) {
493 	    fputs("\n[",f);
494 	    fputs(debug,f);
495 	    fputs("] ",f);
496 	}
497 	nfree(debug);
498     }
499 
500     /*  add msg to the pkt's of the downlinks */
501     if (maxopenpkt == 0) setmaxopen();
502     for (i = 0; i<echo->downlinkCount; i++) {
503 
504         /*  no link at this index -> break; */
505         if (newLinks[i] == NULL) break;
506 #ifdef DO_PERL
507         if ( !perl_export(echo, newLinks[i]->link, msg) ) continue;
508 #endif
509         /*  check packet size */
510         if (newLinks[i]->link->pktFile != NULL && newLinks[i]->link->pktSize != 0) {
511             len = newLinks[i]->link->pkt ? ftell(newLinks[i]->link->pkt) : fsize(newLinks[i]->link->pktFile);
512             if (len >= (newLinks[i]->link->pktSize * 1024L)) { /*  Stop writing to pkt */
513                 if (newLinks[i]->link->pkt) {
514                     fclose(newLinks[i]->link->pkt);
515                     newLinks[i]->link->pkt = NULL;
516                     nopenpkt--;
517                 }
518                 nfree(newLinks[i]->link->pktFile);
519                 nfree(newLinks[i]->link->packFile);
520             }
521         }
522 
523         /*  create pktfile if necessary */
524         if (newLinks[i]->link->pktFile == NULL) {
525             /*  pktFile does not exist */
526             if ( createTempPktFileName(newLinks[i]->link) )
527                 exit_hpt("Could not create new pkt!",1);
528         }
529 
530         makePktHeader(NULL, &header);
531         header.origAddr = *(newLinks[i]->link->ourAka);
532         header.destAddr = newLinks[i]->link->hisAka;
533         if (newLinks[i]->link->pktPwd != NULL)
534             strcpy(header.pktPassword, newLinks[i]->link->pktPwd);
535         if (newLinks[i]->link->pkt == NULL) {
536             newLinks[i]->link->pkt = openPktForAppending(newLinks[i]->link->pktFile, &header);
537             nopenpkt++;
538         }
539 
540         /*  an echomail msg must be adressed to the link */
541         msg->destAddr = header.destAddr;
542         /*  .. and must come from us */
543         msg->origAddr = header.origAddr;
544         rc += writeMsgToPkt(newLinks[i]->link->pkt, *msg);
545         if (rc)
546         {
547             w_log(LL_ERR,"can't write msg to pkt: %s", newLinks[i]->link->pktFile);
548             exit_hpt("Can't write msg to pkt!", 1);
549         }
550         if (nopenpkt >= maxopenpkt-12 || /*  std streams, in pkt, msgbase, log */
551             (newLinks[i]->link->pktSize && ftell(newLinks[i]->link->pkt)>= (long)newLinks[i]->link->pktSize*1024L)) {
552             rc += closeCreatedPkt(newLinks[i]->link->pkt);
553             if (rc) w_log(LL_ERR,"can't close pkt: %s",
554                 newLinks[i]->link->pktFile);
555             newLinks[i]->link->pkt = NULL;
556             nopenpkt--;
557         }
558         if (f) {
559             if (rc) fputs(" failed: ",f);
560             fputs(aka2str(header.destAddr),f);
561             fputc('>',f);
562             fputs(get_filename(newLinks[i]->link->pktFile),f);
563             fputc(' ',f);
564         }
565         if (rc==0) statToss.exported++;
566         else rc=0;
567 #ifdef ADV_STAT
568         if (config->advStatisticsFile != NULL) put_stat(echo, &(header.destAddr), stOUT, msg->textLength+strlen(msg->text+msg->textLength));
569 #endif
570     }
571 
572     if (f) fclose(f);
573     return;
574 }
575 
forwardMsgToLinks(s_area * echo,s_message * msg,hs_addr pktOrigAddr)576 void forwardMsgToLinks(s_area *echo, s_message *msg, hs_addr pktOrigAddr)
577 {
578     s_seenBy *seenBys = NULL, *tempSeenBys = NULL, *path = NULL;
579     UINT     seenByCount = 0 , tempSeenByCount = 0, pathCount = 0;
580 
581     /*  links who does not have their aka in seenBys and thus have not got the echomail */
582     s_arealink **newLinks = NULL, **zoneLinks = NULL, **otherLinks = NULL;
583 
584     createSeenByArrayFromMsg(echo, msg, &seenBys, &seenByCount);
585     createPathArrayFromMsg(msg, &path, &pathCount);
586 
587     createNewLinkArray(seenBys, seenByCount, echo, &newLinks, &zoneLinks, &otherLinks, pktOrigAddr);
588 
589     if(newLinks)
590         forwardToLinks(msg, echo, newLinks, &seenBys, &seenByCount, &path, &pathCount);
591 
592     if (zoneLinks) {
593         /* strip SEEN-BYs when zone-gating and sbkeepAll is disabled */
594         if ((echo->sbkeep_all == 0) && (echo->useAka->zone != pktOrigAddr.zone)) {
595             if (echo->sbkeepCount == 0) {
596                 seenByCount = 0;        /* strip all SEEN-BYs */
597             }
598             else {
599                 /* keep SEEN-BYs found in sbkeep */
600                 createFilteredSeenByArray(seenBys, seenByCount, &tempSeenBys,
601                     &tempSeenByCount, echo->sbkeep, echo->sbkeepCount);
602                 nfree(seenBys);
603                 seenBys = tempSeenBys;
604                 seenByCount = tempSeenByCount;
605             }
606         }
607 
608         forwardToLinks(msg, echo, zoneLinks, &seenBys, &seenByCount, &path, &pathCount);
609     }
610 
611     if(otherLinks)
612     {
613         nfree(seenBys);
614         seenBys = memdup( path, sizeof(s_seenBy) * pathCount );
615         seenByCount = pathCount;
616         forwardToLinks(msg, echo, otherLinks, &seenBys, &seenByCount, &path, &pathCount);
617     }
618 
619     nfree(seenBys);
620     nfree(path);
621     nfree(newLinks);
622     nfree(zoneLinks);
623     nfree(otherLinks);
624 }
625 
626 /* return value: 1 if success, 0 if fail */
627 /* writeAccess MUST BE unsigned !!! */
putMsgInBadArea(s_message * msg,hs_addr pktOrigAddr,unsigned writeAccess)628 int putMsgInBadArea(s_message *msg, hs_addr pktOrigAddr, unsigned writeAccess)
629 {
630     char *tmp = NULL, *line = NULL, *textBuff=NULL, *areaName=NULL, *reason=NULL;
631     char buff[128] = "";
632 
633     w_log(LL_FUNC, "putMsgInBadArea() begin");
634     statToss.bad++;
635 
636     /*  get real name area */
637     line = strchr(msg->text, '\r');
638     if(line == NULL || strncmp(msg->text,"AREA:",5)!=0)
639         areaName = xstrcat(&areaName, "no areatag");
640 	else {
641 	*line = 0;
642 	xstrcat(&areaName, msg->text+5);
643 	*line = '\r';
644     }
645 
646     if(writeAccess>BM_MAXERROR){
647         reason = "Another error";
648     }else if(writeAccess==BM_MSGAPI_ERROR){
649 	reason = strncat( strcpy(buff,"MSGAPIERR: "), strmerr(msgapierr), sizeof(buff)-sizeof("MSGAPIERR: ") );
650     }else{
651         reason = BadmailReasonString[writeAccess];
652     }
653     w_log(LL_ECHOMAIL, "Badmail reason: %s (AREA: %s)", reason, areaName);
654 
655 #ifdef DO_PERL
656     if (perltossbad(msg, areaName, pktOrigAddr, reason)) {
657 	nfree(areaName);
658 	nfree(msg->text);
659         w_log(LL_FUNC, "putMsgInBadArea():perltossbad OK (rc=1)");
660 	return 1;
661     }
662 #endif
663 
664     tmp = msg->text;
665 
666     while ((line = strchr(tmp, '\r')) != NULL) {
667 	if (*(line+1) == '\x01') tmp = line+1;
668 	else { tmp = line+1; *line = 0; break; }
669     }
670 
671     xstrscat(&textBuff, msg->text, "\rFROM: ", aka2str(pktOrigAddr), "\rREASON: ", reason, "\r", NULLP);
672 
673     if (areaName) xscatprintf(&textBuff, "AREANAME: %s\r\r", areaName);
674     xstrcat(&textBuff, tmp);
675     nfree(areaName);
676     nfree(msg->text);
677     msg->text = textBuff;
678     msg->textLength = strlen(msg->text);
679     if (putMsgInArea(&(config->badArea), msg, 0, 0)) {
680 	config->badArea.imported++;
681         w_log(LL_FUNC, "putMsgInBadArea() OK");
682 	return 1;
683     }
684     w_log(LL_FUNC, "putMsgInBadArea() failed");
685     return 0;
686 }
687 
makeMsgToSysop(char * areaName,hs_addr fromAddr,ps_addr uplinkAddr)688 void makeMsgToSysop(char *areaName, hs_addr fromAddr, ps_addr uplinkAddr)
689 {
690     s_area *echo = NULL;
691     unsigned int i, netmail=0;
692     char *buff=NULL;
693     char *strbeg=NULL;
694 
695     if (config->ReportTo) {
696         if (stricmp(config->ReportTo,"netmail")==0) netmail=1;
697         else if (getNetMailArea(config, config->ReportTo) != NULL) netmail=1;
698     } else netmail=1;
699 
700     echo = getArea(config, areaName);
701 
702     if (echo == &(config->badArea)) return;
703 
704     for (i = 0; i < config->addrCount; i++) {
705         if (echo->useAka == &(config->addr[i])) {
706             if (msgToSysop[i] == NULL) {
707 
708                 msgToSysop[i] = makeMessage(echo->useAka,
709                     echo->useAka,
710                     robot->fromName ? robot->fromName : versionStr,
711                     netmail ? (config->sysop ? config->sysop : "Sysop") : "All", "Created new areas",
712                     netmail,
713                     robot->reportsAttr);
714                 msgToSysop[i]->text = createKludges(config,
715                     netmail ? NULL : config->ReportTo,
716                     echo->useAka, echo->useAka,
717                     versionStr);
718 
719 		if (robot->reportsFlags)
720 		    xstrscat(&(msgToSysop[i]->text), "\001FLAGS ",
721 		             robot->reportsFlags, "\r", NULLP);
722                 xstrscat(&(msgToSysop[i]->text), "Action   Name",
723                          print_ch(49, ' '), "By\r", NULLP);
724                 /*  Shitty static variables .... */
725                 xstrscat(&(msgToSysop[i]->text), print_ch(79, '-'), "\r", NULLP);
726                 msgToSysop[i]->recode |= (REC_HDR|REC_TXT);
727                 w_log(LL_NETMAIL,"Created msg to sysop");
728             }
729 
730             /*           New report generation */
731             buff = safe_strdup("");
732             if (config->reportRequester) xstrcat(&buff, aka2str(fromAddr));
733             if (uplinkAddr != NULL) { /*  autocreation with forward request */
734                 xstrscat(&buff, " from ", aka2str(*uplinkAddr), NULLP);
735             }
736             xstrscat(&strbeg, "Created  ", echo->areaName, NULLP);
737 
738             if (echo->description) {
739                 if (strlen(strbeg) + strlen(echo->description) >=77) {
740                     xstrscat(&(msgToSysop[i]->text), strbeg, "\r", NULLP);
741                     nfree(strbeg);
742                     xstrcat(&strbeg, print_ch(9, ' '));
743                 } else {
744                     xstrcat(&strbeg, " ");
745                 }
746                 xstrscat(&strbeg, "\"", echo->description, "\"", NULLP);
747             }
748 
749             xstrcat(&(msgToSysop[i]->text), strbeg);
750 
751             if (strlen(strbeg) + strlen(buff) >= 79) {
752                 xstrscat(&(msgToSysop[i]->text), "\r", print_ch(79-strlen(buff), ' '), buff, "\r", NULLP);
753             } else if (strlen(strbeg) <62 && strlen(buff) < 79-62) { /*  most beautiful */
754                 xstrscat(&(msgToSysop[i]->text), print_ch(62-strlen(strbeg), ' '), buff, "\r", NULLP);
755             } else {
756                 xstrscat(&(msgToSysop[i]->text), print_ch(79-strlen(strbeg)-strlen(buff), ' '), buff, "\r", NULLP);
757             }
758             nfree(buff);
759             nfree(strbeg);
760 
761             break;
762         }
763     }
764 
765 }
766 
writeMsgToSysop()767 void writeMsgToSysop()
768 {
769     char	*ptr = NULL, *seenByPath = NULL;
770     s_area	*echo = NULL;
771     unsigned int i, ccrc = 0;
772     s_seenBy	*seenBys = NULL;
773 
774     for (i = 0; i < config->addrCount; i++) {
775         if (msgToSysop[i]) {
776             xscatprintf(&(msgToSysop[i]->text), " \r--- %s\r * Origin: %s (%s)\r",
777                 (config->tearline) ? config->tearline : "",
778                 (config->origin) ? config->origin : config->name,
779                 aka2str(msgToSysop[i]->origAddr));
780             msgToSysop[i]->textLength = strlen(msgToSysop[i]->text);
781 
782 #ifdef DO_PERL
783             perl_robotmsg(msgToSysop[i], "tosysop");
784 #endif
785 
786             if (msgToSysop[i]->netMail == 1)
787             {
788                 /*  FIXME: should be putMsgInArea */
789                 processNMMsg(msgToSysop[i], NULL, config->ReportTo ?
790                              getNetMailArea(config, config->ReportTo) : NULL, 1, 0);
791                 writeEchoTossLogEntry(config->ReportTo?config->ReportTo:config->netMailAreas[0].areaName);
792             }
793             else {
794                 /*  get echoarea  for this msg */
795                 ptr = strchr(msgToSysop[i]->text, '\r');
796                 *ptr = '\0'; echo = getArea(config, msgToSysop[i]->text + 5); *ptr = '\r';
797 
798                 if (echo != &(config->badArea)) {
799                     if (config->carbonCount != 0)
800                         ccrc = carbonCopy(msgToSysop[i], NULL, echo);
801                     if (echo->msgbType != MSGTYPE_PASSTHROUGH && ccrc <= 1) {
802                         putMsgInArea(echo, msgToSysop[i],1, (MSGSCANNED|MSGSENT|MSGLOCAL));
803                         echo->imported++;  /*  area has got new messages */
804                     }
805 
806                     seenBys = (s_seenBy*) safe_malloc(sizeof(s_seenBy)*(echo->downlinkCount+1));
807                     seenBys[0].net = (UINT16) echo->useAka->net;
808                     seenBys[0].node = (UINT16) echo->useAka->node;
809                     sortSeenBys(seenBys, 1);
810 
811                     seenByPath = createControlText(seenBys, 1, "SEEN-BY: ");
812                     nfree(seenBys);
813 
814                     /*  path line */
815                     /*  only include node-akas in path */
816                     if (echo->useAka->point == 0)
817                         xscatprintf(&seenByPath, "\001PATH: %u/%u\r", echo->useAka->net, echo->useAka->node);
818                     xstrcat(&(msgToSysop[i]->text), seenByPath);
819                     nfree(seenByPath);
820                     if (echo->downlinkCount > 0) {
821                         /*  recoding from internal to transport charSet */
822                         if (config->outtab) {
823                             if (msgToSysop[i]->recode & REC_HDR) {
824                                 recodeToTransportCharset((char*)msgToSysop[i]->fromUserName);
825                                 recodeToTransportCharset((char*)msgToSysop[i]->toUserName);
826                                 recodeToTransportCharset((char*)msgToSysop[i]->subjectLine);
827                                 msgToSysop[i]->recode &= ~REC_HDR;
828                             }
829                             if (msgToSysop[i]->recode & REC_TXT) {
830                                 recodeToTransportCharset((char*)msgToSysop[i]->text);
831                                 msgToSysop[i]->recode &= ~REC_TXT;
832                             }
833                         }
834                         forwardMsgToLinks(echo, msgToSysop[i], msgToSysop[i]->origAddr);
835                         closeOpenedPkt();
836                         writeEchoTossLogEntry(echo->areaName);
837                         tossTempOutbound(config->tempOutbound);
838                     }
839                 } else {
840                     putMsgInBadArea(msgToSysop[i], msgToSysop[i]->origAddr, 0);
841                 }
842             }
843         }
844     }
845 
846 }
847 
processEMMsg(s_message * msg,hs_addr pktOrigAddr,int dontdocc,dword forceattr)848 int processEMMsg(s_message *msg, hs_addr pktOrigAddr, int dontdocc, dword forceattr)
849 {
850     char   *area=NULL, *p = NULL, *q = NULL;
851     s_message* messCC = NULL;
852     s_area *echo=&(config->badArea);
853     s_link *link = NULL;
854     unsigned int days = 0;
855     struct tm msg_tm;
856     time_t msgTime, diffTime;
857     flag_t tFlag;
858     int    writeAccess = 0, rc = 0, ccrc = 0;
859 
860     w_log(LL_FUNC, "%s::processEMMsg() begin", __FILE__);
861 
862     p = strchr(msg->text,'\r');
863     if (p) {
864 	*p='\0';
865 	q = msg->text+5;
866 	while (*q == ' ') q++;
867 	xstrcat(&area, q);
868 	echo = getArea(config, area);
869 	*p='\r';
870     }
871 
872     link = getLinkFromAddr(config, pktOrigAddr);
873 
874     /*  no area found -- trying to autocreate echoarea */
875     if (echo == &(config->badArea)) {
876         /*  check if we should not refuse this area */
877         /*  checking for autocreate option */
878         if ((link != NULL) && (link->areafix.autoCreate != 0)) {
879             if (BM_MAIL_OK == (writeAccess = autoCreate(area, NULL, pktOrigAddr, NULL)))
880                 echo = getArea(config, area);
881             else rc = putMsgInBadArea(msg, pktOrigAddr, writeAccess);
882         } /*  can't create echoarea - put msg in BadArea */
883         else rc = putMsgInBadArea(msg, pktOrigAddr, writeAccess);
884     }
885 
886     nfree(area);
887 
888     if (echo != &(config->badArea)) {
889         /*  area is autocreated! */
890 
891         /*  cheking access of this link */
892         writeAccess = checkAreaLink(echo, pktOrigAddr, 0);
893         if (writeAccess)
894         {
895             rc = putMsgInBadArea(msg, pktOrigAddr, writeAccess);
896 #ifdef ADV_STAT
897             if (config->advStatisticsFile != NULL) put_stat(echo, &pktOrigAddr, stBAD, 0);
898 #endif
899             /* notify link about bad post */
900             if ((link != NULL) && (link->sendNotifyMessages)) {
901                 s_message *tmpmsg;
902                 char *reason = NULL;
903 
904                 if (writeAccess > BM_MAXERROR) {
905                     reason = "Unknown error";
906                 } else {
907                     reason = BadmailReasonString[writeAccess];
908                 }
909 
910                 tmpmsg = makeMessage(link->ourAka, &(link->hisAka),
911                     robot->fromName ? robot->fromName : versionStr,
912                     link->name, "Notification message", 1,
913                     link->areafix.reportsAttr ? link->areafix.reportsAttr : robot->reportsAttr);
914                 tmpmsg->text = createKludges(config, NULL, link->ourAka,
915                     &(link->hisAka), versionStr);
916                 if (link->areafix.reportsFlags)
917                     xstrscat(&(tmpmsg->text), "\001FLAGS ", link->areafix.reportsFlags, "\r",NULLP);
918                 else if (robot->reportsFlags)
919                     xstrscat(&(tmpmsg->text), "\001FLAGS ", robot->reportsFlags, "\r",NULLP);
920 
921                 xstrcat(&tmpmsg->text, "\r Your message was moved to badmail with the following reason:\r\r");
922                 xscatprintf(&tmpmsg->text, " %s\r\r", reason);
923                 xstrcat(&tmpmsg->text, " Header of original message:\r\r");
924                 xscatprintf(&tmpmsg->text, "      Area: %s\r", echo->areaName);
925                 xscatprintf(&tmpmsg->text, "      Date: %s\r", msg->datetime);
926                 xscatprintf(&tmpmsg->text, "      From: %s, %s\r", msg->fromUserName, aka2str(msg->origAddr));
927                 xscatprintf(&tmpmsg->text, "        To: %s\r", msg->toUserName);
928                 xscatprintf(&tmpmsg->text, "   Subject: %s\r", msg->subjectLine);
929                 xstrcat(&tmpmsg->text, "\r Please contact sysop if you think this is a mistake!\r");
930                 xscatprintf(&tmpmsg->text, "\r\r--- %s areafix\r", versionStr);
931 
932                 tmpmsg->textLength = strlen(tmpmsg->text);
933                 processNMMsg(tmpmsg, NULL, getRobotsArea(config), 0, MSGLOCAL);
934                 writeEchoTossLogEntry(getRobotsArea(config)->areaName);
935                 closeOpenedPkt();
936                 freeMsgBuffers(tmpmsg);
937                 nfree(tmpmsg);
938                 nfree(reason);
939 
940                 w_log( LL_AREAFIX, "areafix: write notification msg for %s",aka2str(link->hisAka));
941             }
942         }
943 
944         /* check age of message */
945         if (writeAccess == 0)                     /* ok to proceed */
946         {
947             /* get message age if tooOld or tooNew feature is enabled */
948             if ( (echo->tooOld > 0) || (echo->tooNew > 0) )
949             {
950                 /* get time from message */
951                 tFlag = parse_ftsc_date(&msg_tm, (char*)msg->datetime);
952                 if (! (tFlag & FTSC_BROKEN))
953                 {
954                     msgTime = mktime(&msg_tm);
955                     if (msgTime != (time_t)-1)
956                     {
957                         diffTime = abs(globalTime - msgTime);
958                         diffTime /= (60 * 60 * 24);          /* convert to days */
959                         days = (unsigned int)diffTime;
960                         /* tooOld */
961                         if ((echo->tooOld > 0) && globalTime > msgTime) {
962                             if (days > echo->tooOld) writeAccess = BM_TOO_OLD;
963                         }
964                         /* tooNew */
965                         else if ((echo->tooNew > 0) && globalTime < msgTime) {
966                             if (days > echo->tooNew) writeAccess = BM_TOO_NEW;
967                         }
968                     }
969                 }
970             }
971 
972             if (writeAccess)            /* on any problem move message to BadArea */
973             {
974                 rc = putMsgInBadArea(msg, pktOrigAddr, writeAccess);
975             }
976         }
977 
978         if (writeAccess == 0)                     /* ok to proceed */
979         { /*  access ok - process msg */
980 	    int not_dupe = 1;
981 
982 #ifdef DO_PERL
983 	    w_log(LL_SRCLINE, "toss.c:%u:processEMMsg() #ifdef DO_PERL", __LINE__);
984 	    if ((rc = perlfilter(msg, pktOrigAddr, -1)) == 1)
985 		return not_dupe = 0;
986 	    else if (rc == 2)
987 		return 1;
988 #endif
989 
990 	    if (not_dupe) not_dupe = dupeDetection(echo, *msg);
991             if (not_dupe) {
992                 /*  no dupe */
993 
994                 messCC = MessForCC(msg); /* make copy of original message */
995 
996                 statToss.echoMail++;
997 
998                 /*  if only one downlink, we've got the mail from him */
999                 if ((echo->downlinkCount > 1) ||
1000                     ((echo->downlinkCount > 0) &&
1001                     /*  mail from us */
1002                     (addrComp(pktOrigAddr,*echo->useAka)==0)))
1003                     forwardMsgToLinks(echo, msg, pktOrigAddr);
1004                 w_dbglog( LL_SRCLINE, "%s::processEMMsg():%d", __FILE__, __LINE__);
1005                 /* todo: remove TID from local-generated msgs by hpt post -x
1006                 * (if (addrComp(pktOrigAddr,*echo->useAka)==0)) */
1007 
1008                 if (messCC && !dontdocc)
1009                     ccrc=carbonCopy(messCC, NULL, echo);
1010                 w_dbglog( LL_SRCLINE, "%s::processEMMsg():%d", __FILE__, __LINE__);
1011                 if (ccrc <= 1) {
1012                     echo->imported++;  /*  area has got new messages */
1013 #ifdef ADV_STAT
1014                     if (config->advStatisticsFile != NULL) put_stat(echo, &pktOrigAddr, stNORM, msg->textLength);
1015 #endif
1016                     if (echo->msgbType != MSGTYPE_PASSTHROUGH) {
1017                         if(messCC)
1018                             rc = putMsgInArea(echo, messCC, 1, forceattr);
1019                         else
1020                             rc = putMsgInArea(echo, msg, 1, forceattr);
1021                         statToss.saved += rc;
1022                     }
1023                     else { /*  passthrough */
1024                            /*
1025                            if (echo->downlinkCount==1 && dontdocc==0)
1026                            rc = putMsgInBadArea(msg, pktOrigAddr, 10);
1027                            else {
1028                            statToss.passthrough++;
1029                            rc = 1;
1030                            }
1031                         */
1032                         statToss.passthrough++;
1033                         rc = 1;
1034                     }
1035                 } else rc = 1; /*  normal exit for carbon move & delete */
1036                 freeMsgBuffers(messCC);
1037                 nfree(messCC);
1038             } else {
1039                 /*  msg is dupe */
1040                 if (echo->dupeCheck == dcMove) {
1041                     /*  rc = putMsgInDupeArea(pktOrigAddr, msg, forceattr); */
1042                     rc = putMsgInArea(&(config->dupeArea), msg, 0, forceattr);
1043                 } else rc = 1;
1044                 statToss.dupes++;
1045 #ifdef ADV_STAT
1046                 if (config->advStatisticsFile != NULL) put_stat(echo, &pktOrigAddr, stDUPE, 0);
1047 #endif
1048                 if (rc) config->dupeArea.imported++;
1049             }
1050         }
1051     }
1052     w_log(LL_FUNC, "%s::processEMMsg() rc=%d", __FILE__, rc);
1053     return rc;
1054 }
1055 
processNMMsg(s_message * msg,s_pktHeader * pktHeader,s_area * area,int dontdocc,dword forceattr)1056 int processNMMsg(s_message *msg, s_pktHeader *pktHeader, s_area *area, int dontdocc, dword forceattr)
1057 {
1058     HAREA  netmail;
1059     HMSG   msgHandle;
1060     UINT   len = 0;
1061     char   *bodyStart = NULL;             /*  msg-body without kludgelines start */
1062     char   *ctrlBuf = NULL;               /*  Kludgelines */
1063     XMSG   msgHeader;
1064 /*     char   *slash = NULL; */
1065     unsigned int rc = 0, ccrc = 0, i;
1066 
1067     if (area == NULL) {
1068 	area = &(config->netMailAreas[0]);
1069 	for(i=0; i<config->netMailAreaCount; i++) {
1070 	    if(addrComp(msg->destAddr,*(config->netMailAreas[i].useAka))==0) {
1071 		area = &(config->netMailAreas[i]);
1072 		break;
1073 	    }
1074 	}
1075     }
1076 
1077     if (dupeDetection(area, *msg)==0) {
1078 	/*  msg is dupe */
1079 	if (area->dupeCheck == dcMove) {
1080 	    rc = putMsgInArea(&(config->dupeArea), msg, 0, forceattr);
1081 	} else rc = 1;
1082 	statToss.dupes++;
1083 	if (rc) config->dupeArea.imported++;
1084 	return rc;
1085     }
1086 
1087     if ((config->carbonCount!=0)&&(!dontdocc)) ccrc = carbonCopy(msg, NULL, area);
1088     if (ccrc > 1) return 1; /*  carbon del or move */
1089 
1090     netmail = MsgOpenArea((unsigned char *) area -> fileName, MSGAREA_CRIFNEC,
1091                           (word) area -> msgbType);
1092 
1093     if (netmail != NULL) {
1094 	msgHandle = MsgOpenMsg(netmail, MOPEN_CREATE, 0);
1095 
1096 	if (msgHandle != NULL) {
1097 	    area -> imported++; /*  area has got new messages */
1098 
1099 	    /*  recode from TransportCharset to internal Charset */
1100 	    if ((config->recodeMsgBase) && (config->intab != NULL)) {
1101 		if ((msg->recode & REC_HDR)==0) {
1102 		    recodeToInternalCharset((char*)msg->fromUserName);
1103 		    recodeToInternalCharset((char*)msg->toUserName);
1104 		    recodeToInternalCharset((char*)msg->subjectLine);
1105 		    msg->recode |= REC_HDR;
1106 		}
1107 		if ((msg->recode & REC_TXT)==0) {
1108 		    recodeToInternalCharset((char*)msg->text);
1109 		    msg->recode |= REC_TXT;
1110 		}
1111 	    }
1112 
1113 	    msgHeader = createXMSG(config,msg, pktHeader, forceattr,tossDir);
1114 #ifdef DO_PERL
1115             /* val: force attrs set by perlfilter() hook */
1116             if (perl_setattr) msgHeader.attr = msg->attributes;
1117 #endif
1118 	    /* Create CtrlBuf for SMAPI */
1119             len = msg->textLength;
1120 	    ctrlBuf = (char *) CopyToControlBuf((UCHAR *) msg->text, (UCHAR **)&bodyStart, &len);
1121 	    /* write message */
1122 	    if (MsgWriteMsg(msgHandle, 0, &msgHeader, (UCHAR *)
1123 			    bodyStart, len, len, strlen(ctrlBuf)+1,
1124 			    (UCHAR *) ctrlBuf)!=0)
1125 		w_log(LL_ERR, "Could not write msg to NetmailArea %s! Check the wholeness of messagebase, please.", area->areaName);
1126 	    else rc = 1; /*  normal exit */
1127 	    nfree(ctrlBuf);
1128 	    if (MsgCloseMsg(msgHandle)!=0) { /*  can't close */
1129 		w_log(LL_ERR,"Could not close msg in NetmailArea %s",area->areaName);
1130 		rc = 0;
1131 	    } else { /*  normal close */
1132 		w_log(LL_NETMAIL, "Wrote Netmail: %u:%u/%u.%u -> %u:%u/%u.%u", msg->origAddr.zone, msg->origAddr.net, msg->origAddr.node, msg->origAddr.point, msg->destAddr.zone, msg->destAddr.net, msg->destAddr.node, msg->destAddr.point);
1133 		statToss.netMail++;
1134 	    }
1135 
1136 	} else {
1137 	    w_log(LL_ERR, "Could not create new msg in NetmailArea %s", area -> areaName);
1138 	} /* endif */
1139 
1140 	MsgCloseArea(netmail);
1141     } else {
1142 	fprintf(stderr, "msgapierr - %u\n", msgapierr);
1143 	w_log(LL_ERR, "Could not open NetmailArea %s", area -> areaName);
1144     } /* endif */
1145     return rc;
1146 }
1147 
processMsg(s_message * msg,s_pktHeader * pktHeader,int secure)1148 int processMsg(s_message *msg, s_pktHeader *pktHeader, int secure)
1149 {
1150     int rc;
1151 
1152     w_log(LL_FUNC,"toss.c::processMsg()");
1153     statToss.msgs++;
1154 #ifdef DO_PERL
1155     w_log(LL_SRCLINE, "toss.c:%u:processMsg() #ifdef DO_PERL", __LINE__);
1156     if ((rc = perlfilter(msg, pktHeader->origAddr, secure)) == 1)
1157 	return putMsgInBadArea(msg, pktHeader->origAddr, BM_DENY_BY_FILTER);
1158     else if (rc == 2)
1159 	return 1;
1160 #else
1161     unused(secure);
1162 #endif
1163     if (msg->netMail == 1) {
1164         w_log(LL_NETMAIL, "Netmail from %s to %u:%u/%u.%u", aka2str(msg->origAddr),
1165               msg->destAddr.zone, msg->destAddr.net, msg->destAddr.node, msg->destAddr.point);
1166 	if (config->areafixFromPkt &&
1167 	    isOurAka(config, msg->destAddr) &&
1168 	    strlen(msg->toUserName)>0 &&
1169 	     findInStrArray(robot->names,msg->toUserName) >=0) {
1170 	    rc = processAreaFix(msg, pktHeader, 0);
1171 	} else
1172 	    rc = processNMMsg(msg, pktHeader, NULL, 0, 0);
1173     } else {
1174 	rc = processEMMsg(msg, pktHeader->origAddr, 0, 0);
1175     } /* endif */
1176     w_log(LL_FUNC,"toss.c::processMsg() rc=%d", rc);
1177     return rc;
1178 }
1179 
processPkt(char * fileName,e_tossSecurity sec)1180 int processPkt(char *fileName, e_tossSecurity sec)
1181 {
1182     FILE        *pkt = NULL;
1183     s_pktHeader *header = NULL;
1184     s_message   *msg = NULL;
1185     s_link      *link = NULL;
1186     int         rc = 0, msgrc = 0;
1187     long	pktlen;
1188 
1189     /* +AS+ */
1190     char        *extcmd = NULL;
1191     int         cmdexit;
1192     /* -AS- */
1193     char        processIt = 0; /*  processIt = 1, process all mails */
1194     /*  processIt = 2, process only Netmail */
1195     /*  processIt = 0, do not process pkt */
1196 
1197     w_log(LL_FUNC,"toss.c::processPkt()");
1198 
1199     if ((pktlen = fsize(fileName)) > 60) {
1200 
1201         statToss.inBytes += pktlen;
1202 
1203         /* +AS+ */
1204         if (config->processPkt)
1205         {
1206             extcmd = safe_malloc(strlen(config->processPkt)+strlen(fileName)+2);
1207             sprintf(extcmd,"%s %s",config->processPkt,fileName);
1208             w_log(LL_EXEC, "ProcessPkt: execute string \"%s\"",extcmd);
1209             if ((cmdexit = cmdcall(extcmd)) != 0)
1210                 w_log(LL_ERR, "exec failed, code %d", cmdexit);
1211             nfree(extcmd);
1212         }
1213         /* -AS- */
1214 #ifdef DO_PERL
1215         if (perlpkt(fileName, (sec==secLocalInbound || sec==secProtInbound) ? 1 : 0))
1216             return 6;
1217 #endif
1218 
1219         pkt = fopen(fileName, "rb");
1220         if (pkt == NULL) return 2;
1221         w_log(LL_FILE,"toss.c:processPkt(): opened '%s' (\"rb\" mode)",fileName);
1222 
1223         header = openPkt(pkt);
1224         if (header != NULL) {
1225             /* if ((to_us(header->destAddr)==0) || (sec == secLocalInbound)) { */
1226             if ( isOurAka(config,header->destAddr) || (sec == secLocalInbound)) {
1227                 w_log(LL_PKT, "pkt: %s [%s]", fileName, aka2str(header->origAddr));
1228                 statToss.pkts++;
1229                 link = getLinkFromAddr(config, header->origAddr);
1230                 if ((link!=NULL) && (link->pktPwd==NULL) && (header->pktPassword[0]!='\000'))
1231                     w_log(LL_ERR, "Unexpected Password %s.", header->pktPassword);
1232 
1233                 switch (sec) {
1234         case secLocalInbound:
1235             processIt = 1;
1236             break;
1237 
1238         case secProtInbound:
1239             if ((link != NULL) && (link->pktPwd != NULL) && link->pktPwd[0]) {
1240                 if (stricmp(link->pktPwd, header->pktPassword)==0) {
1241                     processIt = 1;
1242                 } else {
1243                     if ( (header->pktPassword == NULL || header->pktPassword[0] == '\0') &&
1244                         ((link->allowEmptyPktPwd == eSecure) || (link->allowEmptyPktPwd == eOn)) )
1245                     {
1246                         w_log(LL_WARN, "pkt: %s Warning: missing packet password from %i:%i/%i.%i",
1247                             fileName, header->origAddr.zone, header->origAddr.net,
1248                             header->origAddr.node, header->origAddr.point);
1249                         processIt = 1;
1250                     } else {
1251                         w_log(LL_WARN, "pkt: %s Password Error for %i:%i/%i.%i",
1252                             fileName, header->origAddr.zone, header->origAddr.net,
1253                             header->origAddr.node, header->origAddr.point);
1254                             rc = 1;
1255                     }
1256                 }
1257             } else if ((link != NULL) && ((link->pktPwd == NULL) || (strcmp(link->pktPwd, "")==0))) {
1258                 processIt=1;
1259             } else /* if (link == NULL) */ {
1260                 w_log(LL_ERR, "pkt: %s No Link for %i:%i/%i.%i, processing only Netmail",
1261                     fileName, header->origAddr.zone, header->origAddr.net,
1262                     header->origAddr.node, header->origAddr.point);
1263                 processIt = 2;
1264             }
1265             break;
1266 
1267         case secInbound:
1268             if ((link != NULL) && (link->pktPwd != NULL) && link->pktPwd[0]) {
1269 
1270                 if (header->pktPassword && stricmp(link->pktPwd, header->pktPassword)==0) {
1271                     processIt = 1;
1272                 } else {
1273                     if ( (header->pktPassword == NULL || header->pktPassword[0] == '\0') &&
1274                         (link->allowEmptyPktPwd == eOn) )
1275                     {
1276                         w_log(LL_ERR, "pkt: %s Warning: missing packet password from %i:%i/%i.%i",
1277                             fileName, header->origAddr.zone, header->origAddr.net,
1278                             header->origAddr.node, header->origAddr.point);
1279                         processIt = 2; /* Unsecure inbound, do not process echomail */
1280                     } else {
1281                         w_log(LL_ERR, "pkt: %s Password Error for %i:%i/%i.%i",
1282                             fileName, header->origAddr.zone, header->origAddr.net,
1283                             header->origAddr.node, header->origAddr.point);
1284                         rc = 1;
1285                     }
1286                 }
1287             } else if ((link != NULL) && ((link->pktPwd == NULL) || (strcmp(link->pktPwd, "")==0))) {
1288                 processIt=1;
1289             } else /* if (link == NULL) */ {
1290                 w_log(LL_ERR, "pkt: %s No Link for %i:%i/%i.%i, processing only Netmail",
1291                     fileName, header->origAddr.zone, header->origAddr.net,
1292                     header->origAddr.node, header->origAddr.point);
1293                 processIt = 2;
1294             }
1295             break;
1296 
1297                 }
1298 
1299                 if (processIt != 0) {
1300                     while ((msgrc = readMsgFromPkt(pkt, header, &msg)) == 1) {
1301                         if (msg != NULL) {
1302                             if ((processIt == 1) || ((processIt==2) && (msg->netMail==1))) {
1303                                 if (processMsg(msg, header,
1304                                     (sec==secLocalInbound ||
1305                                     sec==secProtInbound ||
1306                                     processIt == 1) ? 1 : 0) != 1 )
1307                                     if (putMsgInBadArea(msg, header->origAddr, BM_MSGAPI_ERROR)==0)
1308                                         rc = 5; /*  can't write to badArea - rename to .err */
1309                             } else rc = 1;
1310                             freeMsgBuffers(msg);
1311                             nfree(msg);
1312                         }
1313                     }
1314                     if (msgrc==2) rc = 3; /*  rename to .bad (wrong msg format) */
1315                     /*  real time of process pkt & msg without external programs */
1316                 }
1317 
1318             } else {
1319                 while ((msgrc = readMsgFromPkt(pkt, header, &msg)) == 1) {
1320                     if (msg != NULL) {
1321                         if (msg->netMail==1)
1322                         {   if (processMsg(msg, header, (sec==secLocalInbound || sec==secProtInbound) ? 1 : 0) !=1 )
1323                         rc=5;
1324                         } else
1325                             break;
1326                         freeMsgBuffers(msg);
1327                         nfree(msg);
1328                     }
1329                 }
1330                 if (msg)
1331                 {	/* echomail pkt not for us */
1332                     freeMsgBuffers(msg);
1333                     nfree(msg);
1334 
1335                     /* PKT is not for us - try to forward it to our links */
1336 
1337                     w_log(LL_ERR, "pkt: %s addressed to %d:%d/%d.%d but not to us",
1338                         fileName, header->destAddr.zone, header->destAddr.net,
1339                         header->destAddr.node, header->destAddr.point);
1340 
1341                     fclose(pkt); pkt = NULL;
1342                     rc = forwardPkt(fileName, header, sec);
1343                 }
1344             }
1345 
1346             nfree(header);
1347 
1348         } else { /*  header == NULL */
1349             w_log(LL_ERR, "pkt: %s wrong pkt-file", fileName);
1350             rc = 3;
1351         }
1352 
1353         if (pkt) fclose(pkt);
1354 
1355     } else statToss.empty++;
1356 
1357 #ifdef DO_PERL
1358     perlpktdone(fileName, rc);
1359 #endif
1360     closeOpenedPkt();
1361     w_log(LL_FUNC,"toss.c::processPkt() OK");
1362     return rc;
1363 }
1364 
1365 
processArc(char * fileName,e_tossSecurity sec)1366 int  processArc(char *fileName, e_tossSecurity sec)
1367 {
1368     unsigned int  i;
1369     int   found, j;
1370     signed int cmdexit;
1371     FILE  *bundle = NULL;
1372     char cmd[256];
1373 
1374     if (sec == secInbound) {
1375         w_log(LL_ERR, "bundle %s: tossing in unsecure inbound, security violation", fileName);
1376         return 1;
1377     };
1378 
1379     /*  find what unpacker to use */
1380     for (i = 0, found = 0; (i < config->unpackCount) && !found; i++) {
1381         bundle = fopen(fileName, "rb");
1382         if (bundle == NULL) return 2;
1383         w_log(LL_FILE,"toss.c:processArc(): opened '%s' (\"rb\" mode)",fileName);
1384 
1385         /*  is offset is negative we look at the end */
1386         fseek(bundle, config->unpack[i].offset, config->unpack[i].offset >= 0 ? SEEK_SET : SEEK_END);
1387         if (ferror(bundle)) { fclose(bundle); continue; };
1388         for (found = 1, j = 0; j < config->unpack[i].codeSize; j++) {
1389             if ((getc(bundle) & config->unpack[i].mask[j]) != config->unpack[i].matchCode[j])
1390                 found = 0;
1391         }
1392         fclose(bundle);
1393     }
1394 
1395     /*  unpack bundle */
1396     if (found) {
1397         fillCmdStatement(cmd,config->unpack[i-1].call,fileName,"",config->tempInbound);
1398         if( fc_stristr(config->unpack[i-1].call, ZIPINTERNAL) )
1399         {
1400             w_log(LL_BUNDLE, "bundle %s: unpacking with zlib", fileName);
1401 #ifdef USE_HPTZIP
1402             cmdexit = UnPackWithZlib(fileName, NULL, config->tempInbound);
1403 #else
1404             cmdexit = 1;
1405             w_log(LL_ERR, "zlib not compiled into hpt", fileName);
1406 #endif
1407         }
1408         else
1409         {
1410             w_log(LL_EXEC, "bundle %s: unpacking with \"%s\"", fileName, cmd);
1411             cmdexit = cmdcall(cmd);
1412         }
1413 
1414         if (cmdexit != 0) {
1415             w_log(LL_ERR, "exec failed, code %d", cmdexit);
1416             return 3;
1417         }
1418 
1419         if (config->afterUnpack) {
1420             w_log(LL_EXEC, "afterUnpack: execute string \"%s\"", config->afterUnpack);
1421             if ((cmdexit = cmdcall(config->afterUnpack)) != 0) {
1422                 w_log(LL_ERR, "exec failed, code %d", cmdexit);
1423             };
1424         }
1425 #ifdef DO_PERL
1426         perlafterunp();
1427 #endif
1428     } else {
1429         w_log(LL_ERR, "bundle %s: cannot find unpacker", fileName);
1430         return 3;
1431     };
1432     statToss.arch++;
1433     remove(fileName);
1434     processDir(config->tempInbound, sec);
1435     return 7;
1436 }
1437 
1438 
1439 typedef struct fileInDir {
1440     char *fileName;
1441     time_t fileTime;
1442 } s_fileInDir;
1443 
filesComparer(const void * elem1,const void * elem2)1444 int filesComparer(const void *elem1, const void *elem2) {
1445     /*  File times comparer for qsort */
1446     if (((s_fileInDir *) elem1) -> fileTime < ((s_fileInDir *) elem2) -> fileTime) return -1;
1447     if (((s_fileInDir *) elem1) -> fileTime > ((s_fileInDir *) elem2) -> fileTime) return 1;
1448     return strcasecmp(((s_fileInDir *) elem1) -> fileName, ((s_fileInDir *) elem2) -> fileName);
1449 }
1450 
1451 static char *validExt[] = { "su", "mo", "tu", "we", "th", "fr", "sa" };
1452 
isArcMail(char * fname)1453 int isArcMail(char *fname)
1454 {
1455 	char *p;
1456 	int i;
1457 	p=strrchr(fname, PATH_DELIM);
1458 	if (p) p++;
1459 	else p=fname;
1460 	/* Amiga? */
1461 	for (i=0; i<8; i++)
1462 		if (!isalnum((unsigned char)p[i]))
1463 			break;
1464 	if (i<8) {
1465 		/* Amiga? */
1466 		for (i=0; i<4; i++) {
1467 			if (!isdigit((unsigned char)*p++)) return 0;
1468 			while (isdigit((unsigned char)*p)) p++;
1469 			if (*p++ != '.') return 0;
1470 		}
1471 	} else {
1472 		p += i;
1473 		if (*p++ != '.') return 0;
1474 	}
1475 	for (i=0; i<sizeof(validExt)/sizeof(validExt[0]); i++)
1476 		if (strncasecmp(p, validExt[i], 2) == 0)
1477 			break;
1478 	if (i == sizeof(validExt)/sizeof(*validExt)) return 0;
1479 	return (isalnum((unsigned char)p[2]) && (p[3] == '\0'));
1480 }
1481 
processDir(char * directory,e_tossSecurity sec)1482 int processDir(char *directory, e_tossSecurity sec)
1483 {
1484     husky_DIR      *dir = NULL;
1485     char           *filename = NULL;
1486     char           *dummy = NULL;
1487     int            rc;
1488     int            pktFile,
1489         arcFile;
1490     long pktCount = 0;
1491     s_fileInDir *files = NULL;
1492     long nfiles=0;
1493     struct stat st;
1494     int dirNameLen;
1495     int filenum;
1496     char *newFileName=NULL;
1497     char *ext[]={NULL, "sec", "asc", "bad", "ntu", "err", "flt"};
1498 
1499 #ifndef __UNIX__
1500     unsigned fattrs;
1501 #endif
1502 
1503     if (directory==NULL) return 0;
1504 
1505     tossDir = directory;
1506 
1507     dirNameLen = strlen(directory);
1508 
1509 #ifdef NOSLASHES
1510     directory[dirNameLen-1]='\0';
1511 #endif
1512 
1513     if (NULL == (dir = husky_opendir(directory))) {
1514 	printf("Can't open dir: %s!\n",directory);
1515 	return 0;
1516     }
1517 
1518     w_log(LL_FUNC, "%s::processDir() begin", __FILE__);
1519 
1520 #ifdef NOSLASHES
1521     directory[dirNameLen-1]='\\';
1522 #endif
1523 
1524     while ((filename = husky_readdir(dir)) != NULL) {
1525 	w_dbglog(LL_DEBUGV, "testing %s\n", filename);
1526 
1527 	dummy = (char *) safe_malloc(dirNameLen + strlen(filename) + 1);
1528 	strcpy(dummy,directory);
1529 	strcat(dummy,filename);
1530 
1531 #if !defined(__UNIX__)
1532 #ifndef HAS_DIRENT_H    /* FFindInfo() and FFindNext() store attributes */
1533 	fattrs = dir->d_attr;
1534 #elif defined(__TURBOC__) || defined(__DJGPP__)
1535 	_dos_getfileattr(dummy, &fattrs);   /*unused, but stay for information*/
1536 #elif defined(__MINGW32__) /* May be move to dirlayer.c ? */
1537 	fattrs = (GetFileAttributes(dummy) & 0x2) ? _A_HIDDEN : 0;
1538 #else
1539 	fattrs = dir->d_attr;
1540 #endif
1541 	if(fattrs & _A_HIDDEN) {
1542 	    nfree(dummy);
1543 	} else
1544 #endif
1545 	    {
1546 		nfiles++;
1547 		files = (s_fileInDir *) safe_realloc(files,nfiles*sizeof(s_fileInDir));
1548 		(files[nfiles-1]).fileName = dummy;
1549 
1550 		if(stat((files[nfiles-1]).fileName, &st)==0) {
1551 		    (files[nfiles-1]).fileTime = st.st_mtime;
1552 		} else {
1553 		    /*  FixMe - don't know what to set :( */
1554 		    (files[nfiles-1]).fileTime = 0L;
1555 		}
1556 
1557 	    }
1558     }
1559     husky_closedir(dir);
1560 
1561     qsort (files, nfiles, sizeof(s_fileInDir), filesComparer);
1562 
1563     for ( filenum=0; filenum < nfiles; filenum++) {
1564 	arcFile = pktFile = 0;
1565 	dummy = (files[filenum]).fileName;
1566 	w_log(LL_FILE, "Look incoming file %s", dummy);
1567 	w_dbglog(LL_DEBUGV,"testing sorted %s", dummy+dirNameLen);
1568 	if ((pktFile = patimat(dummy+dirNameLen, "*.pkt")) == 0)
1569 	    if (isArcMail(dummy+dirNameLen))
1570 		arcFile = 1;
1571 
1572 	if (pktFile || (arcFile && !config->noProcessBundles)) {
1573             pktCount++;
1574 	    rc = 3; /*  nonsence, but compiler warns */
1575 	    if (config->tossingExt != NULL &&
1576 		(newFileName=changeFileSuffix(dummy, config->tossingExt,1)) != NULL){
1577                 if (arcFile)
1578                     w_log(LL_BUNDLE, "bundle %s: renaming to .%s", dummy, config->tossingExt);
1579 		nfree(dummy);
1580 		dummy = newFileName;
1581 		newFileName=NULL;
1582 	    }
1583 	    if (pktFile)
1584 		rc = processPkt(dummy, sec);
1585 	    else /*  if (arcFile) */
1586 		rc = processArc(dummy, sec);
1587 
1588 	    if (rc>=1 && rc<=6) {
1589 		w_log(LL_ERR, "Renaming pkt/arc to .%s",ext[rc]);
1590 		newFileName=changeFileSuffix(dummy, ext[rc], 1);
1591 	    } else {
1592 		if (rc!=7) remove(dummy);
1593 	    }
1594 	}
1595 	nfree(dummy);
1596 	nfree(newFileName);
1597     }
1598     nfree(files);
1599     w_log(LL_FUNC, "%s::processDir() returns %d", __FILE__, pktCount);
1600     return pktCount;
1601 }
1602 
writeStatLog(void)1603 void writeStatLog(void) {
1604     /* write personal mail statistic logfile if statlog is defined in config */
1605     /* if the log file exists, the existing value is increased */
1606 
1607     FILE *f = NULL;
1608     char buffer[256];
1609     int len, x, statNetmail, statCC;
1610 
1611     statNetmail = statToss.netMail; /* number of just received netmails */
1612     statCC = statToss.CC; /* number of just received personal echo mails */
1613 
1614     /* if there are new personal mails and statLog is defined in config */
1615     if (((statNetmail > 0) || (statCC > 0)) && (config->statlog != NULL)) {
1616 	f = fopen(config->statlog, "r");
1617 	if (f != NULL) {  /* and statLog file is readable */
1618             w_log(LL_FILE,"toss.c:writeStatLog(): opened '%s' (\"r\" mode)",config->statlog);
1619 
1620 	    /* then read last personal mail counter and add to actual counter */
1621 	    while(fgets(buffer,sizeof(buffer),f)) {
1622 		len = strlen(buffer);
1623 		for (x=0; x!=len; x++) {
1624 		    if (!strncasecmp(buffer+x, "netmail: ",9)) {
1625 			/* netmail found */
1626 			statNetmail += atoi(buffer+9);
1627 		    }
1628 
1629 		    if (!strncasecmp(buffer+x, "CC: ",4)) {
1630 			/* personal echomail (CC) found */
1631 			statCC += atoi(buffer+4);
1632 		    }
1633 		}
1634 	    }
1635 
1636 	    fclose(f);
1637 	}
1638 
1639 	/* and write personal mail counter for netmails and echo mails */
1640 	f = fopen(config->statlog, "wt");
1641 	if (f != NULL) {
1642             w_log(LL_FILE,"toss.c:writeStatLog(): opened '%s' (\"wt\" mode)",config->statlog);
1643 	    if (statNetmail > 0) {
1644 		fprintf(f, "netmail: %d\n", statNetmail);
1645 	    }
1646 	    if (statCC > 0) {
1647 		fprintf(f, "CC: %d\n", statCC);
1648 	    }
1649 
1650 	    fclose(f);
1651 	}
1652     }
1653 }
1654 
writeTossStatsToLog(void)1655 void writeTossStatsToLog(void) {
1656     unsigned int i;
1657     float inMailsec, outMailsec, inKBsec;
1658     char logchar;
1659 
1660     if (statToss.pkts==0 && statToss.msgs==0)
1661 	logchar='1';
1662     else
1663 	logchar='4';
1664 
1665     if (statToss.realTime == 0) statToss.realTime = 1;
1666 
1667     inMailsec = ((float)(statToss.msgs)) * 1000 / statToss.realTime;
1668     outMailsec = ((float)(statToss.exported)) * 1000 / statToss.realTime;
1669     inKBsec = ((float)(statToss.inBytes)) * 1000 / statToss.realTime / 1024;
1670 
1671     w_log(logchar, "Statistics:");
1672     w_log(logchar, "     arc: % 5d   netMail: % 4d   echoMail: % 5d         CC: % 5d",
1673 	  statToss.arch, statToss.netMail, statToss.echoMail, statToss.CC);
1674     w_log(logchar, "   pkt's: % 5d      dupe: % 4d   passthru: % 5d   exported: % 5d",
1675 	  statToss.pkts, statToss.dupes, statToss.passthrough, statToss.exported);
1676     w_log(logchar, "    msgs: % 5d       bad: % 4d      saved: % 5d      empty: % 5d",
1677 	  statToss.msgs, statToss.bad, statToss.saved, statToss.empty);
1678     w_log(logchar, "   Input: % 8.2f mails/sec        Output: % 8.2f mails/sec", inMailsec, outMailsec);
1679     w_log(logchar, "          % 8.2f kb/sec", inKBsec);
1680     w_log(logchar, "          % 8.2f kb total, processed in %8.3f seconds", ((float) statToss.inBytes / 1024), (float)statToss.realTime / 1000);
1681 
1682     /* write personal mail statistic logfile */
1683     writeStatLog();
1684 
1685     /* Now write areas summary */
1686     w_log(logchar, "Areas summary:");
1687     for (i = 0; i < config->netMailAreaCount; i++)
1688 	if (config->netMailAreas[i].imported > 0)
1689 	    w_log(logchar, "netmail area %s - %d msgs",
1690 		  config->netMailAreas[i].areaName, config->netMailAreas[i].imported);
1691     if (config->dupeArea.imported) w_log(logchar, "dupe area %s - %d msgs",
1692 					 config->dupeArea.areaName,
1693 					 config->dupeArea.imported);
1694     if (config->badArea.imported) w_log(logchar, "bad area %s - %d msgs",
1695 					config->badArea.areaName,
1696 					config->badArea.imported);
1697     for (i = 0; i < config->echoAreaCount; i++)
1698 	if (config->echoAreas[i].imported > 0)
1699 	    w_log(logchar, "echo area %s - %d msgs",
1700 		  config->echoAreas[i].areaName, config->echoAreas[i].imported);
1701     for (i = 0; i < config->localAreaCount; i++)
1702 	if (config->localAreas[i].imported > 0)
1703 	    w_log(logchar, "local area %s - %d msgs",
1704 		  config->localAreas[i].areaName, config->localAreas[i].imported);
1705 }
1706 
find_old_arcmail(s_link * link,FILE * flo)1707 int find_old_arcmail(s_link *link, FILE *flo)
1708 {
1709     char *line = NULL, *bundle=NULL;
1710     ULONG len;
1711     unsigned as;
1712 
1713     while ((line = readLine(flo)) != NULL) {
1714 #ifndef __UNIX__
1715 	line = trimLine(line);
1716 #endif
1717 	if ((*line=='^' || *line=='#') && isArcMail(line + 1)) {
1718 	    nfree(bundle);
1719 	    bundle = safe_strdup(line + 1);
1720 	}
1721 	nfree(line);
1722     }
1723     if (bundle == NULL) return 0;
1724     if (*bundle != '\000') {
1725         int ok = 0;
1726         len = fsize(bundle);
1727         if (len != -1L) {
1728             time_t t = fmtime(bundle);
1729             if (link->arcmailSize != 0)
1730                 as = link->arcmailSize;
1731             else if (config->defarcmailSize != 0)
1732                 as = config->defarcmailSize;
1733             else
1734                 as = 500; /*  default 500 kb max */
1735             /* check size */
1736             ok = (len < as * 1024L);
1737             /* check mtime */
1738             if (ok && t != -1L && link->dailyBundles) {
1739                 time_t t0, cur = time(NULL);
1740                 struct tm *tcur = localtime(&cur);
1741                 tcur->tm_sec = tcur->tm_min = tcur->tm_hour = 0;
1742                 t0 = mktime(tcur);
1743                 if (t < t0) ok = 0;
1744             }
1745             /* use the bundle */
1746             if (ok) {
1747                 link->packFile = (char*)safe_realloc(link->packFile, strlen(bundle)+1);
1748                 strcpy(link->packFile,bundle);
1749                 nfree(bundle);
1750                 return 1;
1751             }
1752 	    }
1753     }
1754     nfree(bundle);
1755     return 0;
1756 }
1757 
arcmail(s_link * tolink)1758 void arcmail(s_link *tolink) {
1759     char cmd[256], *pkt=NULL, *lastPathDelim = NULL, saveChar;
1760     UINT i;
1761     int cmdexit, foa = 0;
1762     FILE *flo = NULL;
1763     s_link *link = NULL;
1764     hs_addr *aka;
1765     e_bundleFileNameStyle bundleNameStyle;
1766 
1767     closeOpenedPkt();
1768     if (config->beforePack) {
1769 	w_log(LL_EXEC, "beforePack: execute string \"%s\"", config->beforePack);
1770 	if ((cmdexit = cmdcall(config->beforePack)) != 0) {
1771 	    w_log(LL_ERR, "exec failed, code %d", cmdexit);
1772 	}
1773     }
1774 #ifdef DO_PERL
1775     perlbeforepack();
1776 #endif
1777 
1778     for (i = 0 ; i < config->linkCount; i++) {
1779         if(tolink) {
1780             link = tolink;
1781             i = config->linkCount;
1782         } else {
1783 	        link = config->links[i];
1784         }
1785 
1786 	/*  only create floFile if we have mail for this link */
1787 	if (link->pktFile != NULL) {
1788 
1789 	    aka = SelectPackAka(link);
1790 
1791 	    if (needUseFileBoxForLinkAka(config,link,aka)) {
1792 
1793 		if (!link->fileBox) link->fileBox = makeFileBoxNameAka (config,link,aka);
1794 
1795 		_createDirectoryTree (link->fileBox);
1796 		if (link->packFile == NULL)
1797 		    if (createPackFileName(link))
1798 			 exit_hpt("Could not create new bundle!",1);
1799 
1800 		if (link->packerDef != NULL) {
1801 /* FIXME  It's need to fix logic: MUST don't allow pack into filebox directly!!!
1802    Normal logic: make bundle in temporary dir, next move(rename!) it into filebox,
1803    and at scanning tempoutbound should to check bundles (not only PKT)
1804 */
1805 		    fillCmdStatement(cmd, link->packerDef->call,
1806 				     link->packFile,
1807 				     link->pktFile, "");
1808 		    w_log(LL_BUNDLE, "Packing for %s %s, %s > %s",
1809 			  aka2str(link->hisAka),
1810 			  link->name, get_filename(link->pktFile),
1811 			  get_filename(link->packFile));
1812 		    w_log(LL_EXEC, "cmd: %s", cmd);
1813 		    if( stricmp(link->packerDef->call, ZIPINTERNAL) == 0 )
1814 		    {
1815 #ifdef USE_HPTZIP
1816 		      cmdexit = PackWithZlib(link->packFile, link->pktFile);
1817 #else
1818 		      cmdexit = -1;
1819               w_log(LL_ERR, "zlib not compiled into hpt");
1820 #endif
1821 		    }else
1822                       cmdexit = cmdcall(cmd);
1823 
1824 		    if (cmdexit==0) remove(link->pktFile);
1825 		    else w_log(LL_ERR, "Error executing packer (errorlevel==%i)", cmdexit);
1826 
1827 		} /*  end packerDef */
1828 		else {
1829 		    /*  there is no packer defined -> put pktFile into fileBox */
1830 		    xstrcat(&pkt, link->fileBox);
1831 		    xstrcat(&pkt, link->pktFile + strlen(config->tempOutbound));
1832 
1833 		    cmdexit = move_file(link->pktFile, pkt, 0);
1834 		    if (cmdexit==0) w_log(LL_BUNDLE, "Leave non-packed mail for %s %s, %s",
1835 					  aka2str(link->hisAka), link->name,
1836 					  get_filename(link->pktFile));
1837 		    else w_log(LL_ERR, "error moving file for %s %s, %s->%s (errorlevel==%i)", aka2str(link->hisAka), link->name, link->pktFile, pkt, errno);
1838 		    nfree(pkt);
1839 		}
1840 
1841 	    } else if (createOutboundFileNameAka(link,link->echoMailFlavour, FLOFILE, aka) == 0) {
1842 		/*  process if the link not busy, else do not create 12345678.?lo */
1843 		flo = fopen(link->floFile, "a+");
1844 
1845 		if (flo == NULL)
1846 		    w_log(LL_ERR, "Cannot open flo file %s",
1847 			  config->links[i]->floFile);
1848 		else {
1849                     w_log(LL_FILE,"toss.c:arcmail(): opened '%s' (\"a+\" mode)",link->floFile);
1850 
1851 		    if (link->linkBundleNameStyle!=eUndef)
1852 			bundleNameStyle=link->linkBundleNameStyle;
1853 		    else if (config->bundleNameStyle!=eUndef)
1854 			bundleNameStyle=config->bundleNameStyle;
1855 		    else bundleNameStyle = eTimeStamp;
1856 
1857 		    if (link->packerDef != NULL) {
1858                     pack_retry:
1859 			/*there is a packer defined -> put packFile into flo */
1860 			/*if we are creating new arcmail bundle -> put packFile into flo*/
1861                         fseek(flo, 0L, SEEK_SET);
1862                         if (!foa) /* retry pack bundle? */
1863                             foa = find_old_arcmail(link, flo);
1864                         else { /* try to generate new bundle name */
1865                             foa = 0;
1866                             link->packFile = NULL;
1867                         }
1868 
1869 			if (link->packFile == NULL)
1870 			    if (createPackFileName(link))
1871 				 exit_hpt("Could not create new bundle!",1);
1872 
1873 			fillCmdStatement(cmd, link->packerDef->call,
1874 					 link->packFile,
1875 					 link->pktFile, "");
1876 			w_log(LL_BUNDLE, "Packing for %s %s, %s > %s",
1877 			      aka2str(link->hisAka), link->name,
1878 			      get_filename(link->pktFile),
1879 			      get_filename(link->packFile));
1880 			w_log(LL_EXEC, "cmd: %s", cmd);
1881             if( stricmp(link->packerDef->call, ZIPINTERNAL) == 0 )
1882             {
1883 #ifdef USE_HPTZIP
1884                 cmdexit = PackWithZlib(link->packFile, link->pktFile);
1885 #else
1886                 cmdexit = -1;
1887                 w_log(LL_ERR, "zlib not compiled into hpt");
1888 #endif
1889             }
1890             else
1891             {
1892                 cmdexit = cmdcall(cmd);
1893             }
1894 			if (cmdexit==0) {
1895 			    if (foa==0) {
1896 				if (bundleNameStyle == eAddrDiff ||
1897 				    bundleNameStyle == eAddrsCRC32 ||
1898 				    bundleNameStyle == eAddrDiffAlways ||
1899 				    bundleNameStyle == eAddrsCRC32Always ||
1900 				    bundleNameStyle == eAmiga)
1901 				    fprintf(flo, "#%s\n", link->packFile);
1902 				else
1903 				    fprintf(flo, "^%s\n", link->packFile);
1904 			    }
1905 			    remove(link->pktFile);
1906                         } else {
1907 			    w_log(LL_ERR, "Error executing packer (errorlevel==%i, %s)",
1908                                   cmdexit, foa ? "retrying" : "permanent error");
1909                             if (foa) goto pack_retry;
1910                         }
1911 
1912 		    } /*  end packerDef */
1913 		    else {
1914 			/*  there is no packer defined -> put pktFile into flo */
1915 			lastPathDelim = strrchr(link->floFile, PATH_DELIM);
1916 
1917 			/*  change path of file to path of flofile */
1918 			saveChar = *(++lastPathDelim);
1919 			*lastPathDelim = '\0';
1920 			xstrcat(&pkt, link->floFile);
1921 			*lastPathDelim = saveChar;
1922 
1923 			if (config->separateBundles) {
1924 
1925 			    if (bundleNameStyle==eAmiga)
1926 				xscatprintf(&pkt, "%u.%u.%u.%u.sep%c",
1927 					    aka->zone, aka->net,
1928 					    aka->node, aka->point,
1929 					    PATH_DELIM);
1930 			    else {
1931 				if (aka->point != 0)
1932 				    xscatprintf(&pkt,"%08x.sep%c",
1933 						aka->point,PATH_DELIM);
1934 				else
1935 				    xscatprintf(&pkt, "%04x%04x.sep%c",
1936 						aka->net,
1937 						aka->node,
1938 						PATH_DELIM);
1939 			    }
1940 			}
1941 
1942 			xstrcat(&pkt, link->pktFile + strlen(config->tempOutbound));
1943 
1944 			cmdexit = move_file(link->pktFile, pkt, 0);
1945 			if (cmdexit==0) {
1946 			    fprintf(flo, "^%s\n", pkt);
1947 			    w_log(LL_BUNDLE, "Leave non-packed mail for %s %s, %s",
1948 				  aka2str(link->hisAka), link->name,
1949 				  get_filename(link->pktFile));
1950 			}
1951 			else w_log(LL_ERR, "error moving file for %s %s, %s->%s (errorlevel==%i)", aka2str(link->hisAka), link->name, link->pktFile, pkt, errno);
1952 			nfree(pkt);
1953 		    }
1954 
1955 		    fclose(flo);
1956 		} /*  end flo */
1957 
1958 		nfree(link->floFile);
1959 		remove(link->bsyFile);
1960 		nfree(link->bsyFile);
1961 	    } /*  end outboundFileNameCreated */
1962 
1963 	    nfree(link->pktFile);
1964 	    nfree(link->packFile);
1965 	} /*  end pkt file */
1966 
1967     } /*  endfor */
1968     return;
1969 }
1970 
1971 static int forwardedPkts = 0;
1972 
forwardPkt(const char * fileName,s_pktHeader * header,e_tossSecurity sec)1973 int forwardPkt(const char *fileName, s_pktHeader *header, e_tossSecurity sec)
1974 {
1975     unsigned int i;
1976     s_link *link = NULL;
1977     char *newfn = NULL;
1978 
1979     for (i = 0 ; i < config->linkCount; i++) {
1980 	if (addrComp(header->destAddr, config->links[i]->hisAka) == 0) {
1981 	    /* we found a link to forward the pkt file to */
1982 
1983 	    link = config->links[i];
1984 
1985 	    /* security checks */
1986 
1987 	    if (link->forwardPkts==fOff) return 4;
1988 	    if ((link->forwardPkts==fSecure)&&(sec != secProtInbound)&&(sec != secLocalInbound)) return 4;
1989 
1990             /* as we have feature freeze currently, */
1991 	    /* I enclose the following code with an ifdef ... */
1992 
1993 	    newfn = makeUniqueDosFileName(config->tempOutbound, "pkt", config);
1994 
1995 	    if (move_file(fileName, newfn, 0) == 0) {  /* save if exist */
1996 
1997 		w_log(LL_PKT, "Forwarding %s to %s as %s",
1998 		      fileName, config->links[i]->name, newfn + strlen(config->tempOutbound));
1999 
2000 		nfree(newfn);
2001 		forwardedPkts = 1;
2002 		return 0;
2003 	    }
2004 	    else
2005 		{
2006 		    w_log(LL_ERR, "Failed moving %s to %s (%s)", fileName,
2007 			  newfn, strerror(errno));
2008 		    nfree(newfn);
2009 		    return 4;
2010 		}
2011 
2012 	}
2013     }
2014 
2015     w_log(LL_ERR, "Packet %s is not for us or our links",fileName);
2016 
2017     return 4;       /* PKT is not for us and we did not find a link to
2018 		       forward the pkt file to */
2019 }
2020 
2021 
2022 /* According to the specs, a .QQQ file does not have two leading
2023    zeros. This routine checks if the file is a .QQQ file, and if so,
2024    it appends the zeros and renames the file to .PKT. */
2025 
2026 
fix_qqq(char * filename)2027 void fix_qqq(char *filename)
2028 {
2029     FILE *f = NULL;
2030     char buffer[2] = { '\0', '\0' };
2031     size_t l = strlen(filename);
2032     char *newname=NULL;
2033 
2034     if (l > 3 && newname != NULL && toupper(filename[l-1]) == 'Q' &&
2035 	toupper(filename[l-2]) == 'Q' && toupper(filename[l-3]) == 'Q')
2036 	{
2037 	    newname = safe_strdup(filename);
2038 
2039 	    strcpy(newname + l - 3, "pkt");
2040 	    if (move_file(newname, filename, 0) == 0)
2041 		{
2042 		    strcpy(filename, newname);
2043 
2044 		    if ((f = fopen(filename, "ab")) != NULL)
2045 			{
2046 			    fwrite(buffer, 2, 1, f);
2047 			    fclose(f);
2048 			}
2049         } else
2050 		    w_log(LL_ERR, "Failed moving %s to %s (%s)", newname,
2051 			  filename, strerror(errno));
2052 	    nfree(newname);
2053 	}
2054 }
2055 
2056 
tossTempOutbound(char * directory)2057 void tossTempOutbound(char *directory)
2058 {
2059     husky_DIR      *dir = NULL;
2060     FILE           *pkt = NULL;
2061     char           *filename = NULL;
2062     char           *dummy = NULL;
2063     s_pktHeader    *header = NULL;
2064     s_link         *link = NULL;
2065     size_t         l;
2066 #ifdef NOSLASHES
2067     int 		  dirNameLen;
2068 #endif
2069 
2070     if (directory==NULL) return;
2071 
2072 #ifdef NOSLASHES
2073     dirNameLen = strlen(directory);
2074     directory[dirNameLen-1]='\0';
2075 #endif
2076 
2077     if (NULL == (dir = husky_opendir(directory))) {
2078         printf("Can't open dir: %s!\n",directory);
2079 	return;
2080     }
2081 
2082 #ifdef NOSLASHES
2083     directory[dirNameLen-1]='\\';
2084 #endif
2085 
2086     while ((filename = husky_readdir(dir)) != NULL) {
2087 	l = strlen(filename);
2088 	if (l > 4 && (stricmp(filename + l - 4, ".pkt") == 0 ||
2089 		      stricmp(filename + l - 4, ".qqq") == 0))
2090 	    {
2091 		dummy = (char *) safe_malloc(strlen(directory)+l+1);
2092 		strcpy(dummy, directory);
2093 		strcat(dummy, filename);
2094 
2095 		fix_qqq(dummy);
2096 
2097 		pkt = fopen(dummy, "rb");
2098 		if (pkt==NULL) continue;
2099 
2100 		header = openPkt(pkt);
2101 		if (header != NULL) {
2102 		    link = getLinkFromAddr (config, header->destAddr);
2103 			nfree(header);
2104 		} else {
2105 		    link = NULL;
2106 		}
2107 
2108 		if (link != NULL) {
2109 
2110 		    if (link->packFile == NULL) {
2111 			if ( createPackFileName(link) )
2112 			    exit_hpt("Could not create new bundle!",1);
2113 		    }
2114 
2115 		    nfree(link->pktFile);
2116 		    link->pktFile = dummy;
2117 
2118 		    fclose(pkt);
2119 		    arcmail(link);
2120 		} else {
2121 		    nfree(dummy);
2122 		    w_log(LL_ERR, "found non packed mail without matching link in tempOutbound");
2123 		    fclose(pkt);
2124 		}
2125 	    }
2126     }
2127 
2128     husky_closedir(dir);
2129     return;
2130 }
2131 
writeImportLog(void)2132 void writeImportLog(void) {
2133     unsigned int i;
2134     FILE *f = NULL;
2135     struct stat buf;
2136 
2137     if (config->importlog) {
2138 
2139 	/*  write importlog */
2140 	f = fopen(config->importlog, "a");
2141 	if (f != NULL) {
2142 
2143 	    for (i = 0; i < config->netMailAreaCount; i++)
2144 		if (config->netMailAreas[i].imported > 0)
2145 		    fprintf(f, "%s\n", config->netMailAreas[i].areaName);
2146 
2147 	    for (i = 0; i < config->echoAreaCount; i++)
2148 		if (config->echoAreas[i].imported > 0 &&
2149 		    config->echoAreas[i].msgbType != MSGTYPE_PASSTHROUGH)
2150 		    fprintf(f, "%s\n", config->echoAreas[i].areaName);
2151 
2152 	    for (i = 0; i < config->localAreaCount; i++)
2153 		if (config->localAreas[i].imported > 0)
2154 		    fprintf(f, "%s\n", config->localAreas[i].areaName);
2155 
2156 	    fclose(f);
2157 #ifdef __UNIX__
2158 	    chown(config->importlog, config->loguid, config->loggid);
2159 	    if (config -> logperm != -1) chmod(config->importlog, config->logperm);
2160 #endif
2161 
2162 	} else w_log(LL_ERR, "Could not open importlogfile");
2163 
2164 	/*  remove empty importlog */
2165 	if (stat(config->importlog, &buf)==0) {
2166 	    if (buf.st_size==0) remove(config->importlog);
2167 	}
2168 
2169     }
2170 }
2171 
2172 #define MAXOPEN_DEFAULT 512
2173 
2174 #if defined(__OS2__)
2175 
2176 #define INCL_DOS
2177 
2178 /* From os2emx.h:
2179 ULONG DosSetMaxFH (ULONG ulCount);
2180 ULONG DosSetRelMaxFH (PLONG pulReqCount, PULONG pulCurMaxFH);
2181 */
2182 
setmaxopen(void)2183 static void setmaxopen(void) {
2184     ULONG cur = 0, add = 0;
2185 
2186     if (DosSetRelMaxFH(&add, &cur) == 0)
2187 	if (cur>=maxopenpkt) return;
2188     if (DosSetMaxFH(maxopenpkt))
2189 	while (cur<maxopenpkt) {
2190 	    add = 1;
2191 	    if (DosSetRelMaxFH(&add, &cur))
2192 		break;
2193 	}
2194 #ifdef __WATCOMC__
2195     _grow_handles(maxopenpkt);
2196 #endif
2197     cur = add = 0;
2198     if (DosSetRelMaxFH(&add, &cur) == 0) {
2199 	maxopenpkt = cur;
2200 	/*  return; */
2201     }
2202 
2203 #elif defined(__UNIX__)
2204 
2205 #include <sys/resource.h>
2206 
2207 static void setmaxopen(void) {
2208 #ifdef RLIMIT_NOFILE
2209     struct rlimit rl;
2210     unsigned maxopenpkt = MAXOPEN_DEFAULT;
2211 
2212     if (getrlimit(RLIMIT_NOFILE, &rl) == 0)
2213 	if (rl.rlim_cur >= MAXOPEN_DEFAULT)
2214 	    return;
2215     /*  try to set max open */
2216     rl.rlim_cur = rl.rlim_max;
2217     if (setrlimit(RLIMIT_NOFILE, &rl) == 0 && rl.rlim_cur >= MAXOPEN_DEFAULT)
2218 	return;
2219     rl.rlim_cur = rl.rlim_max = maxopenpkt;
2220     setrlimit(RLIMIT_NOFILE, &rl);
2221     if (getrlimit(RLIMIT_NOFILE, &rl) == 0) {
2222 	maxopenpkt = rl.rlim_cur;
2223 	return;
2224     }
2225 #endif
2226 
2227 #else /*  windows or unknown OS, just test */
2228 
2229 static void setmaxopen(void) {
2230 
2231 #endif
2232 
2233     {
2234 	int handles[MAXOPEN_DEFAULT];
2235     ULONG i;
2236 	for (i=0; i<MAXOPEN_DEFAULT; i++)
2237 	    if ((handles[i]=dup(1)) == -1)
2238 		break;
2239 	maxopenpkt = i;
2240 	for (i=0; i<maxopenpkt; i++)
2241 	    close(handles[i]);
2242     }
2243     if (maxopenpkt == 0) maxopenpkt = 1;
2244 }
2245 
2246 void toss()
2247 {
2248     FILE *f = NULL;
2249     hs_time timer;
2250 
2251     /*  set stats to 0 */
2252     memset(&statToss, '\0', sizeof(s_statToss));
2253     w_log(LL_START, "Start tossing...");
2254     husky_SetTimer(&timer);
2255     while (processDir(config->localInbound, secLocalInbound));
2256     while (processDir(config->protInbound, secProtInbound));
2257     while (processDir(config->inbound, secInbound));
2258     nfree(globalBuffer); /*  free msg->text global buffer */
2259 
2260     writeDupeFiles();
2261     writeImportLog();
2262 
2263     if (forwardedPkts) {
2264 	tossTempOutbound(config->tempOutbound);
2265 	forwardedPkts = 0;
2266     }
2267 
2268 
2269     statToss.realTime = husky_GetTimer(&timer);
2270     /*  write statToss to Log */
2271     writeTossStatsToLog();
2272     tossTempOutbound(config->tempOutbound);
2273 
2274     /*  create flag for netmail trackers */
2275     if (config->netmailFlag && statToss.netMail) {
2276 	if (NULL == (f = fopen(config->netmailFlag,"a"))) w_log(LL_ERR, "Could not create netmail flag: %s", config->netmailFlag);
2277 	else {
2278 	    w_log(LL_FLAG, "Created netmail flag: %s", config->netmailFlag);
2279 	    fclose(f);
2280 	}
2281     }
2282     w_log(LL_STOP, "End tossing");
2283 }
2284 
2285 int packBadArea(HMSG hmsg, XMSG xmsg, char force)
2286 {
2287     int		rc = 0;
2288     s_message   msg;
2289     s_area	*echo = &(config -> badArea);
2290     hs_addr	pktOrigAddr;
2291     char 	*ptmp = NULL, *line = NULL, *areaName = NULL, *area=NULL, noexp=0;
2292     s_link	*link = NULL;
2293 
2294     makeMsg(hmsg, xmsg, &msg, &(config->badArea), 2);
2295     memset(&pktOrigAddr,'\0',sizeof(hs_addr));
2296     statToss.msgs++; /*  really processed one more msg */
2297 
2298     /*  deleting valet string - "FROM:" and "REASON:" */
2299     ptmp = msg.text;
2300     while ((line = strchr(ptmp, '\r')) != NULL) {
2301 	/* Temporary make it \0 terminated string */
2302 	*line = '\000';
2303 	if (strncmp(ptmp, "FROM: ", 6) == 0 ||
2304 	    strncmp(ptmp, "REASON: ", 8) == 0 ||
2305 	    strncmp(ptmp, "AREANAME: ", 10) == 0) {
2306 	    /*  It's from address */
2307 	    if (*ptmp == 'F') parseFtnAddrZS(ptmp + 6, &pktOrigAddr);
2308 	    /*  Don't export to links */
2309 	    if (*ptmp == 'R') {
2310 		if (strstr(ptmp, "MSGAPIERR: ")!=NULL) noexp=1;
2311 	    }
2312 	    /*  Cut this kludges */
2313 	    if (*ptmp=='A') {
2314 		if (area==NULL) {
2315 		    echo = getArea(config, ptmp+10);
2316 		    xstrcat(&area, ptmp+10);
2317 		}
2318 		memmove(ptmp, line+1, strlen(line+1)+1);
2319 		break;
2320 	    } else {
2321 		memmove(ptmp, line+1, strlen(line+1)+1);
2322 		continue;
2323 	    }
2324 	} else {
2325 	    if ((strncmp(ptmp, "AREA:", 5)==0 ||
2326 		 strncmp(ptmp, "\001AREA:", 6)==0) && area==NULL) {
2327 		/* translating name of the area to uppercase */
2328 		strUpper(ptmp);
2329 		areaName = (*ptmp!='\001') ? ptmp+5 : ptmp+6;
2330 		/*  if the areaname begins with a space */
2331 		while (*areaName == ' ') areaName++;
2332 		echo = getArea(config, areaName);
2333 		xstrcat(&area, areaName);
2334 	    };
2335 	    ptmp = line+1;
2336 	};
2337 	*line = '\r';
2338     }
2339 
2340     if (echo == &(config->badArea)) {
2341 	link = getLinkFromAddr(config, pktOrigAddr);
2342 	if (link && link->areafix.autoCreate && area) {
2343 	    if (0 == autoCreate(area, NULL, pktOrigAddr, NULL))
2344 		echo = getArea(config, area);
2345 	}
2346     }
2347     nfree(area);
2348 
2349     if (echo == &(config->badArea)) {
2350 	freeMsgBuffers(&msg);
2351 	return rc;
2352     }
2353 
2354     if (checkAreaLink(echo, pktOrigAddr, 0) == 0 || force) {
2355 	if (dupeDetection(echo, msg)==1 || noexp) {
2356 	    /*  no dupe or toss whithout export to links */
2357 
2358 	    if (config->carbonCount != 0) carbonCopy(&msg, NULL, echo);
2359 
2360 	    echo->imported++;  /*  area has got new messages */
2361 #ifdef ADV_STAT
2362             if (config->advStatisticsFile != NULL) put_stat(echo, &pktOrigAddr, stNORM, msg.textLength);
2363 #endif
2364 	    if (echo->msgbType != MSGTYPE_PASSTHROUGH) {
2365 		rc = putMsgInArea(echo, &msg,1, 0);
2366 		statToss.saved += rc;
2367 	    } else {
2368 		statToss.passthrough++;
2369 		rc = 1; /*  passthrough always work */
2370 	    }
2371 
2372 	    if (noexp==0) { /*  recode & export to links */
2373 		/*  recoding from internal to transport charSet */
2374 		if (config->outtab) {
2375 		    if (msg.recode & REC_HDR) {
2376 			recodeToTransportCharset((char*)msg.fromUserName);
2377 			recodeToTransportCharset((char*)msg.toUserName);
2378 			recodeToTransportCharset((char*)msg.subjectLine);
2379 			msg.recode &= ~REC_HDR;
2380 		    }
2381 		    if (msg.recode & REC_TXT) {
2382 			recodeToTransportCharset((char*)msg.text);
2383 			msg.recode &= ~REC_TXT;
2384 		    }
2385 		}
2386 
2387 		if (echo->downlinkCount > 0) {
2388 		    forwardMsgToLinks(echo, &msg, pktOrigAddr);
2389 		}
2390 	    }
2391 
2392 	} else {
2393 	    /*  msg is dupe */
2394 	    if (echo->dupeCheck == dcMove) {
2395 		rc = putMsgInArea(&(config->dupeArea), &msg, 0, 0);
2396 	    } else rc = 1; /*  dupeCheck del */
2397 	    if (rc) config->dupeArea.imported++;
2398 #ifdef ADV_STAT
2399             if (config->advStatisticsFile != NULL) put_stat(echo, &pktOrigAddr, stDUPE, 0);
2400 #endif
2401 	}
2402 
2403     } else rc = 0;
2404 
2405     freeMsgBuffers(&msg);
2406     return rc;
2407 }
2408 
2409 void tossFromBadArea(char force)
2410 {
2411     HAREA area;
2412     HMSG  hmsg;
2413     XMSG  xmsg;
2414     dword highestMsg, i;
2415     int   delmsg;
2416 
2417     area = MsgOpenArea((UCHAR *) config->badArea.fileName,
2418 		       MSGAREA_NORMAL, (word)(config->badArea.msgbType|MSGTYPE_ECHO));
2419     if (area != NULL) {
2420 	w_log(LL_START, "Scanning area: %s", config->badArea.areaName);
2421 	highestMsg = MsgGetNumMsg(area);
2422 
2423 	for (i=1; i<=highestMsg; highestMsg--) {
2424 	    hmsg = MsgOpenMsg(area, MOPEN_RW, i);
2425 	    if (hmsg == NULL) continue;      /*  msg# does not exist */
2426 	    MsgReadMsg(hmsg, &xmsg, 0, 0, NULL, 0, NULL);
2427 	    delmsg = packBadArea(hmsg, xmsg, force);
2428 
2429 	    MsgCloseMsg(hmsg);
2430 
2431 	    if (delmsg) MsgKillMsg(area, i);
2432 	    else { i++; highestMsg++; }
2433 	}
2434 
2435 	MsgCloseArea(area);
2436 
2437 	closeOpenedPkt();
2438 	writeDupeFiles();
2439 	writeImportLog();
2440 
2441 	w_log(LL_STAT, "Statistics");
2442 	w_log(LL_STAT, "    scanned: % 5d   saved: % 7d   CC: % 2d", statToss.msgs, statToss.saved, statToss.CC);
2443 	w_log(LL_STAT, "    exported: % 4d   passthru: % 4d", statToss.exported, statToss.passthrough);
2444 
2445 	tossTempOutbound(config->tempOutbound);
2446 
2447     } else w_log(LL_ERR, "Could not open %s", config->badArea.fileName);
2448 }
2449