
/*
 *
 * APRS Services for TNOS 2.30 - April/May, 2001
 *
 * Designed and written by VE4KLM, Maiko Langelaar
 *
 * For non-commercial use (Ham Radio) only !!!
 *
 */

#include "global.h"

#ifdef	APRSD

#include "mbuf.h"
#include "ax25.h"
#include "udp.h"
#include <ctype.h>
#include "aprs.h"

#if !defined(_lint)
static char rcsid[] OPTIONAL = "$Id: aprs.c,v 1.2 2001/05/07 10:28:20 brian Exp $";
#endif

static char data_APZxxx[300];	/* make sure we have 'lots' of room */

extern unsigned long internal_hostid;	/* the only kludge so far */

static int aprs_send (char *data, int len)
{
	struct mbuf *bp;
	struct socket lsock,fsock;

	lsock.address = INADDR_ANY;
	lsock.port = 1315;

	if (internal_hostid == 0)	/* protection from not being set */
		return -1;
	
	fsock.address = internal_hostid;	/* kludge for now */
	fsock.port = 93;

	if ((bp = alloc_mbuf (len)) == NULLBUF)
		return -1;

	strncpy ((char*)bp->data, data, len);

	bp->cnt = (int16)len;

	send_udp (&lsock, &fsock, 0, 0, bp, 0, 0, 0);

	return 0;
}

static int strip_nonprintables (char *data, int len)
{
	char *ptr = data + len - 1;

	while (ptr > data && !isprint (*ptr))
	{
		ptr--;
		len --;
	}

	return len;
}

/*
 * 02May2001, VE4KLM, Now have a proper function to validate the
 * possible data type identifiers we can expect (or rather, want)
 * to receive at this time. I don't support ALL of them yet.
 */

static int dti_is_valid (char dti)
{
	int retval = 0;	/* default not supported */

	switch (dti)
	{
		case '!':
		case '#':
		case '$':
		case '%':
		case '*':
		case '/':
		case ':':
		case ';':
		case '<':
		case '=':
		case '>':
		case '?':
		case '@':
		case '_':
		case '}':

			retval = 1;
			break;
	}

	return retval;
}

static char aprs_dest[2] = { 'A' << 1, 'P' << 1 };

static char beac_dest[2] = { 'B' << 1, 'E' << 1 };

int aprs_processing (struct ax25 *hdr, struct mbuf *bp)
{
	char tmp[AXBUF],  *ptr, *ptr2;

	int len, cnt;

	/*
	 * At present - only allow packets destined for callsigns 'BEACON'
	 * and 'ID', or any callsign beginning with the letters 'AP'.
	 */
	if ((hdr->dest[0] == aprs_dest[0] && hdr->dest[1] == aprs_dest[1]) ||
		(hdr->dest[0] == beac_dest[0] && hdr->dest[1] == beac_dest[1]))
	{
		/* If we get in here, then we have a possible APRS frame */

		ptr2 = bp->data + 2;	/* skip ax25 ctl and pid fields */

		len = bp->cnt - 2;

		/*
		 * Now validate the Data Type Identifier to see if this is
		 * really an APRS frame. Note, not all possible identifiers
		 * may be supported by this TNOS APRS Server implementation.
		 */

		if (dti_is_valid (*ptr2))
		{
			/*
			 * If we get in here, then it's almost for sure an APRS
			 * frame. Now build a full message to send to an aprs.net
			 * server - prepend the data with a source path header,
			 * and send out via internal UDP to our TNOS server.
		 	 */

			ptr = data_APZxxx;

			ptr += sprintf (ptr, "%s>", pax25 (tmp, hdr->source));

			ptr += sprintf (ptr, "%s", pax25 (tmp, hdr->dest));

			if (hdr->ndigis)
			{
				for (cnt = 0; cnt < hdr->ndigis; cnt++)
				{
					ptr += sprintf (ptr, ",%s", pax25 (tmp, hdr->digis[cnt]));
				}

				/* the last digi needs an asterisk to identify it */
				ptr += sprintf (ptr, "*");
			}

			ptr += sprintf (ptr, ":%.*s", len, ptr2);

			/* strip off non-printable characters from end of text data */
			len = strip_nonprintables (data_APZxxx, strlen (data_APZxxx));

			data_APZxxx[len] = '\n';	/* newline */
			len++;
			data_APZxxx[len] = '\0';	/* terminate */
			len++;

			/* use UDP to send it to myself (I use UDP to talk inside TNOS) */
			aprs_send (data_APZxxx, len);
		}

		return 1;
	}

	return 0;
}

#endif

