2015-07-27 01:17:23 +00:00
|
|
|
//
|
|
|
|
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
|
|
|
//
|
2023-06-14 00:37:08 +00:00
|
|
|
// Copyright (C) 2015, 2016, 2023 John Langner, WB2OSZ
|
2015-07-27 01:17:23 +00:00
|
|
|
//
|
|
|
|
// This program 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 of the License, or
|
|
|
|
// (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* Module: pfilter.c
|
|
|
|
*
|
|
|
|
* Purpose: Packet filtering based on characteristics.
|
|
|
|
*
|
|
|
|
* Description: Sometimes it is desirable to digipeat or drop packets based on rules.
|
|
|
|
* For example, you might want to pass only weather information thru
|
|
|
|
* a cross band digipeater or you might want to drop all packets from
|
|
|
|
* an abusive user that is overloading the channel.
|
|
|
|
*
|
|
|
|
* The filter specifications are loosely modeled after the IGate Server-side Filter
|
|
|
|
* Commands: http://www.aprs-is.net/javaprsfilter.aspx
|
|
|
|
*
|
|
|
|
* We add AND, OR, NOT, and ( ) to allow very flexible control.
|
|
|
|
*
|
|
|
|
*---------------------------------------------------------------*/
|
|
|
|
|
2016-07-03 22:09:34 +00:00
|
|
|
#include "direwolf.h"
|
2015-07-27 01:17:23 +00:00
|
|
|
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <assert.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
|
|
|
|
#include "ax25_pad.h"
|
|
|
|
#include "textcolor.h"
|
|
|
|
#include "decode_aprs.h"
|
|
|
|
#include "latlong.h"
|
|
|
|
#include "pfilter.h"
|
2017-01-01 16:49:55 +00:00
|
|
|
#include "mheard.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Global stuff (to this file)
|
|
|
|
*
|
|
|
|
* These are set by init function.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static struct igate_config_s *save_igate_config_p;
|
|
|
|
static int s_debug = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* Name: pfilter_init
|
|
|
|
*
|
|
|
|
* Purpose: One time initialization when main application starts up.
|
|
|
|
*
|
|
|
|
* Inputs: p_igate_config - IGate configuration.
|
|
|
|
*
|
|
|
|
* debug_level - 0 no debug output.
|
|
|
|
* 1 single summary line with final result. Indent by 1.
|
|
|
|
* 2 details from each filter specification. Indent by 3.
|
|
|
|
* 3 Logical operators. Indent by 2.
|
|
|
|
*
|
|
|
|
*--------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
|
|
void pfilter_init (struct igate_config_s *p_igate_config, int debug_level)
|
|
|
|
{
|
|
|
|
s_debug = debug_level;
|
|
|
|
save_igate_config_p = p_igate_config;
|
|
|
|
}
|
|
|
|
|
2015-07-27 01:17:23 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
typedef enum token_type_e { TOKEN_AND, TOKEN_OR, TOKEN_NOT, TOKEN_LPAREN, TOKEN_RPAREN, TOKEN_FILTER_SPEC, TOKEN_EOL } token_type_t;
|
|
|
|
|
|
|
|
|
|
|
|
#define MAX_FILTER_LEN 1024
|
|
|
|
#define MAX_TOKEN_LEN 1024
|
|
|
|
|
|
|
|
typedef struct pfstate_s {
|
|
|
|
|
|
|
|
int from_chan; /* From and to channels. MAX_CHANS is used for IGate. */
|
|
|
|
int to_chan; /* Used only for debug and error messages. */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Original filter string from config file.
|
|
|
|
* All control characters should be replaced by spaces.
|
|
|
|
*/
|
|
|
|
char filter_str[MAX_FILTER_LEN];
|
|
|
|
int nexti; /* Next available character index. */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Packet object.
|
|
|
|
*/
|
|
|
|
packet_t pp;
|
|
|
|
|
|
|
|
/*
|
2016-11-20 19:58:51 +00:00
|
|
|
* Are we processing APRS or connected mode?
|
2021-09-19 18:51:18 +00:00
|
|
|
* This determines which types of filters are available.
|
2016-11-20 19:58:51 +00:00
|
|
|
*/
|
|
|
|
int is_aprs;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Packet split into separate parts if APRS.
|
2015-07-27 01:17:23 +00:00
|
|
|
* Most interesting fields are:
|
2016-11-20 19:58:51 +00:00
|
|
|
*
|
2015-07-27 01:17:23 +00:00
|
|
|
* g_symbol_table - / \ or overlay
|
|
|
|
* g_symbol_code
|
|
|
|
* g_lat, g_lon - Location
|
|
|
|
* g_name - for object or item
|
|
|
|
* g_comment
|
|
|
|
*/
|
|
|
|
decode_aprs_t decoded;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* These are set by next_token.
|
|
|
|
*/
|
|
|
|
token_type_t token_type;
|
|
|
|
char token_str[MAX_TOKEN_LEN]; /* Printable string representation for use in error messages. */
|
|
|
|
int tokeni; /* Index in original string for enhanced error messages. */
|
|
|
|
|
|
|
|
} pfstate_t;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int parse_expr (pfstate_t *pf);
|
|
|
|
static int parse_or_expr (pfstate_t *pf);
|
|
|
|
static int parse_and_expr (pfstate_t *pf);
|
|
|
|
static int parse_primary (pfstate_t *pf);
|
|
|
|
static int parse_filter_spec (pfstate_t *pf);
|
|
|
|
|
|
|
|
static void next_token (pfstate_t *pf);
|
|
|
|
static void print_error (pfstate_t *pf, char *msg);
|
|
|
|
|
|
|
|
static int filt_bodgu (pfstate_t *pf, char *pattern);
|
|
|
|
static int filt_t (pfstate_t *pf);
|
2017-01-01 16:49:55 +00:00
|
|
|
static int filt_r (pfstate_t *pf, char *sdist);
|
2015-07-27 01:17:23 +00:00
|
|
|
static int filt_s (pfstate_t *pf);
|
2017-01-01 16:49:55 +00:00
|
|
|
static int filt_i (pfstate_t *pf);
|
|
|
|
|
|
|
|
static char *bool2text (int val)
|
|
|
|
{
|
|
|
|
if (val == 1) return "TRUE";
|
|
|
|
if (val == 0) return "FALSE";
|
|
|
|
if (val == -1) return "ERROR";
|
|
|
|
return "OOPS!";
|
|
|
|
}
|
2015-07-27 01:17:23 +00:00
|
|
|
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* Name: pfilter.c
|
|
|
|
*
|
|
|
|
* Purpose: Decide whether a packet should be allowed thru.
|
|
|
|
*
|
|
|
|
* Inputs: from_chan - Channel packet is coming from.
|
|
|
|
* to_chan - Channel packet is going to.
|
|
|
|
* Both are 0 .. MAX_CHANS-1 or MAX_CHANS for IGate.
|
|
|
|
* For debug/error messages only.
|
|
|
|
*
|
2015-09-07 23:56:20 +00:00
|
|
|
* filter - String of filter specs and logical operators to combine them.
|
2015-07-27 01:17:23 +00:00
|
|
|
*
|
|
|
|
* pp - Packet object handle.
|
|
|
|
*
|
2016-11-20 19:58:51 +00:00
|
|
|
* is_aprs - True for APRS, false for connected mode digipeater.
|
|
|
|
* Connected mode allows a subset of the filter types, only
|
|
|
|
* looking at the addresses, not information part contents.
|
|
|
|
*
|
2015-07-27 01:17:23 +00:00
|
|
|
* Returns: 1 = yes
|
|
|
|
* 0 = no
|
|
|
|
* -1 = error detected
|
|
|
|
*
|
|
|
|
* Description: This might be running in multiple threads at the same time so
|
|
|
|
* no static data allowed and take other thread-safe precautions.
|
|
|
|
*
|
|
|
|
*--------------------------------------------------------------------*/
|
|
|
|
|
2016-11-20 19:58:51 +00:00
|
|
|
int pfilter (int from_chan, int to_chan, char *filter, packet_t pp, int is_aprs)
|
2015-07-27 01:17:23 +00:00
|
|
|
{
|
|
|
|
pfstate_t pfstate;
|
|
|
|
char *p;
|
|
|
|
int result;
|
|
|
|
|
2015-09-07 23:56:20 +00:00
|
|
|
assert (from_chan >= 0 && from_chan <= MAX_CHANS);
|
|
|
|
assert (to_chan >= 0 && to_chan <= MAX_CHANS);
|
|
|
|
|
2016-11-20 19:58:51 +00:00
|
|
|
memset (&pfstate, 0, sizeof(pfstate));
|
|
|
|
|
2015-09-07 23:56:20 +00:00
|
|
|
if (pp == NULL) {
|
2017-01-01 16:49:55 +00:00
|
|
|
text_color_set(DW_COLOR_ERROR);
|
2015-09-07 23:56:20 +00:00
|
|
|
dw_printf ("INTERNAL ERROR in pfilter: NULL packet pointer. Please report this!\n");
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
if (filter == NULL) {
|
2017-01-01 16:49:55 +00:00
|
|
|
text_color_set(DW_COLOR_ERROR);
|
2015-09-07 23:56:20 +00:00
|
|
|
dw_printf ("INTERNAL ERROR in pfilter: NULL filter string pointer. Please report this!\n");
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
2015-07-27 01:17:23 +00:00
|
|
|
pfstate.from_chan = from_chan;
|
|
|
|
pfstate.to_chan = to_chan;
|
|
|
|
|
2021-09-19 18:51:18 +00:00
|
|
|
/* Copy filter string, changing any control characters to spaces. */
|
2015-09-07 23:56:20 +00:00
|
|
|
|
2016-11-20 19:58:51 +00:00
|
|
|
strlcpy (pfstate.filter_str, filter, sizeof(pfstate.filter_str));
|
2015-09-07 23:56:20 +00:00
|
|
|
|
2015-07-27 01:17:23 +00:00
|
|
|
pfstate.nexti = 0;
|
|
|
|
for (p = pfstate.filter_str; *p != '\0'; p++) {
|
|
|
|
if (iscntrl(*p)) {
|
|
|
|
*p = ' ';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pfstate.pp = pp;
|
2016-11-20 19:58:51 +00:00
|
|
|
pfstate.is_aprs = is_aprs;
|
|
|
|
|
|
|
|
if (is_aprs) {
|
2022-11-25 22:59:36 +00:00
|
|
|
decode_aprs (&pfstate.decoded, pp, 1, NULL);
|
2016-11-20 19:58:51 +00:00
|
|
|
}
|
2015-07-27 01:17:23 +00:00
|
|
|
|
|
|
|
next_token(&pfstate);
|
|
|
|
|
|
|
|
if (pfstate.token_type == TOKEN_EOL) {
|
|
|
|
/* Empty filter means reject all. */
|
|
|
|
result = 0;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
result = parse_expr (&pfstate);
|
|
|
|
|
|
|
|
if (pfstate.token_type != TOKEN_AND &&
|
|
|
|
pfstate.token_type != TOKEN_OR &&
|
|
|
|
pfstate.token_type != TOKEN_EOL) {
|
|
|
|
|
|
|
|
print_error (&pfstate, "Expected logical operator or end of line here.");
|
|
|
|
result = -1;
|
|
|
|
}
|
|
|
|
}
|
2017-01-01 16:49:55 +00:00
|
|
|
|
|
|
|
if (s_debug >= 1) {
|
|
|
|
text_color_set(DW_COLOR_DEBUG);
|
|
|
|
if (from_chan == MAX_CHANS) {
|
|
|
|
dw_printf (" Packet filter from IGate to radio channel %d returns %s\n", to_chan, bool2text(result));
|
|
|
|
}
|
|
|
|
else if (to_chan == MAX_CHANS) {
|
|
|
|
dw_printf (" Packet filter from radio channel %d to IGate returns %s\n", from_chan, bool2text(result));
|
|
|
|
}
|
|
|
|
else if (is_aprs) {
|
|
|
|
dw_printf (" Packet filter for APRS digipeater from radio channel %d to %d returns %s\n", from_chan, to_chan, bool2text(result));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
dw_printf (" Packet filter for traditional digipeater from radio channel %d to %d returns %s\n", from_chan, to_chan, bool2text(result));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-27 01:17:23 +00:00
|
|
|
return (result);
|
|
|
|
|
|
|
|
} /* end pfilter */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* Name: next_token
|
|
|
|
*
|
|
|
|
* Purpose: Extract the next token from input string.
|
|
|
|
*
|
|
|
|
* Inputs: pf - Pointer to current state information.
|
|
|
|
*
|
|
|
|
* Outputs: See definition of the structure.
|
|
|
|
*
|
|
|
|
* Description: Look for these special operators: & | ! ( ) end-of-line
|
|
|
|
* Anything else is considered a filter specification.
|
|
|
|
* Note that a filter-spec must be followed by space or
|
|
|
|
* end of line. This is so the magic characters can appear in one.
|
|
|
|
*
|
2015-09-07 23:56:20 +00:00
|
|
|
* Future: Maybe allow words like 'OR' as alternatives to symbols like '|'.
|
2015-07-27 01:17:23 +00:00
|
|
|
*
|
|
|
|
* Unresolved Issue:
|
|
|
|
*
|
2015-09-07 23:56:20 +00:00
|
|
|
* Adding the special operators adds a new complication.
|
2015-07-27 01:17:23 +00:00
|
|
|
* How do we handle the case where we want those characters in
|
|
|
|
* a filter specification? For example how do we know if the
|
|
|
|
* last character of /#& means HF gateway or AND the next part
|
|
|
|
* of the expression.
|
|
|
|
*
|
|
|
|
* Approach 1: Require white space after all filter specifications.
|
|
|
|
* Currently implemented.
|
|
|
|
* Simple. Easy to explain.
|
|
|
|
* More readable than having everything squashed together.
|
|
|
|
*
|
|
|
|
* Approach 2: Use escape character to get literal value. e.g. s/#\&
|
|
|
|
* Linux people would be comfortable with this but
|
|
|
|
* others might have a problem with it.
|
|
|
|
*
|
|
|
|
* Approach 3: use quotation marks if it contains special characters or space.
|
|
|
|
* "s/#&" Simple. Allows embedded space but I'm not sure
|
|
|
|
* that's useful. Doesn't hurt to always put the quotes there
|
|
|
|
* if you can't remember which characters are special.
|
|
|
|
*
|
|
|
|
*--------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
static void next_token (pfstate_t *pf)
|
|
|
|
{
|
|
|
|
while (pf->filter_str[pf->nexti] == ' ') {
|
|
|
|
pf->nexti++;
|
|
|
|
}
|
|
|
|
|
|
|
|
pf->tokeni = pf->nexti;
|
|
|
|
|
|
|
|
if (pf->filter_str[pf->nexti] == '\0') {
|
|
|
|
pf->token_type = TOKEN_EOL;
|
2015-09-07 23:56:20 +00:00
|
|
|
strlcpy (pf->token_str, "end-of-line", sizeof(pf->token_str));
|
2015-07-27 01:17:23 +00:00
|
|
|
}
|
|
|
|
else if (pf->filter_str[pf->nexti] == '&') {
|
|
|
|
pf->nexti++;
|
|
|
|
pf->token_type = TOKEN_AND;
|
2015-09-07 23:56:20 +00:00
|
|
|
strlcpy (pf->token_str, "\"&\"", sizeof(pf->token_str));
|
2015-07-27 01:17:23 +00:00
|
|
|
}
|
|
|
|
else if (pf->filter_str[pf->nexti] == '|') {
|
|
|
|
pf->nexti++;
|
|
|
|
pf->token_type = TOKEN_OR;
|
2015-09-07 23:56:20 +00:00
|
|
|
strlcpy (pf->token_str, "\"|\"", sizeof(pf->token_str));
|
2015-07-27 01:17:23 +00:00
|
|
|
}
|
|
|
|
else if (pf->filter_str[pf->nexti] == '!') {
|
|
|
|
pf->nexti++;
|
|
|
|
pf->token_type = TOKEN_NOT;
|
2015-09-07 23:56:20 +00:00
|
|
|
strlcpy (pf->token_str, "\"!\"", sizeof(pf->token_str));
|
2015-07-27 01:17:23 +00:00
|
|
|
}
|
|
|
|
else if (pf->filter_str[pf->nexti] == '(') {
|
|
|
|
pf->nexti++;
|
|
|
|
pf->token_type = TOKEN_LPAREN;
|
2015-09-07 23:56:20 +00:00
|
|
|
strlcpy (pf->token_str, "\"(\"", sizeof(pf->token_str));
|
2015-07-27 01:17:23 +00:00
|
|
|
}
|
|
|
|
else if (pf->filter_str[pf->nexti] == ')') {
|
|
|
|
pf->nexti++;
|
|
|
|
pf->token_type = TOKEN_RPAREN;
|
2015-09-07 23:56:20 +00:00
|
|
|
strlcpy (pf->token_str, "\")\"", sizeof(pf->token_str));
|
2015-07-27 01:17:23 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
char *p = pf->token_str;
|
|
|
|
pf->token_type = TOKEN_FILTER_SPEC;
|
|
|
|
do {
|
|
|
|
*p++ = pf->filter_str[pf->nexti++];
|
|
|
|
} while (pf->filter_str[pf->nexti] != ' ' && pf->filter_str[pf->nexti] != '\0');
|
|
|
|
*p = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
} /* end next_token */
|
|
|
|
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* Name: parse_expr
|
|
|
|
* parse_or_expr
|
|
|
|
* parse_and_expr
|
|
|
|
* parse_primary
|
|
|
|
*
|
|
|
|
* Purpose: Recursive descent parser to evaluate filter specifications
|
|
|
|
* contained within expressions with & | ! ( ).
|
|
|
|
*
|
|
|
|
* Inputs: pf - Pointer to current state information.
|
|
|
|
*
|
|
|
|
* Returns: 1 = yes
|
|
|
|
* 0 = no
|
|
|
|
* -1 = error detected
|
|
|
|
*
|
|
|
|
*--------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
|
|
static int parse_expr (pfstate_t *pf)
|
|
|
|
{
|
|
|
|
int result;
|
|
|
|
|
|
|
|
result = parse_or_expr (pf);
|
|
|
|
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* or_expr:: and_expr [ | and_expr ] ... */
|
|
|
|
|
|
|
|
static int parse_or_expr (pfstate_t *pf)
|
|
|
|
{
|
|
|
|
int result;
|
|
|
|
|
|
|
|
result = parse_and_expr (pf);
|
|
|
|
if (result < 0) return (-1);
|
|
|
|
|
|
|
|
while (pf->token_type == TOKEN_OR) {
|
|
|
|
int e;
|
|
|
|
|
|
|
|
next_token (pf);
|
|
|
|
e = parse_and_expr (pf);
|
2017-01-01 16:49:55 +00:00
|
|
|
|
|
|
|
if (s_debug >= 3) {
|
|
|
|
text_color_set(DW_COLOR_DEBUG);
|
|
|
|
dw_printf (" %s | %s\n", bool2text(result), bool2text(e));
|
|
|
|
}
|
|
|
|
|
2015-07-27 01:17:23 +00:00
|
|
|
if (e < 0) return (-1);
|
|
|
|
result |= e;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* and_expr:: primary [ & primary ] ... */
|
|
|
|
|
|
|
|
static int parse_and_expr (pfstate_t *pf)
|
|
|
|
{
|
|
|
|
int result;
|
|
|
|
|
|
|
|
result = parse_primary (pf);
|
|
|
|
if (result < 0) return (-1);
|
|
|
|
|
|
|
|
while (pf->token_type == TOKEN_AND) {
|
|
|
|
int e;
|
|
|
|
|
|
|
|
next_token (pf);
|
|
|
|
e = parse_primary (pf);
|
2017-01-01 16:49:55 +00:00
|
|
|
|
|
|
|
if (s_debug >= 3) {
|
|
|
|
text_color_set(DW_COLOR_DEBUG);
|
|
|
|
dw_printf (" %s & %s\n", bool2text(result), bool2text(e));
|
|
|
|
}
|
|
|
|
|
2015-07-27 01:17:23 +00:00
|
|
|
if (e < 0) return (-1);
|
|
|
|
result &= e;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* primary:: ( expr ) */
|
|
|
|
/* ! primary */
|
|
|
|
/* filter_spec */
|
|
|
|
|
|
|
|
static int parse_primary (pfstate_t *pf)
|
|
|
|
{
|
|
|
|
int result;
|
|
|
|
|
|
|
|
if (pf->token_type == TOKEN_LPAREN) {
|
|
|
|
|
|
|
|
next_token (pf);
|
|
|
|
result = parse_expr (pf);
|
|
|
|
|
|
|
|
if (pf->token_type == TOKEN_RPAREN) {
|
|
|
|
next_token (pf);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
print_error (pf, "Expected \")\" here.\n");
|
|
|
|
result = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (pf->token_type == TOKEN_NOT) {
|
|
|
|
int e;
|
|
|
|
|
|
|
|
next_token (pf);
|
|
|
|
e = parse_primary (pf);
|
2017-01-01 16:49:55 +00:00
|
|
|
|
|
|
|
if (s_debug >= 3) {
|
|
|
|
text_color_set(DW_COLOR_DEBUG);
|
|
|
|
dw_printf (" ! %s\n", bool2text(e));
|
|
|
|
}
|
|
|
|
|
2015-07-27 01:17:23 +00:00
|
|
|
if (e < 0) result = -1;
|
|
|
|
else result = ! e;
|
|
|
|
}
|
|
|
|
else if (pf->token_type == TOKEN_FILTER_SPEC) {
|
|
|
|
result = parse_filter_spec (pf);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
print_error (pf, "Expected filter specification, (, or ! here.");
|
|
|
|
result = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* Name: parse_filter_spec
|
|
|
|
*
|
|
|
|
* Purpose: Parse and evaluate filter specification.
|
|
|
|
*
|
|
|
|
* Inputs: pf - Pointer to current state information.
|
|
|
|
*
|
|
|
|
* Returns: 1 = yes
|
|
|
|
* 0 = no
|
|
|
|
* -1 = error detected
|
|
|
|
*
|
2016-11-20 19:58:51 +00:00
|
|
|
* Description: All filter specifications are allowed for APRS.
|
|
|
|
* Only those dealing with addresses are allowed for connected digipeater.
|
|
|
|
*
|
|
|
|
* b - budlist (source)
|
|
|
|
* d - digipeaters used
|
|
|
|
* v - digipeaters not used
|
|
|
|
* u - unproto (destination)
|
|
|
|
*
|
2015-07-27 01:17:23 +00:00
|
|
|
*--------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
static int parse_filter_spec (pfstate_t *pf)
|
|
|
|
{
|
|
|
|
int result = -1;
|
|
|
|
|
2016-11-20 19:58:51 +00:00
|
|
|
|
|
|
|
if ( ( ! pf->is_aprs) && strchr ("01bdvu", pf->token_str[0]) == NULL) {
|
|
|
|
|
|
|
|
print_error (pf, "Only b, d, v, and u specifications are allowed for connected mode digipeater filtering.");
|
|
|
|
result = -1;
|
|
|
|
next_token (pf);
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-07-27 01:17:23 +00:00
|
|
|
/* undocumented: can use 0 or 1 for testing. */
|
|
|
|
|
|
|
|
if (strcmp(pf->token_str, "0") == 0) {
|
|
|
|
result = 0;
|
|
|
|
}
|
|
|
|
else if (strcmp(pf->token_str, "1") == 0) {
|
|
|
|
result = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* simple string matching */
|
|
|
|
|
2017-01-01 16:49:55 +00:00
|
|
|
/* b - budlist */
|
|
|
|
|
2015-07-27 01:17:23 +00:00
|
|
|
else if (pf->token_str[0] == 'b' && ispunct(pf->token_str[1])) {
|
2023-06-14 00:37:08 +00:00
|
|
|
/* Budlist - AX.25 source address */
|
|
|
|
/* Could be different than source encapsulated by 3rd party header. */
|
2017-01-01 16:49:55 +00:00
|
|
|
char addr[AX25_MAX_ADDR_LEN];
|
2016-11-20 19:58:51 +00:00
|
|
|
ax25_get_addr_with_ssid (pf->pp, AX25_SOURCE, addr);
|
|
|
|
result = filt_bodgu (pf, addr);
|
2017-01-01 16:49:55 +00:00
|
|
|
|
|
|
|
if (s_debug >= 2) {
|
|
|
|
text_color_set(DW_COLOR_DEBUG);
|
|
|
|
dw_printf (" %s returns %s for %s\n", pf->token_str, bool2text(result), addr);
|
|
|
|
}
|
2015-07-27 01:17:23 +00:00
|
|
|
}
|
2017-01-01 16:49:55 +00:00
|
|
|
|
|
|
|
/* o - object or item name */
|
|
|
|
|
2015-07-27 01:17:23 +00:00
|
|
|
else if (pf->token_str[0] == 'o' && ispunct(pf->token_str[1])) {
|
|
|
|
result = filt_bodgu (pf, pf->decoded.g_name);
|
2017-01-01 16:49:55 +00:00
|
|
|
|
|
|
|
if (s_debug >= 2) {
|
|
|
|
text_color_set(DW_COLOR_DEBUG);
|
|
|
|
dw_printf (" %s returns %s for %s\n", pf->token_str, bool2text(result), pf->decoded.g_name);
|
|
|
|
}
|
2015-07-27 01:17:23 +00:00
|
|
|
}
|
2017-01-01 16:49:55 +00:00
|
|
|
|
|
|
|
/* d - was digipeated by */
|
|
|
|
|
2015-07-27 01:17:23 +00:00
|
|
|
else if (pf->token_str[0] == 'd' && ispunct(pf->token_str[1])) {
|
|
|
|
int n;
|
2023-06-14 00:37:08 +00:00
|
|
|
// Loop on all AX.25 digipeaters.
|
2015-07-27 01:17:23 +00:00
|
|
|
result = 0;
|
|
|
|
for (n = AX25_REPEATER_1; result == 0 && n < ax25_get_num_addr (pf->pp); n++) {
|
2016-01-27 04:45:58 +00:00
|
|
|
// Consider only those with the H (has-been-used) bit set.
|
2015-07-27 01:17:23 +00:00
|
|
|
if (ax25_get_h (pf->pp, n)) {
|
2017-01-01 16:49:55 +00:00
|
|
|
char addr[AX25_MAX_ADDR_LEN];
|
2015-07-27 01:17:23 +00:00
|
|
|
ax25_get_addr_with_ssid (pf->pp, n, addr);
|
|
|
|
result = filt_bodgu (pf, addr);
|
|
|
|
}
|
|
|
|
}
|
2017-01-01 16:49:55 +00:00
|
|
|
|
|
|
|
if (s_debug >= 2) {
|
|
|
|
char path[100];
|
|
|
|
|
|
|
|
ax25_format_via_path (pf->pp, path, sizeof(path));
|
|
|
|
if (strlen(path) == 0) {
|
|
|
|
strcpy (path, "no digipeater path");
|
|
|
|
}
|
|
|
|
text_color_set(DW_COLOR_DEBUG);
|
|
|
|
dw_printf (" %s returns %s for %s\n", pf->token_str, bool2text(result), path);
|
|
|
|
}
|
2015-07-27 01:17:23 +00:00
|
|
|
}
|
2017-01-01 16:49:55 +00:00
|
|
|
|
|
|
|
/* v - via not used */
|
|
|
|
|
2016-01-27 04:45:58 +00:00
|
|
|
else if (pf->token_str[0] == 'v' && ispunct(pf->token_str[1])) {
|
|
|
|
int n;
|
2023-06-14 00:37:08 +00:00
|
|
|
// loop on all AX.25 digipeaters (mnemonic Via)
|
2016-01-27 04:45:58 +00:00
|
|
|
result = 0;
|
|
|
|
for (n = AX25_REPEATER_1; result == 0 && n < ax25_get_num_addr (pf->pp); n++) {
|
|
|
|
// This is different than the previous "d" filter.
|
|
|
|
// Consider only those where the the H (has-been-used) bit is NOT set.
|
|
|
|
if ( ! ax25_get_h (pf->pp, n)) {
|
2017-01-01 16:49:55 +00:00
|
|
|
char addr[AX25_MAX_ADDR_LEN];
|
2016-01-27 04:45:58 +00:00
|
|
|
ax25_get_addr_with_ssid (pf->pp, n, addr);
|
|
|
|
result = filt_bodgu (pf, addr);
|
|
|
|
}
|
|
|
|
}
|
2017-01-01 16:49:55 +00:00
|
|
|
|
|
|
|
if (s_debug >= 2) {
|
|
|
|
char path[100];
|
|
|
|
|
|
|
|
ax25_format_via_path (pf->pp, path, sizeof(path));
|
|
|
|
if (strlen(path) == 0) {
|
|
|
|
strcpy (path, "no digipeater path");
|
|
|
|
}
|
|
|
|
text_color_set(DW_COLOR_DEBUG);
|
|
|
|
dw_printf (" %s returns %s for %s\n", pf->token_str, bool2text(result), path);
|
|
|
|
}
|
2016-01-27 04:45:58 +00:00
|
|
|
}
|
2017-01-01 16:49:55 +00:00
|
|
|
|
2023-06-14 00:37:08 +00:00
|
|
|
/* g - Addressee of message. e.g. "BLN*" for bulletins. */
|
2017-01-01 16:49:55 +00:00
|
|
|
|
2015-07-27 01:17:23 +00:00
|
|
|
else if (pf->token_str[0] == 'g' && ispunct(pf->token_str[1])) {
|
2023-06-14 00:37:08 +00:00
|
|
|
if (pf->decoded.g_message_subtype == message_subtype_message ||
|
|
|
|
pf->decoded.g_message_subtype == message_subtype_ack ||
|
|
|
|
pf->decoded.g_message_subtype == message_subtype_rej ||
|
|
|
|
pf->decoded.g_message_subtype == message_subtype_bulletin ||
|
|
|
|
pf->decoded.g_message_subtype == message_subtype_nws ||
|
|
|
|
pf->decoded.g_message_subtype == message_subtype_directed_query) {
|
2015-07-27 01:17:23 +00:00
|
|
|
result = filt_bodgu (pf, pf->decoded.g_addressee);
|
2017-01-01 16:49:55 +00:00
|
|
|
|
|
|
|
if (s_debug >= 2) {
|
|
|
|
text_color_set(DW_COLOR_DEBUG);
|
|
|
|
dw_printf (" %s returns %s for %s\n", pf->token_str, bool2text(result), pf->decoded.g_addressee);
|
|
|
|
}
|
2015-07-27 01:17:23 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
result = 0;
|
2017-01-01 16:49:55 +00:00
|
|
|
if (s_debug >= 2) {
|
|
|
|
text_color_set(DW_COLOR_DEBUG);
|
|
|
|
dw_printf (" %s returns %s for %s\n", pf->token_str, bool2text(result), "not a message");
|
|
|
|
}
|
2015-07-27 01:17:23 +00:00
|
|
|
}
|
|
|
|
}
|
2017-01-01 16:49:55 +00:00
|
|
|
|
2023-06-14 00:37:08 +00:00
|
|
|
/* u - unproto (AX.25 destination) */
|
2017-01-01 16:49:55 +00:00
|
|
|
|
2015-07-27 01:17:23 +00:00
|
|
|
else if (pf->token_str[0] == 'u' && ispunct(pf->token_str[1])) {
|
2017-01-01 16:49:55 +00:00
|
|
|
/* Probably want to exclude mic-e types */
|
2016-11-20 19:58:51 +00:00
|
|
|
/* because destination is used for part of location. */
|
2015-07-27 01:17:23 +00:00
|
|
|
|
|
|
|
if (ax25_get_dti(pf->pp) != '\'' && ax25_get_dti(pf->pp) != '`') {
|
2017-01-01 16:49:55 +00:00
|
|
|
char addr[AX25_MAX_ADDR_LEN];
|
2015-07-27 01:17:23 +00:00
|
|
|
ax25_get_addr_with_ssid (pf->pp, AX25_DESTINATION, addr);
|
|
|
|
result = filt_bodgu (pf, addr);
|
2017-01-01 16:49:55 +00:00
|
|
|
|
|
|
|
if (s_debug >= 2) {
|
|
|
|
text_color_set(DW_COLOR_DEBUG);
|
|
|
|
dw_printf (" %s returns %s for %s\n", pf->token_str, bool2text(result), addr);
|
|
|
|
}
|
2015-07-27 01:17:23 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
result = 0;
|
2017-01-01 16:49:55 +00:00
|
|
|
if (s_debug >= 2) {
|
|
|
|
text_color_set(DW_COLOR_DEBUG);
|
|
|
|
dw_printf (" %s returns %s for %s\n", pf->token_str, bool2text(result), "MIC-E packet type");
|
|
|
|
}
|
2015-07-27 01:17:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-14 00:37:08 +00:00
|
|
|
/* t - packet type: position, weather, telemetry, etc. */
|
2015-07-27 01:17:23 +00:00
|
|
|
|
|
|
|
else if (pf->token_str[0] == 't' && ispunct(pf->token_str[1])) {
|
|
|
|
|
|
|
|
result = filt_t (pf);
|
2017-01-01 16:49:55 +00:00
|
|
|
|
|
|
|
if (s_debug >= 2) {
|
|
|
|
char *infop = NULL;
|
|
|
|
(void) ax25_get_info (pf->pp, (unsigned char **)(&infop));
|
|
|
|
|
|
|
|
text_color_set(DW_COLOR_DEBUG);
|
|
|
|
dw_printf (" %s returns %s for %c data type indicator\n", pf->token_str, bool2text(result), *infop);
|
|
|
|
}
|
2015-07-27 01:17:23 +00:00
|
|
|
}
|
|
|
|
|
2017-01-01 16:49:55 +00:00
|
|
|
/* r - range */
|
2015-07-27 01:17:23 +00:00
|
|
|
|
|
|
|
else if (pf->token_str[0] == 'r' && ispunct(pf->token_str[1])) {
|
|
|
|
/* range */
|
2017-01-01 16:49:55 +00:00
|
|
|
char sdist[30];
|
|
|
|
strcpy (sdist, "unknown distance");
|
|
|
|
result = filt_r (pf, sdist);
|
|
|
|
|
|
|
|
if (s_debug >= 2) {
|
|
|
|
text_color_set(DW_COLOR_DEBUG);
|
|
|
|
dw_printf (" %s returns %s for %s\n", pf->token_str, bool2text(result), sdist);
|
|
|
|
}
|
2015-07-27 01:17:23 +00:00
|
|
|
}
|
|
|
|
|
2017-01-01 16:49:55 +00:00
|
|
|
/* s - symbol */
|
2015-07-27 01:17:23 +00:00
|
|
|
|
|
|
|
else if (pf->token_str[0] == 's' && ispunct(pf->token_str[1])) {
|
|
|
|
/* symbol */
|
|
|
|
result = filt_s (pf);
|
2017-01-01 16:49:55 +00:00
|
|
|
|
|
|
|
if (s_debug >= 2) {
|
|
|
|
text_color_set(DW_COLOR_DEBUG);
|
|
|
|
if (pf->decoded.g_symbol_table == '/') {
|
|
|
|
dw_printf (" %s returns %s for symbol %c in primary table\n", pf->token_str, bool2text(result), pf->decoded.g_symbol_code);
|
|
|
|
}
|
|
|
|
else if (pf->decoded.g_symbol_table == '\\') {
|
|
|
|
dw_printf (" %s returns %s for symbol %c in alternate table\n", pf->token_str, bool2text(result), pf->decoded.g_symbol_code);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
dw_printf (" %s returns %s for symbol %c with overlay %c\n", pf->token_str, bool2text(result), pf->decoded.g_symbol_code, pf->decoded.g_symbol_table);
|
|
|
|
}
|
|
|
|
}
|
2015-07-27 01:17:23 +00:00
|
|
|
}
|
|
|
|
|
2017-01-01 16:49:55 +00:00
|
|
|
/* i - IGate messaging default */
|
|
|
|
|
|
|
|
else if (pf->token_str[0] == 'i' && ispunct(pf->token_str[1])) {
|
|
|
|
/* IGatge messaging */
|
|
|
|
result = filt_i (pf);
|
|
|
|
|
|
|
|
if (s_debug >= 2) {
|
|
|
|
char *infop = NULL;
|
|
|
|
(void) ax25_get_info (pf->pp, (unsigned char **)(&infop));
|
|
|
|
|
|
|
|
text_color_set(DW_COLOR_DEBUG);
|
2023-06-14 00:37:08 +00:00
|
|
|
if (pf->decoded.g_packet_type == packet_type_message) {
|
2017-01-01 16:49:55 +00:00
|
|
|
dw_printf (" %s returns %s for message to %s\n", pf->token_str, bool2text(result), pf->decoded.g_addressee);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
dw_printf (" %s returns %s for not an APRS 'message'\n", pf->token_str, bool2text(result));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* unrecognized filter type */
|
|
|
|
|
2015-07-27 01:17:23 +00:00
|
|
|
else {
|
|
|
|
char stemp[80];
|
2015-09-07 23:56:20 +00:00
|
|
|
snprintf (stemp, sizeof(stemp), "Unrecognized filter type '%c'", pf->token_str[0]);
|
2015-07-27 01:17:23 +00:00
|
|
|
print_error (pf, stemp);
|
|
|
|
result = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
next_token (pf);
|
|
|
|
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*------------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* Name: filt_bodgu
|
|
|
|
*
|
|
|
|
* Purpose: Filter with text pattern matching
|
|
|
|
*
|
|
|
|
* Inputs: pf - Pointer to current state information.
|
|
|
|
* token_str should have one of these filter specs:
|
|
|
|
*
|
|
|
|
* Budlist b/call1/call2...
|
|
|
|
* Object o/obj1/obj2...
|
|
|
|
* Digipeater d/digi1/digi2...
|
|
|
|
* Group Msg g/call1/call2...
|
2016-01-27 04:45:58 +00:00
|
|
|
* Unproto u/unproto1/unproto2...
|
2017-01-01 16:49:55 +00:00
|
|
|
* Via-not-yet v/digi1/digi2...noteapd
|
2015-07-27 01:17:23 +00:00
|
|
|
*
|
|
|
|
* arg - Value to match from source addr, destination,
|
|
|
|
* used digipeater, object name, etc.
|
|
|
|
*
|
|
|
|
* Returns: 1 = yes
|
|
|
|
* 0 = no
|
|
|
|
* -1 = error detected
|
|
|
|
*
|
|
|
|
* Description: Same function is used for all of these because they are so similar.
|
2021-09-19 18:51:18 +00:00
|
|
|
* Look for exact match to any of the specified strings.
|
2015-07-27 01:17:23 +00:00
|
|
|
* All of them allow wildcarding with single * at the end.
|
|
|
|
*
|
|
|
|
*------------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
static int filt_bodgu (pfstate_t *pf, char *arg)
|
|
|
|
{
|
|
|
|
char str[MAX_TOKEN_LEN];
|
|
|
|
char *cp;
|
|
|
|
char sep[2];
|
|
|
|
char *v;
|
|
|
|
int result = 0;
|
|
|
|
|
2015-09-07 23:56:20 +00:00
|
|
|
strlcpy (str, pf->token_str, sizeof(str));
|
2015-07-27 01:17:23 +00:00
|
|
|
sep[0] = str[1];
|
|
|
|
sep[1] = '\0';
|
|
|
|
cp = str + 2;
|
|
|
|
|
|
|
|
while (result == 0 && (v = strsep (&cp, sep)) != NULL) {
|
|
|
|
|
|
|
|
int mlen;
|
|
|
|
char *w;
|
|
|
|
|
|
|
|
if ((w = strchr(v,'*')) != NULL) {
|
|
|
|
/* Wildcarding. Should have single * on end. */
|
|
|
|
|
|
|
|
mlen = w - v;
|
2017-01-01 16:49:55 +00:00
|
|
|
if (mlen != (int)(strlen(v) - 1)) {
|
2015-07-27 01:17:23 +00:00
|
|
|
print_error (pf, "Any wildcard * must be at the end of pattern.\n");
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
if (strncmp(v,arg,mlen) == 0) result = 1;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* Try for exact match. */
|
|
|
|
if (strcmp(v,arg) == 0) result = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*------------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* Name: filt_t
|
|
|
|
*
|
|
|
|
* Purpose: Filter by packet type.
|
|
|
|
*
|
|
|
|
* Inputs: pf - Pointer to current state information.
|
|
|
|
*
|
|
|
|
* Returns: 1 = yes
|
|
|
|
* 0 = no
|
|
|
|
* -1 = error detected
|
|
|
|
*
|
2023-06-14 00:37:08 +00:00
|
|
|
* Description: The filter is loosely based the type filtering described here:
|
2015-07-27 01:17:23 +00:00
|
|
|
* http://www.aprs-is.net/javAPRSFilter.aspx
|
|
|
|
*
|
2023-06-14 00:37:08 +00:00
|
|
|
* Mostly use g_packet_type and g_message_subtype from decode_aprs.
|
|
|
|
*
|
|
|
|
* References:
|
2015-07-27 01:17:23 +00:00
|
|
|
* http://www.aprs-is.net/WX/
|
2023-06-14 00:37:08 +00:00
|
|
|
* http://wxsvr.aprs.net.au/protocol-new.html (has disappeared)
|
2015-07-27 01:17:23 +00:00
|
|
|
*
|
|
|
|
*------------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
static int filt_t (pfstate_t *pf)
|
|
|
|
{
|
2015-09-07 23:56:20 +00:00
|
|
|
char src[AX25_MAX_ADDR_LEN];
|
|
|
|
char *infop = NULL;
|
2015-07-27 01:17:23 +00:00
|
|
|
char *f;
|
|
|
|
|
2015-09-07 23:56:20 +00:00
|
|
|
memset (src, 0, sizeof(src));
|
2015-07-27 01:17:23 +00:00
|
|
|
ax25_get_addr_with_ssid (pf->pp, AX25_SOURCE, src);
|
|
|
|
(void) ax25_get_info (pf->pp, (unsigned char **)(&infop));
|
|
|
|
|
2015-09-07 23:56:20 +00:00
|
|
|
assert (infop != NULL);
|
|
|
|
|
2015-07-27 01:17:23 +00:00
|
|
|
for (f = pf->token_str + 2; *f != '\0'; f++) {
|
|
|
|
switch (*f) {
|
|
|
|
|
|
|
|
case 'p': /* Position */
|
2023-06-14 00:37:08 +00:00
|
|
|
if (pf->decoded.g_packet_type == packet_type_position) return(1);
|
2015-07-27 01:17:23 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 'o': /* Object */
|
2023-06-14 00:37:08 +00:00
|
|
|
if (pf->decoded.g_packet_type == packet_type_object) return(1);
|
2015-07-27 01:17:23 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 'i': /* Item */
|
2023-06-14 00:37:08 +00:00
|
|
|
if (pf->decoded.g_packet_type == packet_type_item) return(1);
|
2015-07-27 01:17:23 +00:00
|
|
|
break;
|
|
|
|
|
2023-06-14 00:37:08 +00:00
|
|
|
case 'm': // Any "message."
|
|
|
|
if (pf->decoded.g_packet_type == packet_type_message) return(1);
|
2015-07-27 01:17:23 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 'q': /* Query */
|
2023-06-14 00:37:08 +00:00
|
|
|
if (pf->decoded.g_packet_type == packet_type_query) return(1);
|
2015-07-27 01:17:23 +00:00
|
|
|
break;
|
|
|
|
|
2017-07-01 01:23:16 +00:00
|
|
|
case 'c': /* station Capabilities - my extension */
|
|
|
|
/* Most often used for IGate statistics. */
|
2023-06-14 00:37:08 +00:00
|
|
|
if (pf->decoded.g_packet_type == packet_type_capabilities) return(1);
|
2017-07-01 01:23:16 +00:00
|
|
|
break;
|
|
|
|
|
2015-07-27 01:17:23 +00:00
|
|
|
case 's': /* Status */
|
2023-06-14 00:37:08 +00:00
|
|
|
if (pf->decoded.g_packet_type == packet_type_status) return(1);
|
2015-07-27 01:17:23 +00:00
|
|
|
break;
|
|
|
|
|
2023-06-14 00:37:08 +00:00
|
|
|
case 't': /* Telemetry data or metadata */
|
|
|
|
if (pf->decoded.g_packet_type == packet_type_telemetry) return(1);
|
2015-07-27 01:17:23 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 'u': /* User-defined */
|
2023-06-14 00:37:08 +00:00
|
|
|
if (pf->decoded.g_packet_type == packet_type_userdefined) return(1);
|
2015-07-27 01:17:23 +00:00
|
|
|
break;
|
|
|
|
|
2023-06-14 00:37:08 +00:00
|
|
|
case 'h': /* has third party Header - my extension */
|
|
|
|
if (pf->decoded.g_has_thirdparty_header) return (1);
|
2017-07-01 01:23:16 +00:00
|
|
|
break;
|
|
|
|
|
2015-07-27 01:17:23 +00:00
|
|
|
case 'w': /* Weather */
|
2017-07-01 01:23:16 +00:00
|
|
|
|
2023-06-14 00:37:08 +00:00
|
|
|
if (pf->decoded.g_packet_type == packet_type_weather) return(1);
|
2017-07-01 01:23:16 +00:00
|
|
|
|
2023-06-14 00:37:08 +00:00
|
|
|
/* Positions !=/@ with symbol code _ are weather. */
|
2017-07-01 01:23:16 +00:00
|
|
|
/* Object with _ symbol is also weather. APRS protocol spec page 66. */
|
2023-06-14 00:37:08 +00:00
|
|
|
// Can't use *infop because it would not work with 3rd party header.
|
2017-07-01 01:23:16 +00:00
|
|
|
|
2023-06-14 00:37:08 +00:00
|
|
|
if ((pf->decoded.g_packet_type == packet_type_position ||
|
|
|
|
pf->decoded.g_packet_type == packet_type_object) && pf->decoded.g_symbol_code == '_') return (1);
|
2015-07-27 01:17:23 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 'n': /* NWS format */
|
2023-06-14 00:37:08 +00:00
|
|
|
if (pf->decoded.g_packet_type == packet_type_nws) return(1);
|
2015-07-27 01:17:23 +00:00
|
|
|
break;
|
2015-09-07 23:56:20 +00:00
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
|
|
print_error (pf, "Invalid letter in t/ filter.\n");
|
|
|
|
return (-1);
|
|
|
|
break;
|
2015-07-27 01:17:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return (0); /* Didn't match anything. Reject */
|
|
|
|
|
|
|
|
} /* end filt_t */
|
|
|
|
|
|
|
|
|
|
|
|
|
2023-06-14 00:37:08 +00:00
|
|
|
|
2015-07-27 01:17:23 +00:00
|
|
|
/*------------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* Name: filt_r
|
|
|
|
*
|
2015-09-07 23:56:20 +00:00
|
|
|
* Purpose: Is it in range (kilometers) of given location.
|
2015-07-27 01:17:23 +00:00
|
|
|
*
|
|
|
|
* Inputs: pf - Pointer to current state information.
|
|
|
|
* token_str should contain something of format:
|
|
|
|
*
|
|
|
|
* r/lat/lon/dist
|
|
|
|
*
|
|
|
|
* We also need to know the location (if any) from the packet.
|
|
|
|
*
|
|
|
|
* decoded.g_lat & decoded.g_lon
|
|
|
|
*
|
2017-01-01 16:49:55 +00:00
|
|
|
* Outputs: sdist - Distance as a string for troubleshooting.
|
|
|
|
*
|
2015-07-27 01:17:23 +00:00
|
|
|
* Returns: 1 = yes
|
|
|
|
* 0 = no
|
|
|
|
* -1 = error detected
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
*
|
|
|
|
*------------------------------------------------------------------------------*/
|
|
|
|
|
2017-01-01 16:49:55 +00:00
|
|
|
static int filt_r (pfstate_t *pf, char *sdist)
|
2015-07-27 01:17:23 +00:00
|
|
|
{
|
|
|
|
char str[MAX_TOKEN_LEN];
|
|
|
|
char *cp;
|
|
|
|
char sep[2];
|
|
|
|
char *v;
|
|
|
|
double dlat, dlon, ddist, km;
|
|
|
|
|
|
|
|
|
2015-09-07 23:56:20 +00:00
|
|
|
strlcpy (str, pf->token_str, sizeof(str));
|
2015-07-27 01:17:23 +00:00
|
|
|
sep[0] = str[1];
|
|
|
|
sep[1] = '\0';
|
|
|
|
cp = str + 2;
|
|
|
|
|
|
|
|
if (pf->decoded.g_lat == G_UNKNOWN || pf->decoded.g_lon == G_UNKNOWN) {
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
v = strsep (&cp, sep);
|
|
|
|
if (v == NULL) {
|
|
|
|
print_error (pf, "Missing latitude for Range filter.");
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
dlat = atof(v);
|
|
|
|
|
|
|
|
v = strsep (&cp, sep);
|
|
|
|
if (v == NULL) {
|
|
|
|
print_error (pf, "Missing longitude for Range filter.");
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
dlon = atof(v);
|
|
|
|
|
|
|
|
v = strsep (&cp, sep);
|
|
|
|
if (v == NULL) {
|
|
|
|
print_error (pf, "Missing distance for Range filter.");
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
ddist = atof(v);
|
|
|
|
|
|
|
|
km = ll_distance_km (dlat, dlon, pf->decoded.g_lat, pf->decoded.g_lon);
|
|
|
|
|
2017-01-01 16:49:55 +00:00
|
|
|
sprintf (sdist, "%.2f km", km);
|
2015-07-27 01:17:23 +00:00
|
|
|
|
|
|
|
if (km <= ddist) {
|
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*------------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* Name: filt_s
|
|
|
|
*
|
|
|
|
* Purpose: Filter by symbol.
|
|
|
|
*
|
|
|
|
* Inputs: pf - Pointer to current state information.
|
|
|
|
* token_str should contain something of format:
|
|
|
|
*
|
|
|
|
* s/pri/alt/over
|
|
|
|
*
|
|
|
|
* Returns: 1 = yes
|
|
|
|
* 0 = no
|
|
|
|
* -1 = error detected
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
*
|
2017-07-01 01:23:16 +00:00
|
|
|
* s/pri
|
|
|
|
* s/pri/alt
|
|
|
|
* s/pri/alt/
|
|
|
|
* s/pri/alt/over
|
|
|
|
*
|
2015-09-07 23:56:20 +00:00
|
|
|
* "pri" is zero or more symbols from the primary symbol set.
|
2017-07-01 01:23:16 +00:00
|
|
|
* Symbol codes are any printable ASCII character other than | or ~.
|
|
|
|
* (Zero symbols here would be sensible only if later alt part is specified.)
|
2015-09-07 23:56:20 +00:00
|
|
|
* "alt" is one or more symbols from the alternate symbol set.
|
2017-07-01 01:23:16 +00:00
|
|
|
* "over" is overlay characters for the alternate symbol set.
|
|
|
|
* Only upper case letters, digits, and \ are allowed here.
|
|
|
|
* If the last part is not specified, any overlay or lack of overlay, is ignored.
|
|
|
|
* If the last part is specified, only the listed overlays will match.
|
|
|
|
* An explicit lack of overlay is represented by the \ character.
|
2015-07-27 01:17:23 +00:00
|
|
|
*
|
|
|
|
* Examples:
|
2017-07-01 01:23:16 +00:00
|
|
|
* s/O Balloon.
|
|
|
|
* s/-> House or car from primary symbol table.
|
|
|
|
*
|
|
|
|
* s//# Alternate table digipeater, with or without overlay.
|
|
|
|
* s//#/\ Alternate table digipeater, only if no overlay.
|
|
|
|
* s//#/SL1 Alternate table digipeater, with overlay S, L, or 1.
|
|
|
|
* s//#/SL\ Alternate table digipeater, with S, L, or no overlay.
|
|
|
|
*
|
|
|
|
* s/s/s Any variation of watercraft. Either symbol table. With or without overlay.
|
|
|
|
* s/s/s/ Ship or ship sideview, only if no overlay.
|
|
|
|
* s//s/J Jet Ski.
|
|
|
|
*
|
|
|
|
* What if you want to use the / symbol when / is being used as a delimiter here? Recall that you
|
|
|
|
* can use some other special character after the initial lower case letter and this becomes the
|
|
|
|
* delimiter for the rest of the specification.
|
|
|
|
*
|
|
|
|
* Examples:
|
|
|
|
*
|
|
|
|
* s:/ Red Dot.
|
|
|
|
* s::/ Waypoint Destination, with or without overlay.
|
|
|
|
* s:/:/ Either Red Dot or Waypoint Destination.
|
|
|
|
* s:/:/: Either Red Dot or Waypoint Destination, no overlay.
|
|
|
|
*
|
|
|
|
* Bad example:
|
|
|
|
*
|
|
|
|
* Someone tried using this to include ballons: s/'/O/-/#/_
|
|
|
|
* probably following the buddy filter pattern of / between each alternative.
|
|
|
|
* There should be an error message because it has more than 3 delimiter characters.
|
|
|
|
*
|
2015-07-27 01:17:23 +00:00
|
|
|
*
|
|
|
|
*------------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
static int filt_s (pfstate_t *pf)
|
|
|
|
{
|
|
|
|
char str[MAX_TOKEN_LEN];
|
|
|
|
char *cp;
|
2017-07-01 01:23:16 +00:00
|
|
|
char sep[2]; // Delimiter character. Typically / but it could be different.
|
|
|
|
char *pri = NULL, *alt = NULL, *over = NULL, *extra = NULL;
|
|
|
|
char *x;
|
2015-07-27 01:17:23 +00:00
|
|
|
|
|
|
|
|
2015-09-07 23:56:20 +00:00
|
|
|
strlcpy (str, pf->token_str, sizeof(str));
|
2015-07-27 01:17:23 +00:00
|
|
|
sep[0] = str[1];
|
|
|
|
sep[1] = '\0';
|
|
|
|
cp = str + 2;
|
|
|
|
|
2017-07-01 01:23:16 +00:00
|
|
|
|
|
|
|
// First, separate the parts and do a strict syntax check.
|
2017-01-01 16:49:55 +00:00
|
|
|
|
2015-07-27 01:17:23 +00:00
|
|
|
pri = strsep (&cp, sep);
|
2017-01-01 16:49:55 +00:00
|
|
|
|
2017-07-01 01:23:16 +00:00
|
|
|
if (pri != NULL) {
|
|
|
|
|
|
|
|
// Zero length is acceptable if alternate symbol(s) specified. Will check that later.
|
|
|
|
|
|
|
|
for (x = pri; *x != '\0'; x++) {
|
|
|
|
if ( ! isprint(*x) || *x == '|' || *x == '~') {
|
|
|
|
print_error (pf, "Symbol filter, primary must be printable ASCII character(s) other than | or ~.");
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
alt = strsep (&cp, sep);
|
|
|
|
|
|
|
|
if (alt != NULL) {
|
|
|
|
|
|
|
|
// Zero length after second / would be pointless.
|
|
|
|
|
|
|
|
if (strlen(alt) == 0) {
|
|
|
|
print_error (pf, "Nothing specified for alternate symbol table.");
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (x = alt; *x != '\0'; x++) {
|
|
|
|
if ( ! isprint(*x) || *x == '|' || *x == '~') {
|
|
|
|
print_error (pf, "Symbol filter, alternate must be printable ASCII character(s) other than | or ~.");
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
over = strsep (&cp, sep);
|
|
|
|
|
|
|
|
if (over != NULL) {
|
|
|
|
|
|
|
|
// Zero length is acceptable and is not the same as missing.
|
|
|
|
|
|
|
|
for (x = over; *x != '\0'; x++) {
|
|
|
|
if ( (! isupper(*x)) && (! isdigit(*x)) && *x != '\\') {
|
|
|
|
print_error (pf, "Symbol filter, overlay must be upper case letter, digit, or \\.");
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
extra = strsep (&cp, sep);
|
|
|
|
|
|
|
|
if (extra != NULL) {
|
|
|
|
print_error (pf, "More than 3 delimiter characters in Symbol filter.");
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// No alt part is OK if at least one primary symbol was specified.
|
|
|
|
if (strlen(pri) == 0) {
|
|
|
|
print_error (pf, "No symbols specified for Symbol filter.");
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2015-07-27 01:17:23 +00:00
|
|
|
print_error (pf, "Missing arguments for Symbol filter.");
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
2017-07-01 01:23:16 +00:00
|
|
|
|
|
|
|
// This applies only for Position, Object, Item.
|
|
|
|
// decode_aprs() should set symbol code to space to mean undefined.
|
|
|
|
|
|
|
|
if (pf->decoded.g_symbol_code == ' ') {
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Look for Primary symbols.
|
|
|
|
|
|
|
|
if (pf->decoded.g_symbol_table == '/') {
|
|
|
|
if (pri != NULL && strlen(pri) > 0) {
|
|
|
|
return (strchr(pri, pf->decoded.g_symbol_code) != NULL);
|
|
|
|
}
|
2015-07-27 01:17:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (alt == NULL) {
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
//printf ("alt=\"%s\" sym='%c'\n", alt, pf->decoded.g_symbol_code);
|
|
|
|
|
2017-07-01 01:23:16 +00:00
|
|
|
// Look for Alternate symbols.
|
2015-07-27 01:17:23 +00:00
|
|
|
|
2017-07-01 01:23:16 +00:00
|
|
|
if (strchr(alt, pf->decoded.g_symbol_code) != NULL) {
|
2015-07-27 01:17:23 +00:00
|
|
|
|
2017-07-01 01:23:16 +00:00
|
|
|
// We have a match but that might not be enough.
|
|
|
|
// We must see if there was an overlay part specified.
|
2015-07-27 01:17:23 +00:00
|
|
|
|
2017-07-01 01:23:16 +00:00
|
|
|
if (over != NULL) {
|
|
|
|
|
|
|
|
if (strlen(over) > 0) {
|
|
|
|
|
|
|
|
// Non-zero length overlay part was specified.
|
|
|
|
// Need to match one of them.
|
|
|
|
|
|
|
|
return (strchr(over, pf->decoded.g_symbol_table) != NULL);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
|
|
|
|
// Zero length overlay part was specified.
|
|
|
|
// We must have no overlay, i.e. table is \.
|
|
|
|
|
|
|
|
return (pf->decoded.g_symbol_table == '\\');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
|
|
|
|
// No check of overlay part. Just make sure it is not primary table.
|
|
|
|
|
|
|
|
return (pf->decoded.g_symbol_table != '/');
|
|
|
|
}
|
2015-07-27 01:17:23 +00:00
|
|
|
}
|
|
|
|
|
2017-07-01 01:23:16 +00:00
|
|
|
return (0);
|
|
|
|
|
|
|
|
} /* end filt_s */
|
2015-07-27 01:17:23 +00:00
|
|
|
|
|
|
|
|
2017-01-01 16:49:55 +00:00
|
|
|
/*------------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* Name: filt_i
|
|
|
|
*
|
2022-11-25 22:59:36 +00:00
|
|
|
* Purpose: IGate messaging filter.
|
|
|
|
* This would make sense only for IS>RF direction.
|
2017-01-01 16:49:55 +00:00
|
|
|
*
|
|
|
|
* Inputs: pf - Pointer to current state information.
|
|
|
|
* token_str should contain something of format:
|
|
|
|
*
|
|
|
|
* i/time/hops/lat/lon/km
|
|
|
|
*
|
|
|
|
* Returns: 1 = yes
|
|
|
|
* 0 = no
|
|
|
|
* -1 = error detected
|
|
|
|
*
|
|
|
|
* Description: Selection is based on time since last heard on RF, and distance
|
2021-09-19 18:51:18 +00:00
|
|
|
* in terms of digipeater hops and/or physical location.
|
2017-01-01 16:49:55 +00:00
|
|
|
*
|
|
|
|
* i/time
|
|
|
|
* i/time/hops
|
|
|
|
* i/time/hops/lat/lon/km
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* "time" is maximum number of minutes since message addressee was last heard.
|
2020-10-24 15:38:44 +00:00
|
|
|
* This is required. APRS-IS uses 3 hours so that would be a good value here.
|
2017-01-01 16:49:55 +00:00
|
|
|
*
|
|
|
|
* "hops" is maximum number of digpeater hops. (i.e. 0 for heard directly).
|
|
|
|
* If hops is not specified, the maximum transmit digipeater hop count,
|
|
|
|
* from the IGTXVIA configuration will be used.
|
|
|
|
|
|
|
|
* The rest is distanced, in kilometers, from given point.
|
|
|
|
*
|
|
|
|
* Examples:
|
2022-11-25 22:59:36 +00:00
|
|
|
* i/180/0 Heard in past 3 hours directly.
|
2017-01-01 16:49:55 +00:00
|
|
|
* i/45 Past 45 minutes, default max digi hops.
|
2020-10-24 15:38:44 +00:00
|
|
|
* i/180/3 Default time (3 hours), max 3 digi hops.
|
|
|
|
* i/180/8/42.6/-71.3/50.
|
2017-01-01 16:49:55 +00:00
|
|
|
*
|
|
|
|
*
|
|
|
|
* It only makes sense to use this for the IS>RF direction.
|
|
|
|
* The basic idea is that we want to transmit a "message" only if the
|
|
|
|
* addressee has been heard recently and is not too far away.
|
|
|
|
*
|
2022-11-25 22:59:36 +00:00
|
|
|
* That is so we can distinguish messages addressed to a specific
|
|
|
|
* station, and other sundry uses of the addressee field.
|
|
|
|
*
|
2017-01-01 16:49:55 +00:00
|
|
|
* After passing along a "message" we will also allow the next
|
|
|
|
* position report from the sender of the "message."
|
|
|
|
* That is done somewhere else. We are not concerned with it here.
|
|
|
|
*
|
2020-10-24 15:38:44 +00:00
|
|
|
* IMHO, the rules here are too restrictive.
|
|
|
|
*
|
2023-06-14 00:37:08 +00:00
|
|
|
* The APRS-IS would send a "message" to my IGate only if the addressee
|
2022-11-25 22:59:36 +00:00
|
|
|
* has been heard nearby recently. 180 minutes, I believe.
|
2023-06-14 00:37:08 +00:00
|
|
|
* Why would I not want to transmit it?
|
|
|
|
*
|
|
|
|
* Discussion: In retrospect, I think this is far too complicated.
|
|
|
|
* In a future release, I think at options other than time should be removed.
|
|
|
|
* Messages have more value than most packets. Why reduce the chance of successful delivery?
|
|
|
|
*
|
|
|
|
* Consider the following scenario:
|
|
|
|
*
|
|
|
|
* (1) We hear AA1PR-9 by a path of 4 digipeaters.
|
|
|
|
* Looking closer, it's probably only two because there are left over WIDE1-0 and WIDE2-0.
|
|
|
|
*
|
|
|
|
* Digipeater WIDE2 (probably N3LLO-3) audio level = 72(19/15) [NONE] _|||||___
|
|
|
|
* [0.3] AA1PR-9>APY300,K1EQX-7,WIDE1,N3LLO-3,WIDE2*,ARISS::ANSRVR :cq hotg vt aprsthursday{01<0x0d>
|
|
|
|
*
|
|
|
|
* (2) APRS-IS sends a response to us.
|
|
|
|
*
|
|
|
|
* [ig>tx] ANSRVR>APWW11,KJ4ERJ-15*,TCPIP*,qAS,KJ4ERJ-15::AA1PR-9 :N:HOTG 161 Messages Sent{JL}
|
|
|
|
*
|
|
|
|
* (3) Here is our analysis of whether it should be sent to RF.
|
|
|
|
*
|
|
|
|
* Was message addressee AA1PR-9 heard in the past 180 minutes, with 2 or fewer digipeater hops?
|
|
|
|
* No, AA1PR-9 was last heard over the radio with 4 digipeater hops 0 minutes ago.
|
|
|
|
*
|
|
|
|
* The wrong hop count caused us to drop a packet that should have been transmitted.
|
|
|
|
* We could put in a hack to not count the "WIDE*-0" addresses.
|
|
|
|
* That is not correct because other prefixes could be used and we don't know
|
|
|
|
* what they are for other digipeaters.
|
|
|
|
* I think the best solution is to simply ignore the hop count.
|
2020-10-24 15:38:44 +00:00
|
|
|
*
|
2023-08-08 16:34:06 +00:00
|
|
|
* Release 1.7: I got overly ambitious and now realize this is just giving people too much
|
|
|
|
* "rope to hang themselves," drop messages unexpectedly, and accidentally break messaging.
|
|
|
|
* Change documentation to mention only the time limit.
|
|
|
|
* The other functionality will be undocumented and maybe disappear over time.
|
|
|
|
*
|
2017-01-01 16:49:55 +00:00
|
|
|
*------------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
static int filt_i (pfstate_t *pf)
|
|
|
|
{
|
|
|
|
char str[MAX_TOKEN_LEN];
|
|
|
|
char *cp;
|
|
|
|
char sep[2];
|
|
|
|
char *v;
|
2020-10-24 15:38:44 +00:00
|
|
|
|
|
|
|
// http://lists.tapr.org/pipermail/aprssig_lists.tapr.org/2020-July/048656.html
|
|
|
|
// Default of 3 hours should be good.
|
|
|
|
// One might question why to have a time limit at all. Messages are very rare
|
|
|
|
// the the APRS-IS wouldn't be sending it to me unless the addressee was in the
|
|
|
|
// vicinity recently.
|
|
|
|
// TODO: Should produce a warning if a user specified filter does not include "i".
|
|
|
|
|
|
|
|
int heardtime = 180; // 3 hours * 60 min/hr = 180 minutes
|
2017-01-01 16:49:55 +00:00
|
|
|
#if PFTEST
|
|
|
|
int maxhops = 2;
|
|
|
|
#else
|
|
|
|
int maxhops = save_igate_config_p->max_digi_hops; // from IGTXVIA config.
|
|
|
|
#endif
|
|
|
|
double dlat = G_UNKNOWN;
|
|
|
|
double dlon = G_UNKNOWN;
|
|
|
|
double km = G_UNKNOWN;
|
|
|
|
|
|
|
|
|
2023-06-14 00:37:08 +00:00
|
|
|
//char src[AX25_MAX_ADDR_LEN];
|
|
|
|
//char *infop = NULL;
|
|
|
|
//int info_len;
|
2017-01-01 16:49:55 +00:00
|
|
|
//char *f;
|
|
|
|
//char addressee[AX25_MAX_ADDR_LEN];
|
|
|
|
|
|
|
|
|
|
|
|
strlcpy (str, pf->token_str, sizeof(str));
|
|
|
|
sep[0] = str[1];
|
|
|
|
sep[1] = '\0';
|
|
|
|
cp = str + 2;
|
|
|
|
|
|
|
|
// Get parameters or defaults.
|
|
|
|
|
|
|
|
v = strsep (&cp, sep);
|
|
|
|
|
|
|
|
if (v != NULL && strlen(v) > 0) {
|
|
|
|
heardtime = atoi(v);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
print_error (pf, "Missing time limit for IGate message filter.");
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
v = strsep (&cp, sep);
|
|
|
|
|
|
|
|
if (v != NULL) {
|
|
|
|
if (strlen(v) > 0) {
|
|
|
|
maxhops = atoi(v);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
print_error (pf, "Missing max digipeater hops for IGate message filter.");
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
v = strsep (&cp, sep);
|
|
|
|
if (v != NULL && strlen(v) > 0) {
|
|
|
|
dlat = atof(v);
|
|
|
|
|
|
|
|
v = strsep (&cp, sep);
|
|
|
|
if (v != NULL && strlen(v) > 0) {
|
|
|
|
dlon = atof(v);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
print_error (pf, "Missing longitude for IGate message filter.");
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
v = strsep (&cp, sep);
|
|
|
|
if (v != NULL && strlen(v) > 0) {
|
|
|
|
km = atof(v);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
print_error (pf, "Missing distance, in km, for IGate message filter.");
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
v = strsep (&cp, sep);
|
|
|
|
if (v != NULL) {
|
|
|
|
print_error (pf, "Something unexpected after distance for IGate message filter.");
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#if PFTEST
|
|
|
|
text_color_set(DW_COLOR_DEBUG);
|
|
|
|
dw_printf ("debug: IGate message filter, %d minutes, %d hops, %.2f %.2f %.2f km\n",
|
|
|
|
heardtime, maxhops, dlat, dlon, km);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get source address and info part.
|
|
|
|
* Addressee has already been extracted into pf->decoded.g_addressee.
|
|
|
|
*/
|
2023-06-14 00:37:08 +00:00
|
|
|
if (pf->decoded.g_packet_type != packet_type_message) return(0);
|
2017-01-01 16:49:55 +00:00
|
|
|
|
|
|
|
#if defined(PFTEST) || defined(DIGITEST) // TODO: test functionality too, not just syntax.
|
|
|
|
|
|
|
|
(void)dlat; // Suppress set and not used warning.
|
|
|
|
(void)dlon;
|
|
|
|
(void)km;
|
|
|
|
(void)maxhops;
|
|
|
|
(void)heardtime;
|
|
|
|
|
|
|
|
return (1);
|
|
|
|
#else
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Condition 1:
|
|
|
|
* "the receiving station has been heard within range within a predefined time
|
|
|
|
* period (range defined as digi hops, distance, or both)."
|
|
|
|
*/
|
|
|
|
|
|
|
|
int was_heard = mheard_was_recently_nearby ("addressee", pf->decoded.g_addressee, heardtime, maxhops, dlat, dlon, km);
|
|
|
|
|
|
|
|
if ( ! was_heard) return (0);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Condition 2:
|
|
|
|
* "the sending station has not been heard via RF within a predefined time period
|
|
|
|
* (packets gated from the Internet by other stations are excluded from this test)."
|
|
|
|
*
|
|
|
|
* This is the part I'm not so sure about.
|
|
|
|
* I guess the intention is that if the sender can be heard over RF, then the addressee
|
|
|
|
* might hear the sender without the help of Igate stations.
|
|
|
|
* Suppose the sender was 1 digipeater hop to the west and the addressee was 1 digipeater hop to the east.
|
|
|
|
* I can communicate with each of them with 1 digipeater hop but for them to reach each other, they
|
|
|
|
* might need 3 hops and using that many is generally frowned upon and rare.
|
|
|
|
*
|
|
|
|
* Maybe we could compromise here and say the sender must have been heard directly.
|
|
|
|
* It sent the message currently being processed so we must have heard it very recently, i.e. in
|
2020-10-24 15:38:44 +00:00
|
|
|
* the past minute, rather than the usual 180 minutes for the addressee.
|
2017-01-01 16:49:55 +00:00
|
|
|
*/
|
|
|
|
|
2023-06-14 00:37:08 +00:00
|
|
|
was_heard = mheard_was_recently_nearby ("source", pf->decoded.g_src, 1, 0, G_UNKNOWN, G_UNKNOWN, G_UNKNOWN);
|
2017-01-01 16:49:55 +00:00
|
|
|
|
|
|
|
if (was_heard) return (0);
|
|
|
|
|
|
|
|
return (1);
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
} /* end filt_i */
|
|
|
|
|
|
|
|
|
2015-07-27 01:17:23 +00:00
|
|
|
/*-------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* Name: print_error
|
|
|
|
*
|
|
|
|
* Purpose: Print error message with context so someone can figure out what caused it.
|
|
|
|
*
|
|
|
|
* Inputs: pf - Pointer to current state information.
|
|
|
|
*
|
|
|
|
* str - Specific error message.
|
|
|
|
*
|
|
|
|
*--------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
static void print_error (pfstate_t *pf, char *msg)
|
|
|
|
{
|
|
|
|
char intro[50];
|
|
|
|
|
|
|
|
if (pf->from_chan == MAX_CHANS) {
|
|
|
|
|
|
|
|
if (pf->to_chan == MAX_CHANS) {
|
2015-09-07 23:56:20 +00:00
|
|
|
snprintf (intro, sizeof(intro), "filter[IG,IG]: ");
|
2015-07-27 01:17:23 +00:00
|
|
|
}
|
|
|
|
else {
|
2015-09-07 23:56:20 +00:00
|
|
|
snprintf (intro, sizeof(intro), "filter[IG,%d]: ", pf->to_chan);
|
2015-07-27 01:17:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
|
|
|
|
if (pf->to_chan == MAX_CHANS) {
|
2015-09-07 23:56:20 +00:00
|
|
|
snprintf (intro, sizeof(intro), "filter[%d,IG]: ", pf->from_chan);
|
2015-07-27 01:17:23 +00:00
|
|
|
}
|
|
|
|
else {
|
2015-09-07 23:56:20 +00:00
|
|
|
snprintf (intro, sizeof(intro), "filter[%d,%d]: ", pf->from_chan, pf->to_chan);
|
2015-07-27 01:17:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
text_color_set (DW_COLOR_ERROR);
|
|
|
|
|
|
|
|
dw_printf ("%s%s\n", intro, pf->filter_str);
|
|
|
|
dw_printf ("%*s\n", (int)(strlen(intro) + pf->tokeni + 1), "^");
|
|
|
|
dw_printf ("%s\n", msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2015-11-08 01:57:02 +00:00
|
|
|
#if PFTEST
|
2015-07-27 01:17:23 +00:00
|
|
|
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* Name: main & pftest
|
|
|
|
*
|
|
|
|
* Purpose: Unit test for packet filtering.
|
|
|
|
*
|
2015-11-08 01:57:02 +00:00
|
|
|
* Usage: gcc -Wall -o pftest -DPFTEST pfilter.c ax25_pad.o textcolor.o fcs_calc.o decode_aprs.o latlong.o symbols.o telemetry.o tt_text.c misc.a regex.a && ./pftest
|
2015-07-27 01:17:23 +00:00
|
|
|
*
|
|
|
|
*
|
|
|
|
*--------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
|
|
static int error_count = 0;
|
|
|
|
static void pftest (int test_num, char *filter, char *packet, int expected);
|
|
|
|
|
|
|
|
int main ()
|
|
|
|
{
|
|
|
|
|
2015-11-08 01:57:02 +00:00
|
|
|
dw_printf ("Quick test for packet filtering.\n");
|
|
|
|
dw_printf ("Some error messages are normal. Look at the final success/fail message.\n");
|
|
|
|
|
2015-07-27 01:17:23 +00:00
|
|
|
pftest (1, "", "WB2OSZ-5>APDW12,WIDE1-1,WIDE2-1:!4237.14NS07120.83W#PHG7140Chelmsford MA", 0);
|
|
|
|
pftest (2, "0", "WB2OSZ-5>APDW12,WIDE1-1,WIDE2-1:!4237.14NS07120.83W#PHG7140Chelmsford MA", 0);
|
|
|
|
pftest (3, "1", "WB2OSZ-5>APDW12,WIDE1-1,WIDE2-1:!4237.14NS07120.83W#PHG7140Chelmsford MA", 1);
|
|
|
|
|
|
|
|
pftest (10, "0 | 0", "WB2OSZ-5>APDW12,WIDE1-1,WIDE2-1:!4237.14NS07120.83W#PHG7140Chelmsford MA", 0);
|
|
|
|
pftest (11, "0 | 1", "WB2OSZ-5>APDW12,WIDE1-1,WIDE2-1:!4237.14NS07120.83W#PHG7140Chelmsford MA", 1);
|
|
|
|
pftest (12, "1 | 0", "WB2OSZ-5>APDW12,WIDE1-1,WIDE2-1:!4237.14NS07120.83W#PHG7140Chelmsford MA", 1);
|
|
|
|
pftest (13, "1 | 1", "WB2OSZ-5>APDW12,WIDE1-1,WIDE2-1:!4237.14NS07120.83W#PHG7140Chelmsford MA", 1);
|
|
|
|
pftest (14, "0 | 0 | 1", "WB2OSZ-5>APDW12,WIDE1-1,WIDE2-1:!4237.14NS07120.83W#PHG7140Chelmsford MA", 1);
|
|
|
|
|
|
|
|
pftest (20, "0 & 0", "WB2OSZ-5>APDW12,WIDE1-1,WIDE2-1:!4237.14NS07120.83W#PHG7140Chelmsford MA", 0);
|
|
|
|
pftest (21, "0 & 1", "WB2OSZ-5>APDW12,WIDE1-1,WIDE2-1:!4237.14NS07120.83W#PHG7140Chelmsford MA", 0);
|
|
|
|
pftest (22, "1 & 0", "WB2OSZ-5>APDW12,WIDE1-1,WIDE2-1:!4237.14NS07120.83W#PHG7140Chelmsford MA", 0);
|
|
|
|
pftest (23, "1 & 1", "WB2OSZ-5>APDW12,WIDE1-1,WIDE2-1:!4237.14NS07120.83W#PHG7140Chelmsford MA", 1);
|
|
|
|
pftest (24, "1 & 1 & 1", "WB2OSZ-5>APDW12,WIDE1-1,WIDE2-1:!4237.14NS07120.83W#PHG7140Chelmsford MA", 1);
|
|
|
|
pftest (24, "1 & 0 & 1", "WB2OSZ-5>APDW12,WIDE1-1,WIDE2-1:!4237.14NS07120.83W#PHG7140Chelmsford MA", 0);
|
|
|
|
pftest (24, "1 & 1 & 0", "WB2OSZ-5>APDW12,WIDE1-1,WIDE2-1:!4237.14NS07120.83W#PHG7140Chelmsford MA", 0);
|
|
|
|
|
|
|
|
pftest (30, "0 | ! 1", "WB2OSZ-5>APDW12,WIDE1-1,WIDE2-1:!4237.14NS07120.83W#PHG7140Chelmsford MA", 0);
|
|
|
|
pftest (31, "! 1 | ! 0", "WB2OSZ-5>APDW12,WIDE1-1,WIDE2-1:!4237.14NS07120.83W#PHG7140Chelmsford MA", 1);
|
|
|
|
pftest (32, "! ! 1 | 0", "WB2OSZ-5>APDW12,WIDE1-1,WIDE2-1:!4237.14NS07120.83W#PHG7140Chelmsford MA", 1);
|
|
|
|
pftest (33, "1 | ! ! 1", "WB2OSZ-5>APDW12,WIDE1-1,WIDE2-1:!4237.14NS07120.83W#PHG7140Chelmsford MA", 1);
|
|
|
|
|
|
|
|
pftest (40, "1 &(!0 |0 )", "WB2OSZ-5>APDW12,WIDE1-1,WIDE2-1:!4237.14NS07120.83W#PHG7140Chelmsford MA", 1);
|
|
|
|
pftest (41, "0 |(!0 )", "WB2OSZ-5>APDW12,WIDE1-1,WIDE2-1:!4237.14NS07120.83W#PHG7140Chelmsford MA", 1);
|
|
|
|
pftest (42, "1 |(!!0 )", "WB2OSZ-5>APDW12,WIDE1-1,WIDE2-1:!4237.14NS07120.83W#PHG7140Chelmsford MA", 1);
|
|
|
|
pftest (42, "(!(1 ) & (1 ))", "WB2OSZ-5>APDW12,WIDE1-1,WIDE2-1:!4237.14NS07120.83W#PHG7140Chelmsford MA", 0);
|
|
|
|
|
|
|
|
pftest (50, "b/W2UB/WB2OSZ-5/N2GH", "WB2OSZ-5>APDW12,WIDE1-1,WIDE2-1:!4237.14NS07120.83W#PHG7140Chelmsford MA", 1);
|
|
|
|
pftest (51, "b/W2UB/WB2OSZ-14/N2GH", "WB2OSZ-5>APDW12,WIDE1-1,WIDE2-1:!4237.14NS07120.83W#PHG7140Chelmsford MA", 0);
|
|
|
|
pftest (52, "b#W2UB#WB2OSZ-5#N2GH", "WB2OSZ-5>APDW12,WIDE1-1,WIDE2-1:!4237.14NS07120.83W#PHG7140Chelmsford MA", 1);
|
|
|
|
pftest (53, "b#W2UB#WB2OSZ-14#N2GH", "WB2OSZ-5>APDW12,WIDE1-1,WIDE2-1:!4237.14NS07120.83W#PHG7140Chelmsford MA", 0);
|
|
|
|
|
|
|
|
pftest (60, "o/HOME", "WB2OSZ>APDW12,WIDE1-1,WIDE2-1:;home *111111z4237.14N/07120.83W-Chelmsford MA", 0);
|
|
|
|
pftest (61, "o/home", "WB2OSZ>APDW12,WIDE1-1,WIDE2-1:;home *111111z4237.14N/07120.83W-Chelmsford MA", 1);
|
|
|
|
pftest (62, "o/HOME", "HOME>APDW12,WIDE1-1,WIDE2-1:;AWAY *111111z4237.14N/07120.83W-Chelmsford MA", 0);
|
|
|
|
pftest (63, "o/WB2OSZ-5", "WB2OSZ-5>APDW12,WIDE1-1,WIDE2-1:!4237.14NS07120.83W#PHG7140Chelmsford MA", 0);
|
|
|
|
pftest (64, "o/HOME", "WB2OSZ>APDW12,WIDE1-1,WIDE2-1:)home!4237.14N/07120.83W-Chelmsford MA", 0);
|
|
|
|
pftest (65, "o/home", "WB2OSZ>APDW12,WIDE1-1,WIDE2-1:)home!4237.14N/07120.83W-Chelmsford MA", 1);
|
|
|
|
|
|
|
|
pftest (70, "d/DIGI2/DIGI3", "WB2OSZ-5>APDW12,DIGI1,DIGI2,DIGI3,DIGI4:!4237.14NS07120.83W#PHG7140Chelmsford MA", 0);
|
|
|
|
pftest (71, "d/DIGI2/DIGI3", "WB2OSZ-5>APDW12,DIGI1*,DIGI2,DIGI3,DIGI4:!4237.14NS07120.83W#PHG7140Chelmsford MA", 0);
|
|
|
|
pftest (72, "d/DIGI2/DIGI3", "WB2OSZ-5>APDW12,DIGI1,DIGI2*,DIGI3,DIGI4:!4237.14NS07120.83W#PHG7140Chelmsford MA", 1);
|
|
|
|
pftest (73, "d/DIGI2/DIGI3", "WB2OSZ-5>APDW12,DIGI1,DIGI2,DIGI3*,DIGI4:!4237.14NS07120.83W#PHG7140Chelmsford MA", 1);
|
|
|
|
pftest (74, "d/DIGI2/DIGI3", "WB2OSZ-5>APDW12,DIGI1,DIGI2,DIGI3,DIGI4*:!4237.14NS07120.83W#PHG7140Chelmsford MA", 1);
|
|
|
|
pftest (75, "d/DIGI9/DIGI2", "WB2OSZ-5>APDW12,DIGI1,DIGI2*,DIGI3,DIGI4:!4237.14NS07120.83W#PHG7140Chelmsford MA", 1);
|
|
|
|
|
|
|
|
pftest (80, "g/W2UB", "WB2OSZ-5>APDW12::W2UB :text", 1);
|
|
|
|
pftest (81, "g/W2UB/W2UB-*", "WB2OSZ-5>APDW12::W2UB-9 :text", 1);
|
|
|
|
pftest (82, "g/W2UB/*", "WB2OSZ-5>APDW12::XXX :text", 1);
|
|
|
|
pftest (83, "g/W2UB/W*UB", "WB2OSZ-5>APDW12::W2UB-9 :text", -1);
|
|
|
|
pftest (84, "g/W2UB*", "WB2OSZ-5>APDW12::W2UB-9 :text", 1);
|
|
|
|
pftest (85, "g/W2UB*", "WB2OSZ-5>APDW12::W2UBZZ :text", 1);
|
|
|
|
pftest (86, "g/W2UB", "WB2OSZ-5>APDW12::W2UB-9 :text", 0);
|
|
|
|
pftest (87, "g/*", "WB2OSZ-5>APDW12:!4237.14NS07120.83W#PHG7140Chelmsford MA", 0);
|
|
|
|
pftest (88, "g/W*", "WB2OSZ-5>APDW12:!4237.14NS07120.83W#PHG7140Chelmsford MA", 0);
|
|
|
|
|
|
|
|
pftest (90, "u/APWW10", "WA1PLE-5>APWW10,W1MHL,N8VIM,WIDE2*:@022301h4208.75N/07115.16WoAPRS-IS for Win32", 1);
|
|
|
|
pftest (91, "u/TRSY3T", "W1WRA-7>TRSY3T,WIDE1-1,WIDE2-1:`c-:l!hK\\>\"4b}=<0x0d>", 0);
|
|
|
|
pftest (92, "u/APDW11/APDW12", "WB2OSZ-5>APDW12,DIGI1,DIGI2*,DIGI3,DIGI4:!4237.14NS07120.83W#PHG7140Chelmsford MA", 1);
|
|
|
|
pftest (93, "u/APDW", "WB2OSZ-5>APDW12,DIGI1,DIGI2*,DIGI3,DIGI4:!4237.14NS07120.83W#PHG7140Chelmsford MA", 0);
|
|
|
|
|
|
|
|
// rather sparse coverage of the cases
|
|
|
|
pftest (100, "t/mqt", "WB2OSZ-5>APDW12,WIDE1-1,WIDE2-1:!4237.14NS07120.83W#PHG7140Chelmsford MA", 0);
|
|
|
|
pftest (101, "t/mqtp", "WB2OSZ-5>APDW12,WIDE1-1,WIDE2-1:!4237.14NS07120.83W#PHG7140Chelmsford MA", 1);
|
|
|
|
pftest (102, "t/mqtp", "WB2OSZ>APDW12,WIDE1-1,WIDE2-1:;home *111111z4237.14N/07120.83W-Chelmsford MA", 0);
|
|
|
|
pftest (103, "t/mqop", "WB2OSZ>APDW12,WIDE1-1,WIDE2-1:;home *111111z4237.14N/07120.83W-Chelmsford MA", 1);
|
|
|
|
pftest (104, "t/p", "W1WRA-7>TRSY3T,WIDE1-1,WIDE2-1:`c-:l!hK\\>\"4b}=<0x0d>", 1);
|
|
|
|
pftest (104, "t/s", "KB1CHU-13>APWW10,W1CLA-1*,WIDE2-1:>FN42pb/_DX: W1MHL 36.0mi 306<0xb0> 13:24 4223.32N 07115.23W", 1);
|
|
|
|
|
|
|
|
pftest (110, "t/p", "N8VIM>APN391,AB1OC-10,W1MRA*,WIDE2:$ULTW0000000001110B6E27F4FFF3897B0001035E004E04DD00030000<0x0d><0x0a>", 0);
|
|
|
|
pftest (111, "t/w", "N8VIM>APN391,AB1OC-10,W1MRA*,WIDE2:$ULTW0000000001110B6E27F4FFF3897B0001035E004E04DD00030000<0x0d><0x0a>", 1);
|
|
|
|
pftest (112, "t/t", "WM1X>APU25N:@210147z4235.39N/07106.58W_359/000g000t027r000P000p000h89b10234/WX REPORT {UIV32N}<0x0d>", 0);
|
|
|
|
pftest (113, "t/w", "WM1X>APU25N:@210147z4235.39N/07106.58W_359/000g000t027r000P000p000h89b10234/WX REPORT {UIV32N}<0x0d>", 1);
|
|
|
|
|
2023-06-14 00:37:08 +00:00
|
|
|
/* Telemetry metadata should not be classified as message. */
|
2016-03-19 12:10:34 +00:00
|
|
|
pftest (114, "t/t", "KJ4SNT>APMI04::KJ4SNT :PARM.Vin,Rx1h,Dg1h,Eff1h,Rx10m,O1,O2,O3,O4,I1,I2,I3,I4", 1);
|
|
|
|
pftest (115, "t/m", "KJ4SNT>APMI04::KJ4SNT :PARM.Vin,Rx1h,Dg1h,Eff1h,Rx10m,O1,O2,O3,O4,I1,I2,I3,I4", 0);
|
|
|
|
pftest (116, "t/t", "KB1GKN-10>APRX27,UNCAN,WIDE1*:T#491,4.9,0.3,25.0,0.0,1.0,00000000", 1);
|
|
|
|
|
2023-06-14 00:37:08 +00:00
|
|
|
/* Bulletins should not be considered to be messages. Was bug in 1.6. */
|
|
|
|
pftest (117, "t/m", "A>B::W1AW :test", 1);
|
|
|
|
pftest (118, "t/m", "A>B::BLN :test", 0);
|
|
|
|
pftest (119, "t/m", "A>B::NWS :test", 0);
|
2016-03-19 12:10:34 +00:00
|
|
|
|
2023-06-14 00:37:08 +00:00
|
|
|
// https://www.aprs-is.net/WX/
|
|
|
|
pftest (121, "t/p", "CWAPID>APRS::NWS-TTTTT:DDHHMMz,ADVISETYPE,zcs{seq#", 0);
|
2015-07-27 01:17:23 +00:00
|
|
|
pftest (122, "t/p", "CWAPID>APRS::SKYCWA :DDHHMMz,ADVISETYPE,zcs{seq#", 0);
|
|
|
|
pftest (123, "t/p", "CWAPID>APRS:;CWAttttz *DDHHMMzLATLONICONADVISETYPE{seq#", 0);
|
|
|
|
pftest (124, "t/n", "CWAPID>APRS::NWS-TTTTT:DDHHMMz,ADVISETYPE,zcs{seq#", 1);
|
|
|
|
pftest (125, "t/n", "CWAPID>APRS::SKYCWA :DDHHMMz,ADVISETYPE,zcs{seq#", 1);
|
2023-06-14 00:37:08 +00:00
|
|
|
//pftest (126, "t/n", "CWAPID>APRS:;CWAttttz *DDHHMMzLATLONICONADVISETYPE{seq#", 1);
|
2016-03-19 12:10:34 +00:00
|
|
|
pftest (127, "t/", "CWAPID>APRS:;CWAttttz *DDHHMMzLATLONICONADVISETYPE{seq#", 0);
|
2015-07-27 01:17:23 +00:00
|
|
|
|
2017-07-01 01:23:16 +00:00
|
|
|
pftest (128, "t/c", "S0RCE>DEST:<stationcapabilities", 1);
|
|
|
|
pftest (129, "t/h", "S0RCE>DEST:<stationcapabilities", 0);
|
2023-06-14 00:37:08 +00:00
|
|
|
pftest (130, "t/h", "S0RCE>DEST:}WB2OSZ-5>APDW12,DIGI1,DIGI2*,DIGI3,DIGI4:!4237.14NS07120.83W#PHG7140Chelmsford MA", 1);
|
|
|
|
pftest (131, "t/c", "S0RCE>DEST:}WB2OSZ-5>APDW12,DIGI1,DIGI2*,DIGI3,DIGI4:!4237.14NS07120.83W#PHG7140Chelmsford MA", 0);
|
2017-07-01 01:23:16 +00:00
|
|
|
|
|
|
|
pftest (140, "r/42.6/-71.3/10", "WB2OSZ-5>APDW12,WIDE1-1,WIDE2-1:!4237.14NS07120.83W#PHG7140Chelmsford MA", 1);
|
|
|
|
pftest (141, "r/42.6/-71.3/10", "WA1PLE-5>APWW10,W1MHL,N8VIM,WIDE2*:@022301h4208.75N/07115.16WoAPRS-IS for Win32", 0);
|
2015-07-27 01:17:23 +00:00
|
|
|
|
2017-07-01 01:23:16 +00:00
|
|
|
pftest (145, "( t/t & b/WB2OSZ ) | ( t/o & ! r/42.6/-71.3/1 )", "WB2OSZ>APDW12:;home *111111z4237.14N/07120.83W-Chelmsford MA", 1);
|
2015-07-27 01:17:23 +00:00
|
|
|
|
|
|
|
pftest (150, "s/->", "WB2OSZ-5>APDW12:!4237.14NS07120.83W#PHG7140Chelmsford MA", 0);
|
|
|
|
pftest (151, "s/->", "WB2OSZ-5>APDW12:!4237.14N/07120.83W-PHG7140Chelmsford MA", 1);
|
|
|
|
pftest (152, "s/->", "WB2OSZ-5>APDW12:!4237.14N/07120.83W>PHG7140Chelmsford MA", 1);
|
|
|
|
pftest (153, "s/->", "WB2OSZ-5>APDW12:!4237.14N\\07120.83W>PHG7140Chelmsford MA", 0);
|
|
|
|
|
|
|
|
pftest (154, "s//#", "WB2OSZ-5>APDW12:!4237.14NS07120.83W#PHG7140Chelmsford MA", 1);
|
|
|
|
pftest (155, "s//#", "WB2OSZ-5>APDW12:!4237.14N\\07120.83W#PHG7140Chelmsford MA", 1);
|
|
|
|
pftest (156, "s//#", "WB2OSZ-5>APDW12:!4237.14N/07120.83W#PHG7140Chelmsford MA", 0);
|
|
|
|
|
|
|
|
pftest (157, "s//#/\\", "WB2OSZ-5>APDW12:!4237.14NS07120.83W#PHG7140Chelmsford MA", 0);
|
|
|
|
pftest (158, "s//#/\\", "WB2OSZ-5>APDW12:!4237.14N\\07120.83W#PHG7140Chelmsford MA", 1);
|
|
|
|
pftest (159, "s//#/\\", "WB2OSZ-5>APDW12:!4237.14N/07120.83W#PHG7140Chelmsford MA", 0);
|
|
|
|
|
|
|
|
pftest (160, "s//#/LS1", "WB2OSZ-5>APDW12:!4237.14NS07120.83W#PHG7140Chelmsford MA", 1);
|
|
|
|
pftest (161, "s//#/LS1", "WB2OSZ-5>APDW12:!4237.14N\\07120.83W#PHG7140Chelmsford MA", 0);
|
|
|
|
pftest (162, "s//#/LS1", "WB2OSZ-5>APDW12:!4237.14N/07120.83W#PHG7140Chelmsford MA", 0);
|
2017-07-01 01:23:16 +00:00
|
|
|
pftest (163, "s//#/LS\\", "WB2OSZ-5>APDW12:!4237.14N\\07120.83W#PHG7140Chelmsford MA", 1);
|
2015-07-27 01:17:23 +00:00
|
|
|
|
2017-07-01 01:23:16 +00:00
|
|
|
pftest (170, "s:/", "WB2OSZ-5>APDW12:!4237.14N/07120.83W/PHG7140Chelmsford MA", 1);
|
|
|
|
pftest (171, "s:/", "WB2OSZ-5>APDW12:!4237.14N\\07120.83W/PHG7140Chelmsford MA", 0);
|
|
|
|
pftest (172, "s::/", "WB2OSZ-5>APDW12:!4237.14N/07120.83W/PHG7140Chelmsford MA", 0);
|
|
|
|
pftest (173, "s::/", "WB2OSZ-5>APDW12:!4237.14N\\07120.83W/PHG7140Chelmsford MA", 1);
|
|
|
|
pftest (174, "s:/:/", "WB2OSZ-5>APDW12:!4237.14N/07120.83W/PHG7140Chelmsford MA", 1);
|
|
|
|
pftest (175, "s:/:/", "WB2OSZ-5>APDW12:!4237.14N\\07120.83W/PHG7140Chelmsford MA", 1);
|
|
|
|
pftest (176, "s:/:/", "WB2OSZ-5>APDW12:!4237.14NX07120.83W/PHG7140Chelmsford MA", 1);
|
|
|
|
pftest (177, "s:/:/:X", "WB2OSZ-5>APDW12:!4237.14NX07120.83W/PHG7140Chelmsford MA", 1);
|
|
|
|
|
|
|
|
// FIXME: Different on Windows and 64 bit Linux.
|
|
|
|
//pftest (178, "s:/:/:", "WB2OSZ-5>APDW12:!4237.14NX07120.83W/PHG7140Chelmsford MA", 1);
|
|
|
|
|
|
|
|
pftest (179, "s:/:/:\\", "WB2OSZ-5>APDW12:!4237.14NX07120.83W/PHG7140Chelmsford MA", 0);
|
|
|
|
|
|
|
|
pftest (180, "v/DIGI2/DIGI3", "WB2OSZ-5>APDW12,DIGI1,DIGI2,DIGI3,DIGI4:!4237.14NS07120.83W#PHG7140Chelmsford MA", 1);
|
|
|
|
pftest (181, "v/DIGI2/DIGI3", "WB2OSZ-5>APDW12,DIGI1*,DIGI2,DIGI3,DIGI4:!4237.14NS07120.83W#PHG7140Chelmsford MA", 1);
|
|
|
|
pftest (182, "v/DIGI2/DIGI3", "WB2OSZ-5>APDW12,DIGI1,DIGI2*,DIGI3,DIGI4:!4237.14NS07120.83W#PHG7140Chelmsford MA", 1);
|
|
|
|
pftest (183, "v/DIGI2/DIGI3", "WB2OSZ-5>APDW12,DIGI1,DIGI2,DIGI3*,DIGI4:!4237.14NS07120.83W#PHG7140Chelmsford MA", 0);
|
|
|
|
pftest (184, "v/DIGI2/DIGI3", "WB2OSZ-5>APDW12,DIGI1,DIGI2,DIGI3,DIGI4*:!4237.14NS07120.83W#PHG7140Chelmsford MA", 0);
|
|
|
|
pftest (185, "v/DIGI9/DIGI2", "WB2OSZ-5>APDW12,DIGI1,DIGI2*,DIGI3,DIGI4:!4237.14NS07120.83W#PHG7140Chelmsford MA", 0);
|
2016-01-27 04:45:58 +00:00
|
|
|
|
2015-07-27 01:17:23 +00:00
|
|
|
/* Test error reporting. */
|
|
|
|
|
|
|
|
pftest (200, "x/", "CWAPID>APRS:;CWAttttz *DDHHMMzLATLONICONADVISETYPE{seq#", -1);
|
|
|
|
pftest (201, "t/w & ( t/w | t/w ", "CWAPID>APRS:;CWAttttz *DDHHMMzLATLONICONADVISETYPE{seq#", -1);
|
|
|
|
pftest (202, "t/w ) ", "CWAPID>APRS:;CWAttttz *DDHHMMzLATLONICONADVISETYPE{seq#", -1);
|
|
|
|
pftest (203, "!", "CWAPID>APRS:;CWAttttz *DDHHMMzLATLONICONADVISETYPE{seq#", -1);
|
|
|
|
pftest (203, "t/w t/w", "CWAPID>APRS:;CWAttttz *DDHHMMzLATLONICONADVISETYPE{seq#", -1);
|
|
|
|
pftest (204, "r/42.6/-71.3", "WA1PLE-5>APWW10,W1MHL,N8VIM,WIDE2*:@022301h4208.75N/07115.16WoAPRS-IS for Win32", -1);
|
|
|
|
|
2023-06-14 00:37:08 +00:00
|
|
|
pftest (210, "i/30/8/42.6/-71.3/50", "WB2OSZ-5>APDW14::W2UB :Happy Birthday{001", 1);
|
|
|
|
pftest (212, "i/30/8/42.6/-71.3/", "WB2OSZ-5>APDW14::W2UB :Happy Birthday{001", -1);
|
|
|
|
pftest (213, "i/30/8/42.6/-71.3", "WB2OSZ-5>APDW14::W2UB :Happy Birthday{001", -1);
|
|
|
|
pftest (214, "i/30/8/42.6/", "WB2OSZ-5>APDW14::W2UB :Happy Birthday{001", -1);
|
|
|
|
pftest (215, "i/30/8/42.6", "WB2OSZ-5>APDW14::W2UB :Happy Birthday{001", -1);
|
|
|
|
pftest (216, "i/30/8/", "WB2OSZ-5>APDW14::W2UB :Happy Birthday{001", 1);
|
|
|
|
pftest (217, "i/30/8", "WB2OSZ-5>APDW14::W2UB :Happy Birthday{001", 1);
|
2017-01-01 16:49:55 +00:00
|
|
|
|
2017-07-01 01:23:16 +00:00
|
|
|
// FIXME: behaves differently on Windows and Linux. Why?
|
|
|
|
// On Windows we have our own version of strsep because it's not in the MS library.
|
|
|
|
// It must behave differently than the Linux version when nothing follows the last separator.
|
2017-01-01 16:49:55 +00:00
|
|
|
//pftest (228, "i/30/", "WB2OSZ-5>APDW14::W2UB :Happy Birthday{001", 1);
|
|
|
|
|
|
|
|
pftest (229, "i/30", "WB2OSZ-5>APDW14::W2UB :Happy Birthday{001", 1);
|
2023-06-14 00:37:08 +00:00
|
|
|
pftest (230, "i/30", "X>X:}WB2OSZ-5>APDW14::W2UB :Happy Birthday{001", 1);
|
|
|
|
pftest (231, "i/", "WB2OSZ-5>APDW14::W2UB :Happy Birthday{001", -1);
|
|
|
|
|
|
|
|
// Besure bulletins and telemetry metadata don't get included.
|
|
|
|
pftest (234, "i/30", "KJ4SNT>APMI04::KJ4SNT :PARM.Vin,Rx1h,Dg1h,Eff1h,Rx10m,O1,O2,O3,O4,I1,I2,I3,I4", 0);
|
|
|
|
pftest (235, "i/30", "A>B::BLN :test", 0);
|
2017-01-01 16:49:55 +00:00
|
|
|
|
2017-07-01 01:23:16 +00:00
|
|
|
pftest (240, "s/", "WB2OSZ-5>APDW12:!4237.14N/07120.83WOPHG7140Chelmsford MA", -1);
|
|
|
|
pftest (241, "s/'/O/-/#/_", "WB2OSZ-5>APDW12:!4237.14N/07120.83WOPHG7140Chelmsford MA", -1);
|
|
|
|
pftest (242, "s/O/O/c", "WB2OSZ-5>APDW12:!4237.14N/07120.83WOPHG7140Chelmsford MA", -1);
|
|
|
|
pftest (243, "s/O/O/1/2", "WB2OSZ-5>APDW12:!4237.14N/07120.83WOPHG7140Chelmsford MA", -1);
|
|
|
|
pftest (244, "s/O/|/1", "WB2OSZ-5>APDW12:!4237.14N/07120.83WOPHG7140Chelmsford MA", -1);
|
|
|
|
pftest (245, "s//", "WB2OSZ-5>APDW12:!4237.14N/07120.83WOPHG7140Chelmsford MA", -1);
|
|
|
|
pftest (246, "s///", "WB2OSZ-5>APDW12:!4237.14N/07120.83WOPHG7140Chelmsford MA", -1);
|
|
|
|
|
2023-06-14 00:37:08 +00:00
|
|
|
// Third party header - done properly in 1.7.
|
|
|
|
// Packet filter t/h is no longer a mutually exclusive packet type.
|
|
|
|
// Now it is an independent attribute and the encapsulated part is evaluated.
|
|
|
|
|
|
|
|
pftest (250, "o/home", "A>B:}WB2OSZ>APDW12,WIDE1-1,WIDE2-1:;home *111111z4237.14N/07120.83W-Chelmsford MA", 1);
|
|
|
|
pftest (251, "t/p", "A>B:}W1WRA-7>TRSY3T,WIDE1-1,WIDE2-1:`c-:l!hK\\>\"4b}=<0x0d>", 1);
|
|
|
|
pftest (252, "i/180", "A>B:}WB2OSZ-5>APDW14::W2UB :Happy Birthday{001", 1);
|
|
|
|
pftest (253, "t/m", "A>B:}WB2OSZ-5>APDW14::W2UB :Happy Birthday{001", 1);
|
|
|
|
pftest (254, "r/42.6/-71.3/10", "A>B:}WB2OSZ-5>APDW12,WIDE1-1,WIDE2-1:!4237.14NS07120.83W#PHG7140Chelmsford MA", 1);
|
|
|
|
pftest (254, "r/42.6/-71.3/10", "A>B:}WA1PLE-5>APWW10,W1MHL,N8VIM,WIDE2*:@022301h4208.75N/07115.16WoAPRS-IS for Win32", 0);
|
|
|
|
pftest (255, "t/h", "KB1GKN-10>APRX27,UNCAN,WIDE1*:T#491,4.9,0.3,25.0,0.0,1.0,00000000", 0);
|
|
|
|
pftest (256, "t/h", "A>B:}KB1GKN-10>APRX27,UNCAN,WIDE1*:T#491,4.9,0.3,25.0,0.0,1.0,00000000", 1);
|
|
|
|
pftest (258, "t/t", "A>B:}KB1GKN-10>APRX27,UNCAN,WIDE1*:T#491,4.9,0.3,25.0,0.0,1.0,00000000", 1);
|
|
|
|
pftest (259, "t/t", "A>B:}KJ4SNT>APMI04::KJ4SNT :PARM.Vin,Rx1h,Dg1h,Eff1h,Rx10m,O1,O2,O3,O4,I1,I2,I3,I4", 1);
|
|
|
|
|
|
|
|
pftest (270, "g/BLN*", "WB2OSZ>APDW17::BLN1xxxxx:bulletin text", 1);
|
|
|
|
pftest (271, "g/BLN*", "A>B:}WB2OSZ>APDW17::BLN1xxxxx:bulletin text", 1);
|
|
|
|
pftest (272, "g/BLN*", "A>B:}WB2OSZ>APDW17::W1AW :xxxx", 0);
|
|
|
|
|
|
|
|
pftest (273, "g/NWS*", "WB2OSZ>APDW17::NWS-xxxxx:weather bulletin", 1);
|
|
|
|
pftest (274, "g/NWS*", "A>B:}WB2OSZ>APDW17::NWS-xxxxx:weather bulletin", 1);
|
|
|
|
pftest (275, "g/NWS*", "A>B:}WB2OSZ>APDW17::W1AW :xxxx", 0);
|
|
|
|
|
|
|
|
// TODO: add b/ with 3rd party header.
|
2017-07-01 01:23:16 +00:00
|
|
|
|
2023-06-14 00:37:08 +00:00
|
|
|
// TODO: to be continued... directed query ...
|
2015-07-27 01:17:23 +00:00
|
|
|
|
|
|
|
if (error_count > 0) {
|
|
|
|
text_color_set (DW_COLOR_ERROR);
|
2023-06-14 00:37:08 +00:00
|
|
|
dw_printf ("\nPacket Filtering Test - FAILED! %d errors\n", error_count);
|
2015-11-08 01:57:02 +00:00
|
|
|
exit (EXIT_FAILURE);
|
2015-07-27 01:17:23 +00:00
|
|
|
}
|
2015-11-08 01:57:02 +00:00
|
|
|
text_color_set (DW_COLOR_REC);
|
|
|
|
dw_printf ("\nPacket Filtering Test - SUCCESS!\n");
|
|
|
|
exit (EXIT_SUCCESS);
|
2015-07-27 01:17:23 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static void pftest (int test_num, char *filter, char *monitor, int expected)
|
|
|
|
{
|
|
|
|
int result;
|
|
|
|
packet_t pp;
|
|
|
|
|
|
|
|
text_color_set (DW_COLOR_DEBUG);
|
|
|
|
dw_printf ("test number %d\n", test_num);
|
|
|
|
|
|
|
|
pp = ax25_from_text (monitor, 1);
|
|
|
|
assert (pp != NULL);
|
|
|
|
|
2016-11-20 19:58:51 +00:00
|
|
|
result = pfilter (0, 0, filter, pp, 1);
|
2015-07-27 01:17:23 +00:00
|
|
|
if (result != expected) {
|
|
|
|
text_color_set (DW_COLOR_ERROR);
|
|
|
|
dw_printf ("Unexpected result for test number %d\n", test_num);
|
|
|
|
error_count++;
|
|
|
|
}
|
|
|
|
|
|
|
|
ax25_delete (pp);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* if TEST */
|
|
|
|
|
|
|
|
/* end pfilter.c */
|
|
|
|
|
|
|
|
|