libfap  1.4
fap.c
Go to the documentation of this file.
1 /* $Id: fap.c 226 2014-11-23 12:33:36Z oh2gve $
2  *
3  * Copyright 2005-2012 Tapio Sokura
4  * Copyright 2007-2012 Heikki Hannikainen
5  *
6  * Perl-to-C modifications
7  * Copyright 2009-2014 Tapio Aaltonen
8  *
9  * This file is part of libfap.
10  *
11  * Libfap is free software; you can redistribute it and/or modify it under the
12  * terms of either:
13  *
14  * a) the GNU General Public License as published by the Free Software
15  * Foundation; either version 1, or (at your option) any later
16  * version, or
17  *
18  * b) the "Artistic License".
19  *
20  * Both licenses can be found in the licenses directory of this source code
21  * package.
22  *
23  * APRS is a registered trademark of APRS Software and Bob Bruninga, WB4APR.
24 */
25 
75 #include "fap.h"
76 #include "helpers.h"
77 #include "helpers2.h"
78 #include "regs.h"
79 #ifdef HAVE_CONFIG_H
80 #include <config.h>
81 #endif
82 
83 #include <stdlib.h>
84 #include <string.h>
85 #include <regex.h>
86 #include <ctype.h>
87 #include <math.h>
88 #include <stdio.h>
89 
90 
92 #define PI 3.14159265
93 
94 #define DEG2RAD(x) (x/360*2*PI)
95 
96 #define RAD2DEG(x) (x*(180/PI))
97 
99 #define FEND 0xc0
100 
101 #define FESC 0xdb
102 
103 #define TFEND 0xdc
104 
105 #define TFESC 0xdd
106 
107 #define FRAME_MAXLEN 512
108 
110 #define AX25_FRAME_UI 0x03
111 
112 #define AX25_PID_APRS 0xf0
113 
114 
115 
116 /* Regexs needed by helpers. */
117 regex_t fapint_regex_header, fapint_regex_ax25call, fapint_regex_digicall, fapint_regex_digicallv6;
118 regex_t fapint_regex_normalpos, fapint_regex_normalamb, fapint_regex_timestamp;
119 regex_t fapint_regex_mice_dstcall, fapint_regex_mice_body, fapint_regex_mice_amb;
120 regex_t fapint_regex_comment, fapint_regex_phgr, fapint_regex_phg, fapint_regex_rng, fapint_regex_altitude;
121 regex_t fapint_regex_mes_dst, fapint_regex_mes_ack, fapint_regex_mes_nack;
122 regex_t fapint_regex_wx1, fapint_regex_wx2, fapint_regex_wx3, fapint_regex_wx4, fapint_regex_wx5;
123 regex_t fapint_regex_wx_r1, fapint_regex_wx_r24, fapint_regex_wx_rami;
124 regex_t fapint_regex_wx_humi, fapint_regex_wx_pres, fapint_regex_wx_lumi, fapint_regex_wx_what;
125 regex_t fapint_regex_wx_snow, fapint_regex_wx_rrc, fapint_regex_wx_any, fapint_regex_wx_soft;
126 regex_t fapint_regex_nmea_chksum, fapint_regex_nmea_dst, fapint_regex_nmea_time, fapint_regex_nmea_date;
127 regex_t fapint_regex_nmea_specou, fapint_regex_nmea_fix, fapint_regex_nmea_altitude, fapint_regex_nmea_flag, fapint_regex_nmea_coord;
128 regex_t fapint_regex_telemetry, fapint_regex_peet_splitter, fapint_regex_kiss_callsign, fapint_regex_kiss_digi;
129 regex_t fapint_regex_base91_telemetry;
130 
131 /* Regex needed in this file. */
132 regex_t fapint_regex_detect_comp, fapint_regex_detect_wx, fapint_regex_detect_telem, fapint_regex_detect_exp;
133 regex_t fapint_regex_kiss_hdrbdy, fapint_regex_hdr_detail;
134 regex_t fapint_regex_hopcount1, fapint_regex_hopcount2;
135 
136 /* Regex status flag. */
137 short fapint_initialized = 0;
138 
139 
140 
141 fap_packet_t* fap_parseaprs(char const* input, unsigned int const input_len, short const is_ax25)
142 {
143  fap_packet_t* result;
144  int i, pos;
145  unsigned int splitpos, body_len;
146  char* body;
147  char* tmp;
148  char poschar, typechar;
149 
150  /* Check initialization status. */
151  if ( !fapint_initialized )
152  {
153  return NULL;
154  }
155 
156  /* Create empty packet to be returned. */
157  result = fapint_create_packet();
158 
159  /* Check for missing params. */
160  if ( input == NULL || input_len == 0 )
161  {
162  result->error_code = malloc(sizeof(fap_error_code_t));
163  if ( result->error_code ) *result->error_code = fapPACKET_NO;
164  return result;
165  }
166 
167  /* Save the original packet. */
168  result->orig_packet = malloc(input_len);
169  result->orig_packet_len = input_len;
170  memcpy(result->orig_packet, input, input_len);
171 
172  /* Find the end of header checking for NULL bytes while doing it. */
173  splitpos = 0;
174  for ( i = 0; i < input_len; ++i )
175  {
176  if ( input[i] == 0 )
177  {
178  result->error_code = malloc(sizeof(fap_error_code_t));
179  if ( result->error_code ) *result->error_code = fapPACKET_INVALID;
180  return result;
181  }
182  if ( input[i] == ':' )
183  {
184  splitpos = i;
185  break;
186  }
187  }
188  /* Check that end was found and body has at least one byte. */
189  if ( splitpos == 0 || splitpos + 1 == input_len )
190  {
191  result->error_code = malloc(sizeof(fap_error_code_t));
192  if ( result->error_code ) *result->error_code = fapPACKET_NOBODY;
193  return result;
194  }
195 
196  /* Save header and body. */
197  result->header = fapint_remove_part(input, input_len, splitpos, input_len, &body_len);
198  result->body = fapint_remove_part(input, input_len, 0, splitpos+1, &result->body_len);
199 
200  /* Parse source, target and path. */
201  if ( !fapint_parse_header(result, is_ax25) )
202  {
203  return result;
204  }
205 
206  /* Create 0-terminated working copy of body. Remember that this added 0 is not always the first 0 in body. */
207  body_len = result->body_len;
208  body = malloc(body_len + 1);
209  memcpy(body, result->body, body_len);
210  body[body_len] = 0;
211 
212  /* Detect packet type char. */
213  typechar = body[0];
214 
215  /* Check for mic-e packet. */
216  if ( (typechar == 0x27 || typechar == 0x60) &&
217  body_len >= 9 )
218  {
219  result->type = malloc(sizeof(fap_packet_type_t));
220  if ( !result->type ) return result;
221  *result->type = fapLOCATION; /* not fapMICE, lol */
222  fapint_parse_mice(result, body+1, body_len-1);
223  }
224  /* Check for normal or compressed location packet. */
225  else if ( typechar == '!' || typechar == '=' || typechar == '/' || typechar == '@' )
226  {
227  /* Check for messaging. */
228  result->messaging = malloc(sizeof(short));
229  if ( !result->messaging ) return result;
230  if ( typechar == '=' || typechar == '@' )
231  {
232  *result->messaging = 1;
233  }
234  else
235  {
236  *result->messaging = 0;
237  }
238  /* Validate body. */
239  if ( body_len >= 14 )
240  {
241  result->type = malloc(sizeof(fap_packet_type_t));
242  if ( !result->type ) return result;
243  *result->type = fapLOCATION;
244  /* Check for timestamp. We use i as obfuscated status flag. Sorry. */
245  i = 1; /* we has no error */
246  if ( typechar == '/' || typechar == '@' )
247  {
248  /* Parse and remove those 7 bytes, removing also the typechar byte. */
249  result->timestamp = malloc(sizeof(time_t));
250  if ( !result->timestamp ) return result;
251  *result->timestamp = fapint_parse_timestamp(body+1);
252  if ( *result->timestamp == 0 )
253  {
254  result->error_code = malloc(sizeof(fap_error_code_t));
255  if ( result->error_code ) *result->error_code = fapTIMESTAMP_INV_LOC;
256  i = 0; /* we has error */
257  }
258  result->raw_timestamp = malloc(7);
259  if ( !result->raw_timestamp ) return result;
260  memcpy(result->raw_timestamp, body+1, 6);
261  result->raw_timestamp[6] = 0;
262  tmp = fapint_remove_part(body, body_len, 0, 8, &body_len);
263  free(body);
264  body = tmp;
265  }
266  else
267  {
268  /* Remove only typechar byte. */
269  tmp = fapint_remove_part(body, body_len, 0, 1, &body_len);
270  free(body);
271  body = tmp;
272  }
273 
274  /* If timestamp check didn't fail, go on with location parsing. */
275  if ( i )
276  {
277  /* Get position type character. */
278  poschar = body[0];
279 
280  /* Detect position type. */
281  if ( poschar >= 48 && poschar <= 57 )
282  {
283  /* It's normal position. */
284  if ( body_len >= 19 )
285  {
286  i = fapint_parse_normal(result, body);
287  /* Check for comments or wx report. */
288  if ( body_len > 19 && i && result->symbol_code != '_' )
289  {
290  fapint_parse_comment(result, body+19, body_len-19);
291  }
292  else if ( body_len > 19 && i )
293  {
294  fapint_parse_wx(result, body+19, body_len-19);
295  }
296  }
297  }
298  else if ( poschar == 47 || poschar == 92 || (poschar >= 65 && poschar <= 90) || (poschar >= 97 && poschar <= 106) )
299  {
300  /* It's compressed position. */
301  if ( body_len >= 13 )
302  {
303  i = fapint_parse_compressed(result, body);
304  /* Check for comment or wx report. */
305  if ( body_len > 13 && i && result->symbol_code != '_' )
306  {
307  fapint_parse_comment(result, body+13, body_len-13);
308  }
309  else if ( body_len > 13 && i )
310  {
311  fapint_parse_wx(result, body+13, body_len-13);
312  }
313  }
314  else
315  {
316  result->error_code = malloc(sizeof(fap_error_code_t));
317  if ( result->error_code ) *result->error_code = fapCOMP_SHORT;
318  }
319  }
320  else if ( poschar == 33 )
321  {
322  /* Weather report from Ultimeter 2000 */
323  if ( result->type == NULL )
324  {
325  result->type = malloc(sizeof(fap_packet_type_t));
326  if ( !result->type ) return result;
327  }
328  *result->type = fapWX;
329  fapint_parse_wx_peet_logging(result, body+1);
330  }
331  else
332  {
333  /* Does not match any known type. */
334  result->error_code = malloc(sizeof(fap_error_code_t));
335  if ( result->error_code ) *result->error_code = fapPACKET_INVALID;
336  }
337  }
338  }
339  else
340  {
341  result->error_code = malloc(sizeof(fap_error_code_t));
342  if ( result->error_code ) *result->error_code = fapPACKET_SHORT;
343  }
344  }
345  /* Check for NMEA data packet. */
346  else if ( typechar == '$' )
347  {
348  if ( body_len > 3 && body[0] == '$' && body[1] == 'G' && body[2] == 'P' )
349  {
350  result->type = malloc(sizeof(fap_packet_type_t));
351  if ( !result->type ) return result;
352  *result->type = fapLOCATION; /* not fapNMEA, lol */
353  fapint_parse_nmea(result, body+1, body_len-1);
354  }
355  else if ( body_len > 5 && body[0] == '$' && body[1] == 'U' && body[2] == 'L' && body[3] == 'T' && body[4] == 'W' )
356  {
357  result->type = malloc(sizeof(fap_packet_type_t));
358  if ( !result->type ) return result;
359  *result->type = fapWX;
360  fapint_parse_wx_peet_packet(result, body+5);
361  }
362  }
363  /* Check for object packet. */
364  else if ( typechar == ';' )
365  {
366  if ( body_len >= 31 )
367  {
368  result->type = malloc(sizeof(fap_packet_type_t));
369  if ( !result->type ) return result;
370  *result->type = fapOBJECT;
371  fapint_parse_object(result, body, body_len);
372  }
373  }
374  /* Check for item packet. */
375  else if ( typechar == ')' )
376  {
377  if ( body_len >= 18 )
378  {
379  result->type = malloc(sizeof(fap_packet_type_t));
380  if ( !result->type ) return result;
381  *result->type = fapITEM;
382  fapint_parse_item(result, body, body_len);
383  }
384  }
385  /* Check for message, bulletin or announcement packet. */
386  else if ( typechar == ':' )
387  {
388  if ( body_len >= 11 )
389  {
390  /* All are labeled as messages for the time being. */
391  result->type = malloc(sizeof(fap_packet_type_t));
392  if ( !result->type ) return result;
393  *result->type = fapMESSAGE;
394  fapint_parse_message(result, body, body_len);
395  }
396  }
397  /* Check for capabilities packet. */
398  else if ( typechar == '<' )
399  {
400  /* At least one other character besides '<' required. */
401  if ( body_len >= 2 )
402  {
403  result->type = malloc(sizeof(fap_packet_type_t));
404  if ( !result->type ) return result;
405  *result->type = fapCAPABILITIES;
406  fapint_parse_capabilities(result, body+1, body_len-1);
407  }
408  }
409  /* Check for status packet. */
410  else if ( typechar == '>' )
411  {
412  /* We can live with empty status reports. */
413  if ( body_len >= 1 )
414  {
415  result->type = malloc(sizeof(fap_packet_type_t));
416  if ( !result->type ) return result;
417  *result->type = fapSTATUS;
418  fapint_parse_status(result, body+1, body_len-1);
419  }
420  }
421  /* Check for weather packet. */
422  else if ( typechar == '_' )
423  {
424  if ( regexec(&fapint_regex_detect_wx, body, 0, NULL, 0) == 0 )
425  {
426  result->type = malloc(sizeof(fap_packet_type_t));
427  if ( !result->type ) return result;
428  *result->type = fapWX;
429  fapint_parse_wx(result, body+9, body_len-9);
430  }
431  else
432  {
433  result->error_code = malloc(sizeof(fap_error_code_t));
434  if ( result->error_code ) *result->error_code = fapWX_UNSUPP;
435  }
436  }
437  /* Check for telemetry packet. */
438  else if ( regexec(&fapint_regex_detect_telem, body, 0, NULL, 0) == 0 )
439  {
440  result->type = malloc(sizeof(fap_packet_type_t));
441  if ( !result->type ) return result;
442  *result->type = fapTELEMETRY;
443  fapint_parse_telemetry(result, body+2);
444  }
445  /* Check for experimental packet. */
446  else if ( regexec(&fapint_regex_detect_exp, body, 0, NULL, 0) == 0 )
447  {
448  result->type = malloc(sizeof(fap_packet_type_t));
449  if ( !result->type ) return result;
450  *result->type = fapEXPERIMENTAL;
451  result->error_code = malloc(sizeof(fap_error_code_t));
452  if ( result->error_code ) *result->error_code = fapEXP_UNSUPP;
453  }
454  /* Check for third party packets. */
455  else if ( typechar == '}' )
456  {
457  /* Come here to avoid the "when all else fails" option. */
458  }
459  /* When all else fails, try to look for a !-position that can occur
460  anywhere within the 40 first characters according to the spec. */
461  else
462  {
463  tmp = strchr(body, '!');
464  if ( tmp != NULL && (pos = tmp-body) < 40 && pos+1 < body_len ) /* Check that pos is not last char. */
465  {
466  result->type = malloc(sizeof(fap_packet_type_t));
467  if ( !result->type ) return result;
468  *result->type = fapLOCATION;
469  poschar = tmp[1];
470 
471  /* Detect position type. */
472  if ( poschar == 47 || poschar == 92 || (poschar >= 65 && poschar <= 90) || (poschar >= 97 && poschar <= 106) )
473  {
474  /* It's compressed position. */
475  if ( body_len >= pos + 1 + 13 )
476  {
477  i = fapint_parse_compressed(result, body+pos+1);
478  /* Check for comment. */
479  if ( body_len - (pos+1) > 13 && i && result->symbol_code != '_' )
480  {
481  fapint_parse_comment(result, body+pos+1+13, body_len-pos-1-13);
482  }
483  }
484  }
485  else if ( isdigit(poschar) )
486  {
487  /* It's normal position. */
488  if ( body_len >= pos + 1 + 19 )
489  {
490  i = fapint_parse_normal(result, tmp+1);
491  /* Check for comment. */
492  if ( body_len - (pos+1) > 19 && i && result->symbol_code != '_' )
493  {
494  fapint_parse_comment(result, body+pos+1+19, body_len-pos-1-19);
495  }
496  }
497  }
498  }
499  else
500  {
501  /* No luck. It's propably not APRS packet at all. */
502  result->error_code = malloc(sizeof(fap_error_code_t));
503  if ( result->error_code ) *result->error_code = fapNO_APRS;
504  }
505  }
506 
507  /* We're done. */
508  free(body);
509 
510  return result;
511 }
512 
513 
514 
515 void fap_explain_error(fap_error_code_t const error, char* output)
516 {
517  /* Dummy check. */
518  if ( output == NULL )
519  {
520  return;
521  }
522 
523  switch (error)
524  {
525  case fapPACKET_NO:
526  sprintf(output, "No packet given to parse");
527  break;
528  case fapPACKET_SHORT:
529  sprintf(output, "Too short packet");
530  break;
531  case fapPACKET_NOBODY:
532  sprintf(output, "No body in packet");
533  break;
534 
535  case fapSRCCALL_NOAX25:
536  sprintf(output, "Source callsign is not a valid AX.25 call");
537  break;
538  case fapSRCCALL_BADCHARS:
539  sprintf(output, "Source callsign contains bad characters");
540  break;
541 
542  case fapDSTPATH_TOOMANY:
543  sprintf(output, "Too many destination path components to be AX.25");
544  break;
545  case fapDSTCALL_NONE:
546  sprintf(output, "No destination field in packet");
547  break;
548  case fapDSTCALL_NOAX25:
549  sprintf(output, "Destination callsign is not a valid AX.25 call");
550  break;
551 
552  case fapDIGICALL_NOAX25:
553  sprintf(output, "Digipeater callsign is not a valid AX.25 call");
554  break;
555  case fapDIGICALL_BADCHARS:
556  sprintf(output, "Digipeater callsign contains bad characters");
557  break;
558 
559  case fapTIMESTAMP_INV_LOC:
560  sprintf(output, "Invalid timestamp in location");
561  break;
562  case fapTIMESTAMP_INV_OBJ:
563  sprintf(output, "Invalid timestamp in object");
564  break;
565  case fapTIMESTAMP_INV_STA:
566  sprintf(output, "Invalid timestamp in status");
567  break;
568  case fapTIMESTAMP_INV_GPGGA:
569  sprintf(output, "Invalid timestamp in GPGGA sentence");
570  break;
571  case fapTIMESTAMP_INV_GPGLL:
572  sprintf(output, "Invalid timestamp in GPGLL sentence");
573  break;
574 
575  case fapPACKET_INVALID:
576  sprintf(output, "Invalid packet");
577  break;
578 
579  case fapNMEA_INV_CVAL:
580  sprintf(output, "Invalid coordinate value in NMEA sentence");
581  break;
582  case fapNMEA_LARGE_EW:
583  sprintf(output, "Too large value in NMEA sentence (east/west)");
584  break;
585  case fapNMEA_LARGE_NS:
586  sprintf(output, "Too large value in NMEA sentence (north/south)");
587  break;
588  case fapNMEA_INV_SIGN:
589  sprintf(output, "Invalid lat/long sign in NMEA sentence");
590  break;
591  case fapNMEA_INV_CKSUM:
592  sprintf(output, "Invalid checksum in NMEA sentence");
593  break;
594 
595  case fapGPRMC_FEWFIELDS:
596  sprintf(output, "Less than ten fields in GPRMC sentence");
597  break;
598  case fapGPRMC_NOFIX:
599  sprintf(output, "No GPS fix in GPRMC sentence");
600  break;
601  case fapGPRMC_INV_TIME:
602  sprintf(output, "Invalid timestamp in GPRMC sentence");
603  break;
604  case fapGPRMC_INV_DATE:
605  sprintf(output, "Invalid date in GPRMC sentence");
606  break;
607  case fapGPRMC_DATE_OUT:
608  sprintf(output, "GPRMC date does not fit in an Unix timestamp");
609  break;
610 
611  case fapGPGGA_FEWFIELDS:
612  sprintf(output, "Less than 11 fields in GPGGA sentence");
613  break;
614  case fapGPGGA_NOFIX:
615  sprintf(output, "No GPS fix in GPGGA sentence");
616  break;
617 
618  case fapGPGLL_FEWFIELDS:
619  sprintf(output, "Less than 5 fields in GPGLL sentence");
620  break;
621  case fapGPGLL_NOFIX:
622  sprintf(output, "No GPS fix in GPGLL sentence");
623  break;
624 
625  case fapNMEA_UNSUPP:
626  sprintf(output, "Unsupported NMEA sentence type");
627  break;
628 
629  case fapOBJ_SHORT:
630  sprintf(output, "Too short object");
631  break;
632  case fapOBJ_INV:
633  sprintf(output, "Invalid object");
634  break;
635  case fapOBJ_DEC_ERR:
636  sprintf(output, "Error in object location decoding");
637  break;
638 
639  case fapITEM_SHORT:
640  sprintf(output, "Too short item");
641  break;
642  case fapITEM_INV:
643  sprintf(output, "Invalid item");
644  break;
645  case fapITEM_DEC_ERR:
646  sprintf(output, "Error in item location decoding");
647  break;
648 
649  case fapLOC_SHORT:
650  sprintf(output, "Too short uncompressed location");
651  break;
652  case fapLOC_INV:
653  sprintf(output, "Invalid uncompressed location");
654  break;
655  case fapLOC_LARGE:
656  sprintf(output, "Degree value too large");
657  break;
658  case fapLOC_AMB_INV:
659  sprintf(output, "Invalid position ambiguity");
660  break;
661 
662  case fapMICE_SHORT:
663  sprintf(output, "Too short mic-e packet");
664  break;
665  case fapMICE_INV:
666  sprintf(output, "Invalid characters in mic-e packet");
667  break;
668  case fapMICE_INV_INFO:
669  sprintf(output, "Invalid characters in mic-e information field");
670  break;
671  case fapMICE_AMB_LARGE:
672  sprintf(output, "Too much position ambiguity in mic-e packet");
673  break;
674  case fapMICE_AMB_INV:
675  sprintf(output, "Invalid position ambiguity in mic-e packet");
676  break;
677  case fapMICE_AMB_ODD:
678  sprintf(output, "Odd position ambiguity in mic-e packet");
679  break;
680 
681  case fapCOMP_INV:
682  sprintf(output, "Invalid compressed packet");
683  break;
684  case fapCOMP_SHORT:
685  sprintf(output, "Short compressed packet");
686  break;
687 
688  case fapMSG_INV:
689  sprintf(output, "Invalid message packet");
690  break;
691 
692  case fapWX_UNSUPP:
693  sprintf(output, "Unsupported weather format");
694  break;
695  case fapUSER_UNSUPP:
696  sprintf(output, "Unsupported user format");
697  break;
698 
699  case fapDX_INV_SRC:
700  sprintf(output, "Invalid DX spot source callsign");
701  break;
702  case fapDX_INF_FREQ:
703  sprintf(output, "Invalid DX spot frequency");
704  break;
705  case fapDX_NO_DX:
706  sprintf(output, "No DX spot callsign found");
707  break;
708 
709  case fapTLM_INV:
710  sprintf(output, "Invalid telemetry packet");
711  break;
712  case fapTLM_LARGE:
713  sprintf(output, "Too large telemetry value");
714  break;
715  case fapTLM_UNSUPP:
716  sprintf(output, "Unsupported telemetry");
717  break;
718 
719  case fapEXP_UNSUPP:
720  sprintf(output, "Unsupported experimental");
721  break;
722  case fapSYM_INV_TABLE:
723  sprintf(output, "Invalid symbol table or overlay");
724  break;
725 
726  case fapNOT_IMPLEMENTED:
727  sprintf(output, "Sorry, feature not implemented yet.");
728  break;
729  case fapNMEA_NOFIELDS:
730  sprintf(output, "No fields in NMEA fields in NMEA packet.");
731  break;
732 
733  case fapNO_APRS:
734  sprintf(output, "Not an APRS packet");
735  break;
736 
737  default:
738  sprintf(output, "Default error message.");
739  break;
740  }
741 }
742 
743 
744 
745 void fap_mice_mbits_to_message(char const* bits, char* output)
746 {
747  /* Dummy check. */
748  if ( bits == NULL || output == NULL )
749  {
750  return;
751  }
752 
753  /* Detect known bit combinations. */
754  if ( strcmp(bits, "111") == 0 ) sprintf(output, "off duty");
755  else if ( strcmp(bits, "222") == 0 ) sprintf(output, "custom 0");
756  else if ( strcmp(bits, "110") == 0 ) sprintf(output, "en route");
757  else if ( strcmp(bits, "220") == 0 ) sprintf(output, "custom 1");
758  else if ( strcmp(bits, "101") == 0 ) sprintf(output, "in service");
759  else if ( strcmp(bits, "202") == 0 ) sprintf(output, "custom 2");
760  else if ( strcmp(bits, "100") == 0 ) sprintf(output, "returning");
761  else if ( strcmp(bits, "200") == 0 ) sprintf(output, "custom 3");
762  else if ( strcmp(bits, "011") == 0 ) sprintf(output, "committed");
763  else if ( strcmp(bits, "022") == 0 ) sprintf(output, "custom 4");
764  else if ( strcmp(bits, "010") == 0 ) sprintf(output, "special");
765  else if ( strcmp(bits, "020") == 0 ) sprintf(output, "custom 5");
766  else if ( strcmp(bits, "001") == 0 ) sprintf(output, "priority");
767  else if ( strcmp(bits, "002") == 0 ) sprintf(output, "custom 6");
768  else if ( strcmp(bits, "000") == 0 ) sprintf(output, "emergency");
769  else sprintf(output, "unknown");
770 }
771 
772 
773 
774 double fap_distance(double lon0, double lat0, double lon1, double lat1)
775 {
776  /* Convert degrees into radians. */
777  lon0 = DEG2RAD(lon0);
778  lat0 = DEG2RAD(lat0);
779  lon1 = DEG2RAD(lon1);
780  lat1 = DEG2RAD(lat1);
781 
782  /* Use the haversine formula for distance calculation
783  * http://mathforum.org/library/drmath/view/51879.html */
784  double dlon = lon1 - lon0;
785  double dlat = lat1 - lat0;
786  double a = pow(sin(dlat/2),2) + cos(lat0) * cos(lat1) * pow(sin(dlon/2), 2);
787  double c = 2 * atan2(sqrt(a), sqrt(1-a));
788 
789  return c * 6366.71; /* in kilometers */
790 }
791 
792 
793 
794 double fap_direction(double lon0, double lat0, double lon1, double lat1)
795 {
796  double direction;
797 
798  /* Convert degrees into radians. */
799  lon0 = DEG2RAD(lon0);
800  lat0 = DEG2RAD(lat0);
801  lon1 = DEG2RAD(lon1);
802  lat1 = DEG2RAD(lat1);
803 
804  /* Direction from Aviation Formulary V1.42 by Ed Williams by way of
805  * http://mathforum.org/library/drmath/view/55417.html */
806  direction = atan2(sin(lon1-lon0)*cos(lat1), cos(lat0)*sin(lat1)-sin(lat0)*cos(lat1)*cos(lon1-lon0));
807  if ( direction < 0 )
808  {
809  /* Make direction positive. */
810  direction += 2 * PI;
811  }
812 
813  return RAD2DEG(direction);
814 }
815 
816 
817 
819 {
820  int i, len;
821  unsigned int hopcount = 0, n, N;
822  short wasdigied;
823  char* element;
824  char* call_ssid;
825 
826  unsigned int const matchcount = 3;
827  regmatch_t matches[matchcount];
828 
829 
830  /* Check input. */
831  if ( !fapint_initialized || packet == NULL || packet->path == NULL )
832  {
833  return -1;
834  }
835 
836  /* Process all path elements. */
837  for ( i = 0; i < packet->path_len; ++i )
838  {
839  wasdigied = 0;
840 
841  /* Check if packet was digied due to this element. */
842  if ( regexec(&fapint_regex_hopcount1, packet->path[i], matchcount, (regmatch_t*)&matches, 0) == 0 )
843  {
844  wasdigied = 1;
845 
846  /* Save working copy of the element, but without the '*'. */
847  len = matches[1].rm_eo - matches[1].rm_so;
848  element = malloc(len+1);
849  if ( !element ) return -1;
850  memcpy(element, packet->path[i]+matches[1].rm_so, len);
851  element[len] = 0;
852 
853  /* Check the callsign for validity and expand it. */
854  call_ssid = fap_check_ax25_call(element, 1);
855  free(element);
856  }
857  else
858  {
859  call_ssid = fap_check_ax25_call(packet->path[i], 1);
860  }
861 
862  /* Check validity test result. */
863  if ( call_ssid == NULL )
864  {
865  return -1;
866  }
867 
868  /* Check for WIDEn-N. */
869  if ( regexec(&fapint_regex_hopcount2, call_ssid, matchcount, (regmatch_t*)&matches, 0) == 0 )
870  {
871  /* Get n and N by converting them from ASCII digits to numbers. */
872  n = call_ssid[matches[1].rm_so] - 48;
873  N = call_ssid[matches[2].rm_so] - 48;
874 
875  /* Add difference to hopcount, if not negative. */
876  if ( (i = n - N) >= 0 )
877  {
878  hopcount += i;
879  }
880  }
881  else
882  {
883  /* No WIDEn-N, TRACE and other things are calculated bases on the '*' indicators. */
884  if ( wasdigied )
885  {
886  hopcount++;
887  }
888  }
889 
890  /* Prepare to check next path element. */
891  free(call_ssid);
892  }
893 
894  return hopcount;
895 }
896 
897 
898 
899 char* fap_check_ax25_call(char const* input, short const add_ssid0)
900 {
901  unsigned int const matchcount = 3;
902  regmatch_t matches[matchcount];
903 
904  int ssid = 0, len;
905  char call[7], ssid_str[4];
906 
907  char* result = NULL;
908  char buf[10];
909 
910 
911  /* Check initialization status. */
912  if ( !fapint_initialized )
913  {
914  return NULL;
915  }
916 
917  /* Check input. */
918  if ( !input || !strlen(input) )
919  {
920  return NULL;
921  }
922 
923  /* Validate callsign. */
924  if ( regexec(&fapint_regex_ax25call, input, matchcount, (regmatch_t*)&matches, 0) == 0 )
925  {
926  /* Get callsign. */
927  memset(call, 0, 7);
928  len = matches[1].rm_eo - matches[1].rm_so;
929  memcpy(call, input+matches[1].rm_so, len);
930 
931  /* Get SSID. */
932  memset(ssid_str, 0, 4);
933  len = matches[2].rm_eo - matches[2].rm_so;
934  memcpy(ssid_str, input+matches[2].rm_so, len);
935 
936  /* If we got ssid, check that it is valid. */
937  if ( len )
938  {
939  ssid = atoi(ssid_str);
940  ssid = 0 - ssid;
941  if ( ssid > 15 )
942  {
943  return NULL;
944  }
945  }
946 
947  /* Create result. */
948  memset(buf, 0, 10);
949  if ( !add_ssid0 && ssid == 0 )
950  {
951  sprintf(buf, "%s", call);
952  }
953  else
954  {
955  sprintf(buf, "%s-%d", call, ssid);
956  }
957 
958  result = malloc( strlen(buf)+1 );
959  if ( !result ) return NULL;
960  strcpy(result, buf);
961  }
962 
963  /* We're done. */
964  return result;
965 }
966 
967 
968 
969 int fap_kiss_to_tnc2(char const* kissframe, unsigned int kissframe_len,
970  char* tnc2frame, unsigned int* tnc2frame_len, unsigned int* tnc_id)
971 {
972  char input[FRAME_MAXLEN];
973  unsigned int input_len = 0;
974 
975  char output[2*FRAME_MAXLEN];
976  unsigned int output_len = 0;
977 
978  int i = 0, j = 0, escape_mode = 0;
979 
980  /* Check that we got params. */
981  if ( !kissframe || !kissframe_len || !tnc2frame || !tnc2frame_len || !tnc_id )
982  {
983  return 0;
984  }
985 
986  /* Check that frame is short enough. */
987  if ( kissframe_len >= FRAME_MAXLEN )
988  {
989  sprintf(output, "Too long KISS frame.");
990  output_len = strlen(output)+1;
991  if ( output_len > *tnc2frame_len ) output_len = *tnc2frame_len;
992  memcpy(tnc2frame, output, output_len);
993  *tnc2frame_len = output_len;
994  return 0;
995  }
996 
997  /* Check for FEND at start, remove if found. */
998  if ( kissframe_len > 0 && (kissframe[0] & 0xff) == FEND )
999  {
1000  kissframe += 1;
1001  kissframe_len -= 1;
1002  }
1003 
1004  /* Check for ending FEND. */
1005  for ( i = 0; i < kissframe_len; ++i )
1006  {
1007  if ( (kissframe[i] & 0xff) == FEND )
1008  {
1009  kissframe_len = i;
1010  }
1011  }
1012 
1013  /* Save and remove tnc id. */
1014  if ( kissframe_len > 0 )
1015  {
1016  *tnc_id = kissframe[0];
1017  kissframe += 1;
1018  kissframe_len -= 1;
1019  }
1020 
1021  /* Perform byte unstuffing. */
1022  j = 0;
1023  for ( i = 0; i < kissframe_len; ++i )
1024  {
1025  if ( (kissframe[i] & 0xff) == FESC )
1026  {
1027  escape_mode = 1;
1028  continue;
1029  }
1030 
1031  if ( escape_mode )
1032  {
1033  if ( (kissframe[i] & 0xff) == TFEND )
1034  {
1035  input[j] = FEND;
1036  }
1037  else if ( (kissframe[i] & 0xff) == TFESC )
1038  {
1039  input[j] = FESC;
1040  }
1041  escape_mode = 0;
1042  ++j;
1043  continue;
1044  }
1045 
1046  input[j] = kissframe[i];
1047  ++j;
1048  }
1049  input_len = j;
1050 
1051  /* Length checking _after_ byte unstuffing. */
1052  if ( input_len < 16 )
1053  {
1054  sprintf(output, "Too short KISS frame (%d bytes after unstuffing).", input_len);
1055  output_len = strlen(output)+1;
1056  if ( output_len > *tnc2frame_len ) output_len = *tnc2frame_len;
1057  memcpy(tnc2frame, output, output_len);
1058  *tnc2frame_len = output_len;
1059  return 0;
1060  }
1061 
1062  // Now we have an AX.25-frame, let's parse it.
1063  return fap_ax25_to_tnc2(input, input_len, tnc2frame, tnc2frame_len);
1064 }
1065 
1066 
1067 
1068 int fap_ax25_to_tnc2(char const* ax25frame, unsigned int ax25frame_len,
1069  char* tnc2frame, unsigned int* tnc2frame_len)
1070 {
1071  int i, j, retval = 1;
1072  char *checked_call, *dst_callsign = NULL;
1073  int part_no, header_len, ssid, digi_count;
1074  char tmp_callsign[10];
1075  char charri;
1076 
1077  char output[2*FRAME_MAXLEN];
1078  unsigned int output_len = 0;
1079 
1080  /* Check that we got params. */
1081  if ( !ax25frame || !ax25frame_len || !tnc2frame || !tnc2frame_len )
1082  {
1083  return 0;
1084  }
1085 
1086  /* Check that frame size is good. */
1087  if ( ax25frame_len >= FRAME_MAXLEN )
1088  {
1089  sprintf(output, "Too long AX.25 frame.");
1090  output_len = strlen(output)+1;
1091  if ( output_len > *tnc2frame_len ) output_len = *tnc2frame_len;
1092  memcpy(tnc2frame, output, output_len);
1093  *tnc2frame_len = output_len;
1094  return 0;
1095  }
1096  if ( ax25frame_len < 16 )
1097  {
1098  sprintf(output, "Too short AX.25 frame (%d bytes).", ax25frame_len);
1099  output_len = strlen(output)+1;
1100  if ( output_len > *tnc2frame_len ) output_len = *tnc2frame_len;
1101  memcpy(tnc2frame, output, output_len);
1102  *tnc2frame_len = output_len;
1103  return 0;
1104  }
1105 
1106  /* Go through the frame to get 4 parts: header, control field, pid and body. */
1107  part_no = 0;
1108  header_len = 0;
1109  memset(tmp_callsign, 0, 10);
1110  digi_count = 0;
1111  j = 0;
1112  for ( i = 0; i < ax25frame_len; ++i )
1113  {
1114  charri = ax25frame[i];
1115 
1116  if ( part_no == 0 )
1117  {
1118  /* New byte to header. */
1119  header_len++;
1120 
1121  /* We're at header, check if it should end with this byte. */
1122  if ( charri & 1 )
1123  {
1124  /* Yes, lets do some checks. */
1125  if ( header_len < 14 || header_len % 7 != 0 )
1126  {
1127  sprintf(output, "Invalid header lenght (%d).", header_len);
1128  output_len = strlen(output)+1;
1129  retval = 0;
1130  break;
1131  }
1132 
1133  /* Go for control field upon next cycle. */
1134  part_no = 1;
1135  }
1136 
1137  /* Check if a callsign is about to be complete. */
1138  if ( header_len && header_len % 7 == 0 )
1139  {
1140  /* This byte is SSID, get the number. */
1141  ssid = (charri >> 1) & 0xf;
1142  if ( ssid != 0 )
1143  {
1144  sprintf(tmp_callsign+6, "-%d", ssid);
1145  }
1146  /* Validate callsign. */
1147  checked_call = fapint_check_kiss_callsign(tmp_callsign);
1148  if ( !checked_call )
1149  {
1150  sprintf(output, "Invalid callsign in header (%s).", tmp_callsign);
1151  output_len = strlen(output)+1;
1152  retval = 0;
1153  break;
1154  }
1155  /* Figure out which part of header this callsign is. */
1156  if ( header_len == 7 )
1157  {
1158  /* We have a destination callsign. */
1159  dst_callsign = checked_call;
1160  }
1161  else if ( header_len == 14 )
1162  {
1163  /* We have a source callsign, copy it to the final frame directly. */
1164  sprintf(output, "%s>%s", checked_call, dst_callsign);
1165  output_len = strlen(checked_call) + 1 + strlen(dst_callsign);
1166  free(dst_callsign);
1167  free(checked_call);
1168  }
1169  else if ( header_len > 14 )
1170  {
1171  /* We're at path part, save the call. */
1172  sprintf(output+output_len, "%s", checked_call);
1173  output_len += strlen(checked_call);
1174  free(checked_call);
1175  /* Get the has-been-repeated flag. */
1176  if ( charri & 0x80 )
1177  {
1178  output[output_len] = '*';
1179  output_len++;
1180  }
1181  digi_count++;
1182  }
1183  else
1184  {
1185  sprintf(output, "Internal error.");
1186  output_len = strlen(output)+1;
1187  retval = 0;
1188  break;
1189  }
1190  /* Check what happens next. */
1191  if ( part_no == 0 )
1192  {
1193  /* More address fields will follow. Check that there's no more than 8 digis in path. */
1194  if ( digi_count >= 8 )
1195  {
1196  sprintf(output, "Too many digis.");
1197  output_len = strlen(output)+1;
1198  retval = 0;
1199  break;
1200  }
1201  output[output_len] = ',';
1202  output_len++;
1203  }
1204  else
1205  {
1206  /* End of header. */
1207  output[output_len] = ':';
1208  output_len++;
1209  }
1210  j = 0;
1211  memset(tmp_callsign, 0, 10);
1212  continue;
1213  }
1214 
1215  /* Shift one bit right to get the ascii character. */
1216  tmp_callsign[j] = (charri & 0xff) >> 1;
1217  ++j;
1218  }
1219  else if ( part_no == 1 )
1220  {
1221  /* We're at control field. We are only interested in UI frames, discard others. */
1222  if ( (charri & 0xff) != AX25_FRAME_UI )
1223  {
1224  retval = 0;
1225  break;
1226  }
1227  part_no = 2;
1228  }
1229  else if ( part_no == 2 )
1230  {
1231  /* We're at pid. */
1232  if ( (charri & 0xff) != AX25_PID_APRS )
1233  {
1234  retval = 0;
1235  break;
1236  }
1237  part_no = 3;
1238  }
1239  else
1240  {
1241  output[output_len] = charri;
1242  output_len++;
1243  }
1244  }
1245 
1246  /* Copy result to output. */
1247  if ( output_len > *tnc2frame_len ) output_len = *tnc2frame_len;
1248  memcpy(tnc2frame, output, output_len);
1249  *tnc2frame_len = output_len;
1250 
1251  return retval;
1252 }
1253 
1254 
1255 
1256 int fap_tnc2_to_kiss(char const* tnc2frame, unsigned int tnc2frame_len, unsigned int const tnc_id,
1257  char* kissframe, unsigned int* kissframe_len)
1258 {
1259  char ax25frame[2*FRAME_MAXLEN];
1260  unsigned int ax25frame_len;
1261  int i;
1262 
1263  /* Initialize slot for starting FEND and tnc id by skipping two first bytes of our conversion buffer. */
1264  ax25frame_len = 2*FRAME_MAXLEN-2;
1265  memset(ax25frame, 0, 2);
1266 
1267  /* Convert into AX.25-frame. */
1268  if ( !fap_tnc2_to_ax25(tnc2frame, tnc2frame_len, ax25frame+2, &ax25frame_len) )
1269  {
1270  strcpy(kissframe, ax25frame);
1271  *kissframe_len = strlen(kissframe);
1272  return 0;
1273  }
1274  ax25frame_len += 2;
1275 
1276  /* Check for room in output buffer. */
1277  if ( *kissframe_len <= ax25frame_len )
1278  {
1279  return 0;
1280  }
1281 
1282  /* Perform byte stuffing. */
1283  *kissframe_len = 2;
1284  for ( i = 2; i < ax25frame_len; ++i )
1285  {
1286  if ( (ax25frame[i] & 0xff) == FEND || (ax25frame[i] & 0xff) == FESC )
1287  {
1288  kissframe[*kissframe_len] = FESC;
1289  (*kissframe_len)++;
1290  if ( (ax25frame[i] & 0xff) == FEND )
1291  {
1292  kissframe[*kissframe_len] = TFEND;
1293  }
1294  else
1295  {
1296  kissframe[*kissframe_len] = TFESC;
1297  }
1298  (*kissframe_len)++;
1299  }
1300  else
1301  {
1302  kissframe[*kissframe_len] = ax25frame[i];
1303  (*kissframe_len)++;
1304  }
1305  }
1306 
1307  /* Put FENDs and tnc id in place. */
1308  kissframe[0] = FEND;
1309  kissframe[1] = tnc_id;
1310  kissframe[*kissframe_len] = FEND;
1311  (*kissframe_len)++;
1312 
1313  return 1;
1314 }
1315 
1316 
1317 
1318 int fap_tnc2_to_ax25(char const* tnc2frame, unsigned int tnc2frame_len,
1319  char* ax25frame, unsigned int* ax25frame_len)
1320 {
1321  char input[FRAME_MAXLEN];
1322 
1323  char output[2*FRAME_MAXLEN];
1324  unsigned int output_len = 0;
1325 
1326  char *header = NULL, *digipeaters = NULL, *body = NULL;
1327  unsigned int digi_count, body_len;
1328 
1329  char sender[6], sender_ssid[4], receiver[6], receiver_ssid[4];
1330  int sender_ssid_num = 0, receiver_ssid_num = 0;
1331 
1332  char digicall[6], digicall_ssid[4], hbit;
1333  int digicall_ssid_num = 0;
1334 
1335  int retval = 1, len, i;
1336  char* tmp_str;
1337 
1338  unsigned int const matchcount = 6;
1339  regmatch_t matches[matchcount];
1340 
1341 
1342  /* Check params. */
1343  if ( !tnc2frame || !tnc2frame_len || tnc2frame_len >= FRAME_MAXLEN || !ax25frame || !ax25frame_len )
1344  {
1345  return 0;
1346  }
1347 
1348  /* Create working copy of input. */
1349  memset(input, 0, FRAME_MAXLEN);
1350  memcpy(input, tnc2frame, tnc2frame_len );
1351 
1352  /* Separate header and body. */
1353  if ( regexec(&fapint_regex_kiss_hdrbdy, input, matchcount, (regmatch_t*)&matches, 0) == 0 )
1354  {
1355  len = matches[1].rm_eo - matches[1].rm_so;
1356  header = malloc(len+1);
1357  if ( !header ) return 0;
1358  memcpy(header, input+matches[1].rm_so, len);
1359  header[len] = 0;
1360 
1361  body_len = matches[2].rm_eo - matches[2].rm_so;
1362  body = malloc(body_len);
1363  if ( !body )
1364  {
1365  free(header);
1366  return 0;
1367  }
1368  memcpy(body, input+matches[2].rm_so, body_len);
1369  }
1370  else
1371  {
1372  sprintf(output, "Failed to separate header and body of TNC-2 packet.");
1373  output_len = strlen(output)+1;
1374  if ( output_len > *ax25frame_len ) output_len = *ax25frame_len;
1375  strcpy(ax25frame, output);
1376  *ax25frame_len = output_len;
1377  return 0;
1378  }
1379 
1380  /* Separate the sender, recipient and digipeaters. */
1381  if ( regexec(&fapint_regex_hdr_detail, header, matchcount, (regmatch_t*)&matches, 0) == 0 )
1382  {
1383  len = matches[1].rm_eo - matches[1].rm_so;
1384  memset(sender, ' ', 6);
1385  memcpy(sender, header+matches[1].rm_so, len);
1386 
1387  len = matches[2].rm_eo - matches[2].rm_so;
1388  memset(sender_ssid, 0, 4);
1389  if ( len )
1390  {
1391  memcpy(sender_ssid, header+matches[2].rm_so, len);
1392  }
1393 
1394  len = matches[3].rm_eo - matches[3].rm_so;
1395  memset(receiver, ' ', 6);
1396  memcpy(receiver, header+matches[3].rm_so, len);
1397 
1398  len = matches[4].rm_eo - matches[4].rm_so;
1399  memset(receiver_ssid, 0, 4);
1400  if ( len )
1401  {
1402  memcpy(receiver_ssid, header+matches[4].rm_so, len);
1403  }
1404 
1405  len = matches[5].rm_eo - matches[5].rm_so;
1406  if ( len )
1407  {
1408  digipeaters = malloc(len+5);
1409  if ( !digipeaters )
1410  {
1411  free(header);
1412  free(body);
1413  return 0;
1414  }
1415  memcpy(digipeaters, header+matches[5].rm_so, len);
1416  digipeaters[len] = 0;
1417  }
1418  }
1419  else
1420  {
1421  free(header);
1422  free(body);
1423  return 0;
1424  }
1425  free(header);
1426 
1427  /* Frame header compilation is done in a easy-to-break-out block. */
1428  while ( 1 )
1429  {
1430  /* Check SSID format and convert to number. */
1431  if ( sender_ssid[0] == '-' )
1432  {
1433  sender_ssid_num = 0 - atoi(sender_ssid);
1434  if ( sender_ssid_num > 15 )
1435  {
1436  retval = 0;
1437  break;
1438  }
1439  }
1440  if ( receiver_ssid[0] == '-' )
1441  {
1442  receiver_ssid_num = 0 - atoi(receiver_ssid);
1443  if ( receiver_ssid_num > 15 )
1444  {
1445  retval = 0;
1446  break;
1447  }
1448  }
1449 
1450  /* Encode destination and source. */
1451  for ( i = 0; i < 6; ++i )
1452  {
1453  output[output_len] = receiver[i] << 1;
1454  output_len++;
1455  }
1456  output[output_len] = 0xe0 | (receiver_ssid_num << 1);
1457  output_len++;
1458  for ( i = 0; i < 6; ++i )
1459  {
1460  output[output_len] = sender[i] << 1;
1461  output_len++;
1462  }
1463  if ( digipeaters )
1464  {
1465  output[output_len] = 0x60 | (sender_ssid_num << 1);
1466  }
1467  else
1468  {
1469  output[output_len] = 0x61 | (sender_ssid_num << 1);
1470  }
1471  output_len++;
1472 
1473  /* If there are digipeaters, add them. */
1474  if ( digipeaters )
1475  {
1476  /* Split into parts. */
1477  tmp_str = strtok(digipeaters+1, ",");
1478  digi_count = 0;
1479  while ( tmp_str != NULL )
1480  {
1481  /* Split into callsign, SSID and h-bit. */
1482  if ( regexec(&fapint_regex_kiss_digi, tmp_str, matchcount, (regmatch_t*)&matches, 0) == 0 )
1483  {
1484  /* digi's plain callsign */
1485  len = matches[1].rm_eo - matches[1].rm_so;
1486  memset(digicall, ' ', 6);
1487  memcpy(digicall, tmp_str+matches[1].rm_so, len);
1488 
1489  /* ssid */
1490  digicall_ssid_num = 0;
1491  len = matches[2].rm_eo - matches[2].rm_so;
1492  if ( len )
1493  {
1494  memset(digicall_ssid, 0, 4);
1495  memcpy(digicall_ssid, tmp_str+matches[2].rm_so, len);
1496 
1497  digicall_ssid_num = 0 - atoi(digicall_ssid);
1498  if ( digicall_ssid_num > 15 )
1499  {
1500  retval = 0;
1501  break;
1502  }
1503  }
1504 
1505  /* h-bit */
1506  hbit = 0x00;
1507  if ( tmp_str[matches[3].rm_so] == '*' )
1508  {
1509  hbit = 0x80;
1510  }
1511 
1512  /* Check for next part. */
1513  tmp_str = strtok(NULL, ",");
1514 
1515  /* Add plain callsign frame. */
1516  for ( i = 0; i < 6; ++i )
1517  {
1518  output[output_len] = digicall[i] << 1;
1519  output_len++;
1520  }
1521  /* Add ssid. */
1522  if ( tmp_str )
1523  {
1524  /* More digipeaters to follow. */
1525  output[output_len] = 0x60 | (digicall_ssid_num << 1) | hbit;
1526  }
1527  else
1528  {
1529  /* Last digipeater. */
1530  output[output_len] = 0x61 | (digicall_ssid_num << 1) | hbit;
1531  }
1532  output_len++;
1533  }
1534  else
1535  {
1536  /* Invalid digi callsign. */
1537  retval = 0;
1538  break;
1539  }
1540  }
1541  }
1542 
1543  /* Frame header compiled. */
1544  break;
1545  }
1546  if ( digipeaters ) free(digipeaters);
1547 
1548 
1549  /* Add frame type and pid. */
1550  output[output_len] = AX25_FRAME_UI;
1551  output_len++;
1552  output[output_len] = AX25_PID_APRS;
1553  output_len++;
1554 
1555  /* Add body. */
1556  memcpy(output+output_len, body, body_len);
1557  output_len += body_len;
1558  free(body);
1559 
1560  /* Check how header compilation went. */
1561  if ( !retval )
1562  {
1563  return 0;
1564  }
1565 
1566  /* Return result. */
1567  if ( output_len > *ax25frame_len ) output_len = *ax25frame_len;
1568  memcpy(ax25frame, output, output_len);
1569  *ax25frame_len = output_len;
1570  return 1;
1571 }
1572 
1573 
1574 
1575 void fap_init()
1576 {
1577  if ( !fapint_initialized )
1578  {
1579  /* Compile regexs. */
1580  regcomp(&fapint_regex_header, "^([A-Z0-9\\-]{1,9})>(.*)$", REG_EXTENDED);
1581  regcomp(&fapint_regex_ax25call, "^([A-Z0-9]{1,6})(-[0-9]{1,2}|())$", REG_EXTENDED);
1582  regcomp(&fapint_regex_digicall, "^([a-zA-Z0-9-]{1,9})([*]?)$", REG_EXTENDED);
1583  regcomp(&fapint_regex_digicallv6, "^([0-9A-F]{32})$", REG_EXTENDED|REG_NOSUB);
1584 
1585  regcomp(&fapint_regex_normalpos, "^([0-9]{2})([0-7 ][0-9 ]\\.[0-9 ]{2})([NnSs])(.)([0-9]{3})([0-7 ][0-9 ]\\.[0-9 ]{2})([EeWw])(.)", REG_EXTENDED);
1586  regcomp(&fapint_regex_normalamb, "^([0-9]{0,4})( {0,4})$", REG_EXTENDED);
1587  regcomp(&fapint_regex_timestamp, "^([0-9]{2})([0-9]{2})([0-9]{2})([zh\\/])", REG_EXTENDED);
1588 
1589  regcomp(&fapint_regex_mice_dstcall, "^[0-9A-LP-Z]{3}[0-9LP-Z]{3}$", REG_EXTENDED|REG_NOSUB);
1590  regcomp(&fapint_regex_mice_body, "^[\\/\\\\A-Z0-9]", REG_EXTENDED|REG_NOSUB);
1591  regcomp(&fapint_regex_mice_amb, "^([0-9]+)(_*)$", REG_EXTENDED);
1592 
1593  regcomp(&fapint_regex_comment, "^([0-9\\. ]{3})\\/([0-9\\. ]{3})", REG_EXTENDED|REG_NOSUB);
1594  regcomp(&fapint_regex_phgr, "^PHG([0-9].[0-9]{2}[1-9A-Z])\\/", REG_EXTENDED|REG_NOSUB);
1595  regcomp(&fapint_regex_phg, "^PHG([0-9].[0-9]{2})", REG_EXTENDED|REG_NOSUB);
1596  regcomp(&fapint_regex_rng, "^RNG([0-9]{4})", REG_EXTENDED|REG_NOSUB);
1597  regcomp(&fapint_regex_altitude, "\\/A=(-[0-9]{5}|[0-9]{6})", REG_EXTENDED);
1598 
1599  regcomp(&fapint_regex_mes_dst, "^:([A-Za-z0-9_ -]{9}):", REG_EXTENDED);
1600  regcomp(&fapint_regex_mes_ack, "^ack([A-Za-z0-9}]{1,5}) *$", REG_EXTENDED);
1601  regcomp(&fapint_regex_mes_nack, "^rej([A-Za-z0-9}]{1,5}) *$", REG_EXTENDED);
1602 
1603  regcomp(&fapint_regex_wx1, "^_{0,1}([0-9 \\.\\-]{3})\\/([0-9 \\.]{3})g([0-9 \\.]+)t(-{0,1}[0-9 \\.]+)", REG_EXTENDED);
1604  regcomp(&fapint_regex_wx2, "^_{0,1}c([0-9 \\.\\-]{3})s([0-9 \\.]{3})g([0-9 \\.]+)t(-{0,1}[0-9 \\.]+)", REG_EXTENDED);
1605  regcomp(&fapint_regex_wx3, "^_{0,1}([0-9 \\.\\-]{3})\\/([0-9 \\.]{3})t(-{0,1}[0-9 \\.]+)", REG_EXTENDED);
1606  regcomp(&fapint_regex_wx4, "^_{0,1}([0-9 \\.\\-]{3})\\/([0-9 \\.]{3})g([0-9 \\.]+)", REG_EXTENDED);
1607  regcomp(&fapint_regex_wx5, "^g([0-9]+)t(-?[0-9 \\.]{1,3})", REG_EXTENDED);
1608 
1609  regcomp(&fapint_regex_wx_r1, "r([0-9]{1,3})", REG_EXTENDED);
1610  regcomp(&fapint_regex_wx_r24, "p([0-9]{1,3})", REG_EXTENDED);
1611  regcomp(&fapint_regex_wx_rami, "P([0-9]{1,3})", REG_EXTENDED);
1612 
1613  regcomp(&fapint_regex_wx_humi, "h([0-9]{1,3})", REG_EXTENDED);
1614  regcomp(&fapint_regex_wx_pres, "b([0-9]{4,5})", REG_EXTENDED);
1615  regcomp(&fapint_regex_wx_lumi, "([lL])([0-9]{1,3})", REG_EXTENDED);
1616  regcomp(&fapint_regex_wx_what, "v([\\-\\+]{0,1}[0-9]+)", REG_EXTENDED);
1617 
1618  regcomp(&fapint_regex_wx_snow, "s([0-9]+)", REG_EXTENDED);
1619  regcomp(&fapint_regex_wx_rrc, "#([0-9]+)", REG_EXTENDED);
1620  regcomp(&fapint_regex_wx_any, "^([rPphblLs#][\\. ]{1,5})+", REG_EXTENDED);
1621  regcomp(&fapint_regex_wx_soft, "^[a-zA-Z0-9\\-\\_]{3,5}$", REG_EXTENDED|REG_NOSUB);
1622 
1623  regcomp(&fapint_regex_nmea_chksum, "^(.+)\\*([0-9A-F]{2})$", REG_EXTENDED);
1624  regcomp(&fapint_regex_nmea_dst, "^(GPS|SPC)([A-Z0-9]{2,3})", REG_EXTENDED);
1625  regcomp(&fapint_regex_nmea_time, "^[:space:]*([0-9]{2})([0-9]{2})([0-9]{2})(()|\\.[0-9]+)[:space:]*$", REG_EXTENDED);
1626  regcomp(&fapint_regex_nmea_date, "^[:space:]*([0-9]{2})([0-9]{2})([0-9]{2})[:space:]*$", REG_EXTENDED);
1627 
1628  regcomp(&fapint_regex_nmea_specou, "^[:space:]*([0-9]+(()|\\.[0-9]+))[:space:]*$", REG_EXTENDED);
1629  regcomp(&fapint_regex_nmea_fix, "^[:space:]*([0-9]+)[:space:]*$", REG_EXTENDED);
1630  regcomp(&fapint_regex_nmea_altitude, "^(-?[0-9]+(()|\\.[0-9]+))$", REG_EXTENDED);
1631  regcomp(&fapint_regex_nmea_flag, "^[:space:]*([NSEWnsew])[:space:]*$", REG_EXTENDED);
1632  regcomp(&fapint_regex_nmea_coord, "^[:space:]*([0-9]{1,3})([0-5][0-9]\\.([0-9]+))[:space:]*$", REG_EXTENDED);
1633 
1634  regcomp(&fapint_regex_telemetry, "^([0-9]+),(-?)([0-9]{1,6}|[0-9]+\\.[0-9]+|\\.[0-9]+)?,(-?)([0-9]{1,6}|[0-9]+\\.[0-9]+|\\.[0-9]+)?,(-?)([0-9]{1,6}|[0-9]+\\.[0-9]+|\\.[0-9]+)?,(-?)([0-9]{1,6}|[0-9]+\\.[0-9]+|\\.[0-9]+)?,(-?)([0-9]{1,6}|[0-9]+\\.[0-9]+|\\.[0-9]+)?,([01]{0,8})", REG_EXTENDED);
1635  regcomp(&fapint_regex_peet_splitter, "^([0-9a-f]{4}|----)", REG_EXTENDED|REG_ICASE);
1636  regcomp(&fapint_regex_kiss_callsign, "^([A-Z0-9]+) *(-[0-9]+)?$", REG_EXTENDED);
1637 
1638  regcomp(&fapint_regex_detect_comp, "^[\\/\\\\A-Za-j]$", REG_EXTENDED|REG_NOSUB);
1639  regcomp(&fapint_regex_detect_wx, "^_([0-9]{8})c[- .0-9]{1,3}s[- .0-9]{1,3}", REG_EXTENDED|REG_NOSUB);
1640  regcomp(&fapint_regex_detect_telem, "^T#(.*?),(.*)$", REG_EXTENDED|REG_NOSUB);
1641  regcomp(&fapint_regex_detect_exp, "^\\{\\{", REG_EXTENDED|REG_NOSUB);
1642 
1643  regcomp(&fapint_regex_kiss_hdrbdy, "^([A-Z0-9,*>-]+):(.+)$", REG_EXTENDED);
1644  regcomp(&fapint_regex_hdr_detail, "^([A-Z0-9]{1,6})(-[0-9]{1,2})?>([A-Z0-9]{1,6})(-[0-9]{1,2})?(,.*)?$", REG_EXTENDED);
1645  regcomp(&fapint_regex_kiss_digi, "^([A-Z0-9]{1,6})(-[0-9]{1,2})?(\\*)?$", REG_EXTENDED);
1646 
1647  regcomp(&fapint_regex_base91_telemetry, "\\|([!-{]{2})([!-{]{2})([!-{]{2}|)([!-{]{2}|)([!-{]{2}|)([!-{]{2}|)([!-{]{2}|)\\|", REG_EXTENDED);
1648 
1649  regcomp(&fapint_regex_hopcount1, "^([A-Z0-9-]+)\\*$", REG_EXTENDED);
1650  regcomp(&fapint_regex_hopcount2, "^WIDE([1-7])-([0-7])$", REG_EXTENDED);
1651 
1652 
1653  /* Initialized. */
1654  fapint_initialized = 1;
1655  }
1656 }
1657 
1658 
1659 
1661 {
1662  if ( fapint_initialized )
1663  {
1664  /* Free regexs. */
1665  regfree(&fapint_regex_header);
1666  regfree(&fapint_regex_ax25call);
1667  regfree(&fapint_regex_digicall);
1668  regfree(&fapint_regex_digicallv6);
1669 
1670  regfree(&fapint_regex_normalpos);
1671  regfree(&fapint_regex_normalamb);
1672  regfree(&fapint_regex_timestamp);
1673 
1674  regfree(&fapint_regex_mice_dstcall);
1675  regfree(&fapint_regex_mice_body);
1676  regfree(&fapint_regex_mice_amb);
1677 
1678  regfree(&fapint_regex_comment);
1679  regfree(&fapint_regex_phgr);
1680  regfree(&fapint_regex_phg);
1681  regfree(&fapint_regex_rng);
1682  regfree(&fapint_regex_altitude);
1683 
1684  regfree(&fapint_regex_mes_dst);
1685  regfree(&fapint_regex_mes_ack);
1686  regfree(&fapint_regex_mes_nack);
1687 
1688  regfree(&fapint_regex_wx1);
1689  regfree(&fapint_regex_wx2);
1690  regfree(&fapint_regex_wx3);
1691  regfree(&fapint_regex_wx4);
1692  regfree(&fapint_regex_wx5);
1693 
1694  regfree(&fapint_regex_wx_r1);
1695  regfree(&fapint_regex_wx_r24);
1696  regfree(&fapint_regex_wx_rami);
1697 
1698  regfree(&fapint_regex_wx_humi);
1699  regfree(&fapint_regex_wx_pres);
1700  regfree(&fapint_regex_wx_lumi);
1701  regfree(&fapint_regex_wx_what);
1702 
1703  regfree(&fapint_regex_wx_snow);
1704  regfree(&fapint_regex_wx_rrc);
1705  regfree(&fapint_regex_wx_any);
1706  regfree(&fapint_regex_wx_soft);
1707 
1708  regfree(&fapint_regex_nmea_chksum);
1709  regfree(&fapint_regex_nmea_dst);
1710  regfree(&fapint_regex_nmea_time);
1711  regfree(&fapint_regex_nmea_date);
1712 
1713  regfree(&fapint_regex_nmea_specou);
1714  regfree(&fapint_regex_nmea_fix);
1715  regfree(&fapint_regex_nmea_altitude);
1716  regfree(&fapint_regex_nmea_flag);
1717  regfree(&fapint_regex_nmea_coord);
1718 
1719  regfree(&fapint_regex_telemetry);
1720  regfree(&fapint_regex_peet_splitter);
1721  regfree(&fapint_regex_kiss_callsign);
1722 
1723  regfree(&fapint_regex_detect_comp);
1724  regfree(&fapint_regex_detect_wx);
1725  regfree(&fapint_regex_detect_telem);
1726  regfree(&fapint_regex_detect_exp);
1727 
1728  regfree(&fapint_regex_kiss_hdrbdy);
1729  regfree(&fapint_regex_hdr_detail);
1730  regfree(&fapint_regex_kiss_digi);
1731 
1732  regfree(&fapint_regex_base91_telemetry);
1733 
1734  regfree(&fapint_regex_hopcount1);
1735  regfree(&fapint_regex_hopcount2);
1736 
1737  /* No more initialized. */
1738  fapint_initialized = 0;
1739  }
1740 }
1741 
1742 
1743 
1744 void fap_free(fap_packet_t* packet)
1745 {
1746  unsigned int i;
1747 
1748  if ( packet == NULL )
1749  {
1750  return;
1751  }
1752 
1753  if ( packet->error_code ) { free(packet->error_code); }
1754  if ( packet->type ) { free(packet->type); }
1755 
1756  if ( packet->orig_packet ) { free(packet->orig_packet); }
1757 
1758  if ( packet->header ) { free(packet->header); }
1759  if ( packet->body ) { free(packet->body); }
1760  if ( packet->src_callsign ) { free(packet->src_callsign); }
1761  if ( packet->dst_callsign ) { free(packet->dst_callsign); }
1762  for ( i = 0; i < packet->path_len; ++i )
1763  {
1764  if ( packet->path[i] ) { free(packet->path[i]); }
1765  }
1766  if ( packet->path ) { free(packet->path); }
1767 
1768  if ( packet->latitude ) { free(packet->latitude); }
1769  if ( packet->longitude ) { free(packet->longitude); }
1770  if ( packet->format ) { free(packet->format); }
1771  if ( packet->pos_resolution ) { free(packet->pos_resolution); }
1772  if ( packet->pos_ambiguity ) { free(packet->pos_ambiguity); }
1773 
1774  if ( packet->altitude ) { free(packet->altitude); }
1775  if ( packet->course ) { free(packet->course); }
1776  if ( packet->speed ) { free(packet->speed); }
1777 
1778  if ( packet->messaging ) { free(packet->messaging); }
1779  if ( packet->destination ) { free(packet->destination); }
1780  if ( packet->message ) { free(packet->message); }
1781  if ( packet->message_ack ) { free(packet->message_ack); }
1782  if ( packet->message_nack ) { free(packet->message_nack); }
1783  if ( packet->message_id ) { free(packet->message_id); }
1784  if ( packet->comment ) { free(packet->comment); }
1785 
1786  if ( packet->object_or_item_name ) { free(packet->object_or_item_name); }
1787  if ( packet->alive ) { free(packet->alive); }
1788 
1789  if ( packet->gps_fix_status ) { free(packet->gps_fix_status); }
1790  if ( packet->radio_range ) { free(packet->radio_range); }
1791  if ( packet->phg ) { free(packet->phg); }
1792  if ( packet->timestamp ) { free(packet->timestamp); }
1793  if ( packet->raw_timestamp ) { free(packet->raw_timestamp); }
1794  if ( packet->nmea_checksum_ok ) { free(packet->nmea_checksum_ok); }
1795 
1796  if ( packet->wx_report )
1797  {
1798  if ( packet->wx_report->wind_gust ) { free(packet->wx_report->wind_gust); }
1799  if ( packet->wx_report->wind_dir ) { free(packet->wx_report->wind_dir); }
1800  if ( packet->wx_report->wind_speed ) { free(packet->wx_report->wind_speed); }
1801 
1802  if ( packet->wx_report->temp ) { free(packet->wx_report->temp); }
1803  if ( packet->wx_report->temp_in ) { free(packet->wx_report->temp_in); }
1804 
1805  if ( packet->wx_report->rain_1h ) { free(packet->wx_report->rain_1h); }
1806  if ( packet->wx_report->rain_24h ) { free(packet->wx_report->rain_24h); }
1807  if ( packet->wx_report->rain_midnight ) { free(packet->wx_report->rain_midnight); }
1808 
1809  if ( packet->wx_report->humidity ) { free(packet->wx_report->humidity); }
1810  if ( packet->wx_report->humidity_in ) { free(packet->wx_report->humidity_in); }
1811 
1812  if ( packet->wx_report->pressure ) { free(packet->wx_report->pressure); }
1813  if ( packet->wx_report->luminosity ) { free(packet->wx_report->luminosity); }
1814 
1815  if ( packet->wx_report->snow_24h ) { free(packet->wx_report->snow_24h); }
1816 
1817  if ( packet->wx_report->soft ) { free(packet->wx_report->soft); }
1818 
1819  free(packet->wx_report);
1820  }
1821 
1822  if ( packet->telemetry )
1823  {
1824  if ( packet->telemetry->seq ) { free(packet->telemetry->seq); }
1825  if ( packet->telemetry->val1 ) { free(packet->telemetry->val1); }
1826  if ( packet->telemetry->val2 ) { free(packet->telemetry->val2); }
1827  if ( packet->telemetry->val3 ) { free(packet->telemetry->val3); }
1828  if ( packet->telemetry->val4 ) { free(packet->telemetry->val4); }
1829  if ( packet->telemetry->val5 ) { free(packet->telemetry->val5); }
1830  free(packet->telemetry);
1831  }
1832 
1833  if ( packet->messagebits ) { free(packet->messagebits); }
1834  if ( packet->status ) { free(packet->status); }
1835  for ( i = 0; i < packet->capabilities_len*2; i += 2 )
1836  {
1837  if ( packet->capabilities[i] ) { free(packet->capabilities[i]); }
1838  if ( packet->capabilities[i+1] ) { free(packet->capabilities[i+1]); }
1839  }
1840  if ( packet->capabilities ) { free(packet->capabilities); }
1841 
1842  free(packet);
1843 }