1 /*
2  *	aprsc
3  *
4  *	(c) Matti Aarnio, OH2MQK, <oh2mqk@sral.fi>
5  *
6  *	This program is licensed under the BSD license, which can be found
7  *	in the file LICENSE.
8  *
9  */
10 
11 #include "ac-hdrs.h"
12 
13 #include <string.h>
14 #include <strings.h>
15 #include <ctype.h>
16 #include <stdint.h>
17 #include <math.h>
18 #ifdef HAVE_ALLOCA_H
19 #include <alloca.h>
20 #endif
21 
22 #include "hmalloc.h"
23 #include "hlog.h"
24 #include "worker.h"
25 #include "filter.h"
26 #include "cellmalloc.h"
27 #include "historydb.h"
28 #include "cfgfile.h"
29 #include "config.h"
30 #include "keyhash.h"
31 #include "client_heard.h"
32 #include "version.h"
33 #include "messaging.h"
34 
35 //#define FILTER_CLIENT_DEBUGGING
36 
37 #ifdef FILTER_CLIENT_DEBUGGING
38 #define FILTER_CLIENT_DEBUG(worker, c, fmt, ...) \
39             do { client_printf(worker, c, fmt, __VA_ARGS__); } while (0)
40 #else
41 #define FILTER_CLIENT_DEBUG(fmt, ...)
42 #endif
43 
44 
45 // static double rad2deg(double a) { return a * (180.0 * M_1_PI); }
46 
47 /*
48   See:  http://www.aprs-is.net/javaprssrvr/javaprsfilter.htm
49 
50   a/latN/lonW/latS/lonE Area filter
51   b/call1/call2...  	Budlist filter (*)
52   d/digi1/digi2...  	USED Digipeater filter (*)
53   e/call1/call1/...  	Entry station filter (*)
54   f/call/dist  		Friend Range filter
55   m/dist  		My Range filter
56   o/obj1/obj2...  	Object filter (*)
57   p/aa/bb/cc...  	Prefix filter
58   q/con/ana 	 	q Contruct filter
59   r/lat/lon/dist  	Range filter
60   s/pri/alt/over  	Symbol filter
61   t/poimntqsu*c		Type filter
62   t/poimntqsu*c/call/km	Type filter
63   u/unproto1/unproto2/.. Unproto filter (*)
64   g/call/call2/...      Message destination filter (*)
65 
66   Sample usage frequencies (out of entire APRS-IS):
67 
68    23.7  a/  <-- Optimize!
69     9.2  b/  <-- Optimize?
70     1.4  d/
71     0.2  e/
72     2.2  f/
73    20.9  m/  <-- Optimize!
74     0.2  o/
75    14.4  p/  <-- Optimize!
76     0.0  pk
77     0.0  pm
78     0.4  q/
79    19.0  r/  <-- Optimize!
80     0.1  s_
81     1.6  s/
82     6.6  t/
83     0.1  u/
84 
85 
86   (*) = wild-card supported
87 
88   Undocumented at above web-page, but apparent behaviour is:
89 
90   - Everything not explicitely stated to be case sensitive is
91     case INSENSITIVE
92 
93   - Minus-prefixes on filters behave as is there are two sets of
94     filters:
95 
96        - filters without minus-prefixes add on approved set, and all
97          those without are evaluated at first
98        - filters with minus-prefixes are evaluated afterwards to drop
99          selections after the additive filter has been evaluated
100 
101 
102   - Our current behaviour is: "evaluate everything in entry order,
103     stop at first match",  which enables filters like:
104                p/OH2R -p/OH2 p/OH
105     while javAPRSSrvr filter adjunct behaves like the request is:
106                -p/OH2  p/OH
107     that is, OH2R** stations are not passed thru.
108 
109 */
110 
111 
112 /* FIXME:  What exactly is the meaning of negation on the pattern ?
113 **         Match as a failure to match, and stop searching ?
114 **         Something filter dependent ?
115 **
116 ** javAPRSSrvr Filter Adjunct  manual tells:
117 
118  #14 Exclusion filter
119 
120 All the above filters also support exclusion. Be prefixing the above filters
121 with a dash the result will be the opposite. Any packet that match the exclusion
122 filter will NOT pass. The exclusion filters will be processed first so if there
123 is a match for an exclusion then the packet is not passed no matter any other
124 filter definitions.
125 
126 */
127 
128 #define WildCard      0x80  /* it is wild-carded prefix string  */
129 #define NegationFlag  0x40  /*                                  */
130 #define LengthMask    0x0F  /* only low 4 bits encode length    */
131 
132 /* values above are chosen for 4 byte alignment.. */
133 
134 struct filter_refcallsign_t {
135 	char	callsign[CALLSIGNLEN_MAX+1]; /* size: 10.. */
136 	int8_t	reflen; /* length and flags */
137 };
138 struct filter_head_t {
139 	struct filter_t *next;
140 	const char *text; /* filter text as is		*/
141 	float   f_latN, f_lonE;
142 	union {
143 	  float   f_latS;   /* for A filter */
144 	  float   f_coslat; /* for R filter */
145 	}; /* ANONYMOUS UNION */
146 	union {
147 	  float   f_lonW; /* for A filter */
148 	  float   f_dist; /* for R filter */
149 	}; /* ANONYMOUS UNION */
150 	time_t  hist_age;
151 
152 	char	type;	  /* 1 char			*/
153 	int16_t	negation; /* boolean flag		*/
154 	union {
155 	  int16_t numnames; /* used as named, and as cache validity flag */
156 	  int16_t len1s;    /*  or len1 of s-filter */
157 	}; /* ANONYMOUS UNION */
158 	union {
159 	  int16_t bitflags; /* used as bit-set on T_*** enumerations */
160 	  int16_t len1;     /*  or as len2 of s-filter */
161 	}; /* ANONYMOUS UNION */
162 	union {
163 		struct lens_t { int16_t len2s, len2, len3s, len3; } lens; /* of s-filter */
164 		/* for cases where there is only one.. */
165 		struct filter_refcallsign_t  refcallsign;
166 		/*  hmalloc()ed array, alignment important! */
167 		struct filter_refcallsign_t *refcallsigns;
168 	}; /* ANONYMOUS UNION */
169 };
170 
171 struct filter_t {
172 	struct filter_head_t h;
173 #define FILT_TEXTBUFSIZE (512-sizeof(struct filter_head_t))
174 	char textbuf[FILT_TEXTBUFSIZE];
175 };
176 
177 #define QC_C	0x001 /* Q-filter flag bits */
178 #define QC_X	0x002
179 #define QC_U	0x004
180 #define QC_o	0x008
181 #define QC_O	0x010
182 #define QC_S	0x020
183 #define QC_r	0x040
184 #define QC_R	0x080
185 #define QC_Z	0x100
186 #define QC_I	0x200
187 
188 #define QC_AnalyticsI	0x800
189 
190 /* For q-filter analytics: entrycall igate filter database */
191 struct filter_entrycall_t {
192 	struct filter_entrycall_t *next;
193 	time_t expirytime;
194 	uint32_t hash;
195 	int	len;
196 	char	callsign[CALLSIGNLEN_MAX+1];
197 };
198 
199 struct filter_wx_t {
200 	struct filter_wx_t *next;
201 	time_t expirytime;
202 	uint32_t hash;
203 	int	len;
204 	char	callsign[CALLSIGNLEN_MAX+1];
205 };
206 
207 typedef enum {
208 	MatchExact,
209 	MatchPrefix,
210 	MatchWild
211 } MatchEnum;
212 
213 #define FILTER_ENTRYCALL_HASHSIZE 2048 /* Around 500-600 in db,  this looks
214 					  for collision free result.. */
215 rwlock_t filter_entrycall_rwlock;
216 int filter_entrycall_maxage = 60*60;  /* 1 hour, default.  Validity on
217 					 lookups: 5 minutes less..  */
218 int filter_entrycall_cellgauge;
219 
220 struct filter_entrycall_t *filter_entrycall_hash[FILTER_ENTRYCALL_HASHSIZE];
221 
222 
223 #define FILTER_WX_HASHSIZE 1024        /* Around 300-400 in db,  this looks
224 					  for collision free result.. */
225 rwlock_t filter_wx_rwlock;
226 int filter_wx_maxage = 60*60;         /* 1 hour, default.  Validity on
227 					 lookups: 5 minutes less..  */
228 int filter_wx_cellgauge;
229 
230 struct filter_wx_t *filter_wx_hash[FILTER_WX_HASHSIZE];
231 
232 rwlock_t filter_cellgauge_rwlock;
233 int filter_cellgauge;
234 
235 
236 #ifndef _FOR_VALGRIND_
237 cellarena_t *filter_cells;
238 cellarena_t *filter_entrycall_cells;
239 cellarena_t *filter_wx_cells;
240 #endif
241 
242 int have_filtered_listeners;  /* do we have any filtered listeners, do we need to support them */
243 
244 #define HIST_LOOKUP_INTERVAL 10 /* Cache historydb position lookups this much seconds on
245 				  each filter entry referring to some
246 				  fixed callsign (f,m,t) */
247 
248 
filter_lat2rad(float lat)249 float filter_lat2rad(float lat)
250 {
251 	return (lat * (M_PI / 180.0));
252 }
253 
filter_lon2rad(float lon)254 float filter_lon2rad(float lon)
255 {
256 	return (lon * (M_PI / 180.0));
257 }
258 
259 
filter_init(void)260 void filter_init(void)
261 {
262 	rwl_init(&filter_cellgauge_rwlock);
263 #ifndef _FOR_VALGRIND_
264 	/* A few hundred... */
265 
266 	filter_cells = cellinit( "filter",
267 				 sizeof(struct filter_t),
268 				 __alignof__(struct filter_t),
269 				 CELLMALLOC_POLICY_LIFO,
270 				 512 /* 512 kB at the time,
271 					should be enough forever.. */,
272 				 0 /* minfree */ );
273 
274 	/* printf("filter: sizeof=%d alignof=%d\n",
275 	   sizeof(struct filter_t),__alignof__(struct filter_t)); */
276 
277 	/* Couple thousand */
278 
279 	filter_entrycall_cells = cellinit( "entrycall",
280 					   sizeof(struct filter_entrycall_t),
281 					   __alignof__(struct filter_entrycall_t),
282 					   CELLMALLOC_POLICY_FIFO,
283 					   32 /* 32 kB at the time */,
284 					   0 /* minfree */ );
285 
286 	/* Under 1 thousand.. */
287 
288 	filter_wx_cells = cellinit( "wxcalls",
289 				    sizeof(struct filter_wx_t),
290 				    __alignof__(struct filter_wx_t),
291 				    CELLMALLOC_POLICY_FIFO,
292 				    32 /* 32 kB at the time */,
293 				    0 /* minfree */ );
294 #endif
295 }
296 
filter_entrycall_free(struct filter_entrycall_t * f)297 static void filter_entrycall_free(struct filter_entrycall_t *f)
298 {
299 #ifndef _FOR_VALGRIND_
300 	cellfree( filter_entrycall_cells, f );
301 #else
302 	hfree(f);
303 #endif
304 	-- filter_entrycall_cellgauge;
305 }
306 
307 /*
308  *	filter_entrycall_insert() is for support of  q//i  filters.
309  *	That is, "pass on any message that has traversed thru entry
310  *	igate which has identified itself with qAr or qAR.  Not all
311  *	messages traversed thru such gate will have those same q-cons
312  *	values, thus this database keeps info about entry igate that
313  *	have shown such capability in recent past.
314  *
315  *	This must be called by the incoming_parse() in every case
316  *	(or at least when qcons is either 'r' or 'R'.)
317  *
318  *	The key has no guaranteed alignment, no way to play tricks
319  *	with gcc builtin optimizers.
320  */
321 
filter_entrycall_insert(struct pbuf_t * pb)322 static int filter_entrycall_insert(struct pbuf_t *pb)
323 {
324 	struct filter_entrycall_t *f, **fp, *f2;
325 	/* OK, pre-parsing produced accepted result */
326 	uint32_t hash;
327 	int idx, keylen;
328 	const char qcons = pb->qconst_start[2];
329 	const char *key = pb->qconst_start+4;
330         char uckey[CALLSIGNLEN_MAX+1];
331 
332 	for (keylen = 0; keylen < CALLSIGNLEN_MAX; ++keylen) {
333 		int c = key[keylen];
334 		if (c == ',' || c == ':')
335 			break;
336                 if ('a' <= c && c <= 'z')
337                 	c -= ('a' - 'A');
338                 uckey[keylen] = c;
339                 uckey[keylen+1] = 0;
340 	}
341 	if ((key[keylen] != ',' && key[keylen] != ':') ||
342 	    (keylen < CALLSIGNLEN_MIN))
343 		return 0; /* Bad entry-station callsign */
344 
345 	pb->entrycall_len = keylen; // FIXME: should be in incoming parser...
346 
347 	/* We insert only those that have Q-Constructs of qAR or qAr */
348 	if (qcons != 'r' && qcons != 'R') return 0;
349 
350 	hash = keyhash(uckey, keylen, 0);
351 	idx = (hash ^ (hash >> 11) ^ (hash >> 22) ) % FILTER_ENTRYCALL_HASHSIZE; /* Fold the hashbits.. */
352 
353 	rwl_wrlock(&filter_entrycall_rwlock);
354 
355 	fp = &filter_entrycall_hash[idx];
356 	f2 = NULL;
357 	while (( f = *fp )) {
358 		if ( f->hash == hash ) {
359 			if (f->len == keylen) {
360 				int cmp = memcmp(f->callsign, uckey, keylen);
361 				if (cmp == 0) { /* Have key match */
362 					f->expirytime = tick + filter_entrycall_maxage;
363 					f2 = f;
364 					break;
365 				}
366 			}
367 		}
368 		/* No match at all, advance the pointer.. */
369 		fp = &(f -> next);
370 	}
371 	if (!f2) {
372 
373 		/* Allocate and insert into hash table */
374 
375 		fp = &filter_entrycall_hash[idx];
376 
377 #ifndef _FOR_VALGRIND_
378 		f = cellmalloc(filter_entrycall_cells);
379 #else
380 		f = hmalloc(sizeof(*f));
381 #endif
382 		if (f) {
383 			f->next  = *fp;
384 			f->expirytime = tick + filter_entrycall_maxage;
385 			f->hash  = hash;
386 			f->len   = keylen;
387 			memcpy(f->callsign, uckey, keylen);
388 			memset(f->callsign+keylen, 0, sizeof(f->callsign)-keylen);
389 
390 			*fp = f2 = f;
391 
392 			++ filter_entrycall_cellgauge;
393 		} else {
394 			hlog(LOG_ERR, "filter_entrycall_insert: cellmalloc failed");
395 		}
396 	}
397 
398 	rwl_wrunlock(&filter_entrycall_rwlock);
399 
400 	return (f2 != NULL);
401 }
402 
403 /*
404  *	filter_entrycall_lookup() is for support of  q//i  filters.
405  *	That is, "pass on any message that has traversed thru entry
406  *	igate which has identified itself with qAr or qAR.  Not all
407  *	messages traversed thru such gate will have those same q-cons
408  *	values, thus this keeps database about entry servers that have
409  *	shown such capability in recent past.
410  *
411  *	The key has no guaranteed alignment, no way to play tricks
412  *	with gcc builtin optimizers.
413  */
414 
filter_entrycall_lookup(const struct pbuf_t * pb)415 static int filter_entrycall_lookup(const struct pbuf_t *pb)
416 {
417 	struct filter_entrycall_t *f, **fp, *f2;
418 	const char *key  = pb->qconst_start+4;
419 	const int keylen = pb->entrycall_len;
420 
421 	uint32_t  hash   = keyhashuc(key, keylen, 0);
422 	int idx = ( hash ^ (hash >> 11) ^ (hash >> 22) ) % FILTER_ENTRYCALL_HASHSIZE;   /* fold the hashbits.. */
423 
424 	f2 = NULL;
425 
426 	rwl_rdlock(&filter_entrycall_rwlock);
427 
428 	fp = &filter_entrycall_hash[idx];
429 	while (( f = *fp )) {
430 		if ( f->hash == hash ) {
431 			if (f->len == keylen) {
432 				int rc =  strncasecmp(f->callsign, key, keylen);
433 				if (rc == 0) { /* Have key match, see if it is
434 						  still valid entry ? */
435 					if (f->expirytime < tick - 60) {
436 						f2 = f;
437 						break;
438 					}
439 				}
440 			}
441 		}
442 		/* No match at all, advance the pointer.. */
443 		fp = &(f -> next);
444 	}
445 
446 	rwl_rdunlock(&filter_entrycall_rwlock);
447 
448 	return (f2 != NULL);
449 }
450 
451 /*
452  *	The  filter_entrycall_cleanup()  does purge old entries
453  *	out of the database.  Run about once a minute.
454  */
filter_entrycall_cleanup(void)455 void filter_entrycall_cleanup(void)
456 {
457 	int k, cleancount = 0;
458 	struct filter_entrycall_t *f, **fp;
459 
460 	rwl_wrlock(&filter_entrycall_rwlock);
461 
462 	for (k = 0; k < FILTER_ENTRYCALL_HASHSIZE; ++k) {
463 		fp = & filter_entrycall_hash[k];
464 		while (( f = *fp )) {
465 			/* Did it expire ? */
466 			if (f->expirytime <= tick) {
467 				*fp = f->next;
468 				f->next = NULL;
469 				filter_entrycall_free(f);
470 				++cleancount;
471 				continue;
472 			}
473 			/* No purge, advance the pointer.. */
474 			fp = &(f -> next);
475 		}
476 	}
477 
478 	rwl_wrunlock(&filter_entrycall_rwlock);
479 
480 	// hlog( LOG_DEBUG, "filter_entrycall_cleanup() removed %d entries, count now: %ld",
481 	//       cleancount, filter_entrycall_cellgauge );
482 }
483 
484 /*
485  *	The  filter_entrycall_atend()  does purge all entries
486  *	out of the database.  Run at the exit of the program.
487  *	This exists primarily to make valgrind happy...
488  */
filter_entrycall_atend(void)489 void filter_entrycall_atend(void)
490 {
491 	int k;
492 	struct filter_entrycall_t *f, **fp;
493 
494 	rwl_wrlock(&filter_entrycall_rwlock);
495 
496 	for (k = 0; k < FILTER_ENTRYCALL_HASHSIZE; ++k) {
497 		fp = & filter_entrycall_hash[k];
498 		while (( f = *fp )) {
499 			*fp = f->next;
500 			f->next = NULL;
501 			filter_entrycall_free(f);
502 		}
503 	}
504 
505 	rwl_wrunlock(&filter_entrycall_rwlock);
506 }
507 
508 
filter_entrycall_dump(FILE * fp)509 void filter_entrycall_dump(FILE *fp)
510 {
511 	int k;
512 	struct filter_entrycall_t *f;
513 
514 	rwl_rdlock(&filter_entrycall_rwlock);
515 
516 	for (k = 0; k < FILTER_ENTRYCALL_HASHSIZE; ++k) {
517 		f = filter_entrycall_hash[k];
518 
519 		for ( ; f; f = f->next ) {
520 			fprintf( fp, "%ld\t%s\n",
521 				 (long)f->expirytime, f->callsign );
522 		}
523 	}
524 
525 	rwl_rdunlock(&filter_entrycall_rwlock);
526 }
527 
528 
529 /* ================================================================ */
530 
531 
532 
filter_wx_free(struct filter_wx_t * f)533 static void filter_wx_free(struct filter_wx_t *f)
534 {
535 #ifndef _FOR_VALGRIND_
536 	cellfree( filter_wx_cells, f );
537 #else
538 	hfree(f);
539 #endif
540 	--filter_wx_cellgauge;
541 }
542 
543 /*
544  *	The  filter_wx_insert()  does lookup key storage for problem of:
545  *
546  *	Positionless T_WX packets want also position packets on output filters.
547  */
548 
filter_wx_insert(struct pbuf_t * pb)549 static int filter_wx_insert(struct pbuf_t *pb)
550 {
551 	struct filter_wx_t *f, **fp, *f2;
552 	/* OK, pre-parsing produced accepted result */
553 	const char *key  = pb->data;
554 	const int keylen = pb->srccall_end - key;
555 	uint32_t hash;
556 	int idx;
557         char uckey[CALLSIGNLEN_MAX+1];
558 
559 	/* If it is not a WX packet without position, we are not intrerested */
560 	if (!((pb->packettype & T_WX) && !(pb->flags & F_HASPOS)))
561 		return 0;
562 
563 	for (idx = 0; idx < keylen && idx < CALLSIGNLEN_MAX; ++idx) {
564 		int c = key[idx];
565 		if (c == '>')
566 			break;
567                 if ('a' <= c && c <= 'z')
568                   c -= ('a' - 'A');
569                 uckey[idx] = c;
570                 uckey[idx+1] = 0;
571 	}
572 
573 	hash = keyhash(uckey, keylen, 0);
574 	idx = ( hash ^ (hash >> 10) ^ (hash >> 20) ) % FILTER_WX_HASHSIZE; /* fold the hashbits.. */
575 
576 	rwl_wrlock(&filter_wx_rwlock);
577 
578 	fp = &filter_wx_hash[idx];
579 	f2 = NULL;
580 	while (( f = *fp )) {
581 		if ( f->hash == hash ) {
582 			if (f->len == keylen) {
583 				int cmp = memcmp(f->callsign, uckey, keylen);
584 				if (cmp == 0) { /* Have key match */
585 					f->expirytime = tick + filter_wx_maxage;
586 					f2 = f;
587 					break;
588 				}
589 			}
590 		}
591 		/* No match at all, advance the pointer.. */
592 		fp = &(f -> next);
593 	}
594 	if (!f2) {
595 
596 		/* Allocate and insert into hash table */
597 
598 		fp = &filter_wx_hash[idx];
599 
600 #ifndef _FOR_VALGRIND_
601 		f = cellmalloc(filter_wx_cells);
602 #else
603 		f = hmalloc(sizeof(*f));
604 #endif
605 		++filter_wx_cellgauge;
606 		if (f) {
607 			f->next  = *fp;
608 			f->expirytime = tick + filter_wx_maxage;
609 			f->hash  = hash;
610 			f->len   = keylen;
611 			memcpy(f->callsign, uckey, keylen);
612 			memset(f->callsign+keylen, 0, sizeof(f->callsign)-keylen);
613 
614 			*fp = f2 = f;
615 		} else {
616 			hlog(LOG_ERR, "filter_wx_insert: cellmalloc failed");
617 		}
618 	}
619 
620 	rwl_wrunlock(&filter_wx_rwlock);
621 
622 	return 0;
623 }
624 
filter_wx_lookup(const struct pbuf_t * pb)625 static int filter_wx_lookup(const struct pbuf_t *pb)
626 {
627 	struct filter_wx_t *f, **fp, *f2;
628 	const char *key  = pb->data;
629 	const int keylen = pb->srccall_end - key;
630 
631 	uint32_t  hash   = keyhashuc(key, keylen, 0);
632 	int idx = ( hash ^ (hash >> 10) ^ (hash >> 20) ) % FILTER_WX_HASHSIZE; /* fold the hashbits.. */
633 
634 	f2 = NULL;
635 
636 	rwl_rdlock(&filter_wx_rwlock);
637 
638 	fp = &filter_wx_hash[idx];
639 	while (( f = *fp )) {
640 		if ( f->hash == hash ) {
641 			if (f->len == keylen) {
642 				int rc =  strncasecmp(f->callsign, key, keylen);
643 				if (rc == 0) { /* Have key match, see if it is
644 						  still valid entry ? */
645 					if (f->expirytime < tick - 60) {
646 						f2 = f;
647 						break;
648 					}
649 				}
650 			}
651 		}
652 		/* No match at all, advance the pointer.. */
653 		fp = &(f -> next);
654 	}
655 
656 	rwl_rdunlock(&filter_wx_rwlock);
657 
658 	return (f2 != NULL);
659 }
660 
661 
662 /*
663  *	The  filter_wx_cleanup()  does purge old entries
664  *	out of the database.  Run about once a minute.
665  */
filter_wx_cleanup(void)666 void filter_wx_cleanup(void)
667 {
668 	int k, cleancount = 0;
669 	struct filter_wx_t *f, **fp;
670 
671 	rwl_wrlock(&filter_wx_rwlock);
672 
673 	for (k = 0; k < FILTER_WX_HASHSIZE; ++k) {
674 		fp = & filter_wx_hash[k];
675 		while (( f = *fp )) {
676 			/* Did it expire ? */
677 			if (f->expirytime <= tick) {
678 				*fp = f->next;
679 				f->next = NULL;
680 				filter_wx_free(f);
681 				++cleancount;
682 				continue;
683 			}
684 			/* No purge, advance the pointer.. */
685 			fp = &(f -> next);
686 		}
687 	}
688 
689 	rwl_wrunlock(&filter_wx_rwlock);
690 
691 	// hlog( LOG_DEBUG, "filter_wx_cleanup() removed %d entries, count now: %ld",
692 	//       cleancount, filter_wx_cellgauge );
693 }
694 
695 /*
696  *	The  filter_wx_atend()  does purge all entries
697  *	out of the database.  Run at the exit of the program.
698  *	This exists primarily to make valgrind happy...
699  */
filter_wx_atend(void)700 void filter_wx_atend(void)
701 {
702 	int k;
703 	struct filter_wx_t *f, **fp;
704 
705 	rwl_wrlock(&filter_wx_rwlock);
706 
707 	for (k = 0; k < FILTER_WX_HASHSIZE; ++k) {
708 		fp = & filter_wx_hash[k];
709 		while (( f = *fp )) {
710 			*fp = f->next;
711 			f->next = NULL;
712 			filter_wx_free(f);
713 		}
714 	}
715 
716 	rwl_wrunlock(&filter_wx_rwlock);
717 }
718 
719 
filter_wx_dump(FILE * fp)720 void filter_wx_dump(FILE *fp)
721 {
722 	int k;
723 	struct filter_wx_t *f;
724 
725 	rwl_rdlock(&filter_wx_rwlock);
726 
727 	for (k = 0; k < FILTER_WX_HASHSIZE; ++k) {
728 		f = filter_wx_hash[k];
729 
730 		for ( ; f; f = f->next ) {
731 			fprintf( fp, "%ld\t%s\n",
732 				 (long)f->expirytime, f->callsign );
733 		}
734 	}
735 
736 	rwl_rdunlock(&filter_wx_rwlock);
737 }
738 
739 
740 /* ================================================================ */
741 
aprsc_strnstr(const char * s1,const char * s2,size_t len)742 const char *aprsc_strnstr(const char *s1, const char *s2, size_t len)
743 {
744 	char  c1, c2;
745 	size_t  n;
746 
747 	c2 = *(char *) s2++;
748 
749 	n = strlen(s2);
750 
751 	do {
752 		do {
753 			/* if we're going too far */
754 			if (len-- == 0)
755 				return NULL;
756 
757 			/* pick first char and advance */
758 			c1 = *s1++;
759 
760 			/* end of string? */
761 			if (c1 == 0)
762 				return NULL;
763 		} while (c1 != c2);
764 
765 		/* at least the first character matches... if the needle is longer than
766 		 * what we have left in the haystack, we won't find a match.
767 		 */
768 
769 		if (n > len)
770 			return NULL;
771 
772 	} while (strncmp(s1, s2, n) != 0);
773 
774 	return s1;
775 }
776 
777 
778 /*
779  *	Check if there is a TCPIP* component in the path.
780  *	OPTIMIZE: The flag could be set when TCPIP is inserted, or when the path
781  *	is analyzed on input.
782  */
783 
filter_check_tcpip(struct pbuf_t * pbuf)784 static void filter_check_tcpip(struct pbuf_t *pbuf)
785 {
786 	if (aprsc_strnstr(pbuf->dstcall_end, ",TCPIP*,", pbuf->qconst_start - pbuf->dstcall_end))
787 		pbuf->flags |= F_HAS_TCPIP;
788 }
789 
filter_keyhashes(struct pbuf_t * pb)790 static void filter_keyhashes(struct pbuf_t *pb)
791 {
792 	pb->srccall_hash = keyhashuc(pb->data, pb->srccall_end - pb->data, 0);
793 
794 	if (pb->srcname == pb->data)
795 		pb->srcname_hash = pb->srccall_hash;
796 	else
797 		pb->srcname_hash = keyhashuc(pb->srcname, pb->srcname_len, 0);
798 
799 	if (pb->dstname)
800 		pb->dstname_hash = keyhashuc(pb->dstname, pb->dstname_len, 0);
801 }
802 
filter_preprocess_dupefilter(struct pbuf_t * pbuf)803 void filter_preprocess_dupefilter(struct pbuf_t *pbuf)
804 {
805 	// TODO: could probably skip filter_check_tcpip, and possibly filter_keyhashes too if no filtered listeners
806 	filter_check_tcpip(pbuf);
807 	if (have_filtered_listeners) {
808 		filter_entrycall_insert(pbuf);
809 		filter_wx_insert(pbuf);
810 	}
811 	filter_keyhashes(pbuf);
812 }
813 
filter_postprocess_dupefilter(struct pbuf_t * pbuf)814 void filter_postprocess_dupefilter(struct pbuf_t *pbuf)
815 {
816 	/*
817 	 *    If there is no position at this packet from earlier
818 	 *    processing, try now to find one by the callsign of
819 	 *    the packet sender.
820 	 *
821 	 */
822 	if (!(pbuf->flags & F_HASPOS)) {
823 		struct history_cell_t *hist;
824 		int rc = historydb_lookup(pbuf->srcname, pbuf->srcname_len, &hist);
825 		// hlog( LOG_DEBUG, "postprocess_dupefilter: no pos, looking up '%.*s', rc=%d",
826 		//       pbuf->srcname_len, pbuf->srcname, rc );
827 		if (rc > 0) {
828 			pbuf->lat     = hist->lat;
829 			pbuf->lng     = hist->lon;
830 			pbuf->cos_lat = hist->coslat;
831 
832 			pbuf->flags  |= F_HASPOS;
833 		}
834 	}
835 }
836 
837 
838 /* ================================================================ */
839 
840 /*
841  *	filter_match_on_callsignset()  matches prefixes, or exact keys
842  *	on filters of types:  b, d, e, o, p, u
843  *	('p' and 'b' need OPTIMIZATION - others get it for free)
844  *
845  */
846 
filter_match_on_callsignset(struct filter_refcallsign_t * ref,int keylen,struct filter_t * f,MatchEnum wildok)847 static int filter_match_on_callsignset(struct filter_refcallsign_t *ref, int keylen, struct filter_t *f, MatchEnum wildok)
848 {
849 	int i;
850 	struct filter_refcallsign_t *r  = f->h.refcallsigns;
851 	const char                  *r1 = (const void*)ref->callsign;
852 
853 	for (i = 0; i < f->h.numnames; ++i) {
854 		const int reflen = r[i].reflen;
855 		const int len    = reflen & LengthMask;
856 		const char   *r2 = (const void*)r[i].callsign;
857 
858 		switch (wildok) {
859 		case MatchExact:
860 			if (len != keylen)
861 				continue; /* no match */
862 			/* length OK, compare content */
863 			if (strncasecmp( r1, r2, len ) != 0) continue;
864 			/* So it was an exact match
865 			** Precisely speaking..  we should check that there is
866 			** no WildCard flag, or such.  But then this match
867 			** method should not be used if parser finds any such.
868 			*/
869 			return ( reflen & NegationFlag ? 2 : 1 );
870 			break;
871 		case MatchPrefix:
872 			if (len > keylen || !len) {
873 			/* reference string length is longer than our key */
874 				continue;
875 			}
876 			if (strncasecmp( r1, r2, len ) != 0) continue;
877 
878 			return ( reflen & NegationFlag ? 2 : 1 );
879 			break;
880 		case MatchWild:
881 			if (len > keylen || !len) {
882 			/* reference string length is longer than our key */
883 				continue;
884 			}
885 
886 			if (strncasecmp( r1, r2, len ) != 0) continue;
887 
888 			if (reflen & WildCard)
889 				return ( reflen & NegationFlag ? 2 : 1 );
890 
891 			if (len == keylen)
892 				return ( reflen & NegationFlag ? 2 : 1 );
893 			break;
894 		default:
895 			break;
896 		}
897 	}
898 	return 0; /* no match */
899 
900 }
901 
902 /*
903  *	filter_parse_one_callsignset()  collects multiple callsigns
904  *	on filters of types:  b, d, e, o, p, u
905  *
906  *	If previous filter was of same type as this one, that one's
907  *	refbuf is extended.
908  */
909 
filter_parse_one_callsignset(struct client_t * c,const char * filt0,struct filter_t * f0,struct filter_t * ff,struct filter_t ** ffp,MatchEnum wildok)910 static int filter_parse_one_callsignset(struct client_t *c, const char *filt0, struct filter_t *f0, struct filter_t *ff, struct filter_t **ffp, MatchEnum wildok)
911 {
912 	char prefixbuf[CALLSIGNLEN_MAX+1];
913 	char *k;
914 	const char *p;
915 	int i, refcount, wildcard;
916 	int refmax = 0, extend = 0;
917 	struct filter_refcallsign_t *refbuf;
918 
919 	p = filt0;
920 	if (*p == '-') ++p;
921 	while (*p && *p != '/') ++p;
922 	if (*p == '/') ++p;
923 	/* count the number of prefixes in there.. */
924 	while (*p) {
925 		if (*p) ++refmax;
926 		while (*p && *p != '/') ++p;
927 		if (*p == '/') ++p;
928 	}
929 	if (refmax == 0) return -1; /* No prefixes ?? */
930 
931 	if (ff && ff->h.type == f0->h.type) { /* SAME TYPE,
932 						 extend previous record! */
933 		extend = 1;
934 		refcount = ff->h.numnames + refmax;
935 		//hlog(LOG_DEBUG, "extending, refcount %d numnames %d refmax %d", refcount, ff->h.numnames, refmax);
936 		refbuf   = hrealloc(ff->h.refcallsigns, sizeof(*refbuf) * refcount);
937 		ff->h.refcallsigns = refbuf;
938 		refcount = ff->h.numnames;
939 	} else {
940 		refbuf = hmalloc(sizeof(*refbuf)*refmax);
941 		refcount = 0;
942 		f0->h.refcallsigns = refbuf;
943 		f0->h.numnames     = 0;
944 	}
945 
946 	p = filt0;
947 	if (*p == '-') ++p;
948 	while (*p && *p != '/') ++p;
949 	if (*p == '/') ++p;
950 
951 	//hlog(LOG_DEBUG, "p-filter: '%s'", p);
952 	while (*p)  {
953 		k = prefixbuf;
954 		memset(prefixbuf, 0, sizeof(prefixbuf));
955 		i = 0;
956 		wildcard = 0;
957 		/* loop through the whole callsign, but only copy max CALLSIGNLEN_MAX
958 		 * bytes to the buffer
959 		 */
960 		while (*p != 0 && *p != '/') {
961 			if (*p == '*') {
962 				wildcard = 1;
963 				++p;
964 				if (wildok != MatchWild)
965 					return -1;
966 				continue;
967 			}
968 			if (i < CALLSIGNLEN_MAX) {
969 				*k = *p;
970 				++k;
971 			}
972 			++p;
973 			++i;
974 		}
975 		*k = 0;
976 
977 		/* OK, we have one prefix part collected,
978 		   scan source until next '/' */
979 		if (*p != 0 && *p != '/') ++p;
980 		if (*p == '/') ++p;
981 
982 		/* If there is more of patterns, the loop continues.. */
983 
984 		/* Store the refprefix */
985 		memset(&refbuf[refcount], 0, sizeof(refbuf[refcount]));
986 		memcpy(refbuf[refcount].callsign, prefixbuf, sizeof(refbuf[refcount].callsign));
987 		refbuf[refcount].reflen = strlen(prefixbuf);
988 		if (wildcard)
989 			refbuf[refcount].reflen |= WildCard;
990 		if (f0->h.negation)
991 			refbuf[refcount].reflen |= NegationFlag;
992 		++refcount;
993 	}
994 
995 	f0->h.numnames = refcount;
996 
997 	if (extend) {
998 		char *s;
999 		ff->h.numnames     = refcount;
1000 		i = strlen(ff->h.text) + strlen(filt0)+2;
1001 		if (i <= FILT_TEXTBUFSIZE) {
1002 			/* Fits in our built-in buffer block - like previous..
1003 			** Append on existing buffer
1004 			*/
1005 			s = ff->textbuf + strlen(ff->textbuf);
1006 			sprintf(s, " %s", filt0);
1007 		} else {
1008 			/* It does not fit anymore.. */
1009 			s = hmalloc(i); /* alloc a new one */
1010 			sprintf(s, "%s %s", ff->textbuf, filt0); /* .. and catenate. */
1011 			p = ff->h.text;
1012 			if (ff->h.text != ff->textbuf) /* possibly free old */
1013 				hfree((void*)p);
1014 			ff->h.text = s;     /* store new */
1015 		}
1016 	}
1017 	/* If not extending existing filter item,
1018 	   let main parser do the finalizations */
1019 
1020 	return extend;
1021 }
1022 
filter_parse_one_s(struct client_t * c,const char * filt0,struct filter_t * f0,struct filter_t * ff,struct filter_t ** ffp)1023 static int filter_parse_one_s(struct client_t *c, const char *filt0, struct filter_t *f0, struct filter_t *ff, struct filter_t **ffp)
1024 {
1025 	/* s/pri/alt/over  	Symbol filter
1026 
1027 	   pri = symbols in primary table
1028 	   alt = symbols in alternate table
1029 	   over = overlay character (case sensitive)
1030 
1031 	   For example:
1032 	   s/->   This will pass all House and Car symbols (primary table)
1033 	   s//#   This will pass all Digi with or without overlay
1034 	   s//#/T This will pass all Digi with overlay of capital T
1035 
1036 	   About 10-15 s-filters in entire APRS-IS core at any given time.
1037 	   Up to 520 invocations per second at peak.
1038 	*/
1039 	const char *s = filt0;
1040 	int len1, len2, len3, len4, len5, len6;
1041 
1042 	if (*s == '-')
1043 		++s;
1044 	if (*s == 's' || *s == 'S')
1045 		++s;
1046 	if (*s != '/')
1047 		return -1;
1048 	++s;
1049 
1050 	len1 = len2 = len3 = len4 = len5 = len6 = 0;
1051 
1052 	while (1) {
1053 		len1 = s - filt0;
1054 		while (*s && *s != '/')
1055 			s++;
1056 		len2 = s - filt0;
1057 
1058 		f0->h.len1s = len1;
1059 		f0->h.len1  = len2 - len1;
1060 		f0->h.lens.len2s = f0->h.lens.len2 = f0->h.lens.len3s = f0->h.lens.len3 = 0;
1061 
1062 		if (!*s) break;
1063 
1064 		if (*s == '/') ++s;
1065 		len3 = s - filt0;
1066 		while (*s && *s != '/')
1067 			s++;
1068 		len4 = s - filt0;
1069 
1070 		f0->h.lens.len2s = len3;
1071 		f0->h.lens.len2  = len4 - len3;
1072 
1073 		if (!*s) break;
1074 
1075 		if (*s == '/') ++s;
1076 		len5 = s - filt0;
1077 		while (*s) ++s;
1078 		len6 = s - filt0;
1079 
1080 		f0->h.lens.len3s = len5;
1081 		f0->h.lens.len3  = len6 - len5;
1082 
1083 		break;
1084 	}
1085 
1086 	if ((len6-len5 > 0) && (len4-len3 == 0)) {
1087 		/* overlay but no secondary table.. */
1088 		return -1; /* bad parse */
1089 	}
1090 #if 0
1091 	{
1092 	  const char  *s1 = filt0+len1, *s2 = filt0+len3, *s3 = filt0+len5;
1093 	  int l1 = len2-len1, l2 = len4-len3, l3 = len6-len5;
1094 
1095 	  hlog( LOG_DEBUG, "parse s-filter:  '%.*s'  '%.*s'  '%.*s'",
1096 		l1, s1, l2, s2, l3, s3 );
1097 	}
1098 #endif
1099 	return 0;
1100 }
1101 
1102 
filter_parse(struct client_t * c,const char * filt,int is_user_filter)1103 int filter_parse(struct client_t *c, const char *filt, int is_user_filter)
1104 {
1105 	struct filter_t *f, f0;
1106 	int i;
1107 	const char *filt0 = filt;
1108 	const char *s;
1109 	char dummyc;
1110 	struct filter_t *fp, *fn, *ff, **fff, **ffp, **ffn;
1111 
1112 	if (is_user_filter && c && (!(c->flags & CLFLAGS_USERFILTEROK))) {
1113 		hlog(LOG_DEBUG, "No user-specified filters permitted");
1114 		return -1;
1115 	}
1116 
1117 	if (!c) { /* built-in configuration scanning filter parsing */
1118 		ffp = &f;
1119 		ffn = &f;
1120 		f = NULL;
1121 	} else if (is_user_filter) {
1122 		ffn = &c->neguserfilters;
1123 		ffp = &c->posuserfilters;
1124 	} else {
1125 		ffn = &c->negdefaultfilters;
1126 		ffp = &c->posdefaultfilters;
1127 	}
1128 
1129 	fp = *ffp;
1130 	fn = *ffn;
1131 	for ( ; fp && fp->h.next; fp = fp->h.next)
1132 	  ;
1133 	for ( ; fn && fn->h.next; fn = fn->h.next)
1134 	  ;
1135 	/* f[np]  points to last so far accumulated filter,
1136 	   if none were previously received, it is NULL.. */
1137 
1138 	memset(&f0, 0, sizeof(f0));
1139 	if (*filt == '-') {
1140 		++filt;
1141 		ff  = fn;
1142 		fff = ffn;
1143 	} else {
1144 		ff  = fp;
1145 		fff = ffp;
1146 	}
1147 	f0.h.type = *filt;
1148 
1149 	if (!strchr("abdefgmopqrstuABDEFGMOPQRSTU", *filt)) {
1150 		/* Not valid filter code */
1151 		hlog(LOG_DEBUG, "Bad filter code: %s", filt0);
1152 		return -1;
1153 	}
1154 
1155 	switch (f0.h.type) {
1156 	case 'a':
1157 	case 'A':
1158 		/*  a/latN/lonW/latS/lonE     Area filter -- OPTIMIZE!  */
1159 
1160 		i = sscanf(filt+1, "/%f/%f/%f/%f%c",
1161 			   &f0.h.f_latN, &f0.h.f_lonW,
1162 			   &f0.h.f_latS, &f0.h.f_lonE, &dummyc);
1163 
1164 		if (i == 5 && dummyc == '/')
1165 			i = 4;
1166 
1167 		if (i != 4) {
1168 			hlog(LOG_DEBUG, "Bad filter parse: %s", filt0);
1169 			return -1;
1170 		}
1171 
1172 		if (!( -90.01 < f0.h.f_latN && f0.h.f_latN <  90.01)) {
1173 			hlog(LOG_DEBUG, "Bad filter latN value: %s", filt0);
1174 			return -2;
1175 		}
1176 		if (!(-180.01 < f0.h.f_lonW && f0.h.f_lonW < 180.01)) {
1177 			hlog(LOG_DEBUG, "Bad filter lonW value: %s", filt0);
1178 			return -2;
1179 		}
1180 		if (!( -90.01 < f0.h.f_latS && f0.h.f_latS <  90.01)) {
1181 			hlog(LOG_DEBUG, "Bad filter latS value: %s", filt0);
1182 			return -2;
1183 		}
1184 		if (!(-180.01 < f0.h.f_lonE && f0.h.f_lonE < 180.01)) {
1185 			hlog(LOG_DEBUG, "Bad filter lonE value: %s", filt0);
1186 			return -2;
1187 		}
1188 
1189 		if (f0.h.f_latN < f0.h.f_latS) {
1190 			hlog(LOG_DEBUG, "Bad filter: latN<latS: %s", filt0);
1191 			return -3; /* expect: latN >= latS */
1192 		}
1193 		if (f0.h.f_lonW > f0.h.f_lonE) {
1194 			hlog(LOG_DEBUG, "Bad filter: lonW>lonE: %s", filt0);
1195 			return -3; /* expect: lonW <= lonE */
1196 		}
1197 
1198 		// hlog(LOG_DEBUG, "Filter: %s -> A %.3f %.3f %.3f %.3f",
1199 		//      filt0, f0.h.f_latN, f0.h.f_lonW,
1200 		//      f0.h.f_latS, f0.h.f_lonE);
1201 
1202 		f0.h.f_latN = filter_lat2rad(f0.h.f_latN);
1203 		f0.h.f_lonW = filter_lon2rad(f0.h.f_lonW);
1204 
1205 		f0.h.f_latS = filter_lat2rad(f0.h.f_latS);
1206 		f0.h.f_lonE = filter_lon2rad(f0.h.f_lonE);
1207 
1208 
1209 
1210 		break;
1211 
1212 	case 'b':
1213 	case 'B':
1214 		/*  b/call1/call2...   Budlist filter (*) */
1215 
1216 		i = filter_parse_one_callsignset(c, filt0, &f0, ff, fff, MatchWild );
1217 		if (i < 0)
1218 			return i;
1219 		if (i > 0) /* extended previous */
1220 			return 0;
1221 
1222 
1223 		break;
1224 
1225 	case 'd':
1226 	case 'D':
1227 		/* d/digi1/digi2...  	Used digipeater filter (*)	*/
1228 
1229 		i = filter_parse_one_callsignset(c, filt0, &f0, ff, fff, MatchWild );
1230 		if (i < 0)
1231 			return i;
1232 		if (i > 0) /* extended previous */
1233 			return 0;
1234 
1235 		break;
1236 
1237 	case 'e':
1238 	case 'E':
1239 		/*   e/call1/call1/...  Entry station filter (*) */
1240 
1241 		i = filter_parse_one_callsignset(c, filt0, &f0, ff, fff, MatchWild );
1242 		if (i < 0)
1243 			return i;
1244 		if (i > 0) /* extended previous */
1245 			return 0;
1246 
1247 		break;
1248 
1249 	case 'f':
1250 	case 'F':
1251 		/*  f/call/dist         Friend's range filter  */
1252 
1253 		i = sscanf(filt+1, "/%9[^/]/%f", f0.h.refcallsign.callsign, &f0.h.f_dist);
1254 		if (i != 2 || f0.h.f_dist < 0.1) {
1255 			hlog(LOG_DEBUG, "Bad filter parse: %s", filt0);
1256 			return -1;
1257 		}
1258 
1259 		f0.h.refcallsign.callsign[CALLSIGNLEN_MAX] = 0;
1260 		f0.h.refcallsign.reflen = strlen(f0.h.refcallsign.callsign);
1261 		f0.h.numnames = 0; /* reusing this as "position-cache valid" flag */
1262 
1263 		// hlog(LOG_DEBUG, "Filter: %s -> F xxx %.3f", filt0, f0.h.f_dist);
1264 
1265 		/* NOTE: Could do static location resolving at connect time,
1266 		** and then use the same way as 'r' range does.  The friends
1267 		** are rarely moving...
1268 		*/
1269 
1270 		break;
1271 
1272 	case 'g':
1273 	case 'G':
1274 		/*   g/call1/call1/...  Text message destination filter (*) */
1275 
1276 		i = filter_parse_one_callsignset(c, filt0, &f0, ff, fff, MatchWild );
1277 		if (i < 0)
1278 			return i;
1279 		if (i > 0) /* extended previous */
1280 			return 0;
1281 
1282 		break;
1283 
1284 	case 'm':
1285 	case 'M':
1286 		/*  m/dist            My range filter  */
1287 
1288 		i = sscanf(filt+1, "/%f", &f0.h.f_dist);
1289 		if (i != 1 || f0.h.f_dist < 0.1) {
1290 			hlog(LOG_DEBUG, "Bad filter parse: %s", filt0);
1291 			return -1;
1292 		}
1293 		f0.h.numnames = 0; /* reusing this as "position-cache valid" flag */
1294 
1295 		// hlog(LOG_DEBUG, "Filter: %s -> M %.3f", filt0, f0.h.f_dist);
1296 		break;
1297 
1298 	case 'o':
1299 	case 'O':
1300 		/* o/obje1/obj2...  	Object filter (*)	*/
1301 
1302 		i = filter_parse_one_callsignset(c, filt0, &f0, ff, fff, MatchWild );
1303 		if (i < 0)
1304 			return i;
1305 		if (i > 0) /* extended previous */
1306 			return 0;
1307 
1308 		break;
1309 
1310 	case 'p':
1311 	case 'P':
1312 		/* p/aa/bb/cc...  	Prefix filter
1313 		   Pass traffic with fromCall that start with aa or bb or cc...
1314 		*/
1315 		i = filter_parse_one_callsignset(c, filt0, &f0, ff, fff, MatchPrefix );
1316 		if (i < 0)
1317 			return i;
1318 		if (i > 0) /* extended previous */
1319 			return 0;
1320 
1321 		break;
1322 
1323 	case 'q':
1324 	case 'Q':
1325 		/* q/con/ana           q Contruct filter */
1326 		s = filt+1;
1327 		f0.h.type = 'q';
1328 		f0.h.bitflags = 0; /* For QC_*  flags */
1329 
1330 		if (*s++ != '/') {
1331 			hlog(LOG_DEBUG, "Bad q-filter parse: %s", filt0);
1332 			return -1;
1333 		}
1334 		for ( ; *s && *s != '/'; ++s ) {
1335 			switch (*s) {
1336 			case 'C':
1337 				f0.h.bitflags |= QC_C;
1338 				break;
1339 			case 'X':
1340 				f0.h.bitflags |= QC_X;
1341 				break;
1342 			case 'U':
1343 				f0.h.bitflags |= QC_U;
1344 				break;
1345 			case 'o':
1346 				f0.h.bitflags |= QC_o;
1347 				break;
1348 			case 'O':
1349 				f0.h.bitflags |= QC_O;
1350 				break;
1351 			case 'S':
1352 				f0.h.bitflags |= QC_S;
1353 				break;
1354 			case 'r':
1355 				f0.h.bitflags |= QC_r;
1356 				break;
1357 			case 'R':
1358 				f0.h.bitflags |= QC_R;
1359 				break;
1360 			case 'Z':
1361 				f0.h.bitflags |= QC_Z;
1362 				break;
1363 			case 'I':
1364 				f0.h.bitflags |= QC_I;
1365 				break;
1366 			default:
1367 				hlog(LOG_DEBUG, "Bad q-filter parse: %s", filt0);
1368 				return -1;
1369 			}
1370 		}
1371 		if (*s == '/') { /* second format */
1372 			++s;
1373 			if (*s == 'i' || *s == 'I') {
1374 				f0.h.bitflags |= QC_AnalyticsI;
1375 				++s;
1376 			}
1377 			if (*s) {
1378 				hlog(LOG_DEBUG, "Bad q-filter parse: %s", filt0);
1379 				return -1;
1380 			}
1381 		}
1382 
1383 		break;
1384 
1385 	case 'r':
1386 	case 'R':
1387 		/*  r/lat/lon/dist            Range filter  */
1388 
1389 		i = sscanf(filt+1, "/%f/%f/%f",
1390 			 &f0.h.f_latN, &f0.h.f_lonE, &f0.h.f_dist);
1391 		if (i != 3 || f0.h.f_dist < 0.1) {
1392 			hlog(LOG_DEBUG, "Bad filter parse: %s", filt0);
1393 			return -1;
1394 		}
1395 
1396 		if (!( -90.01 < f0.h.f_latN && f0.h.f_latN <  90.01)) {
1397 			hlog(LOG_DEBUG, "Bad filter lat value: %s", filt0);
1398 			return -2;
1399 		}
1400 		if (!(-180.01 < f0.h.f_lonE && f0.h.f_lonE < 180.01)) {
1401 			hlog(LOG_DEBUG, "Bad filter lon value: %s", filt0);
1402 			return -2;
1403 		}
1404 
1405 		// hlog(LOG_DEBUG, "Filter: %s -> R %.3f %.3f %.3f", filt0, f0.h.f_latN, f0.h.f_lonW, f0.h.f_dist);
1406 
1407 		f0.h.f_latN = filter_lat2rad(f0.h.f_latN);
1408 		f0.h.f_lonE = filter_lon2rad(f0.h.f_lonE);
1409 
1410 		f0.h.f_coslat = cosf( f0.h.f_latN ); /* Store pre-calculated COS of LAT */
1411 		break;
1412 
1413 	case 's':
1414 	case 'S':
1415 		/* s/pri/alt/over  	Symbol filter  */
1416 
1417 		i = filter_parse_one_s( c, filt0, &f0, ff, fff );
1418 		if (i < 0) {
1419 			hlog(LOG_DEBUG, "Bad s-filter syntax: %s", filt0);
1420 			return i;
1421 		}
1422 		if (i > 0) /* extended previous */
1423 			return 0;
1424 		break;
1425 
1426 	case 't':
1427 	case 'T':
1428 		/* t/..............
1429 		   t/............../call/km
1430 		*/
1431 		s = filt+1;
1432 		f0.h.type = 't';
1433 		f0.h.bitflags = 0;
1434 		f0.h.numnames = 0; /* reusing this as "position-cache valid" flag */
1435 
1436 		if (*s++ != '/') {
1437 			hlog(LOG_DEBUG, "Bad filter parse: %s", filt0);
1438 			return -1;
1439 		}
1440 		for ( ; *s && *s != '/'; ++s ) {
1441 			switch (*s) {
1442 			case '*':
1443 				f0.h.bitflags |= ~T_CWOP; /* "ALL" -- excluding CWOP */
1444 				break;
1445 			case 'c': case 'C':
1446 				f0.h.bitflags |= T_CWOP;
1447 				break;
1448 			case 'i': case 'I':
1449 				f0.h.bitflags |= T_ITEM;
1450 				break;
1451 			case 'm': case 'M':
1452 				f0.h.bitflags |= T_MESSAGE;
1453 				break;
1454 			case 'n': case 'N':
1455 				f0.h.bitflags |= T_NWS;
1456 				break;
1457 			case 'o': case 'O':
1458 				f0.h.bitflags |= T_OBJECT;
1459 				break;
1460 			case 'p': case 'P':
1461 				f0.h.bitflags |= T_POSITION;
1462 				break;
1463 			case 'q': case 'Q':
1464 				f0.h.bitflags |= T_QUERY;
1465 				break;
1466 			case 's': case 'S':
1467 				f0.h.bitflags |= T_STATUS;
1468 				break;
1469 			case 't': case 'T':
1470 				f0.h.bitflags |= T_TELEMETRY;
1471 				break;
1472 			case 'u': case 'U':
1473 				f0.h.bitflags |= T_USERDEF;
1474 				break;
1475 			case 'w': case 'W':
1476 				f0.h.bitflags |= T_WX;
1477 				break;
1478 			default:
1479 				hlog(LOG_DEBUG, "Bad filter parse: %s", filt0);
1480 				return -1;
1481 			}
1482 		}
1483 		if (*s == '/' && s[1] != 0) { /* second format */
1484 			i = sscanf(s, "/%9[^/]/%f%c", f0.h.refcallsign.callsign, &f0.h.f_dist, &dummyc);
1485 			if ( i != 2 || f0.h.f_dist < 0.1 || /* 0.1 km minimum radius */
1486 			     strlen(f0.h.refcallsign.callsign) < CALLSIGNLEN_MIN ) {
1487 				hlog(LOG_DEBUG, "Bad filter parse: %s", filt0);
1488 				return -1;
1489 			}
1490 			f0.h.refcallsign.callsign[CALLSIGNLEN_MAX] = 0;
1491 			f0.h.refcallsign.reflen = strlen(f0.h.refcallsign.callsign);
1492 			f0.h.type = 'T'; /* two variants... */
1493 		}
1494 
1495 		break;
1496 
1497 	case 'u':
1498 	case 'U':
1499 		/* u/unproto1/unproto2...  	Unproto filter (*)	*/
1500 
1501 		i = filter_parse_one_callsignset(c, filt0, &f0, ff, fff, MatchWild );
1502 		if (i < 0)
1503 			return i;
1504 		if (i > 0) /* extended previous */
1505 			return 0;
1506 
1507 		break;
1508 
1509 
1510 
1511 	default:;
1512 		/* No pre-parsers for other types */
1513 		// hlog(LOG_DEBUG, "Filter: %s", filt0);
1514 		break;
1515 	}
1516 
1517 	if (!c) return 0; /* Just a verification scan, not actual fill in parse */
1518 
1519 	/* OK, pre-parsing produced accepted result */
1520 #ifndef _FOR_VALGRIND_
1521 	f = cellmalloc(filter_cells);
1522 	if (!f) {
1523 		hlog(LOG_ERR, "filter_parse: cellmalloc failed");
1524 		return -1;
1525 	}
1526 	*f = f0; /* store pre-parsed values */
1527 	if (strlen(filt0) < FILT_TEXTBUFSIZE) {
1528 		strcpy(f->textbuf, filt0);
1529 		f->h.text = f->textbuf;
1530 	} else
1531 		f->h.text = hstrdup(filt0); /* and copy of filter text */
1532 #else
1533 	f = hmalloc(sizeof(*f) + strlen(filt0));
1534 	*f = f0; /* store pre-parsed values */
1535 	f->h.text = f->textbuf;
1536 	strcpy(f->textbuf, filt); /* and copy of filter text */
1537 #endif
1538 	rwl_wrlock(&filter_cellgauge_rwlock);
1539 	++ filter_cellgauge;
1540 	rwl_wrunlock(&filter_cellgauge_rwlock);
1541 
1542 	hlog(LOG_DEBUG, "parsed filter: t=%c n=%d '%s'", f->h.type, f->h.negation, f->h.text);
1543 
1544 	/* link to the tail.. */
1545 	if (ff)
1546 		fff = &ff->h.next;
1547 
1548 	*fff = f;
1549 
1550 	return 0;
1551 }
1552 
1553 /* Discard the defined filter chain */
filter_free(struct filter_t * f)1554 void filter_free(struct filter_t *f)
1555 {
1556 	struct filter_t *fnext;
1557 	int freed = 0;
1558 
1559 	for ( ; f ; f = fnext ) {
1560 		fnext = f->h.next;
1561 		/* If not pointer to internal string, free it.. */
1562 #ifndef _FOR_VALGRIND_
1563 		if (f->h.text != f->textbuf)
1564 			hfree((void*)(f->h.text));
1565 		cellfree(filter_cells, f);
1566 #else
1567 		hfree(f);
1568 #endif
1569 		freed++;
1570 	}
1571 
1572 	rwl_wrlock(&filter_cellgauge_rwlock);
1573 	filter_cellgauge -= freed;
1574 	rwl_wrunlock(&filter_cellgauge_rwlock);
1575 }
1576 
1577 
1578 /*
1579 
1580 #
1581 # Input:  This[La]      Source Latitude, in radians
1582 #         This[Lo]      Source Longitude, in radians
1583 #         That[La]      Destination Latitude, in radians
1584 #         That[Lo]      Destination Longitude, in radians
1585 # Output: R[s]          Distance, in kilometers
1586 #
1587 
1588 function maidenhead_km_distance($This, $That) {
1589 
1590     #Haversine Formula (from R.W. Sinnott, "Virtues of the Haversine",
1591     #Sky and Telescope, vol. 68, no. 2, 1984, p. 159):
1592 
1593     $dlon = $That[Lo] - $This[Lo];
1594     $dlat = $That[La] - $This[La];
1595 
1596     $sinDlat2 = sin($dlat/2);
1597     $sinDlon2 = sin($dlon/2);
1598     $a = ($sinDlat2 * $sinDlat2 +
1599           cos($This[La]) * cos($That[La]) * $sinDlon2 * $sinDlon2);
1600 
1601     # The Haversine Formula can be expressed in terms of a two-argument
1602     # inverse tangent function, atan2(y,x), instead of an inverse sine
1603     # as follows (no bulletproofing is needed for an inverse tangent):
1604 
1605     $c = 2.0 * atan2( sqrt($a), sqrt(1.0-$a) );
1606     # $d = R * $c ; # Radius of ball times angle [radians] ...
1607 
1608 
1609     $R[s] = rad2deg($c) * 111.2;
1610 
1611     return($R);
1612 
1613 }
1614 
1615 */
1616 
maidenhead_km_distance(float lat1,float coslat1,float lon1,float lat2,float coslat2,float lon2)1617 static float maidenhead_km_distance(float lat1, float coslat1, float lon1, float lat2, float coslat2, float lon2)
1618 {
1619 	float sindlat2 = sinf((lat1 - lat2) * 0.5);
1620 	float sindlon2 = sinf((lon1 - lon2) * 0.5);
1621 
1622 	float a = (sindlat2 * sindlat2 +
1623 		   coslat1 * coslat2 * sindlon2 * sindlon2);
1624 
1625 	float c = 2.0 * atan2f( sqrtf(a), sqrtf(1.0 - a));
1626 
1627 	return ((111.2 * 180.0 / M_PI) * c);
1628 }
1629 
1630 
1631 /*
1632  *
1633  *  http://www.aprs-is.net/javaprssrvr/javaprsfilter.htm
1634  *
1635  */
1636 
filter_process_one_a(struct client_t * c,struct pbuf_t * pb,struct filter_t * f)1637 static int filter_process_one_a(struct client_t *c, struct pbuf_t *pb, struct filter_t *f)
1638 {
1639 	/* a/latN/lonW/latS/lonE  	Area filter
1640 
1641 	   The area filter works the same as range filter but the filter
1642 	   is defined as a box of coordinates. The coordinates can also
1643 	   been seen as upper left coordinate and lower right. Lat/lon
1644 	   are decimal degrees.   South and west are negative.
1645 
1646 	   Multiple area filters can be defined at the same time.
1647 
1648 	   Messages addressed to stations within the area are also passed.
1649 	   (by means of aprs packet parse finding out the location..)
1650 
1651 	   50-70 instances in APRS-IS core at any given time.
1652 	   Up to 2500 invocations per second.
1653 	*/
1654 	;
1655 	if (!(pb->flags & F_HASPOS)) /* packet with a position.. (msgs with RECEIVER's position) */
1656 		return 0;
1657 
1658 	if ((pb->lat <= f->h.f_latN) &&
1659 	    (pb->lat >= f->h.f_latS) &&
1660 	    (pb->lng <= f->h.f_lonE) && /* East POSITIVE ! */
1661 	    (pb->lng >= f->h.f_lonW))
1662 		/* Inside the box */
1663 		return f->h.negation ? 2 : 1;
1664 
1665 	return 0;
1666 }
1667 
filter_process_one_b(struct client_t * c,struct pbuf_t * pb,struct filter_t * f)1668 static int filter_process_one_b(struct client_t *c, struct pbuf_t *pb, struct filter_t *f)
1669 {
1670 	/* b/call1/call2...  	Budlist filter
1671 
1672 	   Pass all traffic FROM exact call: call1, call2, ...
1673 	   (* wild card allowed)
1674 
1675 	   50/70 instances in APRS-IS core at any given time.
1676 	   Up to 2500 invocations per second.
1677 	*/
1678 
1679 	struct filter_refcallsign_t ref;
1680 	int i = pb->srccall_end - pb->data;
1681 
1682 	if (i > CALLSIGNLEN_MAX) i = CALLSIGNLEN_MAX;
1683 
1684 	/* source address  "addr">... */
1685 	memcpy( ref.callsign, pb->data, i);
1686 	memset( ref.callsign+i, 0, sizeof(ref.callsign)-i );
1687 
1688 	int r = filter_match_on_callsignset(&ref, i, f, MatchWild);
1689 
1690 	/* match 3rd-party packets based on their innermost srccall,
1691 	 * only works on non-object/item currently
1692 	 */
1693 	if (r == 0 && pb->srcname != pb->data && (pb->packettype & (T_OBJECT|T_ITEM)) == 0) {
1694 		i = pb->srcname_len;
1695 		if (i > CALLSIGNLEN_MAX) i = CALLSIGNLEN_MAX;
1696 
1697 		memcpy( ref.callsign, pb->srcname, i);
1698 		memset( ref.callsign+i, 0, sizeof(ref.callsign)-i );
1699 
1700 		return filter_match_on_callsignset(&ref, i, f, MatchWild);
1701 	}
1702 
1703 	return r;
1704 }
1705 
filter_process_one_d(struct client_t * c,struct pbuf_t * pb,struct filter_t * f)1706 static int filter_process_one_d(struct client_t *c, struct pbuf_t *pb, struct filter_t *f)
1707 {
1708 	/* d/digi1/digi2...  	Digipeater filter
1709 
1710 	   The digipeater filter will pass all packets that have been
1711 	   digipeated by a particular station(s) (the station's call
1712 	   is in the path, and a * is present in that callsign or
1713 	   a following callsign before the Q construct).
1714 	   This filter allows the * wildcard.
1715 
1716 	   25-35 filters in use at any given time.
1717 	   Up to 1300 invocations per second.
1718 	*/
1719 	struct filter_refcallsign_t ref;
1720 	const char *d = pb->srccall_end + 1 + pb->dstcall_len + 1; /* viacall start */
1721 	const char *q = pb->qconst_start-1;
1722 	int rc, i, cl, j = 0;
1723 	int found_call = 0;
1724 
1725 	/*hlog( LOG_INFO, "digifilter:  '%.*s' -> '%.*s'  q-d=%d",
1726 	 *      (int)(pb->packet_len < 50 ? pb->packet_len : 50),
1727 	 *      pb->data, (int)i, d, (int)(q-d) );
1728 	 */
1729 
1730 	for (i = 0; d < q; ) {
1731 		++j;
1732 		if (j > 10) break; /* way too many callsigns... */
1733 
1734 		if (*d == ',') ++d; /* second round and onwards.. */
1735 		/* find end of callsign */
1736 		for (i = 0; i+d <= q && i <= CALLSIGNLEN_MAX; ++i) {
1737 			if (d[i] == ',')
1738 				break;
1739 		}
1740 
1741 		//hlog(LOG_INFO, "d:  -> (%d,%d) '%.*s'", (int)(d-pb->data), i, i, d);
1742 
1743 		/* When matching callsign, ignore trailing '*' */
1744 		cl = i;
1745 		if (d[cl-1] == '*')
1746 			cl--;
1747 
1748 		if (cl > CALLSIGNLEN_MAX) cl = CALLSIGNLEN_MAX;
1749 
1750 		/* digipeater address  ",addr," */
1751 		memcpy( ref.callsign, d, cl);
1752 		memset( ref.callsign+cl, 0, sizeof(ref.callsign)-cl );
1753 
1754 		rc = filter_match_on_callsignset(&ref, cl, f, MatchWild);
1755 		if (rc) {
1756 			if (rc == 1) {
1757 				found_call = 1;
1758 				break;
1759 			}
1760 		}
1761 		d += i;
1762 	}
1763 
1764 	if (!found_call)
1765 		return 0;
1766 
1767 	/* Ok, we found the call. Check if it has a '*' in the end.
1768 	 * Or if one of the following calls does.
1769 	 *
1770 	 * d points to the start of this call, d[i-1] should be it's last character.
1771 	 */
1772 
1773 	if (d[cl] == '*')
1774 		return 1;
1775 
1776 	/* continue looking from next callsign */
1777 	d += i;
1778 	while (d < q) {
1779 		++j;
1780 		if (j > 10) break; /* way too many callsigns... */
1781 
1782 		if (*d == ',')
1783 			d++;
1784 
1785 		/* find end of callsign */
1786 		for (i = 0; i+d <= q && i <= CALLSIGNLEN_MAX; ++i) {
1787 			if (d[i] == ',')
1788 				break;
1789 		}
1790 
1791 		//hlog(LOG_INFO, "d:  -> (%d,%d) '%.*s'", (int)(d-pb->data), i, i, d);
1792 
1793 		/* Is there a trailing '*' in the call? */
1794 		if (d[i-1] == '*')
1795 			return 1;;
1796 
1797 		d += i;
1798 	}
1799 
1800 	return 0;
1801 }
1802 
filter_process_one_e(struct client_t * c,struct pbuf_t * pb,struct filter_t * f)1803 static int filter_process_one_e(struct client_t *c, struct pbuf_t *pb, struct filter_t *f)
1804 {
1805 	/* e/call1/call1/...  	Entry station filter
1806 
1807 	   This filter passes all packets with the specified
1808 	   callsign-SSID(s) immediately following the q construct.
1809 	   This allows filtering based on receiving IGate, etc.
1810 	   Supports * wildcard.
1811 
1812 	   2-6 instances in APRS-IS core at any given time.
1813 	   Up to 200 invocations per second.
1814 	*/
1815 
1816 	struct filter_refcallsign_t ref;
1817 	const char *e = pb->qconst_start+4;
1818 	int         i = pb->entrycall_len;
1819 
1820 	if (i < 1) /* should not happen.. */
1821 		return 0; /* Bad Entry-station callsign */
1822 
1823 	/* entry station address  "qA*,addr," */
1824 	memcpy( ref.callsign, e, i);
1825 	memset( ref.callsign+i, 0, sizeof(ref.callsign)-i );
1826 
1827 	return filter_match_on_callsignset(&ref, i, f, MatchWild);
1828 }
1829 
filter_process_one_f(struct client_t * c,struct pbuf_t * pb,struct filter_t * f)1830 static int filter_process_one_f(struct client_t *c, struct pbuf_t *pb, struct filter_t *f)
1831 {
1832 	/* f/call/dist  	Friend Range filter
1833 	   This is the same as the range filter except that the center is
1834 	   defined as the last known position of call.
1835 
1836 	   Multiple friend filters can be defined at the same time.
1837 
1838 	   Messages addressed to stations within the range are also passed.
1839 	   (by means of aprs packet parse finding out the location..)
1840 
1841 	   NOTE: Could do static location resolving at connect time,
1842 	   and then use the same way as 'r' range does.  The friends
1843 	   are rarely moving...
1844 
1845 	   15-25 instances in APRS-IS core at any given time.
1846 	   Up to 900 invocations per second.
1847 
1848 	   Caching the historydb_lookup() result will lower CPU power
1849 	   spent on the historydb.
1850 	*/
1851 
1852 	struct history_cell_t *history;
1853 
1854 	float r;
1855 	float lat1, lon1, coslat1;
1856 	float lat2, lon2, coslat2;
1857 
1858 	const char *callsign = f->h.refcallsign.callsign;
1859 	int i                = f->h.refcallsign.reflen;
1860 
1861 	if (!(pb->flags & F_HASPOS)) /* packet with a position.. (msgs with RECEIVER's position) */
1862 		return 0; /* No position data... */
1863 
1864 	/* find friend's last location packet */
1865 	if (f->h.hist_age < tick || f->h.hist_age > tick + HIST_LOOKUP_INTERVAL) {
1866 		i = historydb_lookup( callsign, i, &history );
1867 		f->h.numnames = i;
1868 		f->h.hist_age = tick + HIST_LOOKUP_INTERVAL;
1869 		if (!i) return 0; /* no lookup result.. */
1870 		f->h.f_latN   = history->lat;
1871 		f->h.f_lonE   = history->lon;
1872 		f->h.f_coslat = history->coslat;
1873 	}
1874 	if (!f->h.numnames) return 0; /* histdb lookup cache invalid */
1875 
1876 	lat1    = f->h.f_latN;
1877 	lon1    = f->h.f_lonE;
1878 	coslat1 = f->h.f_coslat;
1879 
1880 	lat2    = pb->lat;
1881 	lon2    = pb->lng;
1882 	coslat2 = pb->cos_lat;
1883 
1884 	r = maidenhead_km_distance(lat1, coslat1, lon1, lat2, coslat2, lon2);
1885 
1886 	if (r < f->h.f_dist)  /* Range is less than given limit */
1887 		return (f->h.negation) ? 2 : 1;
1888 
1889 	return 0;
1890 }
1891 
filter_process_one_g(struct client_t * c,struct pbuf_t * pb,struct filter_t * f)1892 static int filter_process_one_g(struct client_t *c, struct pbuf_t *pb, struct filter_t *f)
1893 {
1894 	/* g/call1/call1/...  	Test message recipient callsign filter
1895 
1896 	   This filter passes all packets with the specified
1897 	   callsign-SSID(s) appearing as the text message
1898 	   recipient. Wildcards supported.
1899 
1900 	   Appeared in javAPRSSrvr 4.0, not widely used.
1901 	*/
1902 
1903 	if ( (pb->packettype & T_MESSAGE) == 0 ) /* not a message */
1904 		return 0;
1905 
1906 	struct filter_refcallsign_t ref;
1907 	const char *e = pb->dstname;
1908 	int         i = pb->dstname_len;
1909 
1910 	if (i < 1) /* should not happen.. */
1911 		return 0; /* Bad Entry-station callsign */
1912 
1913 	memcpy( ref.callsign, e, i);
1914 	memset( ref.callsign+i, 0, sizeof(ref.callsign)-i );
1915 
1916 	return filter_match_on_callsignset(&ref, i, f, MatchWild);
1917 }
1918 
filter_process_one_m(struct client_t * c,struct pbuf_t * pb,struct filter_t * f)1919 static int filter_process_one_m(struct client_t *c, struct pbuf_t *pb, struct filter_t *f)
1920 {
1921 	/* m/dist  	My Range filter
1922 	   This is the same as the range filter except that the center is
1923 	   defined as the last known position of the logged in client.
1924 	   A client location stored in the client struct is used instead of
1925 	   the history database, since the filter should work for non-validated
1926 	   clients (such as aprsdroid new users which have not received their
1927 	   passcode quite yet). The historydb may only be updated by packets
1928 	   which are actually forwarded.
1929 
1930 	   Messages addressed to stations within the range are also passed.
1931 	   (by means of aprs packet parse finding out the location..)
1932 
1933 	   NOTE:  MY RANGE is rarely moving, once there is a positional
1934 	   fix, it could stay fixed...
1935 
1936 	   80-120 instances in APRS-IS core at any given time.
1937 	   Up to 4200 invocations per second.
1938 
1939 	   Caching the historydb_lookup() result will lower CPU power
1940 	   spent on the historydb.
1941 	*/
1942 
1943 	float r;
1944 	float lat1, lon1, coslat1;
1945 	float lat2, lon2, coslat2;
1946 	int i;
1947 	struct history_cell_t *history;
1948 
1949 	if (!(pb->flags & F_HASPOS)) /* packet with a position.. (msgs with RECEIVER's position) */
1950 		return 0;
1951 
1952 	if (c->loc_known) {
1953 		/* If client has sent a location, use it. The client may be an unvalidated
1954 		 * client which does not exist in the historydb.
1955 		 */
1956 		r = maidenhead_km_distance(c->lat, c->cos_lat, c->lng, pb->lat, pb->cos_lat, pb->lng);
1957 		if (r < f->h.f_dist)  /* Range is less than given limit */
1958 			return f->h.negation ? 2 : 1;
1959 
1960 		return 0;
1961 	}
1962 
1963 	/* Otherwise, fall back to looking up from the historydb */
1964 
1965 	if (!*c->username) /* Should not happen... */
1966 		return 0;
1967 
1968 	if (f->h.hist_age < tick || f->h.hist_age > tick + HIST_LOOKUP_INTERVAL) {
1969 		i = historydb_lookup( c->username, strlen(c->username), &history );
1970 		f->h.numnames = i;
1971 		if (!i) {
1972 			f->h.hist_age = tick + HIST_LOOKUP_INTERVAL/2;
1973 			return 0; /* no result */
1974 		}
1975 		f->h.hist_age = tick + HIST_LOOKUP_INTERVAL;
1976 		f->h.f_latN   = history->lat;
1977 		f->h.f_lonE   = history->lon;
1978 		f->h.f_coslat = history->coslat;
1979 	}
1980 
1981 	if (!f->h.numnames)
1982 		return 0; /* cached lookup invalid.. */
1983 
1984 	lat1    = f->h.f_latN;
1985 	lon1    = f->h.f_lonE;
1986 	coslat1 = f->h.f_coslat;
1987 
1988 	lat2    = pb->lat;
1989 	lon2    = pb->lng;
1990 	coslat2 = pb->cos_lat;
1991 
1992 	r = maidenhead_km_distance(lat1, coslat1, lon1, lat2, coslat2, lon2);
1993 	if (r < f->h.f_dist)  /* Range is less than given limit */
1994 		return f->h.negation ? 2 : 1;
1995 
1996 	return 0;
1997 }
1998 
filter_process_one_o(struct client_t * c,struct pbuf_t * pb,struct filter_t * f)1999 static int filter_process_one_o(struct client_t *c, struct pbuf_t *pb, struct filter_t *f)
2000 {
2001 	/* o/obj1/obj2...  	Object filter
2002 	   Pass all objects with the exact name of obj1, obj2, ...
2003 	   (* wild card allowed)
2004 	   PROBABLY ALSO ITEMs
2005 
2006 	   Usage frequency: 0.2%
2007 
2008 	   .. 2 cases in entire APRS-IS core at any time.
2009 	   About 50-70 invocations per second at peak.
2010 	*/
2011 	struct filter_refcallsign_t ref;
2012 	int i;
2013 
2014 	if ( (pb->packettype & (T_OBJECT|T_ITEM)) == 0 ) /* not an Object NOR Item */
2015 		return 0;
2016 
2017 	/* parse_aprs() has picked item/object name pointer and length.. */
2018 	i = pb->srcname_len;
2019 	if (i < 1 || i > CALLSIGNLEN_MAX) return 0; /* Bad object/item name */
2020 
2021 	/* object name */
2022 	memcpy( ref.callsign, pb->srcname, i);
2023 	memset( ref.callsign+i, 0, sizeof(ref.callsign)-i );
2024 
2025 	return filter_match_on_callsignset(&ref, i, f, MatchWild);
2026 }
2027 
filter_process_one_p(struct client_t * c,struct pbuf_t * pb,struct filter_t * f)2028 static int filter_process_one_p(struct client_t *c, struct pbuf_t *pb, struct filter_t *f)
2029 {
2030 
2031 	/* p/aa/bb/cc...  	Prefix filter
2032 	   Pass traffic with fromCall that start with aa or bb or cc...
2033 
2034 	   Usage frequency: 14.4%
2035 
2036 	   .. 80-100 cases in entire APRS-IS core at any time.
2037 	   Up to 3500 invocations per second at peak.
2038 	*/
2039 
2040 	struct filter_refcallsign_t ref;
2041 	int i = pb->srccall_end - pb->data;
2042 
2043 	if (i > CALLSIGNLEN_MAX) i = CALLSIGNLEN_MAX;
2044 
2045 	/* source address  "addr">... */
2046 	memcpy( ref.callsign, pb->data, i);
2047 	memset( ref.callsign+i, 0, sizeof(ref.callsign)-i );
2048 
2049 	int r = filter_match_on_callsignset(&ref, i, f, MatchPrefix);
2050 
2051 	/* match 3rd-party packets based on their innermost srccall,
2052 	 * only works on non-object/item currently
2053 	 */
2054 	if (r == 0 && pb->srcname != pb->data && (pb->packettype & (T_OBJECT|T_ITEM)) == 0) {
2055 		i = pb->srcname_len;
2056 
2057 		if (i > CALLSIGNLEN_MAX) i = CALLSIGNLEN_MAX;
2058 
2059 		memcpy( ref.callsign, pb->srcname, i);
2060 		memset( ref.callsign+i, 0, sizeof(ref.callsign)-i );
2061 
2062 		return filter_match_on_callsignset(&ref, i, f, MatchPrefix);
2063 	}
2064 
2065 	return r;
2066 }
2067 
filter_process_one_q(struct client_t * c,struct pbuf_t * pb,struct filter_t * f)2068 static int filter_process_one_q(struct client_t *c, struct pbuf_t *pb, struct filter_t *f)
2069 {
2070 	/* q/con/ana  	q Contruct filter
2071 
2072 	   q = q Construct command
2073 	   con = list of q Construct to pass (case sensitive)
2074 	   ana = analysis based on q Construct.
2075 
2076 	   I = Pass positions from IGATES identified by qAr or qAR.
2077 
2078 	   For example:
2079 	   q/C    Pass all traffic with qAC
2080 	   q/rR   Pass all traffic with qAr or qAR
2081 	   q//I   Pass all position packets from IGATES identified
2082 	          in other packets by qAr or qAR
2083 
2084 	   Usage frequency: 0.4%
2085 
2086 	   .. 2-6 cases in entire APRS-IS core at any time.
2087 	   Up to 200 invocations per second at peak.
2088 	*/
2089 
2090 	const char *e = pb->qconst_start+2;
2091 	int mask;
2092 
2093 	switch (*e) {
2094 	case 'C':
2095 		mask = QC_C;
2096 		break;
2097 	case 'X':
2098 		mask = QC_X;
2099 		break;
2100 	case 'U':
2101 		mask = QC_U;
2102 		break;
2103 	case 'o':
2104 		mask = QC_o;
2105 		break;
2106 	case 'O':
2107 		mask = QC_O;
2108 		break;
2109 	case 'S':
2110 		mask = QC_S;
2111 		break;
2112 	case 'r':
2113 		mask = QC_r;
2114 		break;
2115 	case 'R':
2116 		mask = QC_R;
2117 		break;
2118 	case 'Z':
2119 		mask = QC_Z;
2120 		break;
2121 	case 'I':
2122 		mask = QC_I;
2123 		break;
2124 	default:
2125 		return 0; /* Should not happen... */
2126 		break;
2127 	}
2128 
2129 	if (f->h.bitflags & mask) {
2130 		/* Something matched! */
2131 		return 1;
2132 	}
2133 	if (f->h.bitflags & QC_AnalyticsI) {
2134 		/* Oh ?  Analytical!
2135 		   Has it ever been accepted into entry-igate database ? */
2136 		if (filter_entrycall_lookup(pb))
2137 			return 1; /* Found on entry-igate database! */
2138 	}
2139 
2140 	return 0; /* No match */
2141 }
2142 
2143 
filter_process_one_r(struct client_t * c,struct pbuf_t * pb,struct filter_t * f)2144 static int filter_process_one_r(struct client_t *c, struct pbuf_t *pb, struct filter_t *f)
2145 {
2146 	/* r/lat/lon/dist  	Range filter
2147 
2148 	   Pass posits and objects within dist km from lat/lon.
2149 	   lat and lon are signed degrees, i.e. negative for West/South
2150 	   and positive for East/North.
2151 
2152 	   Multiple range filters can be defined at the same time.
2153 
2154 	   Messages addressed to stations within the range are also passed.
2155 	   (by means of aprs packet parse finding out the location..)
2156 
2157 	   About 120-150 r-filters in entire APRS-IS core at any given time.
2158 	   Up to 5200 invocations per second at peak.
2159 	*/
2160 
2161 	float lat1    = f->h.f_latN;
2162 	float lon1    = f->h.f_lonE;
2163 	float coslat1 = f->h.f_coslat;
2164 	float r;
2165 
2166 	float lat2, lon2, coslat2;
2167 
2168 	if (!(pb->flags & F_HASPOS)) /* packet with a position.. (msgs with RECEIVER's position) */
2169 		return 0;
2170 
2171 	lat2    = pb->lat;
2172 	lon2    = pb->lng;
2173 	coslat2 = pb->cos_lat;
2174 
2175 	r = maidenhead_km_distance(lat1, coslat1, lon1, lat2, coslat2, lon2);
2176 
2177 	// hlog(LOG_DEBUG, "r: lalo: %.4f %.4f / reflalo: %.4f %.4f / dist: %.2f", rad2deg(lat2),rad2deg(lon2), rad2deg(lat1), rad2deg(lon1), r);
2178 
2179 	if (r < f->h.f_dist)  /* Range is less than given limit */
2180 		return (f->h.negation) ? 2 : 1;
2181 
2182 	return 0;
2183 }
2184 
filter_process_one_s(struct client_t * c,struct pbuf_t * pb,struct filter_t * f)2185 static int filter_process_one_s(struct client_t *c, struct pbuf_t *pb, struct filter_t *f)
2186 {
2187 	/* s/pri/alt/over  	Symbol filter
2188 
2189 	   pri = symbols in primary table
2190 	   alt = symbols in alternate table
2191 	   over = overlay character (case sensitive)
2192 
2193 	   For example:
2194 	   s/->   This will pass all House and Car symbols (primary table)
2195 	   s//#   This will pass all Digi with or without overlay
2196 	   s//#/T This will pass all Digi with overlay of capital T
2197 
2198 	   About 10-15 s-filters in entire APRS-IS core at any given time.
2199 	   Up to 520 invocations per second at peak.
2200 	*/
2201 	const char symtable = (pb->symbol[0] == '/') ? '/' : '\\';
2202 	const char symcode  = pb->symbol[1];
2203 	const char symolay  = (pb->symbol[0] != symtable) ? pb->symbol[0] : 0;
2204 
2205 	// hlog( LOG_DEBUG, "s-filt %c|%c|%c  %s", symtable, symcode, symolay ? symolay : '-', f->h.text );
2206 
2207 	if (f->h.len1 != 0) {
2208 		/* Primary table symbols */
2209 		if ( symtable == '/' &&
2210 		     memchr(f->h.text+f->h.len1s, symcode, f->h.len1) != NULL )
2211 			return f->h.negation ? 2 : 1;
2212 		// return 0;
2213 	}
2214 	if (f->h.lens.len3 != 0) {
2215 		/* Secondary table with overlay */
2216 		if ( memchr(f->h.text+f->h.lens.len3s, symolay, f->h.lens.len3) == NULL )
2217 			return 0; // No match on overlay
2218 		if ( memchr(f->h.text+f->h.lens.len2s, symcode, f->h.lens.len2) == NULL )
2219 			return 0; // No match on overlay
2220 		return f->h.negation ? 2 : 1;
2221 	}
2222 	/* OK, no overlay... */
2223 	if (f->h.lens.len2 != 0) {
2224 		/* Secondary table symbols */
2225 		if ( symtable == '\\' &&
2226 		     memchr(f->h.text+f->h.lens.len2s, symcode, f->h.lens.len2) != NULL )
2227 			return f->h.negation ? 2 : 1;
2228 	}
2229 	/* No match */
2230 	return 0;
2231 }
2232 
filter_process_one_t(struct client_t * c,struct pbuf_t * pb,struct filter_t * f)2233 static int filter_process_one_t(struct client_t *c, struct pbuf_t *pb, struct filter_t *f)
2234 {
2235 	/* [-]t/poimntqsu
2236 	   [-]t/poimntqsu/call/km
2237 
2238 	   Type filter 	Pass all traffic based on packet type.
2239 	   One or more types can be defined at the same time, t/otq
2240 	   is a valid definition.
2241 
2242 	   c = CWOP (local extension)
2243 	   * = ALL  (local extension)
2244 
2245 	   i = Items
2246 	   m = Message
2247 	   n = NWS Weather & Weather Objects
2248 	   o = Objects
2249 	   p = Position packets
2250 	   q = Query
2251 	   s = Status
2252 	   t = Telemetry
2253 	   u = User-defined
2254 	   w = Weather
2255 
2256 	   Note: The weather type filter also passes positions packets
2257 	   for positionless weather packets.
2258 
2259 	   The second format allows putting a radius limit around "call"
2260 	   (station callsign-SSID or object name) for the requested station
2261 	   types.
2262 
2263 	   About 40-60 s-filters in entire APRS-IS core at any given time.
2264 	   Up to 2100 invocations per second at peak.
2265 
2266 	   For the second format perhaps 2-3 in APRS-IS at any time.
2267 	   (mapping to 60-100 invocations per second)
2268 
2269 	   Usage examples:
2270 
2271 	   -t/c              Everything except CWOP
2272 	    t/.*./OH2RDY/50  Everything within 50 km of OH2RDY's last known position
2273 	                     ("." is dummy addition for C comments..)
2274 	*/
2275 	int rc = 0;
2276 	if (pb->packettype & f->h.bitflags) /* bitflags as comparison bitmask */
2277 		rc = 1;
2278 
2279 	if (!rc && (f->h.bitflags & T_WX) && (pb->flags & F_HASPOS)) {
2280 		/* "Note: The weather type filter also passes positions packets
2281 		//        for positionless weather packets."
2282 		//
2283 		// 1) recognize positionless weather packets
2284 		// 2) register their source callsigns, do this in  input_parse
2285 		// 3) when filtering for weather data, check non-weather
2286 		//    recognized packets against the database in point 2
2287 		// 4) pass on packets matching point 3
2288 		*/
2289 
2290 		rc = filter_wx_lookup(pb);
2291 	}
2292 	/* Either it stops here, or it continues... */
2293 
2294 	if (rc && f->h.type == 'T') { /* Within a range of callsign ?
2295 				       * Rather rare..  perhaps 2-3 in APRS-IS.
2296 				       */
2297 		const char *callsign    = f->h.refcallsign.callsign;
2298 		const int   callsignlen = f->h.refcallsign.reflen;
2299 		float range, r;
2300 		float lat1, lon1, coslat1;
2301 		float lat2, lon2, coslat2;
2302 		struct history_cell_t *history;
2303 		int i;
2304 
2305 		/* hlog(LOG_DEBUG, "Type filter with callsign range used! '%s'", f->h.text); */
2306 
2307 		if (!(pb->flags & F_HASPOS)) /* packet with a position.. (msgs with RECEIVER's position) */
2308 			return 0; /* No positional data.. */
2309 
2310 		range = f->h.f_dist;
2311 
2312 		/* So..  Now we have a callsign, and we have range.
2313 		   Lets find callsign's location, and range to that item..
2314 		   .. 60-100 lookups per second. */
2315 
2316 		if (f->h.hist_age < tick || f->h.hist_age > tick + HIST_LOOKUP_INTERVAL) {
2317 			i = historydb_lookup( callsign, callsignlen, &history );
2318 			f->h.numnames = i;
2319 
2320 			/* hlog( LOG_DEBUG, "Type filter with callsign range used! call='%s', range=%.1f position %sfound",
2321 			//       callsign, range, i ? "" : "not ");
2322 			*/
2323 
2324 
2325 			if (!i) return 0; /* no lookup result.. */
2326 			f->h.hist_age = tick + HIST_LOOKUP_INTERVAL;
2327 			f->h.f_latN   = history->lat;
2328 			f->h.f_lonE   = history->lon;
2329 			f->h.f_coslat = history->coslat;
2330 		}
2331 		if (!f->h.numnames) return 0; /* No valid data at range center position cache */
2332 
2333 		lat1    = f->h.f_latN;
2334 		lon1    = f->h.f_lonE;
2335 		coslat1 = f->h.f_coslat;
2336 
2337 		lat2    = pb->lat;
2338 		lon2    = pb->lng;
2339 		coslat2 = pb->cos_lat;
2340 
2341 		r = maidenhead_km_distance(lat1, coslat1, lon1, lat2, coslat2, lon2);
2342 
2343 		if (r < range)  /* Range is less than given limit */
2344 			return (f->h.negation) ? 2 : 1;
2345 
2346 		return 0; /* unimplemented! */
2347 	}
2348 
2349 	return (f->h.negation ? (rc+rc) : rc);
2350 }
2351 
filter_process_one_u(struct client_t * c,struct pbuf_t * pb,struct filter_t * f)2352 static int filter_process_one_u(struct client_t *c, struct pbuf_t *pb, struct filter_t *f)
2353 {
2354 	/* u/unproto1/unproto2/...  	Unproto filter
2355 
2356 	   This filter passes all packets with the specified destination
2357 	   callsign-SSID(s) (also known as the To call or unproto call).
2358 	   Supports * wild card.
2359 
2360 	   Seen hardly ever in APRS-IS core, some rare instances in Tier-2.
2361 	*/
2362 
2363 	struct filter_refcallsign_t ref;
2364 	const char *d = pb->srccall_end+1;
2365 	int i;
2366 
2367 	i = pb->dstcall_len;
2368 
2369 	if (i > CALLSIGNLEN_MAX) i = CALLSIGNLEN_MAX;
2370 
2371 	/* hlog( LOG_INFO, "unproto:  '%.*s' -> '%.*s'",
2372 	//       (int)(pb->packet_len < 30 ? pb->packet_len : 30), pb->data, (int)i, d);
2373 	*/
2374 
2375 	/* destination address  ">addr," */
2376 	memcpy( ref.callsign,   d, i);
2377 	memset( ref.callsign+i, 0, sizeof(ref.callsign)-i );
2378 
2379 	return filter_match_on_callsignset(&ref, i, f, MatchWild);
2380 }
2381 
filter_process_one(struct client_t * c,struct pbuf_t * pb,struct filter_t * f)2382 static int filter_process_one(struct client_t *c, struct pbuf_t *pb, struct filter_t *f)
2383 {
2384 	int rc = 0;
2385 
2386 	switch (f->h.type) {
2387 
2388 	case 'a':
2389 	case 'A':
2390 		rc = filter_process_one_a(c, pb, f);
2391 		break;
2392 
2393 	case 'b':
2394 	case 'B':
2395 		rc = filter_process_one_b(c, pb, f);
2396 		break;
2397 
2398 	case 'd':
2399 	case 'D':
2400 		rc = filter_process_one_d(c, pb, f);
2401 		break;
2402 
2403 	case 'e':
2404 	case 'E':
2405 		rc = filter_process_one_e(c, pb, f);
2406 		break;
2407 
2408 	case 'f':
2409 	case 'F':
2410 		rc = filter_process_one_f(c, pb, f);
2411 		break;
2412 
2413 	case 'g':
2414 	case 'G':
2415 		rc = filter_process_one_g(c, pb, f);
2416 		break;
2417 
2418 	case 'm':
2419 	case 'M':
2420 		rc = filter_process_one_m(c, pb, f);
2421 		break;
2422 
2423 	case 'o':
2424 	case 'O':
2425 		rc = filter_process_one_o(c, pb, f);
2426 		break;
2427 
2428 	case 'p':
2429 	case 'P':
2430 		rc = filter_process_one_p(c, pb, f);
2431 		break;
2432 
2433 	case 'q':
2434 	case 'Q':
2435 		rc = filter_process_one_q(c, pb, f);
2436 		break;
2437 
2438 	case 'r':
2439 	case 'R':
2440 		rc = filter_process_one_r(c, pb, f);
2441 		break;
2442 
2443 	case 's':
2444 	case 'S':
2445 		rc = filter_process_one_s(c, pb, f);
2446 		break;
2447 
2448 	case 't':
2449 	case 'T':
2450 		rc = filter_process_one_t(c, pb, f);
2451 		break;
2452 
2453 	case 'u':
2454 	case 'U':
2455 		rc = filter_process_one_u(c, pb, f);
2456 		break;
2457 
2458 	default:
2459 		rc = -1;
2460 		break;
2461 	}
2462 	//hlog(LOG_DEBUG, "filter '%s'  rc=%d", f->h.text, rc);
2463 
2464 	return rc;
2465 }
2466 
filter_process(struct worker_t * self,struct client_t * c,struct pbuf_t * pb)2467 int filter_process(struct worker_t *self, struct client_t *c, struct pbuf_t *pb)
2468 {
2469 	struct filter_t *f;
2470 
2471 	/* messaging support: if (1) this is a text message,
2472 	 * (2) the client is an igate port,
2473 	 * and (3) the message's recipient has been heard
2474 	 * recently on the port, gate the message.
2475 	 */
2476 	if (c->flags & CLFLAGS_IGATE) {
2477 		if (pb->packettype & T_MESSAGE) {
2478 			if (
2479 				(pb->dstname_len == c->username_len && memcmp(pb->dstname, c->username, c->username_len) == 0)
2480 				|| (client_heard_check(c, pb->dstname, pb->dstname_len, pb->dstname_hash))
2481 			) {
2482 				/* insert the source callsign to the courtesy position list */
2483 				client_courtesy_update(c, pb);
2484 				return 1;
2485 			}
2486 		}
2487 		/* Courtesy position: if a message from this source callsign has been
2488 		 * passed to this socket within 30 minutes, do pass on the next
2489 		 * single position packet, too.
2490 		 */
2491 		if (pb->packettype & (T_POSITION|T_OBJECT|T_ITEM)
2492 			&& client_courtesy_needed(c, pb)) {
2493 				FILTER_CLIENT_DEBUG(self, c, "# courtesy position after message\r\n", NULL);
2494 				return 1;
2495 		}
2496 		/* If the source callsign of a packet having TCPIP* in the path has been
2497 		 * recently heard on this socket, do pass on the packets to this socket too.
2498 		 * This lets igates know that the station is also available on the Internet,
2499 		 * and no TX igating to RF should be done.
2500 		 */
2501 		if ((pb->flags & F_HAS_TCPIP) && client_heard_check(c, pb->data, pb->srccall_end - pb->data, pb->srccall_hash)) {
2502 			FILTER_CLIENT_DEBUG(self, c, "# igate support TCPIP* packet from a heard station\r\n", NULL);
2503 			return 1;
2504 		}
2505 	}
2506 
2507 	f = c->negdefaultfilters;
2508 	for ( ; f; f = f->h.next ) {
2509 		int rc = filter_process_one(c, pb, f);
2510 		/* no reports to user about bad filters.. */
2511 		if (rc > 0)
2512 			return 0; // match on filter - no output on client
2513 	}
2514 
2515 	f = c->posdefaultfilters;
2516 	for ( ; f; f = f->h.next ) {
2517 		int rc = filter_process_one(c, pb, f);
2518 		/* no reports to user about bad filters.. */
2519 		if (rc > 0) {
2520 			FILTER_CLIENT_DEBUG(self, c, "# matched server default filter %s\r\n", f->h.text);
2521 			return rc;
2522 		}
2523 	}
2524 
2525 	f = c->neguserfilters;
2526 	for ( ; f; f = f->h.next ) {
2527 		int rc = filter_process_one(c, pb, f);
2528 		if (rc < 0) {
2529 			rc = client_bad_filter_notify(self, c, f->h.text);
2530 			if (rc < 0) /* possibly the client got destroyed here! */
2531 				return rc;
2532 		}
2533 		if (rc > 0) {
2534 			FILTER_CLIENT_DEBUG(self, c, "# matched negative filter %s\r\n", f->h.text);
2535 			return 0; // match on filter - no output on client
2536 		}
2537 	}
2538 
2539 	f = c->posuserfilters;
2540 	for ( ; f; f = f->h.next ) {
2541 		int rc = filter_process_one(c, pb, f);
2542 		if (rc < 0) {
2543 			rc = client_bad_filter_notify(self, c, f->h.text);
2544 			if (rc < 0) /* possibly the client got destroyed here! */
2545 				return rc;
2546 		}
2547 		if (rc > 0) {
2548 			FILTER_CLIENT_DEBUG(self, c, "# matched filter %s\r\n", f->h.text);
2549 			return rc;
2550 		}
2551 	}
2552 
2553 	return 0;
2554 }
2555 
2556 /*
2557  *	Send a reply to a filter command, either using a message or through a comment
2558  *	line on the IS stream
2559  */
2560 
filter_command_reply(struct worker_t * self,struct client_t * c,int in_message,const char * fmt,...)2561 static int filter_command_reply(struct worker_t *self, struct client_t *c, int in_message, const char *fmt, ...)
2562 {
2563 	va_list args;
2564 	char s[PACKETLEN_MAX];
2565 
2566 	va_start(args, fmt);
2567 	vsnprintf(s, PACKETLEN_MAX, fmt, args);
2568 	va_end(args);
2569 
2570 	if (!in_message)
2571 		return client_printf(self, c, "# %s\r\n", s);
2572 
2573 	return messaging_message_client(self, c, "%s", s);
2574 }
2575 
2576 /*
2577  *	filter_commands() implements treatment for incoming client filter requests.
2578  *
2579  *	Return value propagates negative returns from things like  client_write()
2580  *	indicating the struct client_t * object being destroyed.
2581  */
filter_commands(struct worker_t * self,struct client_t * c,int in_message,const char * s,int len)2582 int filter_commands(struct worker_t *self, struct client_t *c, int in_message, const char *s, int len)
2583 {
2584 	char *argv[256];
2585 	struct filter_t *f;
2586 	char *b, *p;
2587 	int i, argc;
2588 
2589 	/* skip over the #filter in the beginning of the command */
2590 	len -= 6;
2591 	s   += 6;
2592 
2593 	if ( *s == '?' && len == 1 ) {
2594 		/* Query current filters */
2595 		int lensum = 0;
2596 
2597 		for (f = c->neguserfilters; f; f = f->h.next) {
2598 			lensum += 2 + strlen(f->h.text);
2599 		}
2600 		for (f = c->posuserfilters; f; f = f->h.next) {
2601 			lensum += 2 + strlen(f->h.text);
2602 		}
2603 
2604 		p = b = alloca(lensum+20);
2605 		p += sprintf(b, "# filters: ");
2606 		for (f = c->neguserfilters; f; f = f->h.next) {
2607 			p += sprintf(p, "%s ", f->h.text);
2608 		}
2609 		for (f = c->posuserfilters; f; f = f->h.next) {
2610 			p += sprintf(p, "%s ", f->h.text);
2611 		}
2612 		p += sprintf(p, "\r\n");
2613 		/* client can be destroyed here.. */
2614 		return c->write(self, c, b, (int)(p-b));
2615 	}
2616 	if (*s != ' ') {
2617 		return filter_command_reply(self, c, in_message, "Filter: Bad input, no space character after filter command");
2618 	}
2619 	++s;
2620 	--len;
2621 
2622 	if ( strncasecmp(s, "default", 7) == 0 && len == 7 ) {
2623 		/* discard any user defined filters that possibly were
2624 		   injected on this connection.  */
2625 		f = c->neguserfilters;
2626 		filter_free(f);
2627 		c->neguserfilters = NULL;
2628 
2629 		f = c->posuserfilters;
2630 		filter_free(f);
2631 		c->posuserfilters = NULL;
2632 		// FIXME: Sleep a bit ? ... no, that would be a way to create a denial of service attack
2633 		// FIXME: there is a danger of SEGV-blowing filter processing...
2634 		return filter_command_reply(self, c, in_message, "User filters reset to default");
2635 	}
2636 
2637 	/* new filter definitions to supersede previous ones */
2638 
2639 	/* Discard old ones. */
2640 	f = c->neguserfilters;
2641 	filter_free(f);
2642 	c->neguserfilters = NULL;
2643 
2644 	f = c->posuserfilters;
2645 	c->posuserfilters = NULL;
2646 	filter_free(f);
2647 	// FIXME: Sleep a bit ? ... no, that would be a way to create a denial of service attack
2648 	// FIXME: there is a danger of SEGV-blowing filter processing...
2649 
2650 	b = hmalloc(len+2);
2651 	memcpy(b, s, len);
2652 	b[len] = 0;
2653 
2654 	// archive a copy of the filters, for status display
2655 	strncpy(c->filter_s, b, FILTER_S_SIZE);
2656 	c->filter_s[FILTER_S_SIZE-1] = 0;
2657 	sanitize_ascii_string(c->filter_s);
2658 
2659 	argc = parse_args( argv, b );
2660 	for (i = 0; i < argc; ++i) {
2661 		filter_parse(c, argv[i], 1); /* user filters */
2662 	}
2663 	hfree(b);
2664 
2665 	return filter_command_reply(self, c, in_message, "filter %s active", c->filter_s);
2666 }
2667 
2668 /*
2669  *	cellmalloc status
2670  */
2671 
2672 #ifndef _FOR_VALGRIND_
filter_cell_stats(struct cellstatus_t * filter_cellst,struct cellstatus_t * filter_entrycall_cellst,struct cellstatus_t * filter_wx_cellst)2673 void filter_cell_stats(struct cellstatus_t *filter_cellst,
2674 	struct cellstatus_t *filter_entrycall_cellst,
2675 	struct cellstatus_t *filter_wx_cellst)
2676 {
2677 	cellstatus(filter_cells, filter_cellst);
2678 	cellstatus(filter_entrycall_cells, filter_entrycall_cellst);
2679 	cellstatus(filter_wx_cells, filter_wx_cellst);
2680 }
2681 #endif
2682