/*****************************************************************************
 * HPT --- FTN NetMail/EchoMail Tosser
 *****************************************************************************
 * Copyright (C) 1997-1999
 *
 * Matthias Tichy
 *
 * Fido:     2:2433/1245 2:2433/1247 2:2432/605.14
 * Internet: mtt@tichy.de
 *
 * Grimmestr. 12         Buchholzer Weg 4
 * 33098 Paderborn       40472 Duesseldorf
 * Germany               Germany
 *
 * Copyright (C) 1999-2002
 *
 * Max Levenkov
 *
 * Fido:     2:5000/117
 * Internet: sackett@mail.ru
 * Novosibirsk, West Siberia, Russia
 *
 * This file is part of HPT.
 *
 * HPT is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2, or (at your option) any
 * later version.
 *
 * HPT is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with HPT; see the file COPYING.  If not, write to the Free
 * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 *****************************************************************************
 * $Id: toss.c,v 1.417.2.13 2003/04/26 09:54:48 d_sergienko Exp $
 */
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <ctype.h>

#ifdef __EMX__
#include <sys/types.h>
#ifndef _A_HIDDEN
#define _A_HIDDEN A_HIDDEN
#endif
#endif

#if (defined(__EMX__) || defined(__MINGW32__)) && defined(__NT__)
/* we can't include windows.h for several reasons ... */
#ifdef __MINGW32__
int __stdcall CharToOemA(char *, char *);
#endif
#define CharToOem CharToOemA
#endif

#include <sys/stat.h>
#if !(defined(__TURBOC__) || (defined (_MSC_VER) && (_MSC_VER >= 1200)))
#include <unistd.h>
#endif

#if defined(OS2)
#include <os2.h>
#endif

#include <fidoconf/fidoconf.h>
#include <fidoconf/common.h>
#include <fidoconf/dirlayer.h>
#include <fidoconf/xstr.h>
#include <fidoconf/afixcmd.h>

#include <pkt.h>
#include <scan.h>
#include <toss.h>
#include <global.h>
#include <seenby.h>
#include <dupe.h>
#include <fidoconf/recode.h>
#include <areafix.h>
#include <version.h>
#include <scanarea.h>
#include <hpt.h>
#ifdef DO_PERL
#include <hptperl.h>
#endif

#include <smapi/msgapi.h>
#include <smapi/stamp.h>
#include <smapi/typedefs.h>
#include <smapi/compiler.h>
#include <smapi/progprot.h>
#include <smapi/patmat.h>

#if defined(__WATCOMC__) || defined(__TURBOC__) || defined(__DJGPP__)
#include <dos.h>
#include <process.h>
#endif
#if (defined(_MSC_VER) && (_MSC_VER >= 1200))
#include <process.h>
#define P_WAIT		_P_WAIT
#endif

#if defined(__MINGW32__) && defined(__NT__)
/* we can't include windows.h for several reasons ... */
int __stdcall GetFileAttributesA(char *);
#define GetFileAttributes GetFileAttributesA
#endif

#if defined(__MINGW32__) || (defined(__WATCOMC__) && (__WATCOMC__ < 1100))
#define NOSLASHES
#endif


#ifdef USE_HPT_ZLIB
#   include "hpt_zlib/hptzip.h"
#endif


extern s_message **msgToSysop;
int save_err;

static int nopenpkt, maxopenpkt;

s_statToss statToss;
int forwardPkt(const char *fileName, s_pktHeader *header, e_tossSecurity sec);
void processDir(char *directory, e_tossSecurity sec);
void makeMsgToSysop(char *areaName, s_addr fromAddr, s_addr *uplinkAddr);
static void setmaxopen(void);

static char *get_filename(char *pathname)
{
    char *ptr = NULL;

    if (pathname == NULL || !(*pathname))
        return pathname;

    ptr = pathname + strlen(pathname) - 1;

    while (*ptr != '/' && *ptr != '\\' && *ptr != ':' && ptr != pathname)
        ptr--;

    if (*ptr == '/' || *ptr == '\\' || *ptr == ':')
        ptr++;

    return ptr;
}   

/*
 * Find the first occurrence of find in s ignoring case
 */
char *hpt_stristr(char *str, char *find)
{
    char ch, sc, *str1 = NULL, *find1 = NULL;

    find++;
    if ((ch = *(find-1)) != 0) {
	do {
	    do {
		str++;
		if ((sc = *(str-1)) == 0) return (NULL);
	    } while (tolower((unsigned char) sc) != tolower((unsigned char) ch));
			
	    for(str1=str,find1=find; *find1 && *str1 && tolower(*find1)==tolower(*str1); str1++,find1++);
			
	} while (*find1);
	str--;
    }
    return ((char *)str);
}

/* return value: 1 if success, 0 if fail */
int putMsgInArea(s_area *echo, s_message *msg, int strip, dword forceattr)
{
    char *ctrlBuff = NULL, *textStart = NULL, *textWithoutArea = NULL;
    UINT textLength = (UINT) msg->textLength;
    //HAREA harea = NULL;
    HMSG  hmsg;
    XMSG  xmsg;
    char /**slash,*/ *p, *q, *tiny;
    int rc = 0;

    if (echo->msgbType==MSGTYPE_PASSTHROUGH) {
        w_log(LL_ERR, "Can't put message to passthrough area %s!", echo->areaName);
        return rc;
    }
      
    if (!msg->netMail) {
	msg->destAddr.zone  = echo->useAka->zone;
	msg->destAddr.net   = echo->useAka->net;
	msg->destAddr.node  = echo->useAka->node;
	msg->destAddr.point = echo->useAka->point;
    }

    if (maxopenpkt == 0) setmaxopen();

    if (echo->harea == NULL) {
	echo->harea = MsgOpenArea((UCHAR *) echo->fileName, MSGAREA_CRIFNEC, 
			/*echo->fperm, echo->uid, echo->gid,*/
			(word)(echo->msgbType | (msg->netMail ? 0 : MSGTYPE_ECHO)));
	if (echo->harea) nopenpkt+=3;
    }
    if (echo->harea != NULL) {
	hmsg = MsgOpenMsg(echo->harea, MOPEN_CREATE, 0);
	if (hmsg != NULL) {

	    // recode from TransportCharset to internal Charset
	    if (config->intab != NULL) {
		if ((msg->recode & REC_HDR)==0) {
		    recodeToInternalCharset((CHAR*)msg->fromUserName);
		    recodeToInternalCharset((CHAR*)msg->toUserName);
		    recodeToInternalCharset((CHAR*)msg->subjectLine);
		    msg->recode |= REC_HDR;
		}
		if ((msg->recode & REC_TXT)==0) {
		    recodeToInternalCharset((CHAR*)msg->text);
		    msg->recode |= REC_TXT;
		}
	    }

	    textWithoutArea = msg->text;

	    if ((strip==1) && (strncmp(msg->text, "AREA:", 5) == 0)) {
		// jump over AREA:xxxxx\r
		while (*(textWithoutArea) != '\r') textWithoutArea++;
		textWithoutArea++;
		textLength -= (size_t) (textWithoutArea - msg->text);
	    }

	    if (echo->killSB) {
		tiny = strrstr(textWithoutArea, " * Origin:");
		if (tiny == NULL) tiny = textWithoutArea;
		if (NULL != (p = strstr(tiny, "\rSEEN-BY: "))) {
		    p[1]='\0';
		    textLength = (size_t) (p - textWithoutArea + 1);
		}
	    } else if (echo->tinySB) {
		tiny = strrstr(textWithoutArea, " * Origin:");
		if (tiny == NULL) tiny = textWithoutArea;
		if (NULL != (p = strstr(tiny, "\rSEEN-BY: "))) {
		    p++;
		    if (NULL != (q = strstr(p,"\001PATH: "))) {
			// memmove(p,q,strlen(q)+1);
			memmove(p,q,textLength-(size_t)(q-textWithoutArea)+1);
			textLength -= (size_t) (q - p);
		    } else {
			p[0]='\0';
			textLength = (size_t) (p - textWithoutArea);
		    }
		}
	    }

	   
	    ctrlBuff = (char *) CopyToControlBuf((UCHAR *) textWithoutArea,
						 (UCHAR **) &textStart,
						 &textLength);
	    // textStart is a pointer to the first non-kludge line
	    xmsg = createXMSG(config,msg, NULL, forceattr,tossDir);

	    if (MsgWriteMsg(hmsg, 0, &xmsg, (byte *) textStart, (dword)
			    textLength, (dword) textLength,
			    (dword)strlen(ctrlBuff), (byte*)ctrlBuff)!=0) 
		w_log(LL_ERR, "Could not write msg in %s!", echo->fileName);
	    else rc = 1; // normal exit

	    if (MsgCloseMsg(hmsg)!=0) {
		w_log(LL_ERR, "Could not close msg in %s!", echo->fileName);
		rc = 0;
	    }
	    nfree(ctrlBuff);
       
	} else w_log(LL_ERR, "Could not create new msg in %s!", echo->fileName);
	/* endif */
	if (nopenpkt>=maxopenpkt-12) {
	    MsgCloseArea(echo->harea);
	    echo->harea = NULL;
	    nopenpkt-=3;
	}
    } else w_log(LL_ERR, "Could not open/create EchoArea %s!", echo->fileName);
    /* endif */
    return rc;
}

/*
int putMsgInDupeArea(s_addr addr, s_message *msg, dword forceattr)
{
	char *textBuff=NULL, *from=NULL;
	
	xscatprintf(&from, "FROM: %s\r", aka2str(addr));
	xstrscat(&textBuff, from, msg->text, NULL);

	msg->textLength += strlen(from);
	nfree(from);
	
	nfree(msg->text);
	msg->text = textBuff;

	return putMsgInArea(&(config->dupeArea), msg, 0, forceattr);
}
*/

void createSeenByArrayFromMsg(s_area *area, s_message *msg, s_seenBy **seenBys, UINT *seenByCount)
{
    char *seenByText=NULL, *start = NULL, *token = NULL;
    unsigned long temp;
    char *endptr = NULL;
    UINT seenByAlloced;

    *seenByCount = seenByAlloced = 0;

    start = strrstr(msg->text, " * Origin:"); // jump over Origin
    if (start == NULL) start = msg->text;

    // find beginning of seen-by lines
    do {
	start = strstr(start, "SEEN-BY:");
	if (start == NULL) return;
	start += 8; // jump over SEEN-BY:

	while (*start == ' ') start++; // find first word after SEEN-BY:
    } while (!isdigit(*start));

    // now that we have the start of the SEEN-BY's we can tokenize the lines and read them in
    xstrcat(&seenByText, start);

    token = strtok(seenByText, " \r\t\376");
    for (;token != NULL; token = strtok(NULL, " \r\t\376")) {
	if (isdigit(*token)) {
	    // parse token
	    temp = strtoul(token, &endptr, 10);
	    if (*endptr==':') {
		token = endptr+1;
		temp = strtoul(token, &endptr, 10);
	    }
	    if (*endptr && *endptr != '/')
		continue;

	    // get new memory
	    if ((*seenByCount)++ >= seenByAlloced)
		(*seenBys) = (s_seenBy*) safe_realloc(*seenBys, sizeof(s_seenBy) * (seenByAlloced+=32));

	    if ((*endptr) == '\0') {
		// only node aka
		(*seenBys)[*seenByCount-1].node = (UINT16) temp;
		// use net aka of last seenBy
		(*seenBys)[*seenByCount-1].net = (*seenBys)[*seenByCount-2].net;
	    } else {
		// net and node aka
		(*seenBys)[*seenByCount-1].net = (UINT16) temp;
		// eat up '/'
		endptr++;
		(*seenBys)[*seenByCount-1].node = (UINT16) atol(endptr);
	    }
	} else if (strcmp(token,"SEEN-BY:")!=0) break; // not digit and not SEEN-BY
	   
    } // end while

    if (*seenByCount != seenByAlloced)
	(*seenBys) = (s_seenBy*) safe_realloc(*seenBys, sizeof(s_seenBy) * (*seenByCount));
    //test output for reading of seenBys...
#ifdef DEBUG_HPT
    for (i=0; i < *seenByCount; i++) printf("%u/%u ", (*seenBys)[i].net, (*seenBys)[i].node);
#endif
//   exit(2);

    nfree(seenByText);
}

void createPathArrayFromMsg(s_message *msg, s_seenBy **seenBys, UINT *seenByCount)
{

    // DON'T GET MESSED UP WITH THE VARIABLES NAMED SEENBY...
    // THIS FUNCTION READS PATH!!!

    char *seenByText=NULL, *start = NULL, *token = NULL;
    char *endptr = NULL;
    unsigned long temp;
    UINT seenByAlloced;
#ifdef DEBUG_HPT
    int i;
#endif

    *seenByCount = seenByAlloced = 0;

    start = strrstr(msg->text, " * Origin:"); // jump over Origin
    if (start == NULL) start = msg->text;

    // find beginning of path lines
    do {
	start = strstr(start, "\001PATH:");
	if (start == NULL) return;
	start += 7; // jump over PATH:

	while (*start == ' ') start++; // find first word after PATH:
    } while (!isdigit(*start));

    // now that we have the start of the PATH' so we can tokenize the lines and read them in
    xstrcat(&seenByText, start);

    token = strtok(seenByText, " \r\t\376");
    for (; token != NULL; token = strtok(NULL, " \r\t\376")) {
	if (isdigit(*token)) {
	    // parse token
	    temp = strtoul(token, &endptr, 10);
	    if (*endptr==':') {
		token = endptr+1;
		temp = strtoul(token, &endptr, 10);
	    }
	    if (*endptr && *endptr != '/')
		continue;

	    // get new memory
	    if ((*seenByCount)++ >= seenByAlloced)
		(*seenBys) = (s_seenBy*) safe_realloc(*seenBys, sizeof(s_seenBy) * (seenByAlloced+=32));

	    if ((*endptr) == '\0') {
		// only node aka
		(*seenBys)[*seenByCount-1].node = (UINT16) temp;
		// use net aka of last seenBy
		(*seenBys)[*seenByCount-1].net = (*seenBys)[*seenByCount-2].net;
	    } else {
		// net and node aka
		(*seenBys)[*seenByCount-1].net = (UINT16) temp;
		// eat up '/'
		endptr++;
		(*seenBys)[*seenByCount-1].node = (UINT16) atol(endptr);
	    }
	} else if (strcmp(token, "\001PATH:")!=0) break; // not digit and not PATH
    }

    if (*seenByCount != seenByAlloced)
	(*seenBys) = (s_seenBy*) safe_realloc(*seenBys, sizeof(s_seenBy) * (*seenByCount));

    // test output for reading of paths...
#ifdef DEBUG_HPT
    for (i=0; i < *seenByCount; i++) printf("%u/%u ", (*seenBys)[i].net, (*seenBys)[i].node);
#endif
    //exit(2);

    nfree(seenByText);
}

/**
  * This function returns 0 if the link is not in seenBy else it returns 1.
  */

int checkLink(s_seenBy *seenBys, UINT seenByCount, s_link *link,
	      s_addr pktOrigAddr, s_area *area)
{
    UINT i,j;

    // the link where we got the mail from
    if (addrComp(pktOrigAddr, link->hisAka) == 0) return 1;

    if (seenBys==NULL) return 0;

    // a point always gets the mail
    // if (link->hisAka.point != 0) return 0;

    // send the mail to links within our node-system
    if ((link->hisAka.zone == area->useAka->zone) &&
        (link->hisAka.net  == area->useAka->net) &&
        (link->hisAka.node == area->useAka->node))
	return 0;

    for (i=0; i < seenByCount; i++) {
	if ((link->hisAka.net==seenBys[i].net) &&
	    (link->hisAka.node==seenBys[i].node)) {
		   
	    for (j=0; j < config->ignoreSeenCount; j++) {
		if (config->ignoreSeen[j].net == seenBys[i].net &&
		    config->ignoreSeen[j].node == seenBys[i].node) {
		    link->sb = 1; // fix for double seen-bys
		    return 0;
		}
	    }
	    for (j=0; j < area->sbignCount; j++) {
		if (area->sbign[j].net == seenBys[i].net &&
		    area->sbign[j].node == seenBys[i].node) {
		    link->sb = 1; // fix for double seen-bys
		    return 0;
		}
	    }

	    return 1;
	}
    }
    return 0;
}

/*
  This function puts all the links of the echoarea in the newLink
  array who does not have got the mail, zoneLinks - the links who
  receive msg with stripped seen-by's.
*/

void createNewLinkArray(s_seenBy *seenBys, UINT seenByCount,
			s_area *echo, s_arealink ***newLinks,
			s_arealink ***zoneLinks, s_addr pktOrigAddr) {
    UINT i, j=0, k=0;
	
    *newLinks = (s_arealink **) scalloc(echo->downlinkCount,sizeof(s_arealink*));
    *zoneLinks = (s_arealink **) scalloc(echo->downlinkCount,sizeof(s_arealink*));
    if (*newLinks==NULL || *zoneLinks==NULL) exit_hpt("out of memory",1);

    for (i=0; i < echo->downlinkCount; i++) {
	// is the link in SEEN-BYs?
	if ( checkLink(seenBys, seenByCount, echo->downlinks[i]->link,
		       pktOrigAddr, echo)!=0) continue;
	// link with "export off"
	if (echo->downlinks[i]->export == 0) continue;

	if (pktOrigAddr.zone==echo->downlinks[i]->link->hisAka.zone) {
	    // links with same zone
	    (*newLinks)[j] = echo->downlinks[i];
	    j++;
	} else {
	    // links in different zones
	    (*zoneLinks)[k] = echo->downlinks[i];
	    k++;
	}
    }
}

void closeOpenedPkt(void) {
    unsigned int i;

    for (i=0; i<config->linkCount; i++)
	if (config->links[i].pkt) {
	    if (closeCreatedPkt(config->links[i].pkt))
		w_log(LL_ERR,"can't close pkt: %s", config->links[i].pktFile);
	    config->links[i].pkt = NULL;
	    nopenpkt--;
	}
    for (i=0; i<config->echoAreaCount; i++)
	if (config->echoAreas[i].harea) {
	    MsgCloseArea(config->echoAreas[i].harea);
	    config->echoAreas[i].harea = NULL;
	    nopenpkt-=3;
	}
    for (i=0; i<config->netMailAreaCount; i++)
	if (config->netMailAreas[i].harea) {
	    MsgCloseArea(config->netMailAreas[i].harea);
	    config->netMailAreas[i].harea = NULL;
	    nopenpkt-=3;
	}
    for (i=0; i<config->localAreaCount; i++)
	if (config->localAreas[i].harea) {
	    MsgCloseArea(config->localAreas[i].harea);
	    config->localAreas[i].harea = NULL;
	    nopenpkt-=3;
	}
    if (config->badArea.harea) {
	MsgCloseArea(config->badArea.harea);
	config->badArea.harea = NULL;
	nopenpkt-=3;
    }
    if (config->dupeArea.harea) {
	MsgCloseArea(config->dupeArea.harea);
	config->dupeArea.harea = NULL;
	nopenpkt-=3;
    }
}

void forwardToLinks(s_message *msg, s_area *echo, s_arealink **newLinks, 
		    s_seenBy **seenBys, UINT *seenByCount,
		    s_seenBy **path, UINT *pathCount) {
    unsigned  int i, rc=0;
    ULONG len;
    FILE *f=NULL;
    s_pktHeader header;
    char *start = NULL, *text = NULL, *seenByText = NULL, *pathText = NULL;
    char *debug=NULL;

    if (newLinks[0] == NULL) return;

    if (echo->debug) {
	xstrscat(&debug, config->logFileDir,
		 (echo->DOSFile) ? "common" : echo->areaName,
		 ".dbg", NULL);
		
	if (config->areasFileNameCase == eLower) 
	    debug = strLower(debug);
	else
	    debug = strUpper(debug);
		
	if ((f=fopen(debug,"a"))==NULL) {
	    w_log(LL_ERR,"can't open file: %s",debug);
	}else w_log(LL_FILE,"toss.c:forwardToLinks(): opened %s (\"a\" mode)",debug);
	nfree(debug);
    }

    for (i=0; i<config->addToSeenCount; i++) {
	(*seenByCount)++;
	(*seenBys) = (s_seenBy*) safe_realloc(*seenBys,sizeof(s_seenBy)*(*seenByCount));
	(*seenBys)[*seenByCount-1].net = (UINT16) config->addToSeen[i].net;
	(*seenBys)[*seenByCount-1].node = (UINT16) config->addToSeen[i].node;
    }
    for (i=0; i<echo->sbaddCount; i++) {
	(*seenByCount)++;
	(*seenBys) = (s_seenBy*) safe_realloc(*seenBys,sizeof(s_seenBy)*(*seenByCount));
	(*seenBys)[*seenByCount-1].net = (UINT16) echo->sbadd[i].net;
	(*seenBys)[*seenByCount-1].node = (UINT16) echo->sbadd[i].node;
    }

    // add our aka to seen-by (zonegating link must strip our aka)
    if (echo->useAka->point==0) {

	for (i=0; i < *seenByCount; i++) {
	    if ((*seenBys)[i].net == echo->useAka->net &&
		(*seenBys)[i].node == echo->useAka->node) break;
	}
		
	if (*seenByCount==i) {
	    (*seenBys) = (s_seenBy*)
		safe_realloc((*seenBys), sizeof(s_seenBy) * (*seenByCount+1));
	    (*seenBys)[*seenByCount].net = (UINT16) echo->useAka->net;
	    (*seenBys)[*seenByCount].node = (UINT16) echo->useAka->node;
	    (*seenByCount)++;
	}
    }

    // add seenBy for newLinks
    for (i=0; i<echo->downlinkCount; i++) {
		
	// no link at this index -> break
	if (newLinks[i] == NULL) break;
	// don't include points in SEEN-BYs
	if (newLinks[i]->link->hisAka.point != 0) continue;
	// fix for IgnoreSeen & -sbign
	if (newLinks[i]->link->sb == 1) continue;

	(*seenBys) = (s_seenBy*) safe_realloc((*seenBys), sizeof(s_seenBy) * (*seenByCount+1));
	(*seenBys)[*seenByCount].net = (UINT16) newLinks[i]->link->hisAka.net;
	(*seenBys)[*seenByCount].node = (UINT16) newLinks[i]->link->hisAka.node;
	(*seenByCount)++;
    }

    sortSeenBys((*seenBys), *seenByCount);

#ifdef DEBUG_HPT
    for (i=0; i< *seenByCount;i++) printf("%u/%u ", (*seenBys)[i].net, (*seenBys)[i].node);
#endif

    if (*pathCount > 0) {
	if (((*path)[*pathCount-1].net != echo->useAka->net) ||
	    ((*path)[*pathCount-1].node != echo->useAka->node)) {
	    // add our aka to path
	    (*path) = (s_seenBy*) safe_realloc((*path), sizeof(s_seenBy) * (*pathCount+1));
	    (*path)[*pathCount].net = (UINT16) echo->useAka->net;
	    (*path)[*pathCount].node = (UINT16) echo->useAka->node;
	    (*pathCount)++;
	}
    } else {
	(*pathCount) = 0;
	(*path) = (s_seenBy*) safe_realloc((*path),sizeof(s_seenBy));
	(*path)[*pathCount].net = (UINT16) echo->useAka->net;
	(*path)[*pathCount].node = (UINT16) echo->useAka->node;
	(*pathCount) = 1;
    }

#ifdef DEBUG_HPT
    for (i=0; i< *pathCount;i++) printf("%u/%u ", (*path)[i].net, (*path)[i].node);
#endif

    text = strrstr(msg->text, " * Origin:"); // jump over Origin
    if (text) { // origin was found
	start = strrchr(text, ')');
	if (start) start++; // normal origin
	else {
	    start = text; // broken origin
	    while(*start && *start!='\r') start++;
	}
	*start='\0';
    } else { // no Origin founded
	text = msg->text;
	start = strstr(text, "\rSEEN-BY: ");
	if (start == NULL) start = strstr(text, "SEEN-BY: ");
	if (start) *start='\0';
	// find start of PATH in Msg
	start = strstr(text, "\001PATH: ");
	if (start) *start='\0'; 
	else start = text+strlen(text);
    }
    msg->textLength = (size_t) (start - msg->text);

	// create new seenByText
    seenByText = createControlText(*seenBys, *seenByCount, "SEEN-BY: ");
    pathText   = createControlText(*path, *pathCount, "\001PATH: ");
    xstrscat(&msg->text, "\r", seenByText, pathText, NULL);
    msg->textLength += 1 + strlen(seenByText) + strlen(pathText);
    nfree(seenByText);
    nfree(pathText);

    if (echo->debug) {
	debug = (char *) GetCtrlToken((byte *)msg->text, (byte *)"MSGID");
	if (f && debug) {
	    fputs("\n[",f);
	    fputs(debug,f);
	    fputs("] ",f);
	}
	nfree(debug);
    }

    // add msg to the pkt's of the downlinks
    if (maxopenpkt == 0) setmaxopen();
    for (i = 0; i<echo->downlinkCount; i++) {

	// no link at this index -> break;
	if (newLinks[i] == NULL) break;

	// check packet size
	if (newLinks[i]->link->pktFile != NULL && newLinks[i]->link->pktSize != 0) {
	    len = newLinks[i]->link->pkt ? ftell(newLinks[i]->link->pkt) : fsize(newLinks[i]->link->pktFile);
	    if (len >= (newLinks[i]->link->pktSize * 1024L)) { // Stop writing to pkt
		if (newLinks[i]->link->pkt) {
		    fclose(newLinks[i]->link->pkt);
		    newLinks[i]->link->pkt = NULL;
		    nopenpkt--;
		}
		nfree(newLinks[i]->link->pktFile);
		nfree(newLinks[i]->link->packFile);
	    }
	}

	// create pktfile if necessary
	if (newLinks[i]->link->pktFile == NULL) {
	    // pktFile does not exist
	    if ( createTempPktFileName(newLinks[i]->link) )
		exit_hpt("Could not create new pkt!",1);
	}

	makePktHeader(NULL, &header);
	header.origAddr = *(newLinks[i]->link->ourAka);
	header.destAddr = newLinks[i]->link->hisAka;
	if (newLinks[i]->link->pktPwd != NULL)
	    strcpy(header.pktPassword, newLinks[i]->link->pktPwd);
	if (newLinks[i]->link->pkt == NULL) {
	    newLinks[i]->link->pkt = openPktForAppending(newLinks[i]->link->pktFile, &header);
	    nopenpkt++;
	}

	// an echomail msg must be adressed to the link
	msg->destAddr = header.destAddr;
	// .. and must come from us
	msg->origAddr = header.origAddr;
	rc += writeMsgToPkt(newLinks[i]->link->pkt, *msg);
	if (rc) w_log(LL_ERR,"can't write msg to pkt: %s",
		      newLinks[i]->link->pktFile);
	if (nopenpkt >= maxopenpkt-12 || // std streams, in pkt, msgbase, log
	    (newLinks[i]->link->pktSize && ftell(newLinks[i]->link->pkt)>=newLinks[i]->link->pktSize * 1024L)) {
	    rc += closeCreatedPkt(newLinks[i]->link->pkt);
	    if (rc) w_log(LL_ERR,"can't close pkt: %s",
		          newLinks[i]->link->pktFile);
	    newLinks[i]->link->pkt = NULL;
	    nopenpkt--;
	}
	if (f) {
	    if (rc) fputs(" failed: ",f);
	    fputs(aka2str(header.destAddr),f);
	    fputc('>',f);
	    fputs(get_filename(newLinks[i]->link->pktFile),f);
	    fputc(' ',f);
	}
	if (rc==0) statToss.exported++;
	else rc=0;
    }

    if (f) fclose(f);
    return;
}

void forwardMsgToLinks(s_area *echo, s_message *msg, s_addr pktOrigAddr)
{
    s_seenBy *seenBys = NULL, *path = NULL;
    UINT     seenByCount, pathCount;
    // links who does not have their aka in seenBys and thus have not got the echomail
    s_arealink **newLinks = NULL, **zoneLinks = NULL;

    createSeenByArrayFromMsg(echo, msg, &seenBys, &seenByCount);
    createPathArrayFromMsg(msg, &path, &pathCount);
   
    createNewLinkArray(seenBys, seenByCount, echo, &newLinks, &zoneLinks, pktOrigAddr);

    forwardToLinks(msg, echo, newLinks, &seenBys, &seenByCount, &path, &pathCount);
    if (zoneLinks!=NULL) {
	if (echo->useAka->zone != pktOrigAddr.zone) seenByCount = 0;
	forwardToLinks(msg, echo, zoneLinks, &seenBys, &seenByCount, &path, &pathCount);
    }

    nfree(seenBys);
    nfree(path);
    nfree(newLinks);
    nfree(zoneLinks);
}

#if defined(UNIX) || defined(__EMX__) || defined(__DJGPP__)
#define HAVE_POPEN
#endif

int processExternal (s_area *echo, s_message *msg,s_carbon carbon) 
{ 
    FILE *msgfp = NULL;
    char *fname = NULL;
    char *progname = NULL, *execstr = NULL, *p = NULL;
    int  rc;

    progname = carbon.areaName;
#ifdef HAVE_POPEN	
    if (*progname == '|') {
	msgfp = popen(progname + 1, "w");
    } else
#endif
	{
	    fname = tmpnam(NULL);
	    msgfp = fopen(fname, "wt");
	};
	
    if (!msgfp) {
	w_log(LL_ERR, "external process %s: cannot create file", progname);
	return 1;
    }else w_log(LL_FILE,"toss.c:processExternal() opened '%s' (\"\" mode)", fname);
    /* Output header info */
    if (!msg->netMail) fprintf(msgfp, "Area: %s\n", echo->areaName);
    fprintf(msgfp, "From: \"%s\" %s\n", msg->fromUserName, aka2str(msg->origAddr));
    fprintf(msgfp, "To:   \"%s\" %s\n", msg->toUserName, aka2str(msg->destAddr));
    fprintf(msgfp, "Date: \"%s\"\n", msg->datetime);
    fprintf(msgfp, "Subject: \"%s\"\n\n", msg->subjectLine);
    /* Output msg text */
    for (p = msg->text; *p ; p++) 
	if (*p == '\r') 
	    fputc('\n', msgfp);
	else
	    fputc(*p, msgfp);
    fputc('\n', msgfp);
#ifdef HAVE_POPEN	
    if (*progname == '|') {
	pclose(msgfp);
	rc = 0;
    } else
#endif
	{
	    /* Execute external program */
	    fclose(msgfp);
	    execstr = safe_malloc(strlen(progname)+strlen(fname)+2);
	    sprintf(execstr, "%s %s", progname, fname);
#ifdef __NT__
	    CharToOem(execstr, execstr); // this is really need?
#endif
	    rc = system(execstr);
	    nfree(execstr);
	    unlink(fname);
	};
    if (rc == -1 || rc == 127) {
	w_log(LL_ERR, "excution of external process %s failed", progname);
    };
    return 0;

}

/* area - area to carbon messages, echo - original echo area */
int processCarbonCopy (s_area *area, s_area *echo, s_message *msg, s_carbon carbon) {
    char *line, *p, *text, *old_text, *reason = carbon.reason;
    int i, old_textLength, export = carbon.export, rc = 0;

    statToss.CC++;

    old_textLength = msg->textLength;
    old_text = msg->text;
    i = old_textLength;

    /* recoding from internal to transport charSet if needed */
    if (config->outtab) {
	if (msg->recode & REC_TXT) {
	    recodeToTransportCharset((CHAR*)msg->text);
	    msg->recode &= ~REC_TXT;
	}
	if (msg->recode & REC_HDR) {
	    recodeToTransportCharset((CHAR*)msg->fromUserName);
	    recodeToTransportCharset((CHAR*)msg->toUserName);
	    recodeToTransportCharset((CHAR*)msg->subjectLine);
	    msg->recode &= ~REC_HDR;
	}
	if (reason) recodeToTransportCharset((CHAR*)reason);
    }
	
    msg->text = NULL;
    msg->textLength = 0;

    line = old_text;

    if (!msg->netMail) {
        xstrscat(&msg->text,
                 (export) ? "AREA:" : "",
                 (export) ? area->areaName : "",
                 (export) ? "\r" : "",
                 "\001AREA:", echo->areaName,
                 "\r" , NULL);
    }
    if (strncmp(line, "AREA:", 5) == 0) {
        /*  jump over AREA:xxxxx\r */
        while ((line-old_text<old_textLength) && (*(line) != '\r')) line++;
        if(line-old_text<old_textLength) line++;
    }

    while(*line == '\001')
    {
        p = strchr(line, '\r');
        if(!p)
            break;
        /* Temporary make it \0 terminated string */
        *p = '\0';
        xstrcat(&msg->text,line);
        /* and then we *must* put '\r' back. */
        xstrcat(&msg->text, "\r");
        *p = '\r';
        line = p+1;
    }
    text = line; /* may be old_text or old_text w/o begining kluges */

    if (!msg->netMail) {
	if ((!config->carbonKeepSb) && (!area->keepsb)) {
	    text = strrstr(old_text, " * Origin:");
	    if (NULL != (p = strstr(text ? text : old_text,"\rSEEN-BY:")))
		i = (size_t) (p - old_text) + 1;
	}
	xstrscat(&msg->text,
                 msg->text ? (msg->text[strlen(msg->text)-1] == '\r' ?"":"\r") : "" ,
		 (config->carbonExcludeFwdFrom) ? "" : " * Forwarded from area '",
		 (config->carbonExcludeFwdFrom) ? "" : echo->areaName,
		 (config->carbonExcludeFwdFrom) ? "" : "'\r",
		 (reason) ? reason : "",
		 (reason) ? "\r" : "",
		 NULL );
	msg->textLength = strlen(msg->text);
    }
    xstralloc(&msg->text,i);   /* add i bytes */
    strncat(msg->text,line,i); /*  copy rest of msg */
    msg->textLength += i;

    if (!export) {
	if (msg->netMail) rc = putMsgInArea(area,msg,0,MSGSENT);
	else rc = putMsgInArea(area,msg,0,0);
	area->imported++;  // area has got new messages
    }
    else if (!msg->netMail) {
	rc = processEMMsg(msg, *area->useAka, 1, 0);
    } else
	rc = processNMMsg(msg, NULL, area, 1, 0);

    nfree(msg->text);
    msg->textLength = old_textLength;
    msg->text = old_text;
    msg->recode &= ~REC_TXT; // old text is always in Transport Charset
    if (config->intab && reason) recodeToInternalCharset((CHAR*)reason);

    return rc;
}


/* Does carbon copying */
/* Return value: 0 if nothing happend, 1 if there was a carbon copy, 
   > 1 if there was a carbon move or carbon delete*/
int carbonCopy(s_message *msg, XMSG *xmsg, s_area *echo)
{
    unsigned int i, rc = 0, result=0;
    char *testptr = NULL, *testptr2 = NULL, *kludge = NULL;
    s_area *area = NULL;
    s_carbon *cb=&(config->carbons[0]);
    s_area **copiedTo = NULL;
    int copiedToCount = 0;
    int ncop;

    if (echo->ccoff==1)
        return 0;
    if (echo->msgbType==MSGTYPE_PASSTHROUGH && config->exclPassCC)
        return 0;

    for (i=0; i<config->carbonCount; i++,++cb) {
        /* Dont come to use netmail on echomail and vise verse */
        if (cb->move!=2 && ((msg->netMail && !cb->netMail) ||
			    (!msg->netMail &&  cb->netMail))) continue;

        area = cb->area;
		
	if(!cb->rule&CC_AND)
            if (!cb->extspawn && // fix for extspawn
                cb->areaName != NULL && // fix for carbonDelete
		// dont CC to the echo the mail comes from
        	!stricmp(echo->areaName,area->areaName)
		) continue;

        switch (cb->ctype) {
        case ct_to:
            result=!stricmp(msg->toUserName,cb->str);
            break;

        case ct_from:
            result=!stricmp(msg->fromUserName,cb->str);
            break;

        case ct_kludge:
	    kludge = (char *) GetCtrlToken((byte *)msg->text, (byte *)cb->str);
	    result = (kludge!=NULL);
	    nfree(kludge);
	    break;

        case ct_subject:
            result=(NULL!=hpt_stristr(msg->subjectLine,cb->str));
            break;

        case ct_msgtext:
	    /* skip area: kludge */
            testptr=msg->text+6+strlen(echo->areaName);
            while(testptr!=NULL){
                testptr=hpt_stristr(testptr,cb->str);
                if(testptr!=NULL){
                    /* look back: a '\1' after a CR        */
                    /* means that it is a kludge           */
                    testptr2=testptr;   /* remind position */
                    while(*--testptr!='\r'); /* not CR    */
		    /* (skipped) area: kludge prevents going back too far :) */
                    if(*++testptr=='\1') /* was a kludge   */
                        testptr=testptr2+strlen(cb->str);
                    else
                        break;
                }
            }
            result=(NULL!=testptr);
            break;

        case ct_addr:
            result=!addrComp(msg->origAddr, cb->addr);
            break;

        case ct_fromarea:
	    result=!stricmp(echo->areaName,cb->str);
            break;

        case ct_group:
            if(echo->group!=NULL){
		/* cb->str for example Fido,xxx,.. */
                testptr=cb->str;
                do{
                    if(NULL==(testptr=hpt_stristr(echo->group,testptr)))
                        break;
                    testptr+=strlen(echo->group);
                    result=(*testptr==',' || *testptr==' ' || !*testptr);
                    testptr-=strlen(echo->group);
                    ++testptr;
                }while(!result);
            }
            break;
        }

        if(cb->rule&CC_NOT) /* NOT on/off */
            result=!result;

        switch(cb->rule&CC_AND){ /* what operation with next result */
        case CC_OR: /* OR */
            if (result && area && cb->move!=2 && !config->carbonAndQuit) { 
                /* check if we've done cc to dest area already */
                for (ncop=0; ncop < copiedToCount && result; ncop++)
                    if (area == copiedTo[ncop]) result = 0;
                if (result) {
                    copiedTo = safe_realloc (copiedTo, (copiedToCount+1) * sizeof (s_area *));
                    copiedTo[copiedToCount] = area;
                    copiedToCount++;
                }
            }

            if(result){
                /* make cc */
                /* Set value: 1 if copy 3 if move */
                rc = cb->move ? 3 : 1;
                if(cb->extspawn)
                    processExternal(echo,msg,*cb);
                else
                    if (cb->areaName && cb->move!=2)
                        if (!processCarbonCopy(area,echo,msg,*cb))
                            rc &= 1;

		// delete CarbonMove and CarbonDelete messages
		if (cb->move && xmsg) xmsg->attr |= MSGKILL;
                if (config->carbonAndQuit)
		    /* not skip quit or delete */
                    if ((cb->areaName && *cb->areaName!='*') ||	cb->move==2) {
                        return rc;
		    }
            }
            break;
        case CC_AND: /* AND */
            if(!result){
                /* following expressions can be skipped until OR */
                for (++i,++cb; i<config->carbonCount; i++,++cb)
                    if(!cb->rule&CC_AND)
                        break; /* this is the last in the AND expr. chain */
            }
            /* else result==TRUE, so continue with next expr. */
            break;
        }
    } /* end for() */

    if (copiedTo) nfree (copiedTo);
    return rc;
}

int putMsgInBadArea(s_message *msg, s_addr pktOrigAddr, int writeAccess)
{
    char *tmp = NULL, *line = NULL, *textBuff=NULL, *areaName=NULL, *reason = NULL;
    
    statToss.bad++;
	 
    // get real name area
    line = strchr(msg->text, '\r');
    if (strncmp(msg->text,"AREA:",5)==0) {
	*line = 0;
	xstrcat(&areaName, msg->text+5);
	*line = '\r';
    }

    switch (writeAccess) {
    case 0: 
	reason = "System not allowed to create new area";
	break;
    case 1: 
	reason = "Sender not allowed to post in this area (access group)";
	break; 
    case 2: 
	reason = "Sender not allowed to post in this area (access level)";
	break;
    case 3: 
	reason = "Sender not allowed to post in this area (access import)";
	break;
    case 4: 
	reason = "Sender not active for this area";
	break;
    case 5:
	reason = "Rejected by filter";
	break;
    case 6:
	switch (msgapierr)
    {
	    case MERR_NONE: reason = "MSGAPIERR: No error";
		break;
	    case MERR_BADH: reason = "MSGAPIERR: Invalid handle passed to function";
		break;
	    case MERR_BADF: reason = "MSGAPIERR: Invalid or corrupted file";
		break;
	    case MERR_NOMEM: reason = "MSGAPIERR: Not enough memory for specified operation";
		break;
	    case MERR_NODS: 
		reason = "MSGAPIERR: Maybe not enough disk space for operation";
		w_log(LL_ERR, "Maybe not enough disk space for operation\r");
		break;
	    case MERR_NOENT: reason = "MSGAPIERR: File/message does not exist";
		break;
	    case MERR_BADA: reason = "MSGAPIERR: Bad argument passed to msgapi function";
		break;
	    case MERR_EOPEN: reason = "MSGAPIERR: Couldn't close - messages still open";
		break;
	    case MERR_NOLOCK: reason = "MSGAPIERR: Base needs to be locked to perform operation";
		break;
	    case MERR_SHARE: reason = "MSGAPIERR: Resource in use by other process";
		break;
	    case MERR_EACCES: reason = "MSGAPIERR: Access denied (can't write to read-only, etc)";
		break;
	    case MERR_BADMSG: reason = "MSGAPIERR: Bad message frame (Squish)";
		break;
	    case MERR_TOOBIG: reason = "MSGAPIERR: Too much text/ctrlinfo to fit in frame (Squish)";
		break;
	    default: reason = "MSGAPIERR: Unknown error";
		break;
	    }

	break;
    case 7:
	reason = "Can't create echoarea with forbidden symbols in areatag";
	break;
    case 8:
	reason = "Sender not found in config file";
	break;
    case 9:
	reason = "Can't open config file";
	break;
    case 10:
	reason = "No downlinks for passthrough area";
	break;
    case 11:
	reason = "lenght of CONFERENCE name is more than 60 symbols";
	break;
    default :
	reason = "Another error";
	break;
    }

#ifdef DO_PERL
    if (perltossbad(msg, areaName, pktOrigAddr, reason)) {
	nfree(areaName);
	nfree(msg->text);
	return 1;
    }
#endif

    tmp = msg->text;

    while ((line = strchr(tmp, '\r')) != NULL) {
	if (*(line+1) == '\x01') tmp = line+1;
	else { tmp = line+1; *line = 0; break; }
    }
	 
    xstrscat(&textBuff, msg->text, "\rFROM: ", aka2str(pktOrigAddr), "\rREASON: ", reason, "\r", NULL);

    if (areaName) xscatprintf(&textBuff, "AREANAME: %s\r\r", areaName);
    xstrcat(&textBuff, tmp);
    nfree(areaName);
    nfree(msg->text);
    msg->text = textBuff;
    msg->textLength = strlen(msg->text);
    if (putMsgInArea(&(config->badArea), msg, 0, 0)) {
	config->badArea.imported++;
	return 1;
    }
    return 0;
}

void makeMsgToSysop(char *areaName, s_addr fromAddr, s_addr *uplinkAddr)
{
    s_area *echo = NULL;
    unsigned int i, netmail=0;
    char *buff=NULL;
    char *strbeg=NULL;
    
    if (config->ReportTo) {
	if (stricmp(config->ReportTo,"netmail")==0) netmail=1;
	else if (getNetMailArea(config, config->ReportTo) != NULL) netmail=1;
    } else netmail=1;

    echo = getArea(config, areaName);
    
    if (echo == &(config->badArea)) return;
    
    for (i = 0; i < config->addrCount; i++) {
	if (echo->useAka == &(config->addr[i])) {
	    if (msgToSysop[i] == NULL) {

		msgToSysop[i] = makeMessage(echo->useAka, 
                                    echo->useAka, 
                                    versionStr,
                                    netmail ? config->sysop : "All", "Created new areas", 
                                    netmail,
                                    config->areafixKillReports);
		msgToSysop[i]->text = createKludges(
                                    config->disableTID,
                                    netmail ? NULL : config->ReportTo, 
                                    echo->useAka, echo->useAka,
                                    versionStr);

		xstrscat(&(msgToSysop[i]->text), "\001FLAGS NPD\r",
		         "Action   Name", print_ch(49, ' '), "By\r", NULL);
		// Shitty static variables ....
		xstrscat(&(msgToSysop[i]->text), print_ch(79, '-'), "\r", NULL);
		msgToSysop[i]->recode |= (REC_HDR|REC_TXT);
		w_log(LL_NETMAIL,"Created msg to sysop");
	    }

//          New report generation
            xstrcat(&buff, aka2str(fromAddr));
            if (uplinkAddr != NULL) { // autocreation with forward request
		xstrcat(&buff, " from ");
		xstrcat(&buff, aka2str(*uplinkAddr));
            }
            xstrscat(&strbeg, "Created  ", echo->areaName, NULL);

            if (echo->description) {
		if (strlen(strbeg) + strlen(echo->description) >=77) {
		    xstrscat(&(msgToSysop[i]->text), strbeg, "\r", NULL);
		    nfree(strbeg);
		    xstrcat(&strbeg, print_ch(9, ' '));
		} else {
		    xstrcat(&strbeg, " ");
		}
		xstrscat(&strbeg, "\"", echo->description, "\"", NULL);
            }

            xstrcat(&(msgToSysop[i]->text), strbeg);

            if (strlen(strbeg) + strlen(buff) >= 79) {
		xstrscat(&(msgToSysop[i]->text), "\r", print_ch(79-strlen(buff), ' '), buff, "\r", NULL);
            } else if (strlen(strbeg) <62 && strlen(buff) < 79-62) { // most beautiful
		xstrscat(&(msgToSysop[i]->text), print_ch(62-strlen(strbeg), ' '), buff, "\r", NULL);
            } else { 
		xstrscat(&(msgToSysop[i]->text), print_ch(79-strlen(strbeg)-strlen(buff), ' '), buff, "\r", NULL);
            }
            nfree(buff);
            nfree(strbeg);

//          Old report generation
//	    xscatprintf(&(msgToSysop[i]->text), "Created  %-53s%s\r", 
//	         echo->areaName, aka2str(fromAddr));

	    break;
	}
    }
    
}

void writeMsgToSysop()
{
    char	*ptr = NULL, *seenByPath = NULL;
    s_area	*echo = NULL;
    unsigned int i, ccrc = 0;
    s_seenBy	*seenBys = NULL;
    
    for (i = 0; i < config->addrCount; i++) {
	if (msgToSysop[i]) {
	    xscatprintf(&(msgToSysop[i]->text), " \r--- %s\r * Origin: %s (%s)\r", 
			(config->tearline) ? config->tearline : "",
			(config->origin) ? config->origin : config->name,
			aka2str(msgToSysop[i]->origAddr));
	    msgToSysop[i]->textLength = strlen(msgToSysop[i]->text);
	    
	    if (msgToSysop[i]->netMail == 1) 
		// FIXME: should be putMsgInArea 
		processNMMsg(msgToSysop[i], NULL, config->ReportTo ?
			     getNetMailArea(config, config->ReportTo) : NULL, 1, 0);
	    else {
		// get echoarea  for this msg    
		ptr = strchr(msgToSysop[i]->text, '\r');
		*ptr = '\0'; echo = getArea(config, msgToSysop[i]->text + 5); *ptr = '\r';
		
		if (echo != &(config->badArea)) {
		    if (config->carbonCount != 0) 
			ccrc = carbonCopy(msgToSysop[i], NULL, echo);
		    if (echo->msgbType != MSGTYPE_PASSTHROUGH && ccrc <= 1) {
        		putMsgInArea(echo, msgToSysop[i],1, (MSGSCANNED|MSGSENT|MSGLOCAL));
        		echo->imported++;  // area has got new messages
		    }

		    seenBys = (s_seenBy*) safe_malloc(sizeof(s_seenBy)*(echo->downlinkCount+1));
		    seenBys[0].net = (UINT16) echo->useAka->net;
		    seenBys[0].node = (UINT16) echo->useAka->node;
		    sortSeenBys(seenBys, 1);
   
		    seenByPath = createControlText(seenBys, 1, "SEEN-BY: ");
		    nfree(seenBys);
   
		    // path line
		    // only include node-akas in path
		    if (echo->useAka->point == 0) 
   			xscatprintf(&seenByPath, "\001PATH: %u/%u\r", echo->useAka->net, echo->useAka->node);
		    xstrcat(&(msgToSysop[i]->text), seenByPath);
		    nfree(seenByPath);
		    if (echo->downlinkCount > 0) {
			// recoding from internal to transport charSet
			if (config->outtab) {
			    if (msgToSysop[i]->recode & REC_HDR) {
				recodeToTransportCharset((CHAR*)msgToSysop[i]->fromUserName);
		    		recodeToTransportCharset((CHAR*)msgToSysop[i]->toUserName);
		    		recodeToTransportCharset((CHAR*)msgToSysop[i]->subjectLine);
				msgToSysop[i]->recode &= ~REC_HDR;
			    }
			    if (msgToSysop[i]->recode & REC_TXT) {
				recodeToTransportCharset((CHAR*)msgToSysop[i]->text);
				msgToSysop[i]->recode &= ~REC_TXT;
			    }
			}
			forwardMsgToLinks(echo, msgToSysop[i], msgToSysop[i]->origAddr);
			closeOpenedPkt();
			tossTempOutbound(config->tempOutbound);
		    }
		} else {
		    putMsgInBadArea(msgToSysop[i], msgToSysop[i]->origAddr, 0);
		}
	    }
	}
    }
    
}

s_arealink *getAreaLink(s_area *area, s_addr aka)
{
    UINT i;

    for (i = 0; i <area->downlinkCount; i++) {
	if (addrComp(aka, area->downlinks[i]->link->hisAka)==0) return area->downlinks[i];
    }
	
    return NULL;
}

// import: type == 0, export: type != 0 
// return value: 0 if access ok, 3 if import/export off, 4 if not linked
int checkAreaLink(s_area *area, s_addr aka, int type)
{
    s_arealink *arealink = NULL;
    int writeAccess = 0;
	
    arealink = getAreaLink(area, aka);
    if (arealink) {
	if (type==0) {
	    if (arealink->import) writeAccess = 0; else writeAccess = 3;
	} else {
	    if (arealink->export) writeAccess = 0; else writeAccess = 3;
	}
    } else {
	if (addrComp(aka, *area->useAka)==0) writeAccess = 0;
	else writeAccess = 4;
    }
	
    return writeAccess;
}

int processEMMsg(s_message *msg, s_addr pktOrigAddr, int dontdocc, dword forceattr)
{
    char   *area=NULL, *p = NULL, *q = NULL;
    s_area *echo=&(config->badArea);
    s_link *link = NULL;
    int    writeAccess = 0, rc = 0, ccrc = 0;

    p = strchr(msg->text,'\r');
    if (p) {
	*p='\0';
	q = msg->text+5;
	while (*q == ' ') q++;
	xstrcat(&area, q);
	echo = getArea(config, area);
	*p='\r';
    }

    // no area found -- trying to autocreate echoarea
    if (echo == &(config->badArea)) {
	// checking for autocreate option
	link = getLinkFromAddr(config, pktOrigAddr);
	if ((link != NULL) && (link->autoAreaCreate != 0)) {
	    if (0 == (writeAccess = autoCreate(area, pktOrigAddr, NULL)))
		echo = getArea(config, area);
	    else rc = putMsgInBadArea(msg, pktOrigAddr, writeAccess);
	} // can't create echoarea - put msg in BadArea
	else rc = putMsgInBadArea(msg, pktOrigAddr, writeAccess);
    }

    nfree(area);

    if (echo != &(config->badArea)) {
	// area is autocreated!

	// cheking access of this link
	writeAccess = checkAreaLink(echo, pktOrigAddr, 0);
	if (writeAccess) rc = putMsgInBadArea(msg, pktOrigAddr, writeAccess);
	else { // access ok - process msg

	    if (dupeDetection(echo, *msg)==1) {
		// no dupe
		statToss.echoMail++;

		// if only one downlink, we've got the mail from him
		if ((echo->downlinkCount > 1) ||
		    ((echo->downlinkCount > 0) && 
		     // mail from us
		     (addrComp(pktOrigAddr,*echo->useAka)==0)))
		    forwardMsgToLinks(echo, msg, pktOrigAddr);

		if ((config->carbonCount!=0)&&(!dontdocc))
		    ccrc=carbonCopy(msg, NULL, echo);

		if (ccrc <= 1) {
		    echo->imported++;  // area has got new messages
		    if (echo->msgbType != MSGTYPE_PASSTHROUGH) {
			rc = putMsgInArea(echo, msg, 1, forceattr);
			statToss.saved += rc;
		    }
		    else { // passthrough
			/*
			  if (echo->downlinkCount==1 && dontdocc==0)
			  rc = putMsgInBadArea(msg, pktOrigAddr, 10);
			  else {
			  statToss.passthrough++;
			  rc = 1;
			  }
			*/
			statToss.passthrough++;
			rc = 1;
		    }
		} else rc = 1; // normal exit for carbon move & delete

	    } else {
		// msg is dupe
		if (echo->dupeCheck == dcMove) {
		    // rc = putMsgInDupeArea(pktOrigAddr, msg, forceattr);
		    rc = putMsgInArea(&(config->dupeArea), msg, 0, forceattr);
		} else rc = 1;
		statToss.dupes++;
		if (rc) config->dupeArea.imported++;
	    }
	}
    }
    return rc;
}

int processNMMsg(s_message *msg, s_pktHeader *pktHeader, s_area *area, int dontdocc, dword forceattr)
{
    HAREA  netmail;
    HMSG   msgHandle;
    UINT   len = 0;
    char   *bodyStart = NULL;             // msg-body without kludgelines start
    char   *ctrlBuf = NULL;               // Kludgelines
    XMSG   msgHeader;
//    char   *slash = NULL;
    unsigned int rc = 0, ccrc = 0, i;

    if (area == NULL) {
	area = &(config->netMailAreas[0]);
	for(i=0; i<config->netMailAreaCount; i++) {
	    if(addrComp(msg->destAddr,*(config->netMailAreas[i].useAka))==0) {
		area = &(config->netMailAreas[i]);
		break;
	    }
	}
    }

    if (dupeDetection(area, *msg)==0) {
	// msg is dupe
	if (area->dupeCheck == dcMove) {
	    rc = putMsgInArea(&(config->dupeArea), msg, 0, forceattr);
	} else rc = 1;
	statToss.dupes++;
	if (rc) config->dupeArea.imported++;
	return rc;
    }

    if ((config->carbonCount!=0)&&(!dontdocc)) ccrc = carbonCopy(msg, NULL, area);
    if (ccrc > 1) return 1; // carbon del or move

    netmail = MsgOpenArea((unsigned char *) area -> fileName, MSGAREA_CRIFNEC,
/*								 config->netMailArea.fperm, config->netMailArea.uid,
								 config->netMailArea.gid, */(word) area -> msgbType);
   
    if (netmail != NULL) {
	msgHandle = MsgOpenMsg(netmail, MOPEN_CREATE, 0);

	if (msgHandle != NULL) {
	    area -> imported++; // area has got new messages

	    // recode from TransportCharset to internal Charset
	    if (config->intab != NULL) {
		if ((msg->recode & REC_HDR)==0) {
		    recodeToInternalCharset((CHAR*)msg->fromUserName);
		    recodeToInternalCharset((CHAR*)msg->toUserName);
		    recodeToInternalCharset((CHAR*)msg->subjectLine);
		    msg->recode |= REC_HDR;
		}
		if ((msg->recode & REC_TXT)==0) {
		    recodeToInternalCharset((CHAR*)msg->text);
		    msg->recode |= REC_TXT;
		}
	    }

	    msgHeader = createXMSG(config,msg, pktHeader, forceattr,tossDir);
	    /* Create CtrlBuf for SMAPI */
            len = msg->textLength;
	    ctrlBuf = (char *) CopyToControlBuf((UCHAR *) msg->text, (UCHAR **) &bodyStart, &len);
	    /* write message */
	    if (MsgWriteMsg(msgHandle, 0, &msgHeader, (UCHAR *)
			    bodyStart, len, len, strlen(ctrlBuf)+1,
			    (UCHAR *) ctrlBuf)!=0) w_log(LL_ERR,"Could not write msg to NetmailArea %s",area->areaName);
	    else rc = 1; // normal exit
	    nfree(ctrlBuf);
	    if (MsgCloseMsg(msgHandle)!=0) { // can't close
		w_log(LL_ERR,"Could not close msg in NetmailArea %s",area->areaName);
		rc = 0;
	    } else { // normal close
		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);
		statToss.netMail++;
	    }

	} else {
	    w_log(LL_ERR, "Could not create new msg in NetmailArea %s", area -> areaName);
	} /* endif */

	MsgCloseArea(netmail);
    } else {
	fprintf(stderr, "msgapierr - %u\n", msgapierr);
	w_log(LL_ERR, "Could not open NetmailArea %s", area -> areaName);
    } /* endif */
    return rc;
}

int processMsg(s_message *msg, s_pktHeader *pktHeader, int secure)
{
    int rc;

    w_log(LL_FUNC,"toss.c::processMsg()");
    statToss.msgs++;
#ifdef DO_PERL
    w_log(LL_SRCLINE, "toss.c:%u:processMsg() #ifdef DO_PERL", __LINE__);
    if ((rc = perlfilter(msg, pktHeader->origAddr, secure)) == 1)
	return putMsgInBadArea(msg, pktHeader->origAddr, 5);
    else if (rc == 2)
	return 1;
#endif
    if (msg->netMail == 1) {
        w_log(LL_NETMAIL, "Netmail from %s to %u:%u/%u.%u", aka2str(msg->origAddr),
              msg->destAddr.zone, msg->destAddr.net, msg->destAddr.node, msg->destAddr.point);
	if (config->areafixFromPkt &&
	    isOurAka(config, msg->destAddr) &&
	    strlen(msg->toUserName)>0 &&
	    (stricmp(msg->toUserName,"areafix")==0 ||
	     stricmp(msg->toUserName,"areamgr")==0 ||
	     stricmp(msg->toUserName,"hpt")==0 ||
	     hpt_stristr(config->areafixNames,msg->toUserName))) {
	    rc = processAreaFix(msg, pktHeader, 0);
	} else
	    rc = processNMMsg(msg, pktHeader, NULL, 0, 0);
    } else {
	rc = processEMMsg(msg, pktHeader->origAddr, 0, 0);
    } /* endif */
    w_log(LL_FUNC,"toss.c::processMsg() rc=%d", rc);
    return rc;
}

int processPkt(char *fileName, e_tossSecurity sec)
{
    FILE        *pkt = NULL;
    s_pktHeader *header = NULL;
    s_message   *msg = NULL;
    s_link      *link = NULL;
    int         rc = 0, msgrc = 0;
    long	pktlen;
    time_t      realtime;
    /* +AS+ */
    char        *extcmd = NULL;
    int         cmdexit;
    /* -AS- */
    char        processIt = 0; // processIt = 1, process all mails
    // processIt = 2, process only Netmail
    // processIt = 0, do not process pkt
   
    w_log(LL_FUNC,"toss.c::processPkt()");

    if ((pktlen = fsize(fileName)) > 60) {

	statToss.inBytes += pktlen;

	/* +AS+ */
	if (config->processPkt)
	    {
		extcmd = safe_malloc(strlen(config->processPkt)+strlen(fileName)+2);
		sprintf(extcmd,"%s %s",config->processPkt,fileName);
		w_log(LL_EXEC, "ProcessPkt: execute string \"%s\"",extcmd);
		if ((cmdexit = system(extcmd)) != 0)
		    w_log(LL_ERR, "exec failed, code %d", cmdexit);
		nfree(extcmd);
	    }
	/* -AS- */
#ifdef DO_PERL
	if (perlpkt(fileName, (sec==secLocalInbound || sec==secProtInbound) ? 1 : 0))
	    return 6;
#endif
       
	pkt = fopen(fileName, "rb");
	if (pkt == NULL) return 2;
        w_log(LL_FILE,"toss.c:processPkt(): opened '%s' (\"rb\" mode)",fileName);
       
	header = openPkt(pkt);
	if (header != NULL) {
	    //if ((to_us(header->destAddr)==0) || (sec == secLocalInbound)) {
        if ( isOurAka(config,header->destAddr) || (sec == secLocalInbound)) {
		w_log(LL_PKT, "pkt: %s [%s]", fileName, aka2str(header->origAddr));
		statToss.pkts++;
		link = getLinkFromAddr(config, header->origAddr);
		if ((link!=NULL) && (link->pktPwd==NULL) && (header->pktPassword[0]!='\000'))
		    w_log(LL_ERR, "Unexpected Password %s.", header->pktPassword);

		switch (sec) {
		case secLocalInbound:
		    processIt = 1;
		    break;
	     
		case secProtInbound:
		    if ((link != NULL) && (link->pktPwd != NULL) && link->pktPwd[0]) {
			if (stricmp(link->pktPwd, header->pktPassword)==0) {
			    processIt = 1;
			} else {
			    if ( (header->pktPassword == NULL || header->pktPassword[0] == '\0') && (link->allowEmptyPktPwd & (eSecure | eOn)) ) {
				w_log(LL_ERR, "pkt: %s Warning: missing packet password from %i:%i/%i.%i",
				      fileName, header->origAddr.zone, header->origAddr.net,
				      header->origAddr.node, header->origAddr.point);
				processIt = 1;
			    } else {
				w_log(LL_ERR, "pkt: %s Password Error for %i:%i/%i.%i",
				      fileName, header->origAddr.zone, header->origAddr.net,
				      header->origAddr.node, header->origAddr.point);
				if (header->pktPassword == NULL || header->pktPassword[0] == '\0')
				    processIt = 2;
				else
				    rc = 1;
			    }
			}
		    } else if ((link != NULL) && ((link->pktPwd == NULL) || (strcmp(link->pktPwd, "")==0))) {
			processIt=1;
		    } else /* if (link == NULL) */ {	
			w_log(LL_ERR, "pkt: %s No Link for %i:%i/%i.%i, processing only Netmail",
			      fileName, header->origAddr.zone, header->origAddr.net,
			      header->origAddr.node, header->origAddr.point);
			processIt = 2;
		    }
		    break;

		case secInbound:
		    if ((link != NULL) && (link->pktPwd != NULL) && link->pktPwd[0]) {

			if (header->pktPassword && stricmp(link->pktPwd, header->pktPassword)==0) {
			    processIt = 1;
			} else {
			    if ( (header->pktPassword == NULL || header->pktPassword[0] == '\0') && (link->allowEmptyPktPwd & (eOn)) ) {
				w_log(LL_ERR, "pkt: %s Warning: missing packet password from %i:%i/%i.%i",
				      fileName, header->origAddr.zone, header->origAddr.net,
				      header->origAddr.node, header->origAddr.point);
				processIt = 2; /* Unsecure inbound, do not process echomail */
			    } else {
				w_log(LL_ERR, "pkt: %s Password Error for %i:%i/%i.%i",
				      fileName, header->origAddr.zone, header->origAddr.net,
				      header->origAddr.node, header->origAddr.point);
				rc = 1;
			    }
			}
		    } else if ((link != NULL) && ((link->pktPwd == NULL) || (strcmp(link->pktPwd, "")==0))) {
			processIt=1;
		    } else /* if (link == NULL) */ {	
			w_log(LL_ERR, "pkt: %s No Link for %i:%i/%i.%i, processing only Netmail",
			      fileName, header->origAddr.zone, header->origAddr.net,
			      header->origAddr.node, header->origAddr.point);
			processIt = 2;
		    }
		    break;
	     
		}

		if (processIt != 0) {
		    realtime = time(NULL);
		    while ((msgrc = readMsgFromPkt(pkt, header, &msg)) == 1) {
			if (msg != NULL) {
			    if ((processIt == 1) || ((processIt==2) && (msg->netMail==1))) {
				if (processMsg(msg, header,
					       (sec==secLocalInbound ||
						sec==secProtInbound ||
						processIt == 1) ? 1 : 0) != 1 )
				    if (putMsgInBadArea(msg, header->origAddr, 6)==0)
					rc = 5; // can't write to badArea - rename to .err
			    } else rc = 1;
			    freeMsgBuffers(msg);
			    nfree(msg);
			}
		    }
		    if (msgrc==2) rc = 3; // rename to .bad (wrong msg format)
		    // real time of process pkt & msg without external programs
		    statToss.realTime += time(NULL) - realtime;
		}
	   
	    } else {
		realtime = time(NULL);
		while ((msgrc = readMsgFromPkt(pkt, header, &msg)) == 1) {
		    if (msg != NULL) {
			if (msg->netMail==1)
			    {   if (processMsg(msg, header, (sec==secLocalInbound || sec==secProtInbound) ? 1 : 0) !=1 )
				rc=5;
			    } else
				break;
			freeMsgBuffers(msg);
			nfree(msg);
		    }
		}
		if (msg)
		    {	/* echomail pkt not for us */
			freeMsgBuffers(msg);
			nfree(msg);
	   
	  		/* PKT is not for us - try to forward it to our links */

			w_log(LL_ERR, "pkt: %s addressed to %d:%d/%d.%d but not for us", 
			      fileName, header->destAddr.zone, header->destAddr.net,       
			      header->destAddr.node, header->destAddr.point);
	   
			fclose(pkt); pkt = NULL;
			rc = forwardPkt(fileName, header, sec);	   
		    }
	    }
	 
	    nfree(header);
	 
	} else { // header == NULL
	    w_log(LL_ERR, "pkt: %s wrong pkt-file", fileName);
	    rc = 3;
	}
       
	if (pkt) fclose(pkt);

    } else statToss.empty++;

#ifdef DO_PERL
    perlpktdone(fileName, rc);
#endif
    closeOpenedPkt();
    w_log(LL_FUNC,"toss.c::processPkt() OK");
    return rc;
}

#if ( (defined __WATCOMC__) || (defined(_MSC_VER) && (_MSC_VER >= 1200)) )
void *mk_lst(char *a)
{
    char *p=a, *q=a, **list=NULL, end=0, num=0;

    while (*p && !end) {
	while (*q && !isspace(*q)) q++;
	if (*q=='\0') end=1;
	*q ='\0';
	list = (char **) safe_realloc(list, ++num*sizeof(char*));
	list[num-1]=(char*)p;
	if (!end) {
	    p=q+1;
	    while(isspace(*p)) p++;
	}
	q=p;
    }
    list = (char **) safe_realloc(list, (++num)*sizeof(char*));
    list[num-1]=NULL;

    return list;
}
#endif

int  processArc(char *fileName, e_tossSecurity sec)
{
    unsigned int  i;
    int   found, j;
    signed int cmdexit;
    FILE  *bundle = NULL;
    char cmd[256];

#if ( (defined __WATCOMC__) || (defined(_MSC_VER) && (_MSC_VER >= 1200)) )
    const char * const *list;
#endif

    if (sec == secInbound) {
	w_log(LL_ERR, "bundle %s: tossing in unsecure inbound, security violation", fileName);
	return 1;
    };

    // find what unpacker to use
    for (i = 0, found = 0; (i < config->unpackCount) && !found; i++) {
	bundle = fopen(fileName, "rb");
	if (bundle == NULL) return 2;
        w_log(LL_FILE,"toss.c:processArc(): opened '%s' (\"rb\" mode)",fileName);

	// is offset is negative we look at the end
	fseek(bundle, config->unpack[i].offset, config->unpack[i].offset >= 0 ? SEEK_SET : SEEK_END);
	if (ferror(bundle)) { fclose(bundle); continue; };
	for (found = 1, j = 0; j < config->unpack[i].codeSize; j++) {
	    if ((getc(bundle) & config->unpack[i].mask[j]) != config->unpack[i].matchCode[j])
		found = 0;
	}
	fclose(bundle);
    }

    // unpack bundle
    if (found) {
	fillCmdStatement(cmd,config->unpack[i-1].call,fileName,"",config->tempInbound);
	if( hpt_stristr(config->unpack[i-1].call, "zipInternal") )
	    {
                w_log(LL_BUNDLE, "bundle %s: unpacking with zlib", fileName);
#ifdef USE_HPT_ZLIB
		cmdexit = UnPackWithZlib(fileName, config->tempInbound);
#else
		cmdexit = 1;
                w_log(LL_ERR, "zlib not compiled into hpt", fileName);
#endif
	    }
	else
	    {
                w_log(LL_EXEC, "bundle %s: unpacking with \"%s\"", fileName, cmd);
#if ( (defined __WATCOMC__) || (defined(_MSC_VER) && (_MSC_VER >= 1200)) )
		list = mk_lst(cmd);
		cmdexit = spawnvp(P_WAIT, cmd, list);
		free((char **)list);
		if (cmdexit != 0) {
		    w_log(LL_ERR, "exec failed: %s, return code: %d", strerror(errno), cmdexit);
		    return 3;
		}
#else
		if ((cmdexit = system(cmd)) != 0) {
		    w_log(LL_ERR, "exec failed, code %d", cmdexit);
		    return 3;
		}
#endif
	    }
	if (config->afterUnpack) {
	    w_log(LL_EXEC, "afterUnpack: execute string \"%s\"", config->afterUnpack);
	    if ((cmdexit = system(config->afterUnpack)) != 0) {
		w_log(LL_ERR, "exec failed, code %d", cmdexit);
	    };
	}
#ifdef DO_PERL
	perlafterunp();
#endif
    } else {
	w_log(LL_ERR, "bundle %s: cannot find unpacker", fileName);
	return 3;
    };
    statToss.arch++;
    remove(fileName);
    processDir(config->tempInbound, sec);
    return 7;
}


typedef struct fileInDir {
    char *fileName;
    time_t fileTime;
} s_fileInDir;
 
int filesComparer(const void *elem1, const void *elem2) {
    // File times comparer for qsort
    if (((s_fileInDir *) elem1) -> fileTime < ((s_fileInDir *) elem2) -> fileTime) return -1;
    if (((s_fileInDir *) elem1) -> fileTime == ((s_fileInDir *) elem2) -> fileTime) return 0;
    return 1;
}

static char *validExt[] = { "su", "mo", "tu", "we", "th", "fr", "sa" };

static int isArcMail(char *fname)
{
	char *p;
	int i;
	p=strrchr(fname, PATH_DELIM);
	if (p) p++;
	else p=fname;
	/* Amiga? */
	for (i=0; i<8; i++)
		if (!isalnum(p[i]))
			break;
	if (i<8) {
		/* Amiga? */
		for (i=0; i<4; i++) {
			if (!isdigit(*p++)) return 0;
			while (isdigit(*p)) p++;
			if (*p++ != '.') return 0;
		}
	} else {
		p += i;
		if (*p++ != '.') return 0;
	}
	for (i=0; i<sizeof(validExt)/sizeof(validExt[0]); i++)
		if (strncasecmp(p, validExt[i], 2) == 0)
			break;
	if (i == sizeof(validExt)/sizeof(*validExt)) return 0;
	return (isalnum(p[2]) && (p[3] == '\0'));
}

void processDir(char *directory, e_tossSecurity sec)
{
    DIR            *dir = NULL;
    struct dirent  *file = NULL;
    char           *dummy = NULL;
    int            rc;
    int            pktFile,
	arcFile;
    s_fileInDir *files = NULL;
    int nfiles=0;
    struct stat st;
    int dirNameLen;
    int filenum;
    char *newFileName=NULL;
    char *ext[]={NULL, "sec", "asc", "bad", "ntu", "err", "flt"};

#ifndef UNIX
    unsigned fattrs;
#endif

    if (directory==NULL) return;

    tossDir = directory;

    dirNameLen = strlen(directory);

#ifdef NOSLASHES
    directory[dirNameLen-1]='\0';
#endif

    if (NULL == (dir = opendir(directory))) {
	printf("Can't open dir: %s!\n",directory);
	return;
    }

#ifdef NOSLASHES
    directory[dirNameLen-1]='\\';
#endif

    while ((file = readdir(dir)) != NULL) {
#ifdef DEBUG_HPT
	printf("testing %s\n", file->d_name);
#endif

	dummy = (char *) safe_malloc(dirNameLen + strlen(file->d_name) + 1);
	strcpy(dummy,directory);
	strcat(dummy,file->d_name);

#if !defined(UNIX)
#if defined(__TURBOC__) || defined(__DJGPP__)
	_dos_getfileattr(dummy, &fattrs);
#elif defined(__MINGW32__)
	fattrs = (GetFileAttributes(dummy) & 0x2) ? _A_HIDDEN : 0;
#else
	fattrs = file->d_attr;
#endif
	if(fattrs & _A_HIDDEN) {
	    nfree(dummy);
	} else
#endif
	    {
		nfiles++;
		files = (s_fileInDir *) safe_realloc(files,nfiles*sizeof(s_fileInDir));
		(files[nfiles-1]).fileName = dummy;

		if(stat((files[nfiles-1]).fileName, &st)==0) {
		    (files[nfiles-1]).fileTime = st.st_mtime;
		} else {
		    // FixMe - don't know what to set :(
		    (files[nfiles-1]).fileTime = 0L;
		}

	    }
    }
    closedir(dir);

    qsort (files, nfiles, sizeof(s_fileInDir), filesComparer);

    for ( filenum=0; filenum < nfiles; filenum++) {
	arcFile = pktFile = 0;
	dummy = (files[filenum]).fileName;
#ifdef DEBUG_HPT
	printf("testing sorted %s\n", dummy);
#endif
	if (!(pktFile = patimat(dummy+dirNameLen, "*.pkt") == 1))
	    if (isArcMail(dummy+dirNameLen))
		arcFile = 1;

	if (pktFile || (arcFile && !config->noProcessBundles)) {

	    rc = 3; // nonsence, but compiler warns
	    if (config->tossingExt != NULL &&
		(newFileName=changeFileSuffix(dummy, config->tossingExt)) != NULL){
		nfree(dummy);
		dummy = newFileName;
		newFileName=NULL;
	    }
	    if (pktFile)
		rc = processPkt(dummy, sec);
	    else // if (arcFile)
		rc = processArc(dummy, sec);

	    if (rc>=1 && rc<=6) {
		w_log(LL_ERR, "Renaming pkt/arc to .%s",ext[rc]);
		newFileName=changeFileSuffix(dummy, ext[rc]);
	    } else {
		if (rc!=7) remove(dummy);
	    }
	}
	nfree(dummy);
	nfree(newFileName);
    }
    nfree(files);
}

void writeStatLog(void) {
    /* write personal mail statistic logfile if statlog is defined in config */
    /* if the log file exists, the existing value is increased */

    FILE *f = NULL;
    char buffer[256];
    int len, x, statNetmail, statCC;

    statNetmail = statToss.netMail; /* number of just received netmails */
    statCC = statToss.CC; /* number of just received personal echo mails */

    /* if there are new personal mails and statLog is defined in config */
    if (((statNetmail > 0) || (statCC > 0)) && (config->statlog != NULL)) {
	f = fopen(config->statlog, "r");
	if (f != NULL) {  /* and statLog file is readable */
            w_log(LL_FILE,"toss.c:writeStatLog(): opened '%s' (\"r\" mode)",config->statlog);

	    /* then read last personal mail counter and add to actual counter */
	    while(fgets(buffer,sizeof(buffer),f)) {
		len = strlen(buffer);
		for (x=0; x!=len; x++) {
		    if (!strncasecmp(buffer+x, "netmail: ",9)) {
			/* netmail found */
			statNetmail += atoi(buffer+9);
		    }

		    if (!strncasecmp(buffer+x, "CC: ",4)) {
			/* personal echomail (CC) found */
			statCC += atoi(buffer+4);
		    }
		}
	    }

	    fclose(f);
	}

	/* and write personal mail counter for netmails and echo mails */
	f = fopen(config->statlog, "wt");
	if (f != NULL) {
            w_log(LL_FILE,"toss.c:writeStatLog(): opened '%s' (\"wt\" mode)",config->statlog);
	    if (statNetmail > 0) {
		fprintf(f, "netmail: %d\n", statNetmail);
	    }
	    if (statCC > 0) {
		fprintf(f, "CC: %d\n", statCC);
	    }
		 
	    fclose(f);
	}
    }
}

void writeTossStatsToLog(void) {
    unsigned int i;
    float inMailsec, outMailsec, inKBsec;
    time_t diff = statToss.realTime;
    char logchar;

    if (statToss.pkts==0 && statToss.msgs==0)
	logchar='1';
    else
	logchar='4';

    if (diff == 0) diff = 1;

    inMailsec = ((float)(statToss.msgs)) / diff;
    outMailsec = ((float)(statToss.exported)) / diff;
    inKBsec = ((float)(statToss.inBytes)) / diff / 1024;

    w_log(logchar, "Statistics:");
    w_log(logchar, "     arc: % 5d   netMail: % 4d   echoMail: % 5d         CC: % 5d",
	  statToss.arch, statToss.netMail, statToss.echoMail, statToss.CC);
    w_log(logchar, "   pkt's: % 5d      dupe: % 4d   passthru: % 5d   exported: % 5d",
	  statToss.pkts, statToss.dupes, statToss.passthrough, statToss.exported);
    w_log(logchar, "    msgs: % 5d       bad: % 4d      saved: % 5d      empty: % 5d",
	  statToss.msgs, statToss.bad, statToss.saved, statToss.empty);
    w_log(logchar, "   Input: % 8.2f mails/sec        Output: % 8.2f mails/sec", inMailsec, outMailsec);
    w_log(logchar, "          % 8.2f kb/sec", inKBsec);

    /* write personal mail statistic logfile */
    writeStatLog();

    /* Now write areas summary */
    w_log(logchar, "Areas summary:");
    for (i = 0; i < config->netMailAreaCount; i++)
	if (config->netMailAreas[i].imported > 0)
	    w_log(logchar, "netmail area %s - %d msgs", 
		  config->netMailAreas[i].areaName, config->netMailAreas[i].imported);
    if (config->dupeArea.imported) w_log(logchar, "dupe area %s - %d msgs", 
					 config->dupeArea.areaName,
					 config->dupeArea.imported);
    if (config->badArea.imported) w_log(logchar, "bad area %s - %d msgs", 
					config->badArea.areaName,
					config->badArea.imported);
    for (i = 0; i < config->echoAreaCount; i++)
	if (config->echoAreas[i].imported > 0)
	    w_log(logchar, "echo area %s - %d msgs", 
		  config->echoAreas[i].areaName, config->echoAreas[i].imported);
    for (i = 0; i < config->localAreaCount; i++)
	if (config->localAreas[i].imported > 0)
	    w_log(logchar, "local area %s - %d msgs", 
		  config->localAreas[i].areaName, config->localAreas[i].imported);
}

int find_old_arcmail(s_link *link, FILE *flo)
{
    char *line = NULL, *bundle=NULL;
    ULONG len;
    unsigned as;

    while ((line = readLine(flo)) != NULL) {
#ifndef UNIX
	line = trimLine(line);
#endif
	if (isArcMail(line) && (*line == '^' || *line == '#')) {
	    nfree(bundle);
	    /* One char for first symbol in flo file */
	    bundle = safe_strdup(line + 1);
	}
	nfree(line);
    }
    if (bundle == NULL) return 0;
    if (*bundle != '\000') {
	len = fsize(bundle);
	if (len != -1L) {
	    if (link->arcmailSize!=0) 
		as = link->arcmailSize;
	    else if (config->defarcmailSize!=0) 
		as = config->defarcmailSize;
	    else
		as = 500; // default 500 kb max
	    if (len < as * 1024L) {
		link->packFile=(char*) safe_realloc(link->packFile,strlen(bundle)+1);
		strcpy(link->packFile,bundle);
		nfree(bundle);
		return 1;
	    }
	}
    }
    nfree(bundle);
    return 0;
}

void arcmail(s_link *tolink) {
    char cmd[256], *pkt=NULL, *lastPathDelim = NULL, saveChar;
    int i, cmdexit, foa;
    FILE *flo = NULL;
    s_link *link = NULL;
    int startlink=0;
    int endlink = config->linkCount;
    e_bundleFileNameStyle bundleNameStyle;
#ifdef __WATCOMC__
    const char * const *list;
#endif

    if (tolink != NULL) {
	startlink = tolink - config->links;
	endlink = startlink + 1;
    }

    if (config->beforePack) {
	w_log(LL_EXEC, "beforePack: execute string \"%s\"", config->beforePack);
	if ((cmdexit = system(config->beforePack)) != 0) {
	    w_log(LL_ERR, "exec failed, code %d", cmdexit);
	};
    }
#ifdef DO_PERL
    perlbeforepack();
#endif

    for (i = startlink ; i < endlink; i++) {

	link = &(config->links[i]);

	// only create floFile if we have mail for this link
	if (link->pktFile != NULL) {
      

	    if (needUseFileBoxForLink(config,link)) {

		if (!link->fileBox) link->fileBox = makeFileBoxName (config,link);

		_createDirectoryTree (link->fileBox);

		if (link->packerDef != NULL) {

		    fillCmdStatement(cmd, link->packerDef->call,
				     link->packFile,
				     link->pktFile, "");
		    w_log(LL_BUNDLE, "Packing for %s %s, %s > %s",
			  aka2str(link->hisAka),
			  link->name, get_filename(link->pktFile),
			  get_filename(link->packFile));
		    w_log(LL_EXEC, "cmd: %s", cmd);
		    if( stricmp(link->packerDef->call, "zipInternal") == 0 )
			{
			    cmdexit = 1;
#ifdef USE_HPT_ZLIB
			    cmdexit = PackWithZlib(link->packFile, link->pktFile);
#endif
			} else {
#ifdef __WATCOMC__
			    list = mk_lst(cmd);
			    cmdexit = spawnvp(P_WAIT, cmd, list);
			    free((char **)list);
#else
			    cmdexit = system(cmd);
#endif
			}
		    if (cmdexit==0) remove(link->pktFile);
		    else w_log(LL_ERR, "Error executing packer (errorlevel==%i)", cmdexit);

		} // end packerDef
		else {
		    // there is no packer defined -> put pktFile into fileBox
		    xstrcat(&pkt, link->fileBox);
		    xstrcat(&pkt, link->pktFile + strlen(config->tempOutbound));

		    cmdexit = rename(link->pktFile, pkt);
		    if (cmdexit==0) w_log(LL_BUNDLE, "Leave non-packed mail for %s %s, %s",
					  aka2str(link->hisAka), link->name,
					  get_filename(link->pktFile));
		    else w_log(LL_ERR, "error moving file for %s %s, %s->%s (errorlevel==%i)", aka2str(link->hisAka), link->name, link->pktFile, pkt, errno);
		    nfree(pkt);
		}
    
	    } else if (createOutboundFileName(link,link->echoMailFlavour, FLOFILE) == 0) {
		// process if the link not busy, else do not create 12345678.?lo

		flo = fopen(link->floFile, "a+");

		if (flo == NULL)
		    w_log(LL_ERR, "Cannot open flo file %s",
			  config->links[i].floFile);
		else {
                    w_log(LL_FILE,"toss.c:arcmail(): opened '%s' (\"a+\" mode)",link->floFile);

		    if (link->linkBundleNameStyle!=eUndef)
			bundleNameStyle=link->linkBundleNameStyle;
		    else if (config->bundleNameStyle!=eUndef)
			bundleNameStyle=config->bundleNameStyle;
		    else bundleNameStyle = eTimeStamp;

		    if (link->packerDef != NULL) {

			// there is a packer defined -> put packFile into flo
			// if we are creating new arcmail bundle  ->  -//-//-
			fseek(flo, 0L, SEEK_SET);
			foa = find_old_arcmail(link, flo);

			fillCmdStatement(cmd, link->packerDef->call,
					 link->packFile,
					 link->pktFile, "");
			w_log(LL_BUNDLE, "Packing for %s %s, %s > %s",
			      aka2str(link->hisAka), link->name,
			      get_filename(link->pktFile),
			      get_filename(link->packFile));
			w_log(LL_EXEC, "cmd: %s", cmd);
			if( stricmp(link->packerDef->call, "zipInternal") == 0 )
			    {
				cmdexit = 1;
#ifdef USE_HPT_ZLIB
				cmdexit = PackWithZlib(link->packFile, link->pktFile);
#endif
			    }
			else
			    {
#ifdef __WATCOMC__
				list = mk_lst(cmd);
				cmdexit = spawnvp(P_WAIT, cmd, list);
				free((char **)list);
#else
				cmdexit = system(cmd);
#endif
			    }
			if (cmdexit==0) {
			    if (foa==0) {
				if (bundleNameStyle == eAddrDiff ||
				    bundleNameStyle == eAddrDiffAlways ||
				    bundleNameStyle == eAmiga)
				    fprintf(flo, "#%s\n", link->packFile);
				else
				    fprintf(flo, "^%s\n", link->packFile);
			    }
			    remove(link->pktFile);
			} else
			    w_log(LL_ERR, "Error executing packer (errorlevel==%i)", 
				  cmdexit);

		    } // end packerDef
		    else {
			// there is no packer defined -> put pktFile into flo
			lastPathDelim = strrchr(link->floFile, PATH_DELIM);

			// change path of file to path of flofile
			saveChar = *(++lastPathDelim);
			*lastPathDelim = '\0';
			xstrcat(&pkt, link->floFile);
			*lastPathDelim = saveChar;

			if (config->separateBundles) {

			    if (bundleNameStyle==eAmiga)
				xscatprintf(&pkt, "%u.%u.%u.%u.sep%c", 
					    link->hisAka.zone, link->hisAka.net,
					    link->hisAka.node, link->hisAka.point,
					    PATH_DELIM);
			    else {
				if (link->hisAka.point != 0)
				    xscatprintf(&pkt,"%08x.sep%c",
						link->hisAka.point,PATH_DELIM);
				else
				    xscatprintf(&pkt, "%04x%04x.sep%c",
						link->hisAka.net,
						link->hisAka.node, 
						PATH_DELIM);
			    }
			}

			xstrcat(&pkt, link->pktFile + strlen(config->tempOutbound));

			cmdexit = rename(link->pktFile, pkt);
			if (cmdexit==0) {
			    fprintf(flo, "^%s\n", pkt);
			    w_log(LL_BUNDLE, "Leave non-packed mail for %s %s, %s",
				  aka2str(link->hisAka), link->name,
				  get_filename(link->pktFile));
			}
			else w_log(LL_ERR, "error moving file for %s %s, %s->%s (errorlevel==%i)", aka2str(link->hisAka), link->name, link->pktFile, pkt, errno);
			nfree(pkt);
		    }

		    fclose(flo);
		} // end flo

		nfree(link->floFile);
		remove(link->bsyFile);
		nfree(link->bsyFile);
	    } // end outboundFileNameCreated

	    nfree(link->pktFile);
	    nfree(link->packFile);
	} // end pkt file

    } // endfor
    return;
}

static int forwardedPkts = 0;

int forwardPkt(const char *fileName, s_pktHeader *header, e_tossSecurity sec)
{
    unsigned int i;
    s_link *link = NULL;
    char *newfn = NULL;
    
    for (i = 0 ; i < config->linkCount; i++) {
	if (addrComp(header->destAddr, config->links[i].hisAka) == 0) {
	    /* we found a link to forward the pkt file to */
	    
	    link = config->links+i;
			
	    /* security checks */
			
	    if (link->forwardPkts==fOff) return 4;
	    if ((link->forwardPkts==fSecure)&&(sec != secProtInbound)&&(sec != secLocalInbound)) return 4;
	    
            /* as we have feature freeze currently, */
	    /* I enclose the following code with an ifdef ... */

	    newfn = makeUniqueDosFileName(config->tempOutbound, "pkt", config);

	    if (move_file(fileName, newfn) == 0) {  /* move successful ! */
		    
		w_log(LL_PKT, "Forwarding %s to %s as %s",
		      fileName, config->links[i].name, newfn + strlen(config->tempOutbound));

		nfree(newfn);
		forwardedPkts = 1;
		return 0;
	    }
	    else
		{
		    w_log(LL_ERR, "Failure moving %s to %s (%s)", fileName,
			  newfn, strerror(errno));
		    nfree(newfn);
		    return 4;
		}

	}
    }

    w_log(LL_ERR, "Packet %s is not to us or our links",fileName);

    return 4;       /* PKT is not for us and we did not find a link to
		       forward the pkt file to */
}


/* According to the specs, a .QQQ file does not have two leading
   zeros. This routine checks if the file is a .QQQ file, and if so,
   it appends the zeros and renames the file to .PKT. */
   

void fix_qqq(char *filename)
{
    FILE *f = NULL;
    char buffer[2] = { '\0', '\0' };
    size_t l = strlen(filename);
    char *newname=NULL;

    if (l > 3 && newname != NULL && toupper(filename[l-1]) == 'Q' &&
	toupper(filename[l-2]) == 'Q' && toupper(filename[l-3]) == 'Q')
	{
	    newname = safe_strdup(filename);

	    strcpy(newname + l - 3, "pkt");
	    if (rename(newname, filename) == 0)
		{
		    strcpy(filename, newname);

		    if ((f = fopen(filename, "ab")) != NULL)
			{
			    fwrite(buffer, 2, 1, f);
			    fclose(f);
			}
		}
	    nfree(newname);
	}
}


void tossTempOutbound(char *directory)
{
    DIR            *dir = NULL;
    FILE           *pkt = NULL;
    struct dirent  *file = NULL;
    char           *dummy = NULL;
    s_pktHeader    *header = NULL;
    s_link         *link = NULL;
    size_t         l;
#ifdef NOSLASHES
    int 		  dirNameLen;
#endif

    if (directory==NULL) return;

#ifdef NOSLASHES
    dirNameLen = strlen(directory);
    directory[dirNameLen-1]='\0';
#endif

    if (NULL == (dir = opendir(directory))) {
        printf("Can't open dir: %s!\n",directory);
	return;
    }

#ifdef NOSLASHES
    directory[dirNameLen-1]='\\';
#endif

    while ((file = readdir(dir)) != NULL) {
	l = strlen(file->d_name);
	if (l > 4 && (stricmp(file->d_name + l - 4, ".pkt") == 0 ||
		      stricmp(file->d_name + l - 4, ".qqq") == 0))
	    {
		dummy = (char *) safe_malloc(strlen(directory)+l+1);
		strcpy(dummy, directory);
		strcat(dummy, file->d_name);

		fix_qqq(dummy);

		pkt = fopen(dummy, "rb");
		if (pkt==NULL) continue;

		header = openPkt(pkt);
		if (header != NULL) {
		    link = getLinkFromAddr (config, header->destAddr);
		} else {
		    link = NULL;
		}
		             
		if (link != NULL) {

		    if (link->packFile == NULL) {
			if ( createTempPktFileName(link) )
			    exit_hpt("Could not create new bundle!",1);
		    }

		    nfree(link->pktFile);
		    link->pktFile = dummy;

		    fclose(pkt);
		    arcmail(link);
		} else {
		    nfree(dummy);
		    w_log(LL_ERR, "found non packed mail without matching link in tempOutbound");
		    fclose(pkt);
		}
	    }
    }

    closedir(dir);
    return;
}

void writeImportLog(void) {
    unsigned int i;
    FILE *f = NULL;
    struct stat buf;

    if (config->importlog) {

	// write importlog
	f = fopen(config->importlog, "a");
	if (f != NULL) {

	    for (i = 0; i < config->netMailAreaCount; i++)
		if (config->netMailAreas[i].imported > 0)
		    fprintf(f, "%s\n", config->netMailAreas[i].areaName);

	    for (i = 0; i < config->echoAreaCount; i++)
		if (config->echoAreas[i].imported > 0 && 
		    config->echoAreas[i].msgbType != MSGTYPE_PASSTHROUGH)
		    fprintf(f, "%s\n", config->echoAreas[i].areaName);
		  
	    for (i = 0; i < config->localAreaCount; i++)
		if (config->localAreas[i].imported > 0)
		    fprintf(f, "%s\n", config->localAreas[i].areaName);
		 
	    fclose(f);
#ifdef UNIX
	    chown(config->importlog, config->loguid, config->loggid);
	    if (config -> logperm != -1) chmod(config->importlog, config->logperm);
#endif

	} else w_log(LL_ERR, "Could not open importlogfile");

	// remove empty importlog
	if (stat(config->importlog, &buf)==0) {
	    if (buf.st_size==0) remove(config->importlog);
	}
	
    }
}

#define MAXOPEN_DEFAULT 512

#if defined(OS2)

#define INCL_DOS

static void setmaxopen(void) {
    ULONG cur, add;
    maxopenpkt = MAXOPEN_DEFAULT;
    cur = add = 0;

    if (DosSetRelMaxFH(&add, &cur) == 0)
	if (cur>=maxopenpkt) return;
    if (DosSetMaxFH(maxopenpkt))
	while (cur<maxopenpkt) {
	    add = 1;
	    if (DosSetRelMaxFH(&add, &cur))
		break;
	}
#ifdef __WATCOMC__
    _grow_handles(maxopenpkt);
#endif
    cur = add = 0;
    if (DosSetRelMaxFH(&add, &cur) == 0) {
	maxopenpkt = cur;
	// return;
    }

#elif defined(UNIX)

#include <sys/resource.h>
#include <unistd.h>

static void setmaxopen(void) {
#ifdef RLIMIT_NOFILE
    struct rlimit rl;
    maxopenpkt = MAXOPEN_DEFAULT;

    if (getrlimit(RLIMIT_NOFILE, &rl) == 0)
	if (rl.rlim_cur >= MAXOPEN_DEFAULT)
	    return;
    // try to set max open
    rl.rlim_cur = rl.rlim_max;
    if (setrlimit(RLIMIT_NOFILE, &rl) == 0 && rl.rlim_cur >= MAXOPEN_DEFAULT)
	return;
    rl.rlim_cur = rl.rlim_max = maxopenpkt;
    setrlimit(RLIMIT_NOFILE, &rl);
    if (getrlimit(RLIMIT_NOFILE, &rl) == 0) {
	maxopenpkt = rl.rlim_cur;
	return;
    }
#endif

#else // windows or unknown OS, just test

static void setmaxopen(void) {

#endif

    {
	int i, handles[MAXOPEN_DEFAULT];
	for (i=0; i<MAXOPEN_DEFAULT; i++)
	    if ((handles[i]=dup(1)) == -1)
		break;
	maxopenpkt = i;
	for (i=0; i<maxopenpkt; i++)
	    close(handles[i]);
    }
    if (maxopenpkt == 0) maxopenpkt = 1;
}

void toss()
{
    FILE *f = NULL;

    // set stats to 0
    memset(&statToss, '\0', sizeof(s_statToss));
    w_log(LL_START, "Start tossing...");
    processDir(config->localInbound, secLocalInbound);
    processDir(config->protInbound, secProtInbound);
    processDir(config->inbound, secInbound);
    nfree(globalBuffer); // free msg->text global buffer

    writeDupeFiles();
    writeImportLog();

    if (forwardedPkts) {
	tossTempOutbound(config->tempOutbound);
	forwardedPkts = 0;
    }

    // write statToss to Log
    writeTossStatsToLog();
    tossTempOutbound(config->tempOutbound);

    // create flag for netmail trackers
    if (config->netmailFlag && statToss.netMail) {
	if (NULL == (f = fopen(config->netmailFlag,"a"))) w_log(LL_ERR, "Could not create netmail flag: %s", config->netmailFlag);
	else {
	    w_log(LL_FLAG, "Created netmail flag: %s", config->netmailFlag);
	    fclose(f);
	}
    }
}

int packBadArea(HMSG hmsg, XMSG xmsg, char force)
{
    int		rc = 0;
    s_message   msg;
    s_area	*echo = &(config -> badArea);
    s_addr	pktOrigAddr;
    char 	*ptmp = NULL, *line = NULL, *areaName = NULL, *area=NULL, noexp=0;
    s_link	*link = NULL;
   
    makeMsg(hmsg, xmsg, &msg, &(config->badArea), 2);
    memset(&pktOrigAddr,'\0',sizeof(s_addr));
    statToss.msgs++; // really processed one more msg
   
    // deleting valet string - "FROM:" and "REASON:"
    ptmp = msg.text;
    while ((line = strchr(ptmp, '\r')) != NULL) {
	/* Temporary make it \0 terminated string */
	*line = '\000';
	if (strncmp(ptmp, "FROM: ", 6) == 0 || 
	    strncmp(ptmp, "REASON: ", 8) == 0 || 
	    strncmp(ptmp, "AREANAME: ", 10) == 0) {
	    // It's from address
	    if (*ptmp == 'F') string2addr(ptmp + 6, &pktOrigAddr);
	    // Don't export to links
	    if (*ptmp == 'R') {
		if (strstr(ptmp, "MSGAPIERR: ")!=NULL) noexp=1;
	    }
	    // Cut this kludges
	    if (*ptmp=='A') {
		if (area==NULL) {
		    echo = getArea(config, ptmp+10);
		    xstrcat(&area, ptmp+10);
		}
		memmove(ptmp, line+1, strlen(line+1)+1);	  
		break;
	    } else {
		memmove(ptmp, line+1, strlen(line+1)+1);	  
		continue;
	    }
	} else { 
	    if ((strncmp(ptmp, "AREA:", 5)==0 ||
		 strncmp(ptmp, "\001AREA:", 6)==0) && area==NULL) {
		//translating name of the area to uppercase
		strUpper(ptmp);
		areaName = (*ptmp!='\001') ? ptmp+5 : ptmp+6;
		// if the areaname begins with a space
		while (*areaName == ' ') areaName++;
		echo = getArea(config, areaName);
		xstrcat(&area, areaName);
	    };
	    ptmp = line+1;
	};
	*line = '\r';
    }

    if (echo == &(config->badArea)) {
	link = getLinkFromAddr(config, pktOrigAddr);
	if (link && link->autoAreaCreate!=0 && area) {
	    if (0 == autoCreate(area, pktOrigAddr, NULL))
		echo = getArea(config, area);
	}
    }
    nfree(area);
   
    if (echo == &(config->badArea)) {
	freeMsgBuffers(&msg);
	return rc;
    }
   
    if (checkAreaLink(echo, pktOrigAddr, 0) == 0 || force) {
	if (dupeDetection(echo, msg)==1 || noexp) {
	    // no dupe or toss whithout export to links
		   
	    if (config->carbonCount != 0) carbonCopy(&msg, NULL, echo);
		   
	    echo->imported++;  // area has got new messages
	    if (echo->msgbType != MSGTYPE_PASSTHROUGH) {
		rc = putMsgInArea(echo, &msg,1, 0);
		statToss.saved += rc;
	    } else {
		statToss.passthrough++;
		rc = 1; // passthrough always work
	    }

	    if (noexp==0) { // recode & export to links
		// recoding from internal to transport charSet
		if (config->outtab) {
		    if (msg.recode & REC_HDR) {
			recodeToTransportCharset((CHAR*)msg.fromUserName);
			recodeToTransportCharset((CHAR*)msg.toUserName);
			recodeToTransportCharset((CHAR*)msg.subjectLine);
			msg.recode &= ~REC_HDR;
		    }
		    if (msg.recode & REC_TXT) {
			recodeToTransportCharset((CHAR*)msg.text);
			msg.recode &= ~REC_TXT;
		    }
		}
   
		if (echo->downlinkCount > 0) {
		    forwardMsgToLinks(echo, &msg, pktOrigAddr);
		}
	    }

	} else {
	    // msg is dupe
	    if (echo->dupeCheck == dcMove) {
		rc = putMsgInArea(&(config->dupeArea), &msg, 0, 0);
	    } else rc = 1; // dupeCheck del
	    if (rc) config->dupeArea.imported++;
	}

    } else rc = 0;
   
    freeMsgBuffers(&msg);
    return rc;
}

void tossFromBadArea(char force)
{
    HAREA area;
    HMSG  hmsg;
    XMSG  xmsg;
    dword highestMsg, i;
    int   delmsg;
   
    area = MsgOpenArea((UCHAR *) config->badArea.fileName,
		       MSGAREA_NORMAL, (word)(config->badArea.msgbType|MSGTYPE_ECHO));
    if (area != NULL) {
	w_log(LL_START, "Scanning area: %s", config->badArea.areaName);
	highestMsg = MsgGetNumMsg(area);

	for (i=1; i<=highestMsg; highestMsg--) {
	    hmsg = MsgOpenMsg(area, MOPEN_RW, i);
	    if (hmsg == NULL) continue;      // msg# does not exist
	    MsgReadMsg(hmsg, &xmsg, 0, 0, NULL, 0, NULL);
	    delmsg = packBadArea(hmsg, xmsg, force);
	 
	    MsgCloseMsg(hmsg);
	 
	    if (delmsg) MsgKillMsg(area, i);
	    else { i++; highestMsg++; }
	}
	   
	MsgCloseArea(area);
	   
	closeOpenedPkt();
	writeDupeFiles();
	writeImportLog();

	w_log(LL_STAT, "Statistics");
	w_log(LL_STAT, "    scanned: % 5d   saved: % 7d   CC: % 2d", statToss.msgs, statToss.saved, statToss.CC);
	w_log(LL_STAT, "    exported: % 4d   passthru: % 4d", statToss.exported, statToss.passthrough);

	tossTempOutbound(config->tempOutbound);
	   
    } else w_log(LL_ERR, "Could not open %s", config->badArea.fileName);
}
