/*****************************************************************************
 * 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.490.2.15 2004/11/28 16:19:06 d_sergienko Exp $
 */
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>

/* compiler.h */
#include <smapi/compiler.h>

#if (defined(__EMX__) || defined(__MINGW32__)) && defined(__NT__)
  /* we can't include windows.h for prevent compiler errors ... */
/*#  include <windows.h>*/
#  define CharToOem CharToOemA
#endif

#ifdef HAS_UNISTD_H
#include <unistd.h>
#endif

#ifdef HAS_IO_H
#include <io.h>
#endif

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

#ifdef HAS_DOS_H
#include <dos.h>
#endif

#if  defined(__NT__)
/* we can't include windows.h for several reasons ... */
#define GetFileAttributes GetFileAttributesA
#endif

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

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

#if defined(A_HIDDEN) && !defined(_A_HIDDEN)
#define _A_HIDDEN A_HIDDEN
#endif

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

/* hpt */
#include <pkt.h>
#include <scan.h>
#include <toss.h>
#include <global.h>
#include <seenby.h>
#include <dupe.h>
#include <areafix.h>
#include <version.h>
#include <scanarea.h>
#include <fcommon.h>
#include <hpt.h>
#include "stat.h"
#ifdef DO_PERL
#include <hptperl.h>
#endif


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


extern s_message **msgToSysop;
int save_err;

static ULONG 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, hs_addr fromAddr, ps_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;
}


/* 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) {
    w_log( LL_SRCLINE, "%s:%d opening %s", __FILE__, __LINE__,echo->fileName);
	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) {
    w_log( LL_SRCLINE, "%s:%d creating msg", __FILE__, __LINE__);
	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);
        w_log( LL_SRCLINE, "%s:%d writing msg", __FILE__, __LINE__);
	    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 */

        w_log( LL_SRCLINE, "%s:%d closing msg", __FILE__, __LINE__);
	    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) {
        w_log( LL_SRCLINE, "%s:%d closing %s", __FILE__, __LINE__,echo->fileName);
	    MsgCloseArea(echo->harea);
	    echo->harea = NULL;
	    nopenpkt-=3;
	}
    } else w_log(LL_ERR, "Could not open/create EchoArea %s!", echo->fileName);
    /* endif */
    w_log( LL_SRCLINE, "%s:%d end rc=%d", __FILE__, __LINE__,rc);
    return rc;
}

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) {
        w_log( LL_SRCLINE, "%s:%d closing %s", __FILE__, __LINE__,config->echoAreas[i].fileName);
	    MsgCloseArea(config->echoAreas[i].harea);
	    config->echoAreas[i].harea = NULL;
	    nopenpkt-=3;
	}
    for (i=0; i<config->netMailAreaCount; i++)
	if (config->netMailAreas[i].harea) {
        w_log( LL_SRCLINE, "%s:%d closing %s", __FILE__, __LINE__,config->netMailAreas[i].fileName);
	    MsgCloseArea(config->netMailAreas[i].harea);
	    config->netMailAreas[i].harea = NULL;
	    nopenpkt-=3;
    }
    for (i=0; i<config->localAreaCount; i++)
    {
        if (config->localAreas[i].harea) {
            w_log( LL_SRCLINE, "%s:%d closing %s", __FILE__, __LINE__,config->localAreas[i].fileName);
            MsgCloseArea(config->localAreas[i].harea);
            config->localAreas[i].harea = NULL;
            nopenpkt-=3;
        }
    }
    if (config->badArea.harea) {
        w_log( LL_SRCLINE, "%s:%d closing %s", __FILE__, __LINE__,config->badArea.fileName);
        MsgCloseArea(config->badArea.harea);
        config->badArea.harea = NULL;
        nopenpkt-=3;
    }
    if (config->dupeArea.harea) {
        w_log( LL_SRCLINE, "%s:%d closing %s", __FILE__, __LINE__,config->dupeArea.fileName);
        MsgCloseArea(config->dupeArea.harea);
        config->dupeArea.harea = NULL;
        nopenpkt-=3;
    }
}


void forwardMsgToLink(s_message *msg, s_area *echo, s_link *link,
                    s_seenBy *seenBys, UINT16 seenByCount,
                    s_seenBy *pathArray, UINT16 pathArrayCount)
{
    UINT16 rc=0;
    ULONG len;
    s_pktHeader header;
    s_seenBy *path = NULL;
    UINT16 pathCount = 0;
#ifdef DEBUG_HPT
    int i;
#endif

    char *start = NULL, *text = NULL, *seenByText = NULL, *pathText = NULL;

#ifdef DEBUG_HPT
    text = createControlText(seenBys, seenByCount, "SEEN-BY: ");
    w_log(LL_DEBUGS, "forwardMsgToLink:%u: %s", __LINE__, text);
    nfree(text);
    text   = createControlText(pathArray, pathArrayCount, "PATH: ");
    w_log(LL_DEBUGS, "forwardMsgToLink:%u: %s", __LINE__, text);
    nfree(text);
#endif

    /*  add our aka to path */
    if (pathArrayCount > 0) {
        path = memdup(pathArray, sizeof(s_seenBy) * pathArrayCount);
        pathCount = pathArrayCount;
        if ((path[pathCount-1].net != link->ourAka->net) ||
            (path[pathCount-1].node != link->ourAka->node)) {
            path = (s_seenBy*) safe_realloc(path, sizeof(s_seenBy) * (pathCount+1));
            path[pathCount].net = (UINT16) link->ourAka->net;
            path[pathCount].node = (UINT16) link->ourAka->node;
            pathCount++;
        }
    } else {
        pathCount = 0;
        path = (s_seenBy*) safe_calloc(sizeof(s_seenBy), 1);
        path[pathCount].net = (UINT16) link->ourAka->net;
        path[pathCount].node = (UINT16) link->ourAka->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 was found */
        text = msg->text;
        start = strstr(text, "\rSEEN-BY: ");
        if (start == NULL) start = strstr(text, "SEEN-BY: ");
        if (start) *start='\0';
        /*  find the 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 */

#ifdef DEBUG_HPT
    text = createControlText(seenBys, seenByCount, "SEEN-BY: ");
    w_log(LL_DEBUGS, "forwardMsgToLink:%u: %s", __LINE__, text);
    text   = createControlText(path, pathCount, "PATH: ");
    w_log(LL_DEBUGS, "forwardMsgToLink:%u: %s", __LINE__, text);
    nfree(text);
#endif

    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);

    /*  add msg to the pkt's of the downlinks */
    if (maxopenpkt == 0) setmaxopen();
    /*  check packet size */
    if (link->pktFile != NULL && link->pktSize != 0) {
        len = link->pkt ? ftell(link->pkt) : fsize(link->pktFile);
        if (len >= (link->pktSize * 1024L)) { /*  Stop writing to pkt */
            if (link->pkt) {
                fclose(link->pkt);
                link->pkt = NULL;
                nopenpkt--;
            }
            nfree(link->pktFile);
            nfree(link->packFile);
        }
    }

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

    makePktHeader(NULL, &header);
    header.origAddr = *(link->ourAka);
    header.destAddr = link->hisAka;
    if (link->pktPwd != NULL)
        strcpy(header.pktPassword, link->pktPwd);
    if (link->pkt == NULL) {
        link->pkt = openPktForAppending(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(link->pkt, *msg);
    if (rc) w_log(LL_ERR,"can't write msg to pkt: %s",
                  link->pktFile);
    if (nopenpkt >= maxopenpkt-12 || /*  std streams, in pkt, msgbase, log */
        (link->pktSize && ftell(link->pkt)>= (long)link->pktSize*1024L)) {
        rc += closeCreatedPkt(link->pkt);
        if (rc) w_log(LL_ERR,"can't close pkt: %s",
                      link->pktFile);
        link->pkt = NULL;
        nopenpkt--;
    }
    if (rc==0) statToss.exported++;
    else rc=0;
#ifdef ADV_STAT
    if (config->advStatisticsFile != NULL) put_stat(echo, &(header.destAddr), stOUT, msg->textLength);
#endif

    return;
}

void forwardMsgToLinks_rsb(s_area *echo, s_message *msg, hs_addr pktOrigAddr, UINT16 rsb)
{
    s_seenBy *seenBys = NULL, *path = NULL;
    UINT16     seenByCount = 0 , pathCount = 0;
    int i;
    char *text;

    /*  links who does not have their aka in seenBys and thus have not got the echomail */
    s_arealink **newLinks = NULL;

    /* init array of seen-bys */
    zero_seenBysZone();
#ifdef DEBUG_HPT
    print_seenBysZone();
#endif
    /* fetch seen-bys from msg */
    createSeenByArrayFromMsg(msg, &seenBys, &seenByCount);
    text = createControlText(seenBys, seenByCount, "");
#ifdef DEBUG_HPT
    w_log(LL_DEBUGS, "forwardMsgToLinks_rsb:%u: SEEN-BY: %s", __LINE__, text);
#endif

    /* fetch path from msg */
    createPathArrayFromMsg(msg, &path, &pathCount);
    text = createControlText(path, pathCount, "");
#ifdef DEBUG_HPT
    w_log(LL_DEBUGS, "forwardMsgToLinks_rsb:%u: PATH: %s", __LINE__, text);
#endif

    if (rsb == 0) {
        /* attach seen-bys of message to seenBysZone with
         zone == pktOrigAddr.zone */
        attachTo_seenBysZone(pktOrigAddr.zone, &seenBys, seenByCount);
        text = createControlText(seenBys, seenByCount, "");
#ifdef DEBUG_HPT
        w_log(LL_DEBUGS, "forwardMsgToLinks_rsb:%u: SEEN-BY: %s", __LINE__, text);
#endif

    } else {
        /* attach path to seenBysZone with zone == pktOrigAddr.zone */
        attachTo_seenBysZone(pktOrigAddr.zone, &path, pathCount);
        text = createControlText(path, pathCount, "");
#ifdef DEBUG_HPT
        w_log(LL_DEBUGS, "forwardMsgToLinks_rsb:%u: PATH: %s", __LINE__, text);
#endif
        /* make a copy of path 'cause 1st is left for seen-bys */
        path = memdup(path, sizeof(s_seenBy) * pathCount);
    }
    /* add seen-bys from addToSeen & -sbadd to all zones */
    processAutoAdd_seenByZone(echo);
#ifdef DEBUG_HPT
    w_log(LL_DEBUGS, "after processAutoAdd_seenByZone()");
    print_seenBysZone();
#endif

    /* build an array of links who will receive this message */
    createNewLinksArray(echo, &newLinks, pktOrigAddr, rsb);

    /* append AKAs of links to seen-by array with sorting by zone */
    addLinksTo_seenByZone(newLinks, echo->downlinkCount);
#ifdef DEBUG_HPT
    w_log(LL_DEBUGS, "after addLinksTo_seenByZone()");
    print_seenBysZone();
#endif
    /* add all our AKAs */
    addAkasTo_seenByZone();
#ifdef DEBUG_HPT
    w_log(LL_DEBUGS, "after addAkasTo_seenByZone()");
    print_seenBysZone();
#endif

    cleanDupes_seenByZone();
#ifdef DEBUG_HPT
    w_log(LL_DEBUGS, "after cleanDupes_seenByZone()");
    print_seenBysZone();
#endif
    /* forward message to each links from an array */
    for (i=0;i<echo->downlinkCount;i++)
    {
        if (newLinks==NULL || newLinks[i] == NULL) break; /* end of list */
        /* forward message to link */
        forwardMsgToLink(msg, echo, newLinks[i]->link,
                         seenBysZone[newLinks[i]->link->hisAka.zone].seenByArray,
                         seenBysZone[newLinks[i]->link->hisAka.zone].seenByCount,
                         path, pathCount);
    }
    /* free all used memory */
    free_seenBysZone();
#ifdef DEBUG_HPT
    w_log(LL_DEBUGS, "after free_seenByZone()");
    print_seenBysZone();
#endif

    nfree(path);
    nfree(newLinks);
}

void forwardMsgToLinks(s_area *echo, s_message *msg, hs_addr pktOrigAddr)
{
    char *msgtext;
    UINT16 textlen;
    msgtext = safe_strdup(msg->text);
    textlen = msg->textLength;
    /* forward message to all links with normal seen-bys */
    forwardMsgToLinks_rsb(echo, msg, pktOrigAddr, 0);
    /* restore original message text with original path & seen-bys */
    nfree(msg->text);
    msg->text = safe_strdup(msgtext);
    msg->textLength = textlen;
    /* and now forward message to links with reduced seen-bys */
    forwardMsgToLinks_rsb(echo, msg, pktOrigAddr, 1);
    /* restore original message text with original path & seen-bys */
    nfree(msg->text);
    msg->text = safe_strdup(msgtext);
    msg->textLength = textlen;
}

/* return value: 1 if success, 0 if fail */
int putMsgInBadArea(s_message *msg, hs_addr pktOrigAddr, int writeAccess)
{
    char *tmp = NULL, *line = NULL, *textBuff=NULL, *areaName=NULL, *reason=NULL;
    char buff[128] = "";

    w_log(LL_FUNC, "putMsgInBadArea() begin");
    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";
	w_log(LL_ECHOMAIL, "Badmail reason: System not allowed to create new area (%s)", areaName);
	break;
    case 1:
	reason = "Sender not allowed to post in this area (access group)";
	w_log(LL_ECHOMAIL, "Badmail reason: Sender not allowed to post in area %s (access group)", areaName);
	break;
    case 2:
	reason = "Sender not allowed to post in this area (access level)";
	w_log(LL_ECHOMAIL, "Badmail reason: Sender not allowed to post in area %s (access level)", areaName);
	break;
    case 3:
	reason = "Sender not allowed to post in this area (access import)";
	w_log(LL_ECHOMAIL, "Badmail reason: Sender not allowed to post in area %s (access import)", areaName);
	break;
    case 4:
	reason = "Sender not active for this area";
	w_log(LL_ECHOMAIL, "Badmail reason: Sender not active for area %s", areaName);
	break;
    case 5:
	reason = "Rejected by filter";
	w_log(LL_ECHOMAIL, "Badmail reason: Rejected by filter");
	break;
    case 6:   /* MSGAPI error */
	reason = strncat( strcpy(buff,"MSGAPIERR: "), strmerr(msgapierr), sizeof(buff)-sizeof("MSGAPIERR: ") );
	w_log(LL_ECHOMAIL, "Badmail reason: %s", reason);
	break;
    case 7:
	reason = "Can't create echoarea with forbidden symbols in areatag";
	w_log(LL_ECHOMAIL, "Badmail reason: Can't create echoarea with forbidden symbols in areatag: '%s'", areaName);
	break;
    case 8:
	reason = "Sender not found in config file";
	w_log(LL_ECHOMAIL, "Badmail reason: Sender not found in config file");
	break;
    case 9:
	reason = "Can't open config file";
	w_log(LL_ECHOMAIL, "Badmail reason: Can't open config file");
	break;
    case 10:
	reason = "No downlinks for passthrough area";
	w_log(LL_ECHOMAIL, "Badmail reason: No downlinks for passthrough area '%s'", areaName);
	break;
    case 11:
	reason = "lenght of CONFERENCE name is more than 60 symbols";
	w_log(LL_ECHOMAIL, "Badmail reason: lenght of CONFERENCE name (areatag) is more than 60 symbols: '%s'", areaName);
	break;
    case 12:
	reason = "Area killed (unsubscribed)";
	w_log(LL_ECHOMAIL, "Badmail reason: area killed (unsubscribed): '%s'", areaName);
	break;
    case 13:
	reason = "New area refused by NewAreaRefuseFile";
	w_log(LL_ECHOMAIL, "Badmail reason: New area '%s' refused by NewAreaRefuseFile", areaName);
	break;
    default :
	reason = "Another error";
	w_log(LL_ECHOMAIL, "Badmail reason: Another error");
	break;
    }

#ifdef DO_PERL
    if (perltossbad(msg, areaName, pktOrigAddr, reason)) {
	nfree(areaName);
	nfree(msg->text);
        w_log(LL_FUNC, "putMsgInBadArea():perltossbad OK (rc=1)");
	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++;
        w_log(LL_FUNC, "putMsgInBadArea() OK");
	return 1;
    }
    w_log(LL_FUNC, "putMsgInBadArea() failed");
    return 0;
}

void makeMsgToSysop(char *areaName, hs_addr fromAddr, ps_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,
                    config->areafixFromName ? config->areafixFromName : versionStr,
                    netmail ? (config->sysop ? config->sysop : "Sysop") : "All", "Created new areas",
                    netmail,
                    config->areafixReportsAttr);
                msgToSysop[i]->text = createKludges(config,
                    netmail ? NULL : config->ReportTo,
                    echo->useAka, echo->useAka,
                    versionStr);

		if (config->areafixReportsFlags)
		    xstrscat(&(msgToSysop[i]->text), "\001FLAGS ",
		             config->areafixReportsFlags, "\r", NULL);
                xstrscat(&(msgToSysop[i]->text),
                    "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);

            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, hs_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, hs_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, hs_addr pktOrigAddr, int dontdocc, dword forceattr)
{
    char   *area=NULL, *p = NULL, *q = NULL;
    s_message* messCC = NULL;
    s_area *echo=&(config->badArea);
    s_link *link = NULL;
    int    writeAccess = 0, rc = 0, ccrc = 0;

    w_log(LL_FUNC, "%s::processEMMsg() begin", __FILE__);

    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)) {
        /*  check if we should not refuse this area */
        /*  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);
#ifdef ADV_STAT
            if (config->advStatisticsFile != NULL) put_stat(echo, &pktOrigAddr, stBAD, 0);
#endif
        }
        else
        { /*  access ok - process msg */

            if (dupeDetection(echo, *msg)==1) {
                /*  no dupe */

                messCC = MessForCC(msg); /* make copy of original message */

                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);
#ifdef DEBUG_HPT
                w_log( LL_SRCLINE, "%s::processEMMsg():%d", __FILE__, __LINE__);
#endif
                /* todo: remove TID from local-generated msgs by hpt post -x
                * (if (addrComp(pktOrigAddr,*echo->useAka)==0)) */

                if (messCC && !dontdocc)
                    ccrc=carbonCopy(messCC, NULL, echo);
#ifdef DEBUG_HPT
                w_log( LL_SRCLINE, "%s::processEMMsg():%d", __FILE__, __LINE__);
#endif
                if (ccrc <= 1) {
                    echo->imported++;  /*  area has got new messages */
#ifdef ADV_STAT
                    if (config->advStatisticsFile != NULL) put_stat(echo, &pktOrigAddr, stNORM, msg->textLength);
#endif
                    if (echo->msgbType != MSGTYPE_PASSTHROUGH) {
                        if(messCC)
                            rc = putMsgInArea(echo, messCC, 1, forceattr);
                        else
                            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 */
                freeMsgBuffers(messCC);
                nfree(messCC);
            } 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++;
#ifdef ADV_STAT
                if (config->advStatisticsFile != NULL) put_stat(echo, &pktOrigAddr, stDUPE, 0);
#endif
                if (rc) config->dupeArea.imported++;
            }
        }
    }
    w_log(LL_FUNC, "%s::processEMMsg() rc=%d", __FILE__, rc);
    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;
#else
    /* prevent compiler warning */
    secure = secure;
#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 &&
	     fc_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 = cmdcall(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_WARN, "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_WARN, "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;
}


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

    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( fc_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 ((cmdexit = cmdcall(cmd)) != 0) {
		    w_log(LL_ERR, "exec failed, code %d", cmdexit);
		    return 3;
		}
	    }
	if (config->afterUnpack) {
	    w_log(LL_EXEC, "afterUnpack: execute string \"%s\"", config->afterUnpack);
	    if ((cmdexit = cmdcall(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 1;
    return strcasecmp(((s_fileInDir *) elem1) -> fileName, ((s_fileInDir *) elem2) -> fileName);
}

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

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
	w_log(LL_DEBUGV, "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
	w_log(LL_DEBUGV,"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,1)) != 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], 1);
	    } 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);
    w_log(logchar, "          % 8.2f kb total, processed in %8.3f seconds", ((float) statToss.inBytes / 1024), (float)statToss.realTime / 1000);

    /* 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 ((*line=='^' || *line=='#') && isArcMail(line + 1)) {
	    nfree(bundle);
	    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;
    hs_addr *aka;
    e_bundleFileNameStyle bundleNameStyle;

    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 = cmdcall(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) {
	
	    aka = SelectPackAka(link);

	    if (needUseFileBoxForLinkAka(config,link,aka)) {

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

		_createDirectoryTree (link->fileBox);
		if (link->packFile == NULL)
		    if (createPackFileName(link))
			 exit_hpt("Could not create new bundle!",1);

		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 )
		    {
#ifdef USE_HPT_ZLIB
		      cmdexit = PackWithZlib(link->packFile, link->pktFile);
#else
		      cmdexit = -1;
#endif
		    }else
                      cmdexit = cmdcall(cmd);

		    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 = move_file(link->pktFile, pkt, 0);
		    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 (createOutboundFileNameAka(link,link->echoMailFlavour, FLOFILE, aka) == 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 -> put packFile into flo*/
			fseek(flo, 0L, SEEK_SET);
			foa = find_old_arcmail(link, flo);

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

			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 )
			    {
#ifdef USE_HPT_ZLIB
				cmdexit = PackWithZlib(link->packFile, link->pktFile);
#else
				cmdexit = -1;
#endif
			    }
			else
			    {
				cmdexit = cmdcall(cmd);
			    }
			if (cmdexit==0) {
			    if (foa==0) {
				if (bundleNameStyle == eAddrDiff ||
				    bundleNameStyle == eAddrsCRC32 ||
				    bundleNameStyle == eAddrDiffAlways ||
				    bundleNameStyle == eAddrsCRC32Always ||
				    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",
					    aka->zone, aka->net,
					    aka->node, aka->point,
					    PATH_DELIM);
			    else {
				if (aka->point != 0)
				    xscatprintf(&pkt,"%08x.sep%c",
						aka->point,PATH_DELIM);
				else
				    xscatprintf(&pkt, "%04x%04x.sep%c",
						aka->net,
						aka->node,
						PATH_DELIM);
			    }
			}

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

			cmdexit = move_file(link->pktFile, pkt, 0);
			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) == 0) {  /* save if exist */
		
		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 (move_file(newname, filename, 0) == 0)
		{
		    strcpy(filename, newname);

		    if ((f = fopen(filename, "ab")) != NULL)
			{
			    fwrite(buffer, 2, 1, f);
			    fclose(f);
			}
        } else
		    w_log(LL_ERR, "Failure moving %s to %s (%s)", newname,
			  filename, strerror(errno));

	    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 ( createPackFileName(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

/* From os2emx.h:
ULONG DosSetMaxFH (ULONG ulCount);
ULONG DosSetRelMaxFH (PLONG pulReqCount, PULONG pulCurMaxFH);
*/

static void setmaxopen(void) {
    ULONG cur = 0, 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>

static void setmaxopen(void) {
#ifdef RLIMIT_NOFILE
    struct rlimit rl;
    unsigned 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 handles[MAXOPEN_DEFAULT];
    ULONG i;
	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);
	}
    }
    w_log(LL_STOP, "End tossing");
}

int packBadArea(HMSG hmsg, XMSG xmsg, char force)
{
    int		rc = 0;
    s_message   msg;
    s_area	*echo = &(config -> badArea);
    hs_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(hs_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 */
#ifdef ADV_STAT
            if (config->advStatisticsFile != NULL) put_stat(echo, &pktOrigAddr, stNORM, msg.textLength);
#endif
	    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++;
#ifdef ADV_STAT
            if (config->advStatisticsFile != NULL) put_stat(echo, &pktOrigAddr, stDUPE, 0);
#endif
	}

    } 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);
}
