/*
 *  SMAPI; Modified Squish MSGAPI
 *
 *  Squish MSGAPI0 is copyright 1991 by Scott J. Dudley.  All rights reserved.
 *  Modifications released to the public domain.
 *
 *  Use of this file is subject to the restrictions contain in the Squish
 *  MSGAPI0 licence agreement.  Please refer to licence.txt for complete
 *  details of the licencing restrictions.  If you do not find the text
 *  of this agreement in licence.txt, or if you do not have this file,
 *  you should contact Scott Dudley at FidoNet node 1:249/106 or Internet
 *  e-mail Scott.Dudley@f106.n249.z1.fidonet.org.
 *
 *  In no event should you proceed to use any of the source files in this
 *  archive without having accepted the terms of the MSGAPI0 licensing
 *  agreement, or such other agreement as you are able to reach with the
 *  author.
 */

#include <string.h>
#include <stdlib.h>
#ifdef UNIX
#include <signal.h>
#endif
#include "alc.h"
#include "prog.h"
#include "msgapi.h"
#include "apidebug.h"
#include "unused.h"

void _SquishCloseOpenAreas(void);
void _SquishInit();
void _SquishDeInit();


static byte *intl = (byte *) "INTL";
static byte *fmpt = (byte *) "FMPT";
static byte *topt = (byte *) "TOPT";
static byte *area_colon = (byte *) "AREA:";

static char *copyright = "MSGAPI - Copyright 1991 by Scott J. Dudley.  All rights reserved.";

/* Global error value for message API routines */

word _stdc msgapierr = 0;

struct _minf _stdc mi;

void _MsgCloseApi(void)
{
/*
  TODO: DeInit (close open areas etc.) for all msgbase types
*/

    _SquishDeInit();
}

#ifdef UNIX
/* Just a dummy alarm-fnct */
static void alrm(int x)
{}     
#endif

sword EXPENTRY MsgOpenApi(struct _minf *minf)
{
#ifdef UNIX
    struct sigaction alrmact;
#endif
    
    unused(copyright);
    mi.req_version = minf->req_version;
    mi.def_zone    = minf->def_zone;
    mi.haveshare   = minf->haveshare = shareloaded();

    /* Version 2 Requested */
    if (mi.req_version > 1 && mi.req_version < 50)
    {
       mi.smapi_version    = minf->smapi_version    = MSGAPI_VERSION;
       mi.smapi_subversion = minf->smapi_subversion = MSGAPI_SUBVERSION;
    }

    _SquishInit();

    atexit(_MsgCloseApi);
    
    /*
     * Set the dummy alarm-fcnt to supress stupid messages.
     */
#ifdef UNIX    
    memset(&alrmact, 0, sizeof(alrmact));
    alrmact.sa_handler = alrm;
    sigaction(SIGALRM, &alrmact, 0);
#endif 

    return 0;
}

sword EXPENTRY MsgCloseApi(void)
{
    _MsgCloseApi();
    return 0;
}

MSG *EXPENTRY MsgOpenArea(byte * name, word mode, word type)
{
    if (type & MSGTYPE_SQUISH) return SquishOpenArea(name, mode, type);
    else if (type & MSGTYPE_JAM) return JamOpenArea(name, mode, type);
    else return SdmOpenArea(name, mode, type);
    
    /* Hey, i'm reading correct ? If not SQUISH and not JAM it must be SDM ?
       That's a good thing to make incompatible code, but we're not M$ !
       TODO: Use MSGTYPE_SDM for checking type-parameter. There could be
             other developer who wants to extend the API with another
             Base-Type */
}

int MsgDeleteBase(char * name, word type)
{
    if (type & MSGTYPE_SQUISH) return SquishDeleteBase(name);
    else if (type & MSGTYPE_JAM) return JamDeleteBase(name);
    else return SdmDeleteBase(name);
}

sword EXPENTRY MsgValidate(word type, byte * name)
{
    if (type & MSGTYPE_SQUISH) return SquishValidate(name);
    else if (type & MSGTYPE_JAM) return JamValidate(name);
    else return SdmValidate(name);
}

/*
 *  Check to see if a message handle is valid.  This function should work
 *  for ALL handlers tied into MsgAPI.  This also checks to make sure that
 *  the area which the message is from is also valid (ie. the message handle
 *  isn't valid unless the area handle of that message is also valid).
 */

sword MSGAPI InvalidMsgh(MSGH * msgh)
{
    if (msgh == NULL || msgh->id != MSGH_ID || InvalidMh(msgh->sq))
    {
        msgapierr = MERR_BADH;
        return TRUE;
    }

    return FALSE;
}

/* Check to ensure that a message area handle is valid. */

sword MSGAPI InvalidMh(MSG * mh)
{
    if (mh == NULL || mh->id != MSGAPI_ID)
    {
        msgapierr = MERR_BADH;
        return TRUE;
    }

    return FALSE;
}

byte *StripNasties(byte * str)
{
    byte *p;

    p = str;
    while (*p != '\0')
    {
        if (*p < ' ')
        {
            *p = ' ';
        }
        p++;
    }

    return str;
}

/* Copy the text itself to a buffer, or count its length if out==NULL */

static word near _CopyToBuf(byte * p, byte * out, byte ** end)
{
    word len = 0;

    if (out)
    {
        *out++ = '\001';
    }

    len++;

    while (*p == '\015' || *p == '\012' || *p == (byte) '\215')
    {
        p++;
    }

    while (*p == '\001' || strncmp((char *) p, (char *) area_colon, 5) == 0)
    {
        /* Skip over the first ^a */

        if (*p == '\001')
        {
            p++;
        }

        while (*p && *p != '\015' && *p != '\012' && *p != (byte) '\215')
        {
            if (out)
            {
                *out++ = *p;
            }

            p++;
            len++;
        }

        if (out)
        {
            *out++ = '\001';
        }

        len++;

        while (*p == '\015' || *p == '\012' || *p == (byte) '\215')
        {
            p++;
        }
    }

    /* Cap the string */

    if (out)
    {
        *out = '\0';
    }

    len++;

    /* Make sure to leave no trailing x01's. */

    if (out && out[-1] == '\001')
    {
        out[-1] = '\0';
    }

    /* Now store the new end location of the kludge lines */

    if (end)
    {
        *end = p;
    }

    return len;
}

byte *EXPENTRY CopyToControlBuf(byte * txt, byte ** newtext, unsigned *length)
{
    byte *cbuf, *end;

    word clen;

    /* Figure out how long the control info is */

    clen = _CopyToBuf(txt, NULL, NULL);

    /* Allocate memory for it */

#define SAFE_CLEN 20

    cbuf = palloc(clen + SAFE_CLEN);
    if (cbuf == NULL)
    {
        return NULL;
    }

    memset(cbuf, '\0', clen + SAFE_CLEN);

    /* Now copy the text itself */

    clen = _CopyToBuf(txt, cbuf, &end);

    if (length)
    {
        *length -= (size_t) (end - txt);
    }

    if (newtext)
    {
        *newtext = end;
    }

    return cbuf;
}

byte *EXPENTRY GetCtrlToken(byte *where, byte *what)
{
    byte *end, *out;
    unsigned int len;

    if (where == NULL || what == NULL) return NULL;
    len = strlen(what);

    do {
	where = (byte *)strchr((char *)where, '\001');
	if (where == NULL) break;
	where++;
    } while (strncmp((char *)where, (char *)what, len));

    if (where == NULL || strlen(where)<len) return NULL;
    
    end = (byte *) strchr((char *) where, '\r');
    if (end == NULL) end = (byte *) strchr((char *) where, '\001');
    if (end == NULL) end = where + strlen((char *) where);

    out = palloc((size_t) (end - where) + 1);
    if (out == NULL) return NULL;

    memmove(out, where, (size_t) (end - where));
    out[(size_t) (end - where)] = '\0';
    return out;
}

void EXPENTRY ConvertControlInfo(byte * ctrl, NETADDR * orig, NETADDR * dest)
{
    byte *p, *s;

    s = GetCtrlToken(ctrl, intl);

    if (s != NULL)
    {
        NETADDR norig, ndest;

        p = s;

        /* Copy the defaults from the original address */

        norig = *orig;
        ndest = *dest;

        /* Parse the destination part of the kludge */

        s += 5;
        Parse_NetNode((char *) s, &ndest.zone, &ndest.net, &ndest.node, &ndest.point);

        while (*s != ' ' && *s)
        {
            s++;
        }

        if (*s)
        {
            s++;
        }

        Parse_NetNode((char *) s, &norig.zone, &norig.net, &norig.node, &norig.point);

        pfree(p);

        /*
         *  Only use this as the "real" zonegate address if the net/node
         *  addresses in the INTL line match those in the message body.
         *  Otherwise, it's probably a gaterouted message!
         */

        if (ndest.net == dest->net && ndest.node == dest->node &&
          norig.net == orig->net && norig.node == orig->node)
        {
            *dest = ndest;
            *orig = norig;

            /*
             *  Only remove the INTL line if it's not gaterouted, which is
             *  why we do it here.
             */

/* mtt: DO NOT CHANGE THE MSGTEXT!!!      */
/*            RemoveFromCtrl(ctrl, intl); */
        }
    }

    /* Handle the FMPT kludge */

    s = GetCtrlToken(ctrl, fmpt);
    if (s != NULL)
    {
        orig->point = (word) atoi((char *) s + 5);
        pfree(s);
        /* mtt: DO NO CHANGE THE MSGTEXT!!!! */
        /* RemoveFromCtrl(ctrl, fmpt);       */
    }

    /* Handle TOPT too */

    s = GetCtrlToken(ctrl, topt);
    if (s != NULL)
    {
        dest->point = (word) atoi((char *) s + 5);
        pfree(s);
        /* mtt: DO NOT CHANGE THE MSGTEXT!!! */
        /* RemoveFromCtrl(ctrl, topt);       */
    }
}

byte *EXPENTRY CvtCtrlToKludge(byte * ctrl)
{
    byte *from, *to, *buf;
    size_t clen;

    clen = strlen((char *) ctrl) + NumKludges((char *) ctrl) + 20;

    buf = palloc(clen);
    if (buf == NULL)
    {
        return NULL;
    }

    to = buf;

    /* Convert ^aKLUDGE^aKLUDGE... into ^aKLUDGE\r^aKLUDGE\r... */

    from = ctrl;
    while (*from == '\001' && from[1])
    {
        /* Only copy out the ^a if it's NOT the area: line */

        if (!eqstrn((char *) from + 1, (char *) area_colon, 5))
        {
            *to++ = *from;
        }

        from++;

        while (*from && *from != '\001')
        {
            *to++ = *from++;
        }

        *to++ = '\r';
    }

    *to = '\0';

    return buf;
}

void EXPENTRY RemoveFromCtrl(byte * ctrl, byte * what)
{
    byte *p;
    unsigned int len = strlen(what);

    while (1) {
	ctrl = strchr((char *)ctrl, '\001');
	if (ctrl == NULL) return;
	if (strncmp((char *)ctrl+1, (char *)what, len)) {
	    ctrl++;
	    continue;
	}
	if (strlen((char *)ctrl + 1) < len) return;
	/* found */
	p = strchr((char *)ctrl + 1, '\001');
	if (p == NULL) {
	    *ctrl = '\0';
	    return;
	}
	strocpy((char *)ctrl, (char *)p);
    }
}

word EXPENTRY NumKludges(char *txt)
{
    word nk = 0;
    char *p;

    for(p=txt; ((p=strchr(p, '\001'))!=NULL); p++) nk++;

    return nk;
}


syntax highlighted by Code2HTML, v. 0.9.1