libfap  1.5
helpers.c
Go to the documentation of this file.
1 /* $Id: helpers.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 
33 #include "helpers.h"
34 #include "helpers2.h"
35 #include "regs.h"
36 #ifdef HAVE_CONFIG_H
37 #include <config.h>
38 #endif
39 
40 #include <stdlib.h>
41 #include <stdio.h>
42 #include <string.h>
43 #include <stdint.h>
44 #include <regex.h>
45 #include <ctype.h>
46 #include <math.h>
47 
48 
49 
50 int fapint_parse_header(fap_packet_t* packet, short const is_ax25)
51 {
52  int i, len, startpos, retval = 1;
53  char* rest = NULL;
54  char* tmp = NULL;
55  char buf_10b[10];
56  fapint_llist_item_t* path;
57  int path_len;
58  fapint_llist_item_t* current_elem;
59  short seenq = 0;
60 
61  unsigned int const matchcount = 3;
62  regmatch_t matches[matchcount];
63 
64  /* Separate source callsign and the rest. */
65  if ( regexec(&fapint_regex_header, packet->header, matchcount, (regmatch_t*)&matches, 0) == 0 )
66  {
67  /* Save (and validate if we're AX.25) the callsign. */
68  tmp = malloc(matches[1].rm_eo+1);
69  if ( !tmp ) return 0;
70  memcpy(tmp, packet->header, matches[1].rm_eo);
71  tmp[matches[1].rm_eo] = 0;
72  if ( is_ax25 )
73  {
74  packet->src_callsign = fap_check_ax25_call(tmp, 0);
75  free(tmp);
76  if ( !packet->src_callsign )
77  {
78  packet->error_code = malloc(sizeof(fap_error_code_t));
79  if ( packet->error_code ) *packet->error_code = fapSRCCALL_NOAX25;
80  retval = 0;
81  }
82  }
83  else
84  {
85  packet->src_callsign = tmp;
86  }
87 
88  /* Save the rest of the header also 0-terminated string. */
89  len = matches[2].rm_eo - matches[2].rm_so;
90  rest = malloc(len+1);
91  if ( !rest ) return 0;
92  memcpy(rest, packet->header + matches[2].rm_so, len);
93  rest[len] = 0;
94  }
95  else
96  {
97  packet->error_code = malloc(sizeof(fap_error_code_t));
98  if ( packet->error_code ) *packet->error_code = fapSRCCALL_BADCHARS;
99  retval = 0;
100  }
101  if ( !retval )
102  {
103  if ( rest ) free(rest);
104  return 0;
105  }
106 
107  /* Find path elements. */
108  len = 0;
109  startpos = 0;
110  path = NULL;
111  path_len = -1;
112  current_elem = NULL;
113  tmp = NULL;
114  for ( i = 0; i < strlen(rest); ++i )
115  {
116  tmp = NULL;
117 
118  /* Look for element boundary. */
119  if ( rest[i] == ',' )
120  {
121  /* Found a bound, let's create a copy of the element it ends. */
122  len = i - startpos;
123  tmp = malloc(len+1);
124  if ( !tmp )
125  {
126  retval = 0;
127  break;
128  }
129  memcpy(tmp, rest+startpos, len);
130  tmp[len] = 0;
131 
132  /* Start to look for next element. */
133  startpos = i + 1;
134  }
135  else if ( i+1 == strlen(rest) )
136  {
137  /* We're at the end, save the last element. */
138  len = i+1 - startpos;
139  tmp = malloc(len+1);
140  if ( !tmp )
141  {
142  retval = 0;
143  break;
144  }
145  memcpy(tmp, rest+startpos, len);
146  tmp[len] = 0;
147  }
148 
149  /* Check if we found something. */
150  if ( tmp )
151  {
152  /* Create list item. */
153  if ( path == NULL )
154  {
155  path = malloc(sizeof(fapint_llist_item_t));
156  if ( !path )
157  {
158  retval = 0;
159  break;
160  }
161  current_elem = path;
162  }
163  else
164  {
165  current_elem->next = malloc(sizeof(fapint_llist_item_t));
166  if ( !current_elem->next )
167  {
168  retval = 0;
169  break;
170  }
171  current_elem = current_elem->next;
172  }
173  current_elem->next = NULL;
174  current_elem->text = tmp;
175 
176  ++path_len;
177  }
178  }
179  if ( !retval )
180  {
181  if ( tmp ) free(tmp);
182  fapint_clear_llist(path);
183  free(rest);
184  return 0;
185  }
186 
187  /* Check that we got at least destination callsign. */
188  if ( !path )
189  {
190  /* Found nothing. */
191  packet->error_code = malloc(sizeof(fap_error_code_t));
192  if ( packet->error_code ) *packet->error_code = fapDSTCALL_NONE;
193  fapint_clear_llist(path);
194  free(rest);
195  return 0;
196  }
197 
198  /* Validate dst call. We are strict here, there should be no need to use
199  * a non-AX.25 compatible destination callsigns in the APRS-IS. */
200  packet->dst_callsign = fap_check_ax25_call(path->text, 0);
201  if ( !packet->dst_callsign )
202  {
203  packet->error_code = malloc(sizeof(fap_error_code_t));
204  if ( packet->error_code ) *packet->error_code = fapDSTCALL_NOAX25;
205  fapint_clear_llist(path);
206  free(rest);
207  return 0;
208  }
209 
210  /* If in AX.25 mode, check that path length is valid. */
211  if ( is_ax25 && path_len > MAX_DIGIS )
212  {
213  packet->error_code = malloc(sizeof(fap_error_code_t));
214  if ( packet->error_code ) *packet->error_code = fapDSTPATH_TOOMANY;
215  fapint_clear_llist(path);
216  free(rest);
217  return 0;
218  }
219 
220  /* Validate path elements, saving them while going. */
221  packet->path = calloc(path_len, sizeof(char*));
222  if ( !packet->path )
223  {
224  fapint_clear_llist(path);
225  free(rest);
226  }
227  for ( i = 0; i < path_len; ++i ) packet->path[i] = NULL;
228  i = 0;
229  current_elem = path->next;
230  while ( current_elem != NULL )
231  {
232  /* First we validate the element in a relaxed, APRS-IS-compatible way. */
233  if ( regexec(&fapint_regex_digicall, current_elem->text, matchcount, (regmatch_t*)&matches, 0) == 0 )
234  {
235  /* Check if we need to be AX.25-strict. */
236  if ( is_ax25 )
237  {
238  /* Create a copy the element without the has-been-repeated flag. */
239  memset(buf_10b, 0, 10);
240  memcpy(buf_10b, current_elem->text, matches[1].rm_eo);
241 
242  /* Validate it in AX.25-way. */
243  tmp = fap_check_ax25_call(buf_10b, 1);
244  if ( !tmp )
245  {
246  packet->error_code = malloc(sizeof(fap_error_code_t));
247  if ( packet->error_code ) *packet->error_code = fapDIGICALL_NOAX25;
248  retval = 0;
249  break;
250  }
251  free(tmp);
252  }
253 
254  /* Save the callsign as originally given. */
255  len = strlen(current_elem->text);
256  packet->path[i] = malloc(len+1);
257  if ( !packet->path[i] )
258  {
259  retval = 0;
260  break;
261  }
262  strcpy(packet->path[i], current_elem->text);
263 
264  /* Check if this element was a q-construct. */
265  if ( !seenq && current_elem->text[0] == 'q' ) seenq = 1;
266  }
267  /* This includes accepting IPv6 addresses after q-construct. */
268  else if ( seenq && regexec(&fapint_regex_digicallv6, current_elem->text, 0, NULL, 0) == 0 )
269  {
270  /* Save the callsign as originally given. */
271  len = strlen(current_elem->text);
272  packet->path[i] = malloc(len+1);
273  if ( !packet->path[i] )
274  {
275  retval = 0;
276  break;
277  }
278  strcpy(packet->path[i], current_elem->text);
279  }
280  else
281  {
282  packet->error_code = malloc(sizeof(fap_error_code_t));
283  if ( packet->error_code ) *packet->error_code = fapDIGICALL_BADCHARS;
284  retval = 0;
285  break;
286  }
287 
288  /* Get next element. */
289  current_elem = current_elem->next;
290  ++i;
291  }
292  if ( !retval )
293  {
294  fapint_clear_llist(path);
295  for ( len = 0; len <= i; ++len ) { free(packet->path[len]); }
296  free(packet->path);
297  packet->path = NULL;
298  free(rest);
299  return 0;
300  }
301  packet->path_len = path_len;
302 
303  /* Header parsed. */
304  fapint_clear_llist(path);
305  free(rest);
306  return 1;
307 }
308 
309 
310 
311 int fapint_parse_mice(fap_packet_t* packet, char const* input, unsigned int const input_len)
312 {
313  int len, error, i, lon;
314  unsigned int tmp_us;
315  char *rest, *tmp_str;
316  char dstcall[7], latitude[7], buf_6b[6], longitude[6];
317  double speed, course_speed, course_speed_tmp, course;
318  char dao[3];
319 
320  unsigned int const matchcount = 3;
321  regmatch_t matches[matchcount];
322 
323  /* Body must be at least 8 chars long. Destination callsign must exist. */
324  if ( input_len < 8 || packet->dst_callsign == NULL )
325  {
326  packet->error_code = malloc(sizeof(fap_error_code_t));
327  if ( packet->error_code ) *packet->error_code = fapMICE_SHORT;
328  return 0;
329  }
330 
331  /* Create copy of dst call without ssid. */
332  memset(dstcall, 0, 7);
333  for ( i = 0; i < strlen(packet->dst_callsign) && i < 6; ++i )
334  {
335  if ( packet->dst_callsign[i] == '-' ) break;
336  dstcall[i] = packet->dst_callsign[i];
337  }
338  if ( strlen(dstcall) != 6 )
339  {
340  packet->error_code = malloc(sizeof(fap_error_code_t));
341  if ( packet->error_code ) *packet->error_code = fapMICE_SHORT;
342  return 0;
343  }
344 
345  /* Validate target call. */
346  if ( regexec(&fapint_regex_mice_dstcall, dstcall, 0, NULL, 0) != 0 )
347  {
348  /* A-K characters are not used in the last 3 characters and MNO are never used. */
349  packet->error_code = malloc(sizeof(fap_error_code_t));
350  if ( packet->error_code ) *packet->error_code = fapMICE_INV;
351  return 0;
352  }
353 
354  /* Get symbol table. */
355  packet->symbol_table = input[7];
356 
357  /* Validate body. */
358  /* "^[\x26-\x7f][\x26-\x61][\x1c-\x7f]{2}[\x1c-\x7d][\x1c-\x7f][\x21-\x7b\x7d][\/\\A-Z0-9]" */
359  error = 0;
360  if ( input[0] < 0x26 || (unsigned char)input[0] > 0x7f ) error = 1;
361  if ( input[1] < 0x26 || input[1] > 0x61 ) error = 1;
362  if ( input[2] < 0x1c || (unsigned char)input[2] > 0x7f ) error = 1;
363  if ( input[3] < 0x1c || (unsigned char)input[3] > 0x7f ) error = 1;
364  if ( input[4] < 0x1c || input[4] > 0x7d ) error = 1;
365  if ( input[5] < 0x1c || (unsigned char)input[5] > 0x7f ) error = 1;
366  if ( input[6] != 0x7d && (input[6] < 0x21 || input[6] > 0x7b) ) error = 1;
367  if ( error || regexec(&fapint_regex_mice_body, input+7, 0, NULL, 0) != 0 )
368  {
369  packet->error_code = malloc(sizeof(fap_error_code_t));
370  if ( packet->error_code )
371  {
372  /* Validate symbol table. */
373  if ( ( packet->symbol_table == '/' ) ||
374  ( packet->symbol_table == '\\' ) ||
375  ( packet->symbol_table >= 'A' && packet->symbol_table <= 'Z' ) ||
376  isdigit(packet->symbol_table) )
377  {
378  // It's okay, we have some other error.
379  *packet->error_code = fapMICE_INV_INFO;
380  }
381  else
382  {
383  // It's not okay.
384  *packet->error_code = fapSYM_INV_TABLE;
385  }
386  }
387  return 0;
388  }
389 
390  /* Store pos format. */
391  packet->format = malloc(sizeof(fap_pos_format_t));
392  if ( !packet->format )
393  {
394  return 0;
395  }
396  *packet->format = fapPOS_MICE;
397 
398  /* Start process from the target call to find latitude, message bits, N/S
399  * and W/E indicators and long. offset. */
400 
401  /* First create a translated copy to find latitude. */
402  memset(latitude, 0, 7);
403  for ( i = 0; i < 6; ++i )
404  {
405  if ( dstcall[i] >= 'A' && dstcall[i] <= 'J' )
406  {
407  /* A-J -> 0-9 */
408  latitude[i] = dstcall[i] - 17;
409  }
410  else if ( dstcall[i] >= 'P' && dstcall[i] <= 'Y' )
411  {
412  /* P-Y -> 0-9 */
413  latitude[i] = dstcall[i] - 32;
414  }
415  else if ( dstcall[i] == 'K' || dstcall[i] == 'L' || dstcall[i] == 'Z' )
416  {
417  /* pos amb */
418  latitude[i] = '_';
419  }
420  else
421  {
422  latitude[i] = dstcall[i];
423  }
424  }
425 
426  /* Check the amount of position ambiguity. */
427  packet->pos_ambiguity = malloc(sizeof(unsigned int));
428  if ( !packet->pos_ambiguity ) return 0;
429  if ( regexec(&fapint_regex_mice_amb, latitude, matchcount, (regmatch_t*)&matches, 0) != 0 )
430  {
431  packet->error_code = malloc(sizeof(fap_error_code_t));
432  if ( packet->error_code ) *packet->error_code = fapMICE_AMB_LARGE;
433  return 0;
434  }
435  *packet->pos_ambiguity = matches[2].rm_eo - matches[2].rm_so;
436 
437  /* Validate ambiguity. */
438  if ( *packet->pos_ambiguity > 4 )
439  {
440  packet->error_code = malloc(sizeof(fap_error_code_t));
441  if ( packet->error_code ) *packet->error_code = fapMICE_AMB_INV;
442  return 0;
443  }
444 
445  /* Calculate position resolution. */
446  packet->pos_resolution = malloc(sizeof(double));
447  if ( !packet->pos_resolution ) return 0;
448  *packet->pos_resolution = fapint_get_pos_resolution(2 - *packet->pos_ambiguity);
449 
450  /* Convert the latitude to the midvalue if position ambiguity is used. */
451  if ( *packet->pos_ambiguity >= 4 )
452  {
453  /* The minute is between 0 and 60, so the midpoint is 30. */
454  tmp_str = strchr(latitude, '_');
455  *tmp_str = '3';
456  }
457  else
458  {
459  /* First digit is changed to 5. */
460  if ( (tmp_str = strchr(latitude, '_')) != NULL )
461  {
462  *tmp_str = '5';
463  }
464  }
465 
466  /* Remaining digits are changed to 0. */
467  while ( (tmp_str = strchr(latitude, '_')) != NULL )
468  {
469  *tmp_str = '0';
470  }
471 
472  /* Convert latitude degrees into number and save it. */
473  buf_6b[0] = latitude[0]; buf_6b[1] = latitude[1];
474  buf_6b[2] = 0;
475  packet->latitude = malloc(sizeof(double));
476  if ( !packet->latitude ) return 0;
477  *packet->latitude = atof(buf_6b);
478 
479  /* Same for minutes. */
480  buf_6b[0] = latitude[2]; buf_6b[1] = latitude[3];
481  buf_6b[2] = '.';
482  buf_6b[3] = latitude[4]; buf_6b[4] = latitude[5];
483  buf_6b[5] = 0;
484  *packet->latitude += atof(buf_6b)/60;
485 
486  /* Check the north/south direction and correct the latitude if necessary. */
487  if ( dstcall[3] <= 0x4c )
488  {
489  *packet->latitude = 0 - *packet->latitude;
490  }
491 
492  /* Get the message bits. 1 is standard one-bit and 2 is custom one-bit. */
493  packet->messagebits = malloc(4);
494  if ( !packet->messagebits ) return 0;
495  for ( i = 0; i < 3; ++i )
496  {
497  if ( (dstcall[i] >= '0' && dstcall[i] <= '9') || dstcall[i] == 'L' )
498  {
499  packet->messagebits[i] = '0';
500  }
501  else if ( dstcall[i] >= 'P' && dstcall[i] <= 'Z' )
502  {
503  packet->messagebits[i] = '1';
504  }
505  else if ( dstcall[i] >= 'A' && dstcall[i] <= 'K' )
506  {
507  packet->messagebits[i] = '2';
508  }
509  }
510  packet->messagebits[3] = 0;
511 
512  /* Decode the longitude, the first three bytes of the body after the data
513  * type indicator. First longitude degrees, remember the longitude offset. */
514  lon = input[0] - 28;
515  if ( dstcall[4] >= 0x50 )
516  {
517  lon += 100;
518  }
519  if ( lon >= 180 && lon <= 189 )
520  {
521  lon -= 80;
522  }
523  else if ( lon >= 190 && lon <= 199 )
524  {
525  lon -= 190;
526  }
527  packet->longitude = malloc(sizeof(double));
528  if ( !packet->longitude ) return 0;
529  *packet->longitude = lon;
530 
531  /* Get longitude minutes. */
532  memset(longitude, 0, 6);
533  lon = input[1] - 28;
534  if ( lon >= 60 )
535  {
536  lon -= 60;
537  }
538  sprintf(longitude, "%02d.%02d", lon, input[2] - 28);
539 
540  /* Apply pos amb and save. */
541  if ( *packet->pos_ambiguity == 4 )
542  {
543  /* Minutes are not used. */
544  *packet->longitude += 0.5;
545  }
546  else if ( *packet->pos_ambiguity == 3 )
547  {
548  /* 1 minute digit is used. */
549  tmp_str = malloc(3);
550  tmp_str[0] = longitude[0]; tmp_str[1] = '5'; tmp_str[2] = 0;
551  *packet->longitude += atof(tmp_str)/60;
552  free(tmp_str);
553  }
554  else if ( *packet->pos_ambiguity == 2 )
555  {
556  /* Whole minutes are used. */
557  memset(buf_6b, 0, 6);
558  buf_6b[0] = longitude[0];
559  buf_6b[1] = longitude[1];
560  buf_6b[2] = '.';
561  buf_6b[3] = '5';
562  *packet->longitude += atof(buf_6b)/60;
563  }
564  else if ( *packet->pos_ambiguity == 1 )
565  {
566  /* Whole minutes and 1 decimal are used. */
567  longitude[4] = '5';
568  *packet->longitude += atof(longitude)/60;
569  }
570  else if ( *packet->pos_ambiguity == 0 )
571  {
572  *packet->longitude += atof(longitude)/60;
573  }
574  else
575  {
576  packet->error_code = malloc(sizeof(fap_error_code_t));
577  if ( packet->error_code ) *packet->error_code = fapMICE_AMB_ODD;
578  return 0;
579  }
580 
581  /* Check E/W sign. */
582  if ( dstcall[5] >= 0x50 )
583  {
584  *packet->longitude = 0 - *packet->longitude;
585  }
586 
587  /* Now onto speed and course. */
588  speed = (input[3] - 28) * 10;
589  course_speed = input[4] - 28;
590  course_speed_tmp = floor(course_speed / 10);
591  speed += course_speed_tmp;
592  course_speed -= course_speed_tmp * 10;
593  course = 100 * course_speed;
594  course += input[5] - 28;
595 
596  /* Some adjustment. */
597  if ( speed >= 800 )
598  {
599  speed -= 800;
600  }
601  if ( course >= 400 )
602  {
603  course -= 400;
604  }
605 
606  /* Save values. */
607  packet->speed = malloc(sizeof(double));
608  if ( !packet->speed ) return 0;
609  *packet->speed = speed * KNOT_TO_KMH;
610  if ( course >= 0 )
611  {
612  packet->course = malloc(sizeof(unsigned int));
613  if ( !packet->course ) return 0;
614  *packet->course = course;
615  }
616 
617  /* Save symbol code. */
618  packet->symbol_code = input[6];
619 
620  /* If there's something left, create working copy of it. */
621  if ( (len = input_len - 8) > 0 )
622  {
623  rest = malloc(len);
624  memcpy(rest, input+8, len);
625  }
626  else
627  {
628  /* Nothing left, we're ok and out. */
629  return 1;
630  }
631 
632  /* Check for Mic-E telemetry. */
633 /*
634  bzero(buf_6b, 6);
635  fprintf(stderr, "SEARCHING 2-CHANNEL MIC-E TELEMETRY\n");
636  if ( rest[0] == '\'' )
637  {
638  for (i = 1; i <= 4; i++ )
639  {
640  if ( !isxdigit(rest[i]) )
641  {
642  i = 0;
643  break;
644  }
645  }
646  if ( i > 0 )
647  {
648  fprintf(stderr, "FOUND 2-CHANNEL MIC-E TELEMETRY\n");
649  packet->telemetry = malloc(sizeof(fap_telemetry_t));
650  if ( !packet->telemetry ) return;
651  packet->telemetry->val1 = malloc(sizeof(double));
652  if ( !packet->telemetry->val1 ) return;
653  buf_6b[0] = rest[1];
654  buf_6b[1] = rest[2];
655  *packet->telemetry->val1 = strtol(buf_6b, NULL, 16);
656  packet->telemetry->val3 = malloc(sizeof(double));
657  if ( !packet->telemetry->val3 ) return;
658  buf_6b[0] = rest[3];
659  buf_6b[1] = rest[4];
660  *packet->telemetry->val3 = strtol(buf_6b, NULL, 16);
661  }
662  }
663  fprintf(stderr, "DONE\n");
664  fprintf(stderr, "SEARCHING 5-CHANNEL MIC-E TELEMETRY\n");
665  if ( rest[0] == '`' )
666  {
667  for ( i = 1; i <= 10; i++ )
668  {
669  if ( !isxdigit(rest[i]) )
670  {
671  i = 0;
672  break;
673  }
674  }
675  if ( i > 0 )
676  {
677  fprintf(stderr, "FOUND 2 CHANNEL MIC-E TELEMETRY\n");
678  }
679  }
680  fprintf(stderr, "DONE\n");
681 */
682  /* Check for possible altitude. Altitude is base-91 coded and in format
683  * "xxx}" where x are the base-91 digits in meters, origin is 10000 meters
684  * below sea. */
685  for ( i = 0; i+3 < len; ++i )
686  {
687  /* Check for possible altitude digit. */
688  if ( rest[i] >= 0x21 && rest[i] <= 0x7b )
689  {
690  /* Check remaining digits for altitudeness. */
691  if ( (rest[i+1] >= 0x21 && rest[i+1] <= 0x7b) &&
692  (rest[i+2] >= 0x21 && rest[i+2] <= 0x7b) &&
693  rest[i+3] == '}' )
694  {
695  /* Save altitude. */
696  packet->altitude = malloc(sizeof(double));
697  if ( !packet->altitude )
698  {
699  free(rest);
700  return 0;
701  }
702  *packet->altitude = ( (rest[i] - 33) * pow(91,2) +
703  (rest[i+1] - 33) * 91 +
704  (rest[i+2] - 33) ) - 10000;
705  /* Remove altitude. */
706  tmp_str = fapint_remove_part(rest, len, i, i+4, &tmp_us);
707  free(rest);
708  rest = tmp_str;
709  len = tmp_us;
710  /* We're done. */
711  break;
712  }
713  }
714  }
715 
716  /* Check for base-91 comment telemetry. */
717  fapint_parse_comment_telemetry(packet, &rest, &len);
718 
719  /* If we still hafe stuff left, check for !DAO!, take the last occurrence (per recommendation). */
720  if ( len > 0 )
721  {
722  for ( i = len-1; i >= 0 ; --i )
723  {
724  if ( i + 4 < len && rest[i] == '!' &&
725  0x21 <= rest[i+1] && rest[i+1] <= 0x7b &&
726  0x20 <= rest[i+2] && rest[i+2] <= 0x7b &&
727  0x20 <= rest[i+3] && rest[i+3] <= 0x7b &&
728  rest[i+4] == '!' )
729  {
730  memcpy(dao, rest+i+1, 3);
731  /* Validate and save dao. */
732  if ( fapint_parse_dao(packet, dao) )
733  {
734  /* Remove !DAO!. */
735  tmp_str = fapint_remove_part(rest, len, i, i+5, &tmp_us);
736  free(rest);
737  rest = tmp_str;
738  len = tmp_us;
739  break;
740  }
741  }
742  }
743  }
744 
745  /* If there's something left, save it as a comment. */
746  if ( len > 0 )
747  {
748  packet->comment = rest;
749  packet->comment_len = len;
750  }
751 
752  return 1;
753 }
754 
755 
756 time_t fapint_parse_timestamp(char const* input)
757 {
758  char buf_3b[3];
759  unsigned int first, second, third;
760  char type;
761  struct tm now_struct, fwd_struct, back_struct, tmp_struct;
762  time_t thismonth, nextmonth, prevmonth, result;
763  const time_t now = time(NULL);
764 
765  unsigned int const matchcount = 5;
766  regmatch_t matches[matchcount];
767 
768  gmtime_r(&now, &now_struct);
769 
770  /* Validate input. */
771  if ( !input )
772  {
773  return 0;
774  }
775  if ( regexec(&fapint_regex_timestamp, input, matchcount, (regmatch_t*)&matches, 0) == 0 )
776  {
777  buf_3b[2] = 0;
778  /* Get three numbers. */
779  memcpy(buf_3b, input+matches[1].rm_so, 2);
780  first = atoi(buf_3b);
781  memcpy(buf_3b, input+matches[2].rm_so, 2);
782  second = atoi(buf_3b);
783  memcpy(buf_3b, input+matches[3].rm_so, 2);
784  third = atoi(buf_3b);
785 
786  /* Get type flag. */
787  type = input[matches[4].rm_so];
788  }
789  else
790  {
791  return 0;
792  }
793 
794  /* Continue based on stamp type. */
795  if ( type == 'h' )
796  {
797  /* HMS in UTC -format, check for valid time. */
798  if ( first > 23 || second > 59 || third > 59 )
799  {
800  return 0;
801  }
802 
803  /* Convert into unixtime. */
804  memcpy((struct tm*)&tmp_struct, &now_struct, sizeof(struct tm));
805  tmp_struct.tm_sec = third;
806  tmp_struct.tm_min = second;
807  tmp_struct.tm_hour = first;
808  result = timegm((struct tm*)&tmp_struct);
809 
810  /* If the time is more than about one hour into the future, roll the
811  timestamp one day backwards. */
812  if ( now + 3900 < result )
813  {
814  result -= 86400;
815  }
816  /* If the time is more than about 23 hours into the past, roll the
817  timestamp one day forwards. */
818  else if ( now - 82500 > result )
819  {
820  result += 86400;
821  }
822  return result;
823  }
824  else if ( type == 'z' || type == '/' )
825  {
826  /* DHM in UTC (z) or local(/). Always intepret local to mean local to this computer. */
827  if ( first < 1 || first > 31 || second > 23 || third > 59 )
828  {
829  return 0;
830  }
831 
832  /* If time is under about 12 hours into the future, go there.
833  Otherwise get the first matching time in the past. */
834 
835  /* Form the possible timestamps. */
836 
837  /* This month. */
838  memcpy((struct tm*)&tmp_struct, &now_struct, sizeof(struct tm));
839  tmp_struct.tm_mday = first;
840  tmp_struct.tm_hour = second;
841  tmp_struct.tm_min = third;
842  tmp_struct.tm_sec = 0;
843  thismonth = timegm((struct tm*)&tmp_struct);
844 
845  /* Next month. */
846  memcpy((struct tm*)&tmp_struct, &now_struct, sizeof(struct tm));
847  tmp_struct.tm_mon += 1;
848  tmp_struct.tm_mday = first;
849  tmp_struct.tm_hour = second;
850  tmp_struct.tm_min = third;
851  tmp_struct.tm_sec = 0;
852  nextmonth = timegm((struct tm*)&tmp_struct);
853 
854  /* Previous month. */
855  memcpy((struct tm*)&tmp_struct, &now_struct, sizeof(struct tm));
856  if ( tmp_struct.tm_mon == 0 )
857  {
858  tmp_struct.tm_mon = 11;
859  tmp_struct.tm_year -= 1;
860  }
861  else
862  {
863  tmp_struct.tm_mon -= 1;
864  }
865  tmp_struct.tm_mday = first;
866  tmp_struct.tm_hour = second-1;
867  tmp_struct.tm_min = third;
868  tmp_struct.tm_sec = 0;
869  prevmonth = timegm((struct tm*)&tmp_struct);
870 
871  /* Select the timestamp to use. Pick the timestamp that is largest,
872  but under about 12 hours from current time. */
873  if ( nextmonth - now < 43400 )
874  {
875  result = nextmonth;
876  }
877  else if ( thismonth - now < 43400 )
878  {
879  result = thismonth;
880  }
881  else
882  {
883  result = prevmonth;
884  }
885 
886  /* Convert local to UTC. */
887  if ( type == '/' )
888  {
889  result += timezone;
890  }
891 
892  return result;
893  }
894 
895  return 0;
896 }
897 
898 
899 int fapint_parse_compressed(fap_packet_t* packet, char const* input)
900 {
901  int i;
902  char symboltable, symbolcode;
903  char lat[4], lon[4];
904  char c1, s1, comptype;
905  char cs;
906 
907  /* Validate compressed position and things. */
908  if ( strlen(input) < 13 )
909  {
910  packet->error_code = malloc(sizeof(fap_error_code_t));
911  if ( packet->error_code ) *packet->error_code = fapCOMP_INV;
912  return 0;
913  }
914  if ( !(
915  (input[0] >= 'A' && input[0] <= 'Z') ||
916  (input[0] >= 'a' && input[0] <= 'j') ||
917  input[0] == '/' ||
918  input[0] == '\\')
919  )
920  {
921  packet->error_code = malloc(sizeof(fap_error_code_t));
922  if ( packet->error_code ) *packet->error_code = fapCOMP_INV;
923  return 0;
924  }
925  for ( i = 1; i <= 8; ++i )
926  {
927  if ( input[i] < 0x21 || input[i] > 0x7b )
928  {
929  packet->error_code = malloc(sizeof(fap_error_code_t));
930  if ( packet->error_code ) *packet->error_code = fapCOMP_INV;
931  return 0;
932  }
933  }
934  if ( input[9] != 0x7d && (input[9] < 0x21 || input[9] > 0x7b) )
935  {
936  packet->error_code = malloc(sizeof(fap_error_code_t));
937  if ( packet->error_code ) *packet->error_code = fapCOMP_INV;
938  return 0;
939  }
940  for ( i = 10; i <= 12; ++i )
941  {
942  if ( input[i] < 0x20 || input[i] > 0x7b )
943  {
944  packet->error_code = malloc(sizeof(fap_error_code_t));
945  if ( packet->error_code ) *packet->error_code = fapCOMP_INV;
946  return 0;
947  }
948  }
949 
950  /* Store pos format. */
951  packet->format = malloc(sizeof(fap_pos_format_t));
952  if ( !packet->format )
953  {
954  return 0;
955  }
956  *packet->format = fapPOS_COMPRESSED;
957 
958  /* Get symbol. */
959  symboltable = input[0];
960  symbolcode = input[9];
961 
962  /* Get position. */
963  for ( i = 0; i < 4; ++i )
964  {
965  lat[i] = input[i+1] - 33;
966  lon[i] = input[i+5] - 33;
967  }
968 
969  /* Get other data. */
970  c1 = input[10] - 33;
971  s1 = input[11] - 33;
972  comptype = input[12] - 33;
973 
974  /* Save symbol table. Table chars (a-j) are converted to numbers 0-9. */
975  if ( symboltable >= 'a' && symboltable <= 'j' )
976  {
977  symboltable -= 81;
978  }
979  packet->symbol_table = symboltable;
980 
981  /* Save symbol code as is. */
982  packet->symbol_code = symbolcode;
983 
984 
985  /* Calculate position. */
986  packet->latitude = malloc(sizeof(double));
987  if ( !packet->latitude ) return 0;
988  *packet->latitude = 90 - ( (lat[0] * pow(91,3) + lat[1] * pow(91,2) + lat[2] * 91 + lat[3]) / 380926);
989  packet->longitude = malloc(sizeof(double));
990  if ( !packet->latitude ) return 0;
991  *packet->longitude = -180 + ( (lon[0] * pow(91,3) + lon[1] * pow(91,2) + lon[2] * 91 + lon[3]) / 190463);
992 
993  /* Save best-case position resolution in meters: 1852 meters * 60 minutes in a degree * 180 degrees / 91^4. */
994  packet->pos_resolution = malloc(sizeof(double));
995  if ( !packet->pos_resolution ) return 0;
996  *packet->pos_resolution = 0.291;
997 
998  /* GPS fix status, only if csT is used. */
999  if ( c1 != -1 )
1000  {
1001  packet->gps_fix_status = malloc(sizeof(short));
1002  if ( !packet->gps_fix_status ) return 0;
1003  if ( (comptype & 0x20) == 0x20 )
1004  {
1005  *packet->gps_fix_status = 1;
1006  }
1007  else
1008  {
1009  *packet->gps_fix_status = 0;
1010  }
1011  }
1012 
1013  /* Check the compression type, if GPGGA, then the cs bytes are altitude.
1014  * Otherwise try to decode it as course and speed and finally as radio range.
1015  * If c is space, then csT is not used. Also require that s is not a space. */
1016  if ( c1 == -1 || s1 == -1 )
1017  {
1018  /* csT not used. */
1019  }
1020  else if ( (comptype & 0x18) == 0x10 )
1021  {
1022  /* cs is altitude. */
1023  cs = c1 * 91 + s1;
1024  packet->altitude = malloc(sizeof(double));
1025  if ( !packet->altitude ) return 0;
1026  /* Convert directly to meters. */
1027  *packet->altitude = pow(1.002, cs) * 0.3048;
1028  }
1029  else if ( c1 >= 0 && c1 <= 89 )
1030  {
1031  packet->course = malloc(sizeof(unsigned int));
1032  if ( !packet->course ) return 0;
1033  if ( c1 == 0 )
1034  {
1035  /* Special case of north, APRS spec uses zero for unknown and 360 for north.
1036  * So remember to convert north here. */
1037  *packet->course = 360;
1038  }
1039  else
1040  {
1041  *packet->course = c1 * 4;
1042  }
1043  /* Convert directly to km/h. */
1044  packet->speed = malloc(sizeof(double));
1045  if ( !packet->speed ) return 0;
1046  *packet->speed = ( pow(1.08, s1) - 1 ) * KNOT_TO_KMH;
1047  }
1048  else if ( c1 == 90 )
1049  {
1050  /* Convert directly to km. */
1051  packet->radio_range = malloc(sizeof(unsigned int));
1052  if ( !packet->radio_range ) return 0;
1053  *packet->radio_range = 2 * pow(1.08, s1) * MPH_TO_KMH;
1054  }
1055 
1056  return 1;
1057 }
1058 
1059 
1060 int fapint_parse_normal(fap_packet_t* packet, char const* input)
1061 {
1062  char sind, wind;
1063  short is_south = 0;
1064  short is_west = 0;
1065  char lat_deg[3], lat_min[6], lon_deg[4], lon_min[6], tmp_5b[5];
1066  double lat, lon;
1067 
1068  unsigned int const matchcount = 9;
1069  regmatch_t matches[matchcount];
1070 
1071 
1072  /* Check length. */
1073  if ( strlen(input) < 19 )
1074  {
1075  packet->error_code = malloc(sizeof(fap_error_code_t));
1076  if ( packet->error_code ) *packet->error_code = fapLOC_SHORT;
1077  return 0;
1078  }
1079 
1080  /* Save pos format. */
1081  packet->format = malloc(sizeof(fap_pos_format_t));
1082  if ( !packet->format )
1083  {
1084  return 0;
1085  }
1086  *packet->format = fapPOS_UNCOMPRESSED;
1087 
1088  /* Validate. */
1089  if ( regexec(&fapint_regex_normalpos, input, matchcount, (regmatch_t*)&matches, 0) != 0 )
1090  {
1091  packet->error_code = malloc(sizeof(fap_error_code_t));
1092  if ( packet->error_code ) *packet->error_code = fapLOC_INV;
1093  return 0;
1094  }
1095  if ( input[18] != 0x7d && (input[18] < 0x21 || input[18] > 0x7b) )
1096  {
1097  packet->error_code = malloc(sizeof(fap_error_code_t));
1098  if ( packet->error_code ) *packet->error_code = fapLOC_INV;
1099  return 0;
1100  }
1101 
1102  /* Save hemisphere info. */
1103  sind = toupper(input[matches[3].rm_so]);
1104  wind = toupper(input[matches[7].rm_so]);
1105 
1106  /* Save symbol table and code. */
1107  packet->symbol_table = input[matches[4].rm_so];
1108  packet->symbol_code = input[18];
1109 
1110  /* Save position numbers as NULL-terminated strings. */
1111  memset(lat_deg, 0, 3);
1112  memcpy(lat_deg, input+matches[1].rm_so, 2);
1113  memset(lat_min, 0, 6);
1114  memcpy(lat_min, input+matches[2].rm_so, 5);
1115  memset(lon_deg, 0, 4);
1116  memcpy(lon_deg, input+matches[5].rm_so, 3);
1117  memset(lon_min, 0, 6);
1118  memcpy(lon_min, input+matches[6].rm_so, 5);
1119 
1120  /* Validate symbol table. */
1121  if ( ( packet->symbol_table == '/' ) ||
1122  ( packet->symbol_table == '\\' ) ||
1123  ( packet->symbol_table >= 'A' && packet->symbol_table <= 'Z' ) ||
1124  isdigit(packet->symbol_table) )
1125  {
1126  // It's okay.
1127  }
1128  else
1129  {
1130  // It's not.
1131  packet->error_code = malloc(sizeof(fap_error_code_t));
1132  if ( packet->error_code ) *packet->error_code = fapSYM_INV_TABLE;
1133  return 0;
1134  }
1135 
1136  /* Convert hemisphere indicators to numbers. */
1137  if ( sind == 'S' ) is_south = 1;
1138  if ( wind == 'W' ) is_west = 1;
1139 
1140  /* Convert degrees to numbers and check them. */
1141  lat = atoi(lat_deg);
1142  lon = atoi(lon_deg);
1143  if ( lat > 89 || lon > 179 )
1144  {
1145  packet->error_code = malloc(sizeof(fap_error_code_t));
1146  if ( packet->error_code ) *packet->error_code = fapLOC_LARGE;
1147  return 0;
1148  }
1149 
1150  /* Prepare to parse position ambiguity. */
1151  packet->pos_ambiguity = malloc(sizeof(unsigned int));
1152  if ( !packet->pos_ambiguity ) return 0;
1153 
1154  /* First task is to create a copy without the decimal separator. */
1155  tmp_5b[0] = lat_min[0];
1156  tmp_5b[1] = lat_min[1];
1157  tmp_5b[2] = lat_min[3];
1158  tmp_5b[3] = lat_min[4];
1159  tmp_5b[4] = 0;
1160 
1161  /* Calculate ambiguity, which is the amount of spaces at the end. */
1162  if ( regexec(&fapint_regex_normalamb, tmp_5b, matchcount, (regmatch_t*)&matches, 0) != 0 )
1163  {
1164  packet->error_code = malloc(sizeof(fap_error_code_t));
1165  if ( packet->error_code ) *packet->error_code = fapLOC_AMB_INV;
1166  return 0;
1167  }
1168  *packet->pos_ambiguity = matches[2].rm_eo - matches[2].rm_so;
1169 
1170  /* Continue depending on amount of position ambiguity. */
1171  packet->latitude = malloc(sizeof(double));
1172  packet->longitude = malloc(sizeof(double));
1173  if ( !packet->latitude || !packet->longitude ) return 0;
1174  switch ( *packet->pos_ambiguity )
1175  {
1176  case 0:
1177  /* Validate longitude and save values. */
1178  if ( strchr(lon_min, ' ') != NULL )
1179  {
1180  packet->error_code = malloc(sizeof(fap_error_code_t));
1181  if ( packet->error_code ) *packet->error_code = fapLOC_AMB_INV;
1182  return 0;
1183  }
1184  else
1185  {
1186  *packet->latitude = lat + atof(lat_min)/60;
1187  *packet->longitude = lon + atof(lon_min)/60;
1188  }
1189  break;
1190  case 4:
1191  /* Disregard the minutes and add 0.5 to the degree values. */
1192  *packet->latitude = lat + 0.5;
1193  *packet->longitude = lon + 0.5;
1194  break;
1195  case 1:
1196  case 2:
1197  /* Blank digits are just ignored. */
1198  *packet->latitude = lat + atof(lat_min)/60;
1199  *packet->longitude = lon + atof(lon_min)/60;
1200  break;
1201  case 3:
1202  /* Single minute digit is set to 5, minute decimals are ignored. */
1203  lat_min[1] = '5';
1204  memset(lat_min+2, 0, 4);
1205  lon_min[1] = '5';
1206  memset(lon_min+2, 0, 4);
1207  *packet->latitude = lat + atof(lat_min)/60;
1208  *packet->longitude = lon + atof(lon_min)/60;
1209  break;
1210  default:
1211  packet->error_code = malloc(sizeof(fap_error_code_t));
1212  if ( packet->error_code ) *packet->error_code = fapLOC_AMB_INV;
1213  return 0;
1214  }
1215 
1216  /* Apply hemisphere indicators. */
1217  if ( is_south )
1218  {
1219  *packet->latitude = 0 - *packet->latitude;
1220  }
1221  if ( is_west )
1222  {
1223  *packet->longitude = 0 - *packet->longitude;
1224  }
1225 
1226  /* Calculate position resolution based on position ambiguity. */
1227  packet->pos_resolution = malloc(sizeof(double));
1228  if ( !packet->pos_resolution ) return 0;
1229  *packet->pos_resolution = fapint_get_pos_resolution(2 - *packet->pos_ambiguity);
1230 
1231  return 1;
1232 }
1233 
1234 
1235 
1236 void fapint_parse_comment(fap_packet_t* packet, char const* input, unsigned int const input_len)
1237 {
1238  char course[4], speed[4], range[5], altitude[7], dao[3];
1239  int i, tmp_s;
1240  char* tmp_str, *rest = NULL;
1241  unsigned int rest_len = 0, tmp_us;
1242 
1243  unsigned int const matchcount = 2;
1244  regmatch_t matches[matchcount];
1245 
1246 
1247  /* First check the possible APRS data extension, immediately following the
1248  packet. Then check for PHG. */
1249  if ( input_len >= 7 )
1250  {
1251  /* Look for data. */
1252  if ( regexec(&fapint_regex_comment, input, 0, NULL, 0) == 0 )
1253  {
1254  /* Get and validate course, if not already available. 0 stands for invalid. */
1255  if ( !packet->course )
1256  {
1257  memcpy(course, input, 3);
1258  course[3] = 0;
1259  packet->course = malloc(sizeof(unsigned int));
1260  if ( !packet->course ) return;
1261  *packet->course = 0;
1262  if ( isdigit(course[0]) && isdigit(course[1]) && isdigit(course[2]) )
1263  {
1264  tmp_s = atoi(course);
1265  if ( tmp_s >= 1 && tmp_s <= 360 )
1266  {
1267  /* It's valid, let's save it. */
1268  *packet->course = tmp_s;
1269  }
1270  }
1271  }
1272 
1273  /* Get and validate speed, if not available already. */
1274  if ( !packet->speed )
1275  {
1276  /* There's no speed value for invalid, so we leave it unallocated by default. */
1277  memcpy(speed, input+4, 3);
1278  speed[3] = 0;
1279  if ( isdigit(speed[0]) && isdigit(speed[1]) && isdigit(speed[2]) )
1280  {
1281  tmp_s = atoi(&speed[0]);
1282  packet->speed = malloc(sizeof(double));
1283  if ( !packet->speed ) return;
1284  *packet->speed = tmp_s * KNOT_TO_KMH;
1285  }
1286  }
1287 
1288  /* Save the rest. */
1289  rest = fapint_remove_part(input, input_len, 0, 7, &rest_len);
1290  }
1291  /* Look for PHGR. */
1292  else if ( regexec(&fapint_regex_phgr, input, 0, NULL, 0) == 0 &&
1293  input[4] >= 0x30 && input[4] <= 0x7e )
1294  {
1295  /* Save PHGR. */
1296  packet->phg = malloc(6);
1297  if ( !packet->phg ) return;
1298  memcpy(packet->phg, input+3, 5);
1299  packet->phg[5] = 0;
1300 
1301  /* Save the rest. */
1302  rest = fapint_remove_part(input, input_len, 0, 8, &rest_len);
1303  }
1304  /* Look for PHG. */
1305  else if ( regexec(&fapint_regex_phg, input, 0, NULL, 0) == 0 &&
1306  input[4] >= 0x30 && input[4] <= 0x7e )
1307  {
1308  /* Save PHG. */
1309  packet->phg = malloc(5);
1310  if ( !packet->phg ) return;
1311  memcpy(packet->phg, input+3, 4);
1312  packet->phg[4] = 0;
1313 
1314  /* Save the rest. */
1315  rest = fapint_remove_part(input, input_len, 0, 7, &rest_len);
1316  }
1317  /* Look for RNG. */
1318  else if ( regexec(&fapint_regex_rng, input, 0, NULL, 0) == 0 )
1319  {
1320  /* Save and validate range. There's no invalid range value. */
1321  memcpy(range, input+3, 4);
1322  range[4] = 0;
1323  tmp_s = atoi(range);
1324  packet->radio_range = malloc(sizeof(unsigned int));
1325  if ( !packet->radio_range ) return;
1326  *packet->radio_range = tmp_s * MPH_TO_KMH;
1327 
1328  /* Save the rest. */
1329  rest = fapint_remove_part(input, input_len, 0, 7, &rest_len);
1330  }
1331  else
1332  {
1333  rest = malloc(input_len+1);
1334  if ( !rest ) return;
1335  memcpy(rest, input, input_len);
1336  rest_len = input_len;
1337  rest[rest_len] = 0;
1338  }
1339  }
1340  else if ( input_len > 0 )
1341  {
1342  rest = malloc(input_len+1);
1343  if ( !rest ) return;
1344  memcpy(rest, input, input_len);
1345  rest_len = input_len;
1346  rest[rest_len] = 0;
1347  }
1348 
1349  /* Check if we still have something left. */
1350  if ( rest_len > 0 )
1351  {
1352  /* Check for optional altitude anywhere in the comment, take the first occurrence. */
1353  if ( regexec(&fapint_regex_altitude, rest, matchcount, (regmatch_t*)&matches, 0) == 0 )
1354  {
1355  /* Save altitude, if not already there. */
1356  if ( !packet->altitude )
1357  {
1358  memcpy(altitude, rest+matches[1].rm_so, 6);
1359  altitude[6] = 0;
1360  tmp_s = atoi(altitude);
1361  packet->altitude = malloc(sizeof(double));
1362  *packet->altitude = tmp_s * FT_TO_M;
1363  }
1364 
1365  /* Remove altitude. */
1366  tmp_str = fapint_remove_part(rest, rest_len, matches[1].rm_so-3, matches[1].rm_eo, &tmp_us);
1367  free(rest);
1368  rest = tmp_str;
1369  rest_len = tmp_us;
1370  }
1371  }
1372 
1373  /* Check for base-91 comment telemetry. */
1374  fapint_parse_comment_telemetry(packet, &rest, &rest_len);
1375 
1376  /* If we still hafe stuff left, check for !DAO!, take the last occurrence (per recommendation). */
1377  if ( rest_len > 0 )
1378  {
1379  for ( i = rest_len-1; i >= 0 ; --i )
1380  {
1381  if ( i + 4 < rest_len && rest[i] == '!' &&
1382  0x21 <= rest[i+1] && rest[i+1] <= 0x7b &&
1383  0x20 <= rest[i+2] && rest[i+2] <= 0x7b &&
1384  0x20 <= rest[i+3] && rest[i+3] <= 0x7b &&
1385  rest[i+4] == '!' )
1386  {
1387  memcpy(dao, rest+i+1, 3);
1388  /* Validate and save dao. */
1389  if ( fapint_parse_dao(packet, dao) )
1390  {
1391  /* Remove !DAO!. */
1392  tmp_str = fapint_remove_part(rest, rest_len, i, i+5, &tmp_us);
1393  free(rest);
1394  rest = tmp_str;
1395  rest_len = tmp_us;
1396  break;
1397  }
1398  }
1399  }
1400  }
1401 
1402  /* If there's something left, save it as a comment. */
1403  if ( rest_len > 0 )
1404  {
1405  packet->comment = rest;
1406  packet->comment_len = rest_len;
1407  }
1408 }
1409 
1410 
1411 
1412 int fapint_parse_nmea(fap_packet_t* packet, char const* input, unsigned int const input_len)
1413 {
1414  char* rest;
1415  unsigned int rest_len;
1416  int i, len, retval = 1;
1417 
1418  char* checksum_area;
1419  char checksum_given_str[3];
1420  long int checksum_given;
1421  long int checksum_calculated = 0;
1422 
1423  fapint_llist_item_t* nmea_field_list = NULL, *current_elem = NULL;
1424  char** nmea_fields = NULL;
1425  unsigned int nmea_field_count;
1426  char* tmp_str;
1427 
1428  char buf_3b[3];
1429  unsigned int year, month, day, hours, mins, secs;
1430  struct tm timestamp;
1431 
1432  unsigned int const matchcount = 5;
1433  regmatch_t matches[matchcount];
1434 
1435  /* Create working copy of input with no trailing white spaces. */
1436  for ( i = input_len-1; i >= 0; ++i )
1437  {
1438  if ( !isspace(input[i]) )
1439  {
1440  break;
1441  }
1442  }
1443  rest_len = i+1;
1444 
1445  if ( rest_len > 0 )
1446  {
1447  rest = malloc(rest_len+1);
1448  if ( !rest ) return 0;
1449  memcpy(rest, input, rest_len);
1450  rest[rest_len] = 0;
1451  }
1452  else
1453  {
1454  return 0;
1455  }
1456 
1457  /* Verify first, if it is provided. */
1458  if ( regexec(&fapint_regex_nmea_chksum, rest, matchcount, (regmatch_t*)&matches, 0) == 0 )
1459  {
1460  len = matches[1].rm_eo - matches[1].rm_so;
1461  checksum_area = malloc(len+1);
1462  if ( !checksum_area )
1463  {
1464  free(rest);
1465  return 0;
1466  }
1467  memcpy(checksum_area, rest+matches[1].rm_so, len);
1468  checksum_area[len] = 0;
1469 
1470  checksum_given_str[0] = rest[matches[2].rm_so];
1471  checksum_given_str[1] = rest[matches[2].rm_so+1];
1472  checksum_given_str[2] = 0;
1473  checksum_given = strtol(checksum_given_str, NULL, 16);
1474 
1475  for ( i = 0; i < strlen(checksum_area); ++i )
1476  {
1477  checksum_calculated ^= checksum_area[i];
1478  }
1479  free(checksum_area);
1480 
1481  if ( checksum_given != checksum_calculated )
1482  {
1483  packet->error_code = malloc(sizeof(fap_error_code_t));
1484  if ( packet->error_code ) *packet->error_code = fapNMEA_INV_CKSUM;
1485  free(rest);
1486  return 0;
1487  }
1488 
1489  /* Make a note of the existance of a checksum. */
1490  packet->nmea_checksum_ok = malloc(sizeof(short));
1491  if ( !packet->nmea_checksum_ok )
1492  {
1493  free(rest);
1494  return 0;
1495  }
1496  *packet->nmea_checksum_ok = 1;
1497 
1498  /* Remove checksum. */
1499  rest = fapint_remove_part(rest, rest_len, matches[2].rm_so-1, matches[2].rm_eo, &rest_len);
1500  }
1501  else
1502  {
1503  printf("no checksum in (%s)", rest);
1504  }
1505 
1506  /* Format is NMEA. */
1507  packet->format = malloc(sizeof(fap_pos_format_t));
1508  if ( !packet->format )
1509  {
1510  free(rest);
1511  return 0;
1512  }
1513  *packet->format = fapPOS_NMEA;
1514 
1515  /* Use a dot as a default symbol if one is not defined in the destination callsign. */
1517  {
1518  packet->symbol_table = '/';
1519  packet->symbol_code = '/';
1520  }
1521 
1522  /* Split to NMEA fields. */
1523  tmp_str = strtok(rest, ",");
1524  nmea_field_count = 0;
1525  while ( tmp_str != NULL )
1526  {
1527  /* Create new element. */
1528  if ( !nmea_field_list )
1529  {
1530  nmea_field_list = malloc(sizeof(fapint_llist_item_t));
1531  if ( !nmea_field_list ) return 0;
1532  current_elem = nmea_field_list;
1533  }
1534  else
1535  {
1536  current_elem->next = malloc(sizeof(fapint_llist_item_t));
1537  if ( !current_elem->next )
1538  {
1539  retval = 0;
1540  break;
1541  }
1542  current_elem = current_elem->next;
1543  }
1544  current_elem->next = NULL;
1545 
1546  /* Save element. */
1547  current_elem->text = malloc(strlen(tmp_str)+1);
1548  if ( !current_elem->text )
1549  {
1550  retval = 0;
1551  break;
1552  }
1553  strcpy(current_elem->text, tmp_str);
1554  nmea_field_count++;
1555 
1556  /* Try to get next. */
1557  tmp_str = strtok(NULL, ",");
1558  }
1559  if ( !retval )
1560  {
1561  fapint_clear_llist(nmea_field_list);
1562  free(rest);
1563  return 0;
1564  }
1565 
1566  /* Collect NMEA fields into an array. */
1567  do
1568  {
1569  if ( !nmea_field_count )
1570  {
1571  packet->error_code = malloc(sizeof(fap_error_code_t));
1572  if ( packet->error_code ) *packet->error_code = fapNMEA_NOFIELDS;
1573  retval = 0;
1574  break;
1575  }
1576  else
1577  {
1578  nmea_fields = calloc(nmea_field_count, sizeof(char*));
1579  if ( !nmea_fields )
1580  {
1581  retval = 0;
1582  break;
1583  }
1584  for ( i = 0; i < nmea_field_count; ++i ) nmea_fields[i] = NULL;
1585  current_elem = nmea_field_list;
1586  i = 0;
1587  while ( current_elem != NULL )
1588  {
1589  nmea_fields[i] = malloc(strlen(current_elem->text)+1);
1590  if ( !nmea_fields[i] )
1591  {
1592  retval = 0;
1593  break;
1594  }
1595  strcpy(nmea_fields[i], current_elem->text);
1596  current_elem = current_elem->next;
1597  i++;
1598  }
1599  }
1600  }
1601  while ( 0 );
1602  fapint_clear_llist(nmea_field_list);
1603  if ( !retval )
1604  {
1605  free(nmea_fields);
1606  free(rest);
1607  return 0;
1608  }
1609 
1610 
1611  /* Now check the sentence type and get as much info as we can (want). */
1612  while ( retval )
1613  {
1614  if ( strcmp(nmea_fields[0], "GPRMC") == 0 )
1615  {
1616  /* We want at least 10 fields. */
1617  if ( nmea_field_count < 10 )
1618  {
1619  packet->error_code = malloc(sizeof(fap_error_code_t));
1620  if ( packet->error_code ) *packet->error_code = fapGPRMC_FEWFIELDS;
1621  retval = 0;
1622  break;
1623  }
1624 
1625  /* Check for fix. */
1626  if ( strcmp(nmea_fields[2], "A" ) != 0 )
1627  {
1628  packet->error_code = malloc(sizeof(fap_error_code_t));
1629  if ( packet->error_code ) *packet->error_code = fapGPRMC_NOFIX;
1630  retval = 0;
1631  break;
1632  }
1633 
1634  /* Check and get timestamp. */
1635  if ( regexec(&fapint_regex_nmea_time, nmea_fields[1], matchcount, (regmatch_t*)&matches, 0) == 0 )
1636  {
1637  buf_3b[2] = 0;
1638  memcpy(buf_3b, nmea_fields[1]+matches[1].rm_so, 2);
1639  hours = atoi(buf_3b);
1640  memcpy(buf_3b, nmea_fields[1]+matches[2].rm_so, 2);
1641  mins = atoi(buf_3b);
1642  memcpy(buf_3b, nmea_fields[1]+matches[3].rm_so, 2);
1643  secs = atoi(buf_3b);
1644 
1645  if ( hours > 23 || mins > 59 || secs > 59 )
1646  {
1647  packet->error_code = malloc(sizeof(fap_error_code_t));
1648  if ( packet->error_code ) *packet->error_code = fapGPRMC_INV_TIME;
1649  retval = 0;
1650  break;
1651  }
1652  }
1653  else
1654  {
1655  packet->error_code = malloc(sizeof(fap_error_code_t));
1656  if ( packet->error_code ) *packet->error_code = fapGPRMC_INV_TIME;
1657  retval = 0;
1658  break;
1659  }
1660 
1661  /* Check and get date. */
1662  if ( regexec(&fapint_regex_nmea_date, nmea_fields[9], matchcount, (regmatch_t*)&matches, 0) == 0 )
1663  {
1664  buf_3b[2] = 0;
1665  memcpy(buf_3b, nmea_fields[9]+matches[1].rm_so, 2);
1666  day = atoi(buf_3b);
1667  memcpy(buf_3b, nmea_fields[9]+matches[2].rm_so, 2);
1668  month = atoi(buf_3b);
1669  memcpy(buf_3b, nmea_fields[9]+matches[3].rm_so, 2);
1670  year = atoi(buf_3b);
1671 
1672  /* Check the date for validity. Assume years 0-69 are 21st
1673  century and years 70-99 are 20th century. */
1674  if ( year < 70 )
1675  {
1676  year += 2000;
1677  }
1678  else
1679  {
1680  year += 1900;
1681  }
1682  if ( !fapint_check_date(year, month, day) )
1683  {
1684  packet->error_code = malloc(sizeof(fap_error_code_t));
1685  if ( packet->error_code ) *packet->error_code = fapGPRMC_INV_DATE;
1686  retval = 0;
1687  break;
1688  }
1689  }
1690  else
1691  {
1692  packet->error_code = malloc(sizeof(fap_error_code_t));
1693  if ( packet->error_code ) *packet->error_code = fapGPRMC_INV_DATE;
1694  retval = 0;
1695  break;
1696  }
1697 
1698  /* Save date and time. We can only handle 32-bit unix timestamps,
1699  so we need to check for non-representable years. */
1700  if ( year >= 2038 || year < 1970 )
1701  {
1702  packet->error_code = malloc(sizeof(fap_error_code_t));
1703  if ( packet->error_code ) *packet->error_code = fapGPRMC_DATE_OUT;
1704  retval = 0;
1705  break;
1706  }
1707  else
1708  {
1709  timestamp.tm_sec = secs;
1710  timestamp.tm_min = mins;
1711  timestamp.tm_hour = hours;
1712  timestamp.tm_mday = day;
1713  timestamp.tm_mon = month-1;
1714  timestamp.tm_year = year-1900;
1715  timestamp.tm_isdst = 0;
1716  packet->timestamp = malloc(sizeof(time_t));
1717  if ( !packet->timestamp )
1718  {
1719  retval = 0;
1720  break;
1721  }
1722  *packet->timestamp = (time_t)mktime(&timestamp) - (time_t)timezone;
1723  }
1724 
1725  /* Get speed, if available. */
1726  if ( regexec(&fapint_regex_nmea_specou, nmea_fields[7], matchcount, (regmatch_t*)&matches, 0) == 0 )
1727  {
1728  len = matches[1].rm_eo - matches[1].rm_so;
1729  tmp_str = malloc(len+1);
1730  if ( !tmp_str )
1731  {
1732  retval = 0;
1733  break;
1734  }
1735  memcpy(tmp_str, nmea_fields[7]+matches[1].rm_so, len);
1736  tmp_str[len] = 0;
1737 
1738  packet->speed = malloc(sizeof(double));
1739  if ( !packet->speed )
1740  {
1741  retval = 0;
1742  break;
1743  }
1744  *packet->speed = atof(tmp_str) * KNOT_TO_KMH;
1745  free(tmp_str); tmp_str = NULL;
1746  }
1747 
1748  /* Get course, if available. */
1749  if ( regexec(&fapint_regex_nmea_specou, nmea_fields[8], matchcount, (regmatch_t*)&matches, 0) == 0 )
1750  {
1751  len = matches[1].rm_eo - matches[1].rm_so;
1752  tmp_str = malloc(len+1);
1753  if ( !tmp_str )
1754  {
1755  retval = 0;
1756  break;
1757  }
1758  memcpy(tmp_str, nmea_fields[8]+matches[1].rm_so, len);
1759  tmp_str[len] = 0;
1760 
1761  packet->course = malloc(sizeof(unsigned int));
1762  if ( !packet->course )
1763  {
1764  retval = 0;
1765  break;
1766  }
1767  *packet->course = atof(tmp_str) + 0.5;
1768  free(tmp_str); tmp_str = NULL;
1769 
1770  /* If zero, set to 360 because in APRS zero means invalid course... */
1771  if ( *packet->course == 0 )
1772  {
1773  *packet->course = 360;
1774  }
1775  else if ( *packet->course > 360 )
1776  {
1777  *packet->course = 0;
1778  }
1779  }
1780 
1781  /* Get latitude and longitude. */
1782  if ( !fapint_get_nmea_latlon(packet, nmea_fields[3], nmea_fields[4]) )
1783  {
1784  retval = 0;
1785  break;
1786  }
1787  if ( !fapint_get_nmea_latlon(packet, nmea_fields[5], nmea_fields[6]) )
1788  {
1789  retval = 0;
1790  break;
1791  }
1792 
1793  /* We have everything we want, return. */
1794  break;
1795  }
1796  else if ( strcmp(nmea_fields[0], "GPGGA") == 0 )
1797  {
1798  /* We want at least 11 fields. */
1799  if ( nmea_field_count < 11 )
1800  {
1801  packet->error_code = malloc(sizeof(fap_error_code_t));
1802  if ( packet->error_code ) *packet->error_code = fapGPGGA_FEWFIELDS;
1803  retval = 0;
1804  break;
1805  }
1806 
1807  /* Check for fix. */
1808  if ( regexec(&fapint_regex_nmea_fix, nmea_fields[6], matchcount, (regmatch_t*)&matches, 0) == 0 )
1809  {
1810  len = matches[1].rm_eo - matches[1].rm_so;
1811  tmp_str = malloc(len+1);
1812  if ( tmp_str )
1813  {
1814  retval = 0;
1815  break;
1816  }
1817  memcpy(tmp_str, nmea_fields[8]+matches[1].rm_so, len);
1818  tmp_str[len] = 0;
1819  if ( atoi(tmp_str) < 1 )
1820  {
1821  free(tmp_str);
1822  packet->error_code = malloc(sizeof(fap_error_code_t));
1823  if ( packet->error_code ) *packet->error_code = fapGPGGA_NOFIX;
1824  retval = 0;
1825  break;
1826  }
1827  free(tmp_str); tmp_str = NULL;
1828  }
1829  else
1830  {
1831  packet->error_code = malloc(sizeof(fap_error_code_t));
1832  if ( packet->error_code ) *packet->error_code = fapGPGGA_NOFIX;
1833  retval = 0;
1834  break;
1835  }
1836 
1837  /* Use the APRS time parsing routines to check the time and convert
1838  it to timestamp. But before that, remove a possible decimal
1839  part. */
1840  if ( strlen(nmea_fields[1]) < 6 )
1841  {
1842  packet->error_code = malloc(sizeof(fap_error_code_t));
1843  if ( packet->error_code ) *packet->error_code = fapTIMESTAMP_INV_GPGGA;
1844  retval = 0;
1845  break;
1846  }
1847  tmp_str = malloc(8);
1848  if ( !tmp_str )
1849  {
1850  retval = 0;
1851  break;
1852  }
1853  memcpy(tmp_str, nmea_fields[1], 6);
1854  tmp_str[6] = 'h';
1855  tmp_str[7] = 0;
1856  packet->timestamp = malloc(sizeof(time_t));
1857  if ( !packet->timestamp )
1858  {
1859  retval = 0;
1860  break;
1861  }
1862  *packet->timestamp = fapint_parse_timestamp(tmp_str);
1863  free(tmp_str); tmp_str = NULL;
1864  if ( *packet->timestamp == 0 )
1865  {
1866  packet->error_code = malloc(sizeof(fap_error_code_t));
1867  if ( packet->error_code ) *packet->error_code = fapTIMESTAMP_INV_GPGGA;
1868  retval = 0;
1869  break;
1870  }
1871 
1872  /* Latitude and longitude. */
1873  if ( !fapint_get_nmea_latlon(packet, nmea_fields[2], nmea_fields[3]) )
1874  {
1875  retval = 0;
1876  break;
1877  }
1878  if ( !fapint_get_nmea_latlon(packet, nmea_fields[4], nmea_fields[5]) )
1879  {
1880  retval = 0;
1881  break;
1882  }
1883 
1884  /* Altitude, only meters are accepted. */
1885  if ( strcmp(nmea_fields[0], "M") == 0 &&
1886  regexec(&fapint_regex_nmea_altitude, nmea_fields[9], matchcount, (regmatch_t*)&matches, 0) == 0 )
1887  {
1888  len = matches[1].rm_eo - matches[1].rm_so;
1889  tmp_str = malloc(len+1);
1890  if ( !tmp_str )
1891  {
1892  retval = 0;
1893  break;
1894  }
1895  memcpy(tmp_str, nmea_fields[8]+matches[1].rm_so, len);
1896  tmp_str[len] = 0;
1897  packet->altitude = malloc(sizeof(double));
1898  if ( !packet->altitude )
1899  {
1900  retval = 0;
1901  break;
1902  }
1903  *packet->altitude = atoi(tmp_str);
1904  free(tmp_str); tmp_str = NULL;
1905  }
1906 
1907  /* Ok. */
1908  break;
1909  }
1910  else if ( strcmp(nmea_fields[0], "GPGLL") == 0 )
1911  {
1912  /* We want at least 5 fields. */
1913  if ( nmea_field_count < 5 )
1914  {
1915  packet->error_code = malloc(sizeof(fap_error_code_t));
1916  if ( packet->error_code ) *packet->error_code = fapGPGLL_FEWFIELDS;
1917  retval = 0;
1918  break;
1919  }
1920 
1921  /* Latitude and longitude. */
1922  if ( !fapint_get_nmea_latlon(packet, nmea_fields[1], nmea_fields[2]) )
1923  {
1924  retval = 0;
1925  break;
1926  }
1927  if ( !fapint_get_nmea_latlon(packet, nmea_fields[3], nmea_fields[4]) )
1928  {
1929  retval = 0;
1930  break;
1931  }
1932 
1933  /* Use the APRS time parsing routines to check the time and convert
1934  it to timestamp. But before that, remove a possible decimal
1935  part. */
1936  if ( nmea_field_count >= 6 && strlen(nmea_fields[5]) >= 6 )
1937  {
1938  tmp_str = malloc(8);
1939  if ( !tmp_str )
1940  {
1941  retval = 0;
1942  break;
1943  }
1944  memcpy(tmp_str, nmea_fields[5], 6);
1945  tmp_str[6] = 'h';
1946  tmp_str[7] = 0;
1947  packet->timestamp = malloc(sizeof(time_t));
1948  if ( !packet->timestamp )
1949  {
1950  retval = 0;
1951  break;
1952  }
1953  *packet->timestamp = fapint_parse_timestamp(tmp_str);
1954  free(tmp_str); tmp_str = NULL;
1955  if ( *packet->timestamp == 0 )
1956  {
1957  packet->error_code = malloc(sizeof(fap_error_code_t));
1958  if ( packet->error_code ) *packet->error_code = fapTIMESTAMP_INV_GPGLL;
1959  retval = 0;
1960  break;
1961  }
1962  }
1963 
1964  /* Check if fix validity is available. */
1965  if ( nmea_field_count >= 7 )
1966  {
1967  if ( strcmp(nmea_fields[0], "GPGLL") == 0 )
1968  {
1969  packet->error_code = malloc(sizeof(fap_error_code_t));
1970  if ( packet->error_code ) *packet->error_code = fapGPGLL_NOFIX;
1971  retval = 0;
1972  break;
1973  }
1974  }
1975 
1976  /* Ok. */
1977  break;
1978  }
1979  else
1980  {
1981  packet->error_code = malloc(sizeof(fap_error_code_t));
1982  if ( packet->error_code ) *packet->error_code = fapNMEA_UNSUPP;
1983  retval = 0;
1984  }
1985  break;
1986  }
1987 
1988 
1989  for ( i = 0; i < nmea_field_count; ++i )
1990  {
1991  free(nmea_fields[i]);
1992  }
1993  if ( tmp_str ) free(tmp_str);
1994  if ( nmea_fields ) free(nmea_fields);
1995  free(rest);
1996  return retval;
1997 }
1998 
1999 
2000 
2001 int fapint_parse_object(fap_packet_t* packet, char const* input, unsigned int const input_len)
2002 {
2003  int i;
2004 
2005  /* Validate object length. At least 31 non-null chars are needed. */
2006  if ( strlen(input) < 31 )
2007  {
2008  packet->error_code = malloc(sizeof(fap_error_code_t));
2009  if ( packet->error_code ) *packet->error_code = fapOBJ_SHORT;
2010  return 0;
2011  }
2012 
2013  /* Validate and store object name. */
2014  for ( i = 1; i < 10; ++i )
2015  {
2016  if ( input[i] < 0x20 || input[i] > 0x7e )
2017  {
2018  packet->error_code = malloc(sizeof(fap_error_code_t));
2019  if ( packet->error_code ) *packet->error_code = fapOBJ_INV;
2020  return 0;
2021  }
2022  }
2023  packet->object_or_item_name = malloc(10);
2024  if ( !packet->object_or_item_name ) return 0;
2025  memcpy(packet->object_or_item_name, input+1, 9);
2026  packet->object_or_item_name[9] = 0;
2027 
2028  /* Validate and store object status. */
2029  if ( input[i] == '*' )
2030  {
2031  packet->alive = malloc(sizeof(int));
2032  if ( !packet->alive ) return 0;
2033  *packet->alive = 1;
2034  }
2035  else if ( input[i] == '_' )
2036  {
2037  packet->alive = malloc(sizeof(int));
2038  if ( !packet->alive ) return 0;
2039  *packet->alive = 0;
2040  }
2041  else
2042  {
2043  packet->error_code = malloc(sizeof(fap_error_code_t));
2044  if ( packet->error_code ) *packet->error_code = fapOBJ_INV;
2045  return 0;
2046  }
2047 
2048  /* Validate and store timestamp. */
2049  packet->timestamp = malloc(sizeof(time_t));
2050  if ( !packet->timestamp ) return 0;
2051  *packet->timestamp = fapint_parse_timestamp(input+11);
2052  if ( *packet->timestamp == 0)
2053  {
2054  packet->error_code = malloc(sizeof(fap_error_code_t));
2055  if ( packet->error_code ) *packet->error_code = fapTIMESTAMP_INV_OBJ;
2056  return 0;
2057  }
2058 
2059  /* Check location type. */
2060  i = 18;
2061  if ( input[i] == '/' || input[i] == '\\' ||
2062  (input[i] >= 'A' && input[i] <= 'Z') ||
2063  (input[i] >= 'a' && input[i] <= 'j')
2064  )
2065  {
2066  /* It's compressed. */
2067  if ( !fapint_parse_compressed(packet, input+i) )
2068  {
2069  return 0;
2070  }
2071  i += 13;
2072  }
2073  else if ( isdigit(input[i]) )
2074  {
2075  /* It's normal. */
2076  if ( !fapint_parse_normal(packet, input+i) )
2077  {
2078  return 0;
2079  }
2080  i += 19;
2081  }
2082  else
2083  {
2084  packet->error_code = malloc(sizeof(fap_error_code_t));
2085  if ( packet->error_code ) *packet->error_code = fapOBJ_DEC_ERR;
2086  return 0;
2087  }
2088 
2089  /* Check the APRS data extension and possible comments, unless it is a weather report (we don't want erroneus ourse/speed figures and weather in the comments..) */
2090  if ( packet->symbol_code != '_' )
2091  {
2092  fapint_parse_comment(packet, (char*)input+i, input_len-i);
2093  }
2094  else
2095  {
2096  fapint_parse_wx(packet, (char*)input+i, input_len-i);
2097  }
2098 
2099  return 1;
2100 }
2101 
2102 
2103 int fapint_parse_item(fap_packet_t* packet, char const* input, unsigned int const input_len)
2104 {
2105  int len, i;
2106 
2107  /* Check length. */
2108  if ( input_len < 18 )
2109  {
2110  packet->error_code = malloc(sizeof(fap_error_code_t));
2111  if ( packet->error_code ) *packet->error_code = fapITEM_SHORT;
2112  return 0;
2113  }
2114 
2115  /* Validate item bytes up to location. */
2116  if ( input[0] != ')' )
2117  {
2118  packet->error_code = malloc(sizeof(fap_error_code_t));
2119  if ( packet->error_code ) *packet->error_code = fapITEM_INV;
2120  return 0;
2121  }
2122  len = 0;
2123  for ( i = 1; i <= 9; ++i )
2124  {
2125  if ( input[i] == 0x20 ||
2126  (input[i] >= 0x22 && input[i] <= 0x5e) ||
2127  (input[i] >= 0x60 && input[i] <= 0x7e) )
2128  {
2129  len = i;
2130  }
2131  else
2132  {
2133  break;
2134  }
2135  }
2136  if ( input[i] == '!' )
2137  {
2138  packet->alive = malloc(sizeof(int));
2139  if ( !packet->alive ) return 0;
2140  *packet->alive = 1;
2141  }
2142  else if ( input[i] == '_' )
2143  {
2144  packet->alive = malloc(sizeof(int));
2145  if ( !packet->alive ) return 0;
2146  *packet->alive = 0;
2147  }
2148  else
2149  {
2150  packet->error_code = malloc(sizeof(fap_error_code_t));
2151  if ( packet->error_code ) *packet->error_code = fapITEM_INV;
2152  return 0;
2153  }
2154 
2155  /* Save item name with null termination. */
2156  packet->object_or_item_name = malloc(len+1);
2157  if ( !packet->object_or_item_name ) return 0;
2158  memcpy(packet->object_or_item_name, input+1, len);
2159  packet->object_or_item_name[len] = 0;
2160 
2161  /* Check location type. */
2162  i = len + 2;
2163  if ( input[i] == '/' || input[i] == '\\' ||
2164  (input[i] >= 'A' && input[i] <= 'Z') ||
2165  (input[i] >= 'a' && input[i] <= 'j')
2166  )
2167  {
2168  /* It's compressed. */
2169  if ( !fapint_parse_compressed(packet, input+i) )
2170  {
2171  return 0;
2172  }
2173  i += 13;
2174  }
2175  else if ( isdigit(input[i]) )
2176  {
2177  /* It's normal. */
2178  if ( !fapint_parse_normal(packet, input+i) )
2179  {
2180  return 0;
2181  }
2182  i += 19;
2183  }
2184  else
2185  {
2186  packet->error_code = malloc(sizeof(fap_error_code_t));
2187  if ( packet->error_code ) *packet->error_code = fapITEM_DEC_ERR;
2188  return 0;
2189  }
2190 
2191  /* Check the APRS data extension and possible comments, unless it is a weather report (we don't want erroneus ourse/speed figures and weather in the comments..) */
2192  if ( packet->symbol_code != '_' )
2193  {
2194  fapint_parse_comment(packet, (char*)input+i, input_len-i);
2195  }
2196 
2197  return 1;
2198 }
2199 
2200 
2201 int fapint_parse_message(fap_packet_t* packet, char const* input, unsigned int const input_len)
2202 {
2203  int i, len;
2204  char* tmp;
2205  short skipping_spaces = 1;
2206 
2207  unsigned int const matchcount = 3;
2208  regmatch_t matches[matchcount];
2209 
2210 
2211  /* Check length. */
2212  if ( input_len < 12 )
2213  {
2214  packet->error_code = malloc(sizeof(fap_error_code_t));
2215  if ( packet->error_code ) *packet->error_code = fapMSG_INV;
2216  return 0;
2217  }
2218 
2219  /* Validate and save destination. */
2220  if ( regexec(&fapint_regex_mes_dst, input, matchcount, (regmatch_t*)&matches, 0) == 0 )
2221  {
2222  /* Get length and strip trailing spaces. */
2223  len = matches[1].rm_eo - matches[1].rm_so;
2224  for ( i = matches[1].rm_eo-1; i > 0; --i )
2225  {
2226  if ( input[i] == ' ' )
2227  {
2228  --len;
2229  }
2230  else
2231  {
2232  break;
2233  }
2234  }
2235 
2236  /* Save with null-termination. */
2237  packet->destination = malloc(len+1);
2238  if ( !packet->destination ) return 0;
2239  memcpy(packet->destination, input+matches[1].rm_so, len);
2240  packet->destination[len] = 0;
2241  }
2242  else
2243  {
2244  packet->error_code = malloc(sizeof(fap_error_code_t));
2245  if ( packet->error_code ) *packet->error_code = fapMSG_INV;
2246  return 0;
2247  }
2248 
2249  /* Find message length. */
2250  len = 0;
2251  for ( i = 11; i < input_len; ++i )
2252  {
2253  if ( (input[i] >= 0x20 && input[i] <= 0x7e) || ((unsigned char)input[i] >= 0x80 && (unsigned char)input[i] <= 0xfe) )
2254  {
2255  len = i - 10;
2256  }
2257  else
2258  {
2259  break;
2260  }
2261  }
2262  if ( len == 0 )
2263  {
2264  packet->error_code = malloc(sizeof(fap_error_code_t));
2265  if ( packet->error_code ) *packet->error_code = fapMSG_INV;
2266  return 0;
2267  }
2268 
2269  /* Save message. */
2270  packet->message = malloc(len+1);
2271  if ( !packet->message ) return 0;
2272  memcpy(packet->message, input+11, len);
2273  packet->message[len] = 0;
2274 
2275  /* Check if message is an ack, save id if it is. */
2276  if ( regexec(&fapint_regex_mes_ack, packet->message, matchcount, (regmatch_t*)&matches, 0) == 0 )
2277  {
2278  len = matches[1].rm_eo - matches[1].rm_so;
2279  packet->message_ack = malloc(len+1);
2280  if ( !packet->message_ack ) return 0;
2281  memcpy(packet->message_ack, packet->message+matches[1].rm_so, len);
2282  packet->message_ack[len] = 0;
2283  }
2284 
2285  /* Check if message is a nack, save id if it is. */
2286  if ( regexec(&fapint_regex_mes_nack, packet->message, matchcount, (regmatch_t*)&matches, 0) == 0 )
2287  {
2288  len = matches[1].rm_eo - matches[1].rm_so;
2289  packet->message_nack = malloc(len+1);
2290  if ( !packet->message_nack ) return 0;
2291  memcpy(packet->message_nack, packet->message+matches[1].rm_so, len);
2292  packet->message_nack[len] = 0;
2293  }
2294 
2295  /* Separate message-id from the body, if present. */
2296  len = 0;
2297  for ( i = strlen(packet->message)-1; i >= 0 ; i-- )
2298  {
2299  if ( skipping_spaces && !isspace(packet->message[i]) )
2300  {
2301  /* Last non-space char of the id. */
2302  skipping_spaces = 0;
2303  }
2304  else if ( skipping_spaces )
2305  {
2306  continue;
2307  }
2308 
2309  /* New char of id. First check that it can be part of id. */
2310  if ( !(isalnum(packet->message[i]) || packet->message[i] == '{') )
2311  {
2312  break;
2313  }
2314 
2315  /* Check that we're not too long yet. */
2316  len++;
2317  if ( len > 6 )
2318  {
2319  break;
2320  }
2321 
2322  /* Check if id starts here. */
2323  if ( packet->message[i] == '{' )
2324  {
2325  /* Create copy of message without the id. */
2326  tmp = packet->message;
2327  packet->message = malloc(i+1);
2328  if ( !packet->message )
2329  {
2330  free(tmp);
2331  return 0;
2332  }
2333  memcpy(packet->message, tmp, i);
2334  packet->message[i] = 0;
2335 
2336  /* Save message id. */
2337  packet->message_id = malloc(len+1);
2338  if ( !packet->message_id )
2339  {
2340  free(tmp);
2341  return 0;
2342  }
2343  memcpy(packet->message_id, tmp+i+1, len);
2344  packet->message_id[len] = 0;
2345 
2346  /* Get rid of the old message. */
2347  free(tmp);
2348 
2349  break;
2350  }
2351  }
2352 
2353  /* Catch telemetry messages. */
2354  if ( strcmp(packet->src_callsign, packet->destination) == 0 &&
2355  ( strstr(packet->message, "BITS.") != NULL ||
2356  strstr(packet->message, "PARM.") != NULL ||
2357  strstr(packet->message, "UNIT.") != NULL ||
2358  strstr(packet->message, "EQNS.") != NULL
2359  )
2360  )
2361  {
2362  if ( packet->type == NULL )
2363  {
2364  packet->type = malloc(sizeof(fap_packet_type_t));
2365  if ( !packet->type ) return 0;
2366  }
2367  *packet->type = fapTELEMETRY_MESSAGE;
2368  }
2369 
2370  return 1;
2371 }
2372 
2373 int fapint_parse_capabilities(fap_packet_t* packet, char const* input, unsigned int const input_len)
2374 {
2375  fapint_llist_item_t* caps = NULL;
2376  int cap_count = 0;
2377  fapint_llist_item_t* current_elem = NULL;
2378 
2379  char* tmp_str, *sepa;
2380  int cap_len, cap_startpos, i, retval = 1;
2381  unsigned int foo, saved, sepa_pos;
2382 
2383  /* Find capabilities. */
2384  cap_startpos = 0;
2385  for ( i = 0; i < input_len; ++i )
2386  {
2387  tmp_str = NULL;
2388 
2389  /* Look for element boundary. */
2390  if ( input[i] == ',' )
2391  {
2392  /* Found a bound, let's create a copy of the capability it ends. */
2393  cap_len = i - cap_startpos;
2394  tmp_str = malloc(cap_len+1);
2395  if ( !tmp_str )
2396  {
2397  retval = 0;
2398  break;
2399  }
2400  memcpy(tmp_str, input+cap_startpos, cap_len);
2401  tmp_str[cap_len] = 0;
2402 
2403  /* Start to look for next element. */
2404  cap_startpos = i + 1;
2405  }
2406  else if ( i+1 == input_len )
2407  {
2408  /* We're at the end, save the last element. */
2409  cap_len = i+1 - cap_startpos;
2410  tmp_str = malloc(cap_len+1);
2411  if ( !tmp_str )
2412  {
2413  retval = 0;
2414  break;
2415  }
2416  memcpy(tmp_str, input+cap_startpos, cap_len);
2417  tmp_str[cap_len] = 0;
2418  }
2419 
2420  /* Check if we found something. */
2421  if ( tmp_str )
2422  {
2423  /* Create list item. */
2424  if ( caps == NULL )
2425  {
2426  caps = malloc(sizeof(fapint_llist_item_t));
2427  if ( !caps )
2428  {
2429  retval = 0;
2430  break;
2431  }
2432  current_elem = caps;
2433  }
2434  else
2435  {
2436  current_elem->next = malloc(sizeof(fapint_llist_item_t));
2437  if ( !current_elem->next )
2438  {
2439  retval = 0;
2440  break;
2441  }
2442  current_elem = current_elem->next;
2443  }
2444  current_elem->next = NULL;
2445  current_elem->text = tmp_str;
2446 
2447  ++cap_count;
2448  }
2449  }
2450  if ( !retval )
2451  {
2452  fapint_clear_llist(caps);
2453  return 0;
2454  }
2455 
2456  /* At least one capability is needed for the packet to be valid. */
2457  if ( cap_count == 0 )
2458  {
2459  return 0;
2460  }
2461 
2462  /* Save capabilites. */
2463  packet->capabilities = calloc(cap_count*2, sizeof(char*));
2464  if ( !packet->capabilities )
2465  {
2466  fapint_clear_llist(caps);
2467  return 0;
2468  }
2469  for ( i = 0; i < cap_count; ++i ) packet->capabilities[i] = NULL;
2470  packet->capabilities_len = cap_count;
2471  i = 0;
2472  current_elem = caps;
2473  while ( current_elem != NULL )
2474  {
2475  saved = 0;
2476  /* Find value splitpos. */
2477  if ( (sepa = strchr(current_elem->text, '=')) != NULL )
2478  {
2479  sepa_pos = sepa - current_elem->text - 1;
2480  /* Check that splitpos is not first or last char. */
2481  if ( sepa_pos < input_len )
2482  {
2483  packet->capabilities[i] = fapint_remove_part(current_elem->text, strlen(current_elem->text), sepa_pos, strlen(current_elem->text), &foo);
2484  packet->capabilities[i+1] = fapint_remove_part(current_elem->text, strlen(current_elem->text), 0, sepa_pos+2, &foo);
2485  saved = 1;
2486  }
2487  }
2488 
2489  /* If the cap was not yet saved, save it without value. */
2490  if ( !saved )
2491  {
2492  packet->capabilities[i] = malloc(strlen(current_elem->text)+1);
2493  if ( !packet->capabilities[i] )
2494  {
2495  retval = 0;
2496  break;
2497  }
2498  strcpy(packet->capabilities[i], current_elem->text);
2499  packet->capabilities[i+1] = NULL;
2500  }
2501 
2502  /* Get next element. */
2503  current_elem = current_elem->next;
2504  i += 2;
2505  }
2506  fapint_clear_llist(caps);
2507 
2508  return retval;
2509 }
2510 
2511 
2512 
2513 int fapint_parse_status(fap_packet_t* packet, char const* input, unsigned int const input_len)
2514 {
2515  short has_timestamp = 0;
2516  int i;
2517 
2518  /* Check for timestamp. */
2519  if ( input_len > 6 )
2520  {
2521  has_timestamp = 1;
2522  for ( i = 0; i < 6; ++i )
2523  {
2524  if ( !isdigit(input[i]) )
2525  {
2526  has_timestamp = 0;
2527  break;
2528  }
2529  }
2530  if ( input[6] != 'z' )
2531  {
2532  has_timestamp = 0;
2533  }
2534  }
2535 
2536  /* Save rest as status. */
2537  if ( has_timestamp )
2538  {
2539  packet->timestamp = malloc(sizeof(time_t));
2540  if ( !packet->timestamp ) return 0;
2541  *packet->timestamp = fapint_parse_timestamp(input);
2542  if ( *packet->timestamp == 0 )
2543  {
2544  packet->error_code = malloc(sizeof(fap_error_code_t));
2545  if ( packet->error_code ) *packet->error_code = fapTIMESTAMP_INV_STA;
2546  return 0;
2547  }
2548  packet->status = fapint_remove_part(input, input_len, 0, 7, &packet->status_len);
2549  }
2550  else
2551  {
2552  packet->status = malloc(input_len);
2553  if ( !packet->status ) return 0;
2554  memcpy(packet->status, input, input_len);
2555  packet->status_len = input_len;
2556  }
2557 
2558  return 1;
2559 }
2560 
2561 
2562 
2563 int fapint_parse_wx(fap_packet_t* packet, char const* input, unsigned int const input_len)
2564 {
2565  char wind_dir[4], wind_speed[4], *wind_gust = NULL, *temp = NULL;
2566  char buf_5b[6];
2567  int len, retval = 1;
2568  char* rest = NULL, *tmp_str;
2569  unsigned int rest_len, tmp_us;
2570 
2571  unsigned int const matchcount = 5;
2572  regmatch_t matches[matchcount];
2573 
2574  /* Check that we have something to look at. */
2575  if ( !packet || !input || !input_len )
2576  {
2577  return 0;
2578  }
2579 
2580  /* Initialize result vars. */
2581  memset(wind_dir, 0, 4);
2582  memset(wind_speed, 0, 4);
2583 
2584  /* Look for wind and temperature. Remaining bytes are copied to report var. */
2585  if ( regexec(&fapint_regex_wx1, input, matchcount, (regmatch_t*)&matches, 0) == 0 )
2586  {
2587  memcpy(wind_dir, input+matches[1].rm_so, 3);
2588  wind_dir[3] = 0;
2589 
2590  memcpy(wind_speed, input+matches[2].rm_so, 3);
2591  wind_speed[3] = 0;
2592 
2593  len = matches[3].rm_eo - matches[3].rm_so;
2594  wind_gust = malloc(len+1);
2595  if ( !wind_gust ) return 0;
2596  memcpy(wind_gust, input+matches[3].rm_so, len);
2597  wind_gust[len] = 0;
2598 
2599  len = matches[4].rm_eo - matches[4].rm_so;
2600  temp = malloc(len+1);
2601  if ( !temp )
2602  {
2603  free(wind_gust);
2604  return 0;
2605  }
2606  memcpy(temp, input+matches[4].rm_so, len);
2607  temp[len] = 0;
2608 
2609  rest = fapint_remove_part(input, input_len, 0, matches[4].rm_eo, &rest_len);
2610  }
2611  else if ( regexec(&fapint_regex_wx2, input, 5, matches, 0) == 0 )
2612  {
2613  memcpy(wind_dir, input+matches[1].rm_so, 3);
2614  wind_dir[3] = 0;
2615 
2616  memcpy(wind_speed, input+matches[2].rm_so, 3);
2617  wind_speed[3] = 0;
2618 
2619  len = matches[3].rm_eo - matches[3].rm_so;
2620  wind_gust = malloc(len+1);
2621  if ( !wind_gust ) return 0;
2622  memcpy(wind_gust, input+matches[3].rm_so, len);
2623  wind_gust[len] = 0;
2624 
2625  len = matches[4].rm_eo - matches[4].rm_so;
2626  temp = malloc(len+1);
2627  if ( !temp )
2628  {
2629  free(wind_gust);
2630  return 0;
2631  }
2632  memcpy(temp, input+matches[4].rm_so, len);
2633  temp[len] = 0;
2634 
2635  rest = fapint_remove_part(input, input_len, 0, matches[4].rm_eo, &rest_len);
2636  }
2637  else if ( regexec(&fapint_regex_wx3, input, 4, matches, 0) == 0 )
2638  {
2639  memcpy(wind_dir, input+matches[1].rm_so, 3);
2640  wind_dir[3] = 0;
2641 
2642  memcpy(wind_speed, input+matches[2].rm_so, 3);
2643  wind_speed[3] = 0;
2644 
2645  len = matches[3].rm_eo - matches[3].rm_so;
2646  wind_gust = malloc(len+1);
2647  if ( !wind_gust ) return 0;
2648  memcpy(wind_gust, input+matches[3].rm_so, len);
2649  wind_gust[len] = 0;
2650 
2651  rest = fapint_remove_part(input, input_len, 0, matches[3].rm_eo, &rest_len);
2652  }
2653  else if ( regexec(&fapint_regex_wx4, input, 4, matches, 0) == 0 )
2654  {
2655  memcpy(wind_dir, input+matches[1].rm_so, 3);
2656  wind_dir[3] = 0;
2657 
2658  memcpy(wind_speed, input+matches[2].rm_so, 3);
2659  wind_speed[3] = 0;
2660 
2661  len = matches[3].rm_eo - matches[3].rm_so;
2662  wind_gust = malloc(len+1);
2663  if ( !wind_gust ) return 0;
2664  memcpy(wind_gust, input+matches[3].rm_so, len);
2665  wind_gust[len] = 0;
2666 
2667  rest = fapint_remove_part(input, input_len, 0, matches[3].rm_eo, &rest_len);
2668  }
2669  else if ( regexec(&fapint_regex_wx5, input, 3, matches, 0) == 0 )
2670  {
2671  len = matches[1].rm_eo - matches[1].rm_so;
2672  wind_gust = malloc(len+1);
2673  if ( !wind_gust ) return 0;
2674  memcpy(wind_gust, input+matches[1].rm_so, len);
2675  wind_gust[len] = 0;
2676 
2677  len = matches[2].rm_eo - matches[2].rm_so;
2678  temp = malloc(len+1);
2679  if ( !temp )
2680  {
2681  free(wind_gust);
2682  return 0;
2683  }
2684  memcpy(temp, input+matches[2].rm_so, len);
2685  temp[len] = 0;
2686 
2687  rest = fapint_remove_part(input, input_len, 0, matches[2].rm_eo, &rest_len);
2688  }
2689  else
2690  {
2691  return 0;
2692  }
2693 
2694  if ( temp == NULL && rest_len > 0 && regexec(&fapint_regex_wx5, rest, matchcount, (regmatch_t*)&matches, 0) == 0 )
2695  {
2696  len = matches[1].rm_eo - matches[1].rm_so;
2697  temp = malloc(len+1);
2698  if ( !temp )
2699  {
2700  if ( wind_gust ) free(wind_gust);
2701  free(rest);
2702  return 0;
2703  }
2704  memcpy(temp, rest+matches[1].rm_so, len);
2705  temp[len] = 0;
2706 
2707  tmp_str = fapint_remove_part(rest, rest_len, matches[1].rm_so-1, matches[1].rm_eo, &tmp_us);
2708  free(rest);
2709  rest = tmp_str;
2710  rest_len = tmp_us;
2711  }
2712 
2713  /* Prepare to get results. */
2714  packet->wx_report = malloc(sizeof(fap_wx_report_t));
2715  if ( !packet->wx_report )
2716  {
2717  if ( wind_gust ) free(wind_gust);
2718  if ( temp ) free(temp);
2719  if ( rest ) free(rest);
2720  return 0;
2721  }
2723 
2724  /* Save values. */
2725  do
2726  {
2727  if ( fapint_is_number(wind_gust) )
2728  {
2729  packet->wx_report->wind_gust = malloc(sizeof(double));
2730  if ( !packet->wx_report->wind_gust )
2731  {
2732  retval = 0;
2733  break;
2734  }
2735  *packet->wx_report->wind_gust = atof(wind_gust) * MPH_TO_MS;
2736  }
2737  if ( fapint_is_number(wind_dir) )
2738  {
2739  packet->wx_report->wind_dir = malloc(sizeof(int));
2740  if ( !packet->wx_report->wind_dir )
2741  {
2742  retval = 0;
2743  break;
2744  }
2745  *packet->wx_report->wind_dir = atoi(wind_dir);
2746  }
2747  if ( fapint_is_number(wind_speed) )
2748  {
2749  packet->wx_report->wind_speed = malloc(sizeof(double));
2750  if ( !packet->wx_report->wind_speed )
2751  {
2752  retval = 0;
2753  break;
2754  }
2755  *packet->wx_report->wind_speed = atof(wind_speed) * MPH_TO_MS;
2756  }
2757  if ( fapint_is_number(temp) )
2758  {
2759  packet->wx_report->temp = malloc(sizeof(double));
2760  if ( !packet->wx_report->temp )
2761  {
2762  retval = 0;
2763  break;
2764  }
2765  *packet->wx_report->temp = FAHRENHEIT_TO_CELCIUS(atof(temp));
2766  }
2767  } while ( 0 );
2768  if ( wind_gust )
2769  {
2770  free(wind_gust);
2771  wind_gust = NULL;
2772  }
2773  if ( temp )
2774  {
2775  free(temp);
2776  temp = NULL;
2777  }
2778  if ( !retval )
2779  {
2780  free(rest);
2781  return 0;
2782  }
2783 
2784  /* Then some rain values. */
2785  do
2786  {
2787  if ( rest_len > 0 && regexec(&fapint_regex_wx_r1, rest, matchcount, (regmatch_t*)&matches, 0) == 0 )
2788  {
2789  len = matches[1].rm_eo - matches[1].rm_so;
2790  memset(buf_5b, 0, 6);
2791  memcpy(buf_5b, rest+matches[1].rm_so, len);
2792  packet->wx_report->rain_1h = malloc(sizeof(double));
2793  if ( !packet->wx_report->rain_1h )
2794  {
2795  retval = 0;
2796  break;
2797  }
2798  *packet->wx_report->rain_1h = atof(buf_5b) * HINCH_TO_MM;
2799 
2800  tmp_str = fapint_remove_part(rest, rest_len, matches[1].rm_so-1, matches[1].rm_eo, &tmp_us);
2801  free(rest);
2802  rest = tmp_str;
2803  rest_len = tmp_us;
2804  }
2805  if ( rest_len > 0 && regexec(&fapint_regex_wx_r24, rest, 2, matches, 0) == 0 )
2806  {
2807  len = matches[1].rm_eo - matches[1].rm_so;
2808  memset(buf_5b, 0, 4);
2809  memcpy(buf_5b, rest+matches[1].rm_so, len);
2810  packet->wx_report->rain_24h = malloc(sizeof(double));
2811  if ( !packet->wx_report->rain_24h )
2812  {
2813  retval = 0;
2814  break;
2815  }
2816  *packet->wx_report->rain_24h = atof(buf_5b) * HINCH_TO_MM;
2817 
2818  tmp_str = fapint_remove_part(rest, rest_len, matches[1].rm_so-1, matches[1].rm_eo, &tmp_us);
2819  free(rest);
2820  rest = tmp_str;
2821  rest_len = tmp_us;
2822  }
2823  if ( rest_len > 0 && regexec(&fapint_regex_wx_rami, rest, 2, matches, 0) == 0 )
2824  {
2825  len = matches[1].rm_eo - matches[1].rm_so;
2826  memset(buf_5b, 0, 4);
2827  memcpy(buf_5b, rest+matches[1].rm_so, len);
2828  packet->wx_report->rain_midnight = malloc(sizeof(double));
2829  if ( !packet->wx_report->rain_midnight )
2830  {
2831  retval = 0;
2832  break;
2833  }
2834  *packet->wx_report->rain_midnight = atof(buf_5b) * HINCH_TO_MM;
2835 
2836  tmp_str = fapint_remove_part(rest, rest_len, matches[1].rm_so-1, matches[1].rm_eo, &tmp_us);
2837  free(rest);
2838  rest = tmp_str;
2839  rest_len = tmp_us;
2840  }
2841  } while ( 0 );
2842  if ( !retval )
2843  {
2844  free(rest);
2845  return 0;
2846  }
2847 
2848  /* Humidity. */
2849  if ( rest_len > 0 && regexec(&fapint_regex_wx_humi, rest, 2, matches, 0) == 0 )
2850  {
2851  len = matches[1].rm_eo - matches[1].rm_so;
2852  memset(buf_5b, 0, 6);
2853  memcpy(buf_5b, rest+matches[1].rm_so, len);
2854  if ( (tmp_us = atoi(buf_5b)) <= 100 )
2855  {
2856  packet->wx_report->humidity = malloc(sizeof(unsigned int));
2857  if ( !packet->wx_report->humidity )
2858  {
2859  free(rest);
2860  return 0;
2861  }
2862  if ( tmp_us == 0 ) tmp_us = 100;
2863  *packet->wx_report->humidity = tmp_us;
2864  }
2865 
2866  tmp_str = fapint_remove_part(rest, rest_len, matches[1].rm_so-1, matches[1].rm_eo, &tmp_us);
2867  free(rest);
2868  rest = tmp_str;
2869  rest_len = tmp_us;
2870  }
2871 
2872  /* Pressure. */
2873  if ( rest_len > 0 && regexec(&fapint_regex_wx_pres, rest, 2, matches, 0) == 0 )
2874  {
2875  len = matches[1].rm_eo - matches[1].rm_so;
2876  memset(buf_5b, 0, 6);
2877  memcpy(buf_5b, rest+matches[1].rm_so, len);
2878  packet->wx_report->pressure = malloc(sizeof(double));
2879  if ( !packet->wx_report->pressure )
2880  {
2881  free(rest);
2882  return 0;
2883  }
2884  *packet->wx_report->pressure = atoi(buf_5b)/10.0; // tenths of mbars to mbars
2885 
2886  tmp_str = fapint_remove_part(rest, rest_len, matches[1].rm_so-1, matches[1].rm_eo, &tmp_us);
2887  free(rest);
2888  rest = tmp_str;
2889  rest_len = tmp_us;
2890  }
2891 
2892  /* Luminosity. */
2893  if ( rest_len > 0 && regexec(&fapint_regex_wx_lumi, rest, 3, matches, 0) == 0 )
2894  {
2895  len = matches[2].rm_eo - matches[2].rm_so;
2896  memset(buf_5b, 0, 6);
2897  memcpy(buf_5b, rest+matches[2].rm_so, len);
2898  packet->wx_report->luminosity = malloc(sizeof(unsigned int));
2899  if ( !packet->wx_report->luminosity )
2900  {
2901  free(rest);
2902  return 0;
2903  }
2904  *packet->wx_report->luminosity = atoi(buf_5b);
2905  if ( input[matches[1].rm_so] == 'l' )
2906  {
2907  *packet->wx_report->luminosity += 1000;
2908  }
2909 
2910  tmp_str = fapint_remove_part(rest, rest_len, matches[1].rm_so, matches[2].rm_eo, &tmp_us);
2911  free(rest);
2912  rest = tmp_str;
2913  rest_len = tmp_us;
2914  }
2915 
2916  /* What? */
2917  if ( rest_len > 0 && regexec(&fapint_regex_wx_what, rest, 2, matches, 0) == 0 )
2918  {
2919  tmp_str = fapint_remove_part(rest, rest_len, matches[1].rm_so-1, matches[1].rm_eo, &tmp_us);
2920  free(rest);
2921  rest = tmp_str;
2922  rest_len = tmp_us;
2923  }
2924 
2925  /* Snowfall. */
2926  if ( rest_len > 0 && regexec(&fapint_regex_wx_snow, rest, 2, matches, 0) == 0 )
2927  {
2928  len = matches[1].rm_eo - matches[1].rm_so;
2929  if ( len > 5 ) len = 5;
2930  memset(buf_5b, 0, 6);
2931  memcpy(buf_5b, rest+matches[1].rm_so, len);
2932  packet->wx_report->snow_24h = malloc(sizeof(double));
2933  if ( !packet->wx_report->snow_24h )
2934  {
2935  free(rest);
2936  return 0;
2937  }
2938  *packet->wx_report->snow_24h = atof(buf_5b) * HINCH_TO_MM;
2939 
2940  tmp_str = fapint_remove_part(rest, rest_len, matches[1].rm_so-1, matches[1].rm_eo, &tmp_us);
2941  free(rest);
2942  rest = tmp_str;
2943  rest_len = tmp_us;
2944  }
2945 
2946  /* Raw rain counter. */
2947  if ( rest_len > 0 && regexec(&fapint_regex_wx_rrc, rest, 2, matches, 0) == 0 )
2948  {
2949  tmp_str = fapint_remove_part(rest, rest_len, matches[1].rm_so-1, matches[1].rm_eo, &tmp_us);
2950  free(rest);
2951  rest = tmp_str;
2952  rest_len = tmp_us;
2953  }
2954 
2955  /* Remove any remaining known report parts. */
2956  if ( rest_len > 0 && regexec(&fapint_regex_wx_any, rest, 2, matches, 0) == 0 )
2957  {
2958  tmp_str = fapint_remove_part(rest, rest_len, matches[1].rm_so, matches[1].rm_eo, &tmp_us);
2959  free(rest);
2960  rest = tmp_str;
2961  rest_len = tmp_us;
2962  }
2963 
2964  /* If there's still something left, we can't know what it is. We do some guesswork nevertheless. */
2965 
2966  /* Check if it could be wx software id. */
2967  if ( rest_len > 0 && regexec(&fapint_regex_wx_soft, rest, 0, NULL, 0) == 0 )
2968  {
2969  packet->wx_report->soft = rest;
2970  }
2971  /* If not, it is propaby a comment. */
2972  else if ( rest_len > 0 && packet->comment == NULL )
2973  {
2974  packet->comment = rest;
2975  packet->comment_len = rest_len;
2976  }
2977  else
2978  {
2979  free(rest);
2980  }
2981 
2982  return 1;
2983 }
2984 
2985 
2986 
2987 int fapint_parse_telemetry(fap_packet_t* packet, char const* input)
2988 {
2989  unsigned int matchcount = 13;
2990  regmatch_t matches[matchcount];
2991 
2992  char* tmp_str;
2993  int len1, len2;
2994 
2995  /* Check params. */
2996  if ( !packet || !input )
2997  {
2998  return 0;
2999  }
3000  if ( regexec(&fapint_regex_telemetry, input, matchcount, (regmatch_t*)&matches, 0) == 0 )
3001  {
3002  /* Initialize results. */
3003  packet->telemetry = malloc(sizeof(fap_telemetry_t));
3004  if ( !packet->telemetry ) return 0;
3006 
3007  /* seq */
3008  len1 = matches[1].rm_eo - matches[1].rm_so;
3009  tmp_str = malloc(len1+1);
3010  if ( !tmp_str ) return 0;
3011  memcpy(tmp_str, input+matches[1].rm_so, len1);
3012  tmp_str[len1] = 0;
3013  packet->telemetry->seq = malloc(sizeof(unsigned int));
3014  if ( !packet->telemetry->seq ) return 0;
3015  *packet->telemetry->seq = atoi(tmp_str);
3016  free(tmp_str);
3017 
3018  /* val1 */
3019  len1 = matches[2].rm_eo - matches[2].rm_so;
3020  len2 = matches[3].rm_eo - matches[3].rm_so;
3021  tmp_str = malloc(len1+len2+1);
3022  if ( !tmp_str ) return 0;
3023  memcpy(tmp_str, input+matches[2].rm_so, len1);
3024  memcpy(tmp_str+len1, input+matches[3].rm_so, len2);
3025  tmp_str[len1+len2] = 0;
3026  packet->telemetry->val1 = malloc(sizeof(double));
3027  if ( !packet->telemetry->val1 ) return 0;
3028  *packet->telemetry->val1 = atof(tmp_str);
3029  free(tmp_str);
3030 
3031  /* val2 */
3032  len1 = matches[4].rm_eo - matches[4].rm_so;
3033  len2 = matches[5].rm_eo - matches[5].rm_so;
3034  tmp_str = malloc(len1+len2+1);
3035  if ( !tmp_str ) return 0;
3036  memcpy(tmp_str, input+matches[4].rm_so, len1);
3037  memcpy(tmp_str+len1, input+matches[5].rm_so, len2);
3038  tmp_str[len1+len2] = 0;
3039  packet->telemetry->val2 = malloc(sizeof(double));
3040  if ( !packet->telemetry->val2 ) return 0;
3041  *packet->telemetry->val2 = atof(tmp_str);
3042  free(tmp_str);
3043 
3044  /* val3 */
3045  len1 = matches[6].rm_eo - matches[6].rm_so;
3046  len2 = matches[7].rm_eo - matches[7].rm_so;
3047  tmp_str = malloc(len1+len2+1);
3048  if ( !tmp_str ) return 0;
3049  memcpy(tmp_str, input+matches[6].rm_so, len1);
3050  memcpy(tmp_str+len1, input+matches[7].rm_so, len2);
3051  tmp_str[len1+len2] = 0;
3052  packet->telemetry->val3 = malloc(sizeof(double));
3053  if ( !packet->telemetry->val3 ) return 0;
3054  *packet->telemetry->val3 = atof(tmp_str);
3055  free(tmp_str);
3056 
3057  /* val4 */
3058  len1 = matches[8].rm_eo - matches[8].rm_so;
3059  len2 = matches[9].rm_eo - matches[9].rm_so;
3060  tmp_str = malloc(len1+len2+1);
3061  if ( !tmp_str ) return 0;
3062  memcpy(tmp_str, input+matches[8].rm_so, len1);
3063  memcpy(tmp_str+len1, input+matches[9].rm_so, len2);
3064  tmp_str[len1+len2] = 0;
3065  packet->telemetry->val4 = malloc(sizeof(double));
3066  if ( !packet->telemetry->val4 ) return 0;
3067  *packet->telemetry->val4 = atof(tmp_str);
3068  free(tmp_str);
3069 
3070  /* val5 */
3071  len1 = matches[10].rm_eo - matches[10].rm_so;
3072  len2 = matches[11].rm_eo - matches[11].rm_so;
3073  tmp_str = malloc(len1+len2+1);
3074  if ( !tmp_str ) return 0;
3075  memcpy(tmp_str, input+matches[10].rm_so, len1);
3076  memcpy(tmp_str+len1, input+matches[11].rm_so, len2);
3077  tmp_str[len1+len2] = 0;
3078  packet->telemetry->val5 = malloc(sizeof(double));
3079  if ( !packet->telemetry->val5 ) return 0;
3080  *packet->telemetry->val5 = atof(tmp_str);
3081  free(tmp_str);
3082 
3083  /* bits */
3084  len1 = matches[12].rm_eo - matches[12].rm_so;
3085  memcpy(packet->telemetry->bits, input+matches[12].rm_so, len1);
3086  }
3087  else
3088  {
3089  packet->error_code = malloc(sizeof(fap_error_code_t));
3090  if ( packet->error_code ) *packet->error_code = fapTLM_INV;
3091  return 0;
3092  }
3093 
3094  return 1;
3095 }
3096 
3097 
3098 
3099 int fapint_parse_wx_peet_logging(fap_packet_t* packet, char const* input)
3100 {
3101  fapint_llist_item_t* parts, *current_elem;
3102  unsigned int part_count;
3103 
3104  int i, retval = 1;
3105 
3106  unsigned int matchcount = 2;
3107  regmatch_t matches[matchcount];
3108 
3109 
3110  /* Split report into parts. */
3111  parts = NULL;
3112  current_elem = NULL;
3113  part_count = 0;
3114  i = 0;
3115  while ( regexec(&fapint_regex_peet_splitter, input+i, matchcount, matches, 0) == 0 )
3116  {
3117  if ( !parts )
3118  {
3119  parts = malloc(sizeof(fapint_llist_item_t));
3120  if ( !parts )
3121  {
3122  retval = 0;
3123  break;
3124  }
3125  current_elem = parts;
3126  }
3127  else
3128  {
3129  current_elem->next = malloc(sizeof(fapint_llist_item_t));
3130  if ( !current_elem->next )
3131  {
3132  retval = 0;
3133  break;
3134  }
3135  current_elem = current_elem->next;
3136  }
3137  current_elem->next = NULL;
3138  if ( input[i+matches[1].rm_so] != '-' )
3139  {
3140  current_elem->text = malloc(5);
3141  memcpy(current_elem->text, input+i+matches[1].rm_so, 4);
3142  current_elem->text[4] = 0;
3143  }
3144  else
3145  {
3146  current_elem->text = NULL;
3147  }
3148  part_count++;
3149 
3150  /* Prepare for next element. */
3151  i += 4;
3152  if ( i >= strlen(input) ) break;
3153  }
3154  if ( !retval || !part_count )
3155  {
3156  fapint_clear_llist(parts);
3157  return 0;
3158  }
3159 
3160  /* Prepare to return results. */
3161  packet->wx_report = malloc(sizeof(fap_wx_report_t));
3162  if ( !packet->wx_report )
3163  {
3164  fapint_clear_llist(parts);
3165  return 0;
3166  }
3168 
3169  /* Check parts one at a time. */
3170  do
3171  {
3172  current_elem = parts;
3173 
3174  /* instant wind speed */
3175  if ( current_elem->text )
3176  {
3177  packet->wx_report->wind_speed = malloc(sizeof(double));
3178  if ( !packet->wx_report->wind_speed )
3179  {
3180  retval = 0;
3181  break;
3182  }
3183  *packet->wx_report->wind_speed = strtol(current_elem->text, NULL, 16) * KMH_TO_MS / 10.0;
3184  }
3185  current_elem = current_elem->next;
3186 
3187  /* wind direction */
3188  if ( current_elem )
3189  {
3190  if ( current_elem->text )
3191  {
3192  packet->wx_report->wind_dir = malloc(sizeof(unsigned int));
3193  if ( !packet->wx_report->wind_dir )
3194  {
3195  retval = 0;
3196  break;
3197  }
3198  *packet->wx_report->wind_dir = floor(strtol(current_elem->text, NULL, 16) * 1.41176 + 0.5);
3199  }
3200  current_elem = current_elem->next;
3201  }
3202  else
3203  {
3204  break;
3205  }
3206 
3207  /* temperature */
3208  if ( current_elem )
3209  {
3210  if ( current_elem->text )
3211  {
3212  packet->wx_report->temp = malloc(sizeof(double));
3213  if ( !packet->wx_report->temp )
3214  {
3215  retval = 0;
3216  break;
3217  }
3218  *packet->wx_report->temp = FAHRENHEIT_TO_CELCIUS(strtol(current_elem->text, NULL, 16)/10.0);
3219  }
3220  current_elem = current_elem->next;
3221  }
3222  else
3223  {
3224  break;
3225  }
3226 
3227  /* rain since midnight */
3228  if ( current_elem )
3229  {
3230  if ( current_elem->text )
3231  {
3232  packet->wx_report->rain_midnight = malloc(sizeof(double));
3233  if ( !packet->wx_report->rain_midnight )
3234  {
3235  retval = 0;
3236  break;
3237  }
3238  *packet->wx_report->rain_midnight = strtol(current_elem->text, NULL, 16) * HINCH_TO_MM;
3239  }
3240  current_elem = current_elem->next;
3241  }
3242  else
3243  {
3244  break;
3245  }
3246 
3247  /* pressure */
3248  if ( current_elem )
3249  {
3250  if ( current_elem->text )
3251  {
3252  packet->wx_report->pressure = malloc(sizeof(double));
3253  if ( !packet->wx_report->pressure )
3254  {
3255  retval = 0;
3256  break;
3257  }
3258  *packet->wx_report->pressure = strtol(current_elem->text, NULL, 16) / 10.0;
3259  }
3260  current_elem = current_elem->next;
3261  }
3262  else
3263  {
3264  break;
3265  }
3266 
3267  /* inside temperature */
3268  if ( current_elem )
3269  {
3270  if ( current_elem->text )
3271  {
3272  packet->wx_report->temp_in = malloc(sizeof(double));
3273  if ( !packet->wx_report->temp_in )
3274  {
3275  retval = 0;
3276  break;
3277  }
3278  *packet->wx_report->temp_in = FAHRENHEIT_TO_CELCIUS(strtol(current_elem->text, NULL, 16)/10.0);
3279  }
3280  current_elem = current_elem->next;
3281  }
3282  else
3283  {
3284  break;
3285  }
3286 
3287  /* humidity */
3288  if ( current_elem )
3289  {
3290  if ( current_elem->text )
3291  {
3292  packet->wx_report->humidity = malloc(sizeof(unsigned int));
3293  if ( !packet->wx_report->humidity )
3294  {
3295  retval = 0;
3296  break;
3297  }
3298  *packet->wx_report->humidity = strtol(current_elem->text, NULL, 16)/10.0;
3299  }
3300  current_elem = current_elem->next;
3301  }
3302  else
3303  {
3304  break;
3305  }
3306 
3307  /* inside humidity */
3308  if ( current_elem )
3309  {
3310  if ( current_elem->text )
3311  {
3312  packet->wx_report->humidity_in = malloc(sizeof(unsigned int));
3313  if ( !packet->wx_report->humidity_in )
3314  {
3315  retval = 0;
3316  break;
3317  }
3318  *packet->wx_report->humidity_in = strtol(current_elem->text, NULL, 16)/10.0;
3319  }
3320  current_elem = current_elem->next;
3321  }
3322  else
3323  {
3324  break;
3325  }
3326 
3327  /* date */
3328  if ( current_elem )
3329  {
3330  current_elem = current_elem->next;
3331  }
3332  else
3333  {
3334  break;
3335  }
3336 
3337  /* time */
3338  if ( current_elem )
3339  {
3340  current_elem = current_elem->next;
3341  }
3342  else
3343  {
3344  break;
3345  }
3346 
3347  /* rain since midnight (again?) */
3348  if ( current_elem )
3349  {
3350  if ( current_elem->text )
3351  {
3352  *packet->wx_report->rain_midnight = strtol(current_elem->text, NULL, 16) * HINCH_TO_MM;
3353  }
3354  current_elem = current_elem->next;
3355 
3356  /* avg wind speed */
3357  if ( current_elem && current_elem->text )
3358  {
3359  *packet->wx_report->wind_speed = strtol(current_elem->text, NULL, 16) * KMH_TO_MS / 10.0;
3360  }
3361  current_elem = current_elem->next;
3362  }
3363 
3364  } while ( 0 );
3365  fapint_clear_llist(parts);
3366 
3367  return retval;
3368 }
3369 
3370 
3371 
3372 int fapint_parse_wx_peet_packet(fap_packet_t* packet, char const* input)
3373 {
3374  fapint_llist_item_t* parts, *current_elem;
3375  unsigned int part_count;
3376 
3377  int i, retval = 1;
3378  int16_t temp;
3379 
3380  unsigned int matchcount = 2;
3381  regmatch_t matches[matchcount];
3382 
3383 
3384  /* Split report into parts. */
3385  parts = NULL;
3386  current_elem = NULL;
3387  part_count = 0;
3388  i = 0;
3389  while ( regexec(&fapint_regex_peet_splitter, input+i, matchcount, matches, 0) == 0 )
3390  {
3391  if ( !parts )
3392  {
3393  parts = malloc(sizeof(fapint_llist_item_t));
3394  if ( !parts ) return 0;
3395  current_elem = parts;
3396  }
3397  else
3398  {
3399  current_elem->next = malloc(sizeof(fapint_llist_item_t));
3400  if ( !current_elem->next )
3401  {
3402  retval = 0;
3403  break;
3404  }
3405  current_elem = current_elem->next;
3406  }
3407  current_elem->next = NULL;
3408  if ( input[i+matches[1].rm_so] != '-' )
3409  {
3410  current_elem->text = malloc(5);
3411  if ( !current_elem->text )
3412  {
3413  retval = 0;
3414  break;
3415  }
3416  memcpy(current_elem->text, input+i+matches[1].rm_so, 4);
3417  current_elem->text[4] = 0;
3418  }
3419  else
3420  {
3421  current_elem->text = NULL;
3422  }
3423  part_count++;
3424 
3425  /* Prepare for next element. */
3426  i += 4;
3427  if ( i >= strlen(input) ) break;
3428  }
3429  if ( !retval || !part_count )
3430  {
3431  fapint_clear_llist(parts);
3432  return 0;
3433  }
3434 
3435  /* Prepare to return results. */
3436  packet->wx_report = malloc(sizeof(fap_wx_report_t));
3437  if ( !packet->wx_report )
3438  {
3439  fapint_clear_llist(parts);
3440  return 0;
3441  }
3443 
3444  /* Check parts one at a time. */
3445  do
3446  {
3447  current_elem = parts;
3448 
3449  /* wind gust */
3450  if ( current_elem->text )
3451  {
3452  packet->wx_report->wind_gust = malloc(sizeof(double));
3453  if ( !packet->wx_report->wind_gust )
3454  {
3455  retval = 0;
3456  break;
3457  }
3458  *packet->wx_report->wind_gust = strtol(current_elem->text, NULL, 16) * KMH_TO_MS / 10.0;
3459  }
3460  current_elem = current_elem->next;
3461 
3462  /* wind direction */
3463  if ( current_elem )
3464  {
3465  if ( current_elem->text )
3466  {
3467  packet->wx_report->wind_dir = malloc(sizeof(unsigned int));
3468  if ( !packet->wx_report->wind_dir )
3469  {
3470  retval = 0;
3471  break;
3472  }
3473  *packet->wx_report->wind_dir = floor(strtol(current_elem->text, NULL, 16) * 1.41176 + 0.5);
3474  }
3475  current_elem = current_elem->next;
3476  }
3477  else
3478  {
3479  break;
3480  }
3481 
3482  /* temperature */
3483  if ( current_elem )
3484  {
3485  if ( current_elem->text )
3486  {
3487  packet->wx_report->temp = malloc(sizeof(double));
3488  if ( !packet->wx_report->temp )
3489  {
3490  retval = 0;
3491  break;
3492  }
3493  temp = strtol(current_elem->text, NULL, 16);
3494  *packet->wx_report->temp = FAHRENHEIT_TO_CELCIUS(temp/10.0);
3495  }
3496  current_elem = current_elem->next;
3497  }
3498  else
3499  {
3500  break;
3501  }
3502 
3503  /* rain since midnight */
3504  if ( current_elem )
3505  {
3506  if ( current_elem->text )
3507  {
3508  packet->wx_report->rain_midnight = malloc(sizeof(double));
3509  if ( !packet->wx_report->rain_midnight )
3510  {
3511  retval = 0;
3512  break;
3513  }
3514  *packet->wx_report->rain_midnight = strtol(current_elem->text, NULL, 16) * HINCH_TO_MM;
3515  }
3516  current_elem = current_elem->next;
3517  }
3518  else
3519  {
3520  break;
3521  }
3522 
3523  /* pressure */
3524  if ( current_elem )
3525  {
3526  if ( current_elem->text )
3527  {
3528  packet->wx_report->pressure = malloc(sizeof(double));
3529  if ( !packet->wx_report->pressure )
3530  {
3531  retval = 0;
3532  break;
3533  }
3534  *packet->wx_report->pressure = strtol(current_elem->text, NULL, 16) / 10.0;
3535  }
3536  current_elem = current_elem->next;
3537  }
3538  else
3539  {
3540  break;
3541  }
3542 
3543  /* barometer delta */
3544  if ( current_elem )
3545  {
3546  current_elem = current_elem->next;
3547  }
3548  else
3549  {
3550  break;
3551  }
3552 
3553  /* barometer corr. factor */
3554  if ( current_elem )
3555  {
3556  current_elem = current_elem->next;
3557  }
3558  else
3559  {
3560  break;
3561  }
3562 
3563  /* barometer corr. factor */
3564  if ( current_elem )
3565  {
3566  current_elem = current_elem->next;
3567  }
3568  else
3569  {
3570  break;
3571  }
3572 
3573  /* humidity */
3574  if ( current_elem )
3575  {
3576  if ( current_elem->text )
3577  {
3578  packet->wx_report->humidity = malloc(sizeof(unsigned int));
3579  if ( !packet->wx_report->humidity )
3580  {
3581  retval = 0;
3582  break;
3583  }
3584  *packet->wx_report->humidity = strtol(current_elem->text, NULL, 16)/10.0;
3585  }
3586  current_elem = current_elem->next;
3587  }
3588  else
3589  {
3590  break;
3591  }
3592 
3593  /* date */
3594  if ( current_elem )
3595  {
3596  current_elem = current_elem->next;
3597  }
3598  else
3599  {
3600  break;
3601  }
3602 
3603  /* time */
3604  if ( current_elem )
3605  {
3606  current_elem = current_elem->next;
3607  }
3608  else
3609  {
3610  break;
3611  }
3612 
3613  /* rain since midnight */
3614  if ( current_elem )
3615  {
3616  if ( current_elem->text )
3617  {
3618  *packet->wx_report->rain_midnight = strtol(current_elem->text, NULL, 16) * HINCH_TO_MM;
3619  }
3620  current_elem = current_elem->next;
3621  }
3622  else
3623  {
3624  break;
3625  }
3626 
3627  /* wind speed */
3628  if ( current_elem )
3629  {
3630  if ( current_elem->text )
3631  {
3632  packet->wx_report->wind_speed = malloc(sizeof(double));
3633  if ( !packet->wx_report->wind_speed )
3634  {
3635  retval = 0;
3636  break;
3637  }
3638  *packet->wx_report->wind_speed = strtol(current_elem->text, NULL, 16) * KMH_TO_MS / 10.0;
3639  }
3640  current_elem = current_elem->next;
3641  }
3642  else
3643  {
3644  break;
3645  }
3646  /* That's all folks. */
3647  break;
3648  } while ( 0 );
3649  fapint_clear_llist(parts);
3650 
3651  return retval;
3652 }
3653 
3654 
3655 
3656 int fapint_parse_dao(fap_packet_t* packet, char input[3])
3657 {
3658  double lon_off = 0.0, lat_off = 0.0;
3659 
3660  /* Datum character is the first character and also defines how the rest is interpreted. */
3661  if ( 'A' <= input[0] && input[0] <= 'Z' && isdigit(input[1]) && isdigit(input[2]) )
3662  {
3663  /* Human readable. */
3664  packet->dao_datum_byte = input[0];
3665  if ( packet->pos_resolution == NULL )
3666  {
3667  packet->pos_resolution = malloc(sizeof(double));
3668  if ( !packet->pos_resolution ) return 0;
3669  }
3671  lat_off = (input[1]-48.0) * 0.001 / 60.0;
3672  lon_off = (input[2]-48.0) * 0.001 / 60.0;
3673  }
3674  else if ( 'a' <= input[0] && input[0] <= 'z' &&
3675  0x21 <= input[1] && input[1] <= 0x7b &&
3676  0x21 <= input[2] && input[2] <= 0x7b )
3677  {
3678  /* Base-91. */
3679  packet->dao_datum_byte = toupper(input[0]); /* Save in uppercase. */
3680  if ( packet->pos_resolution == NULL )
3681  {
3682  packet->pos_resolution = malloc(sizeof(double));
3683  if ( !packet->pos_resolution ) return 0;
3684  }
3686  /* Scale base-91. */
3687  lat_off = (input[1]-33.0)/91.0 * 0.01 / 60.0;
3688  lon_off = (input[2]-33.0)/91.0 * 0.01 / 60.0;
3689  }
3690  else if ( 0x21 <= input[0] && input[0] <= 0x7b &&
3691  input[1] == ' ' && input[2] == ' ' )
3692  {
3693  /* Only datum information, no lat/lon digits. */
3694  if ( 'a' <= input[0] && input[0] <= 'z' )
3695  {
3696  packet->dao_datum_byte = toupper(input[0]);
3697  }
3698  else
3699  {
3700  packet->dao_datum_byte = input[0];
3701  }
3702  }
3703  else
3704  {
3705  /* Invalid !DAO! */
3706  return 0;
3707  }
3708 
3709  /* Cautiously check N/S and E/W. */
3710  if ( packet->latitude )
3711  {
3712  if ( *packet->latitude < 0 )
3713  {
3714  *packet->latitude -= lat_off;
3715  }
3716  else
3717  {
3718  *packet->latitude += lat_off;
3719  }
3720  }
3721  if ( packet->longitude )
3722  {
3723  if ( *packet->longitude < 0 )
3724  {
3725  *packet->longitude -= lon_off;
3726  }
3727  else
3728  {
3729  *packet->longitude += lon_off;
3730  }
3731  }
3732 
3733  return 1;
3734 }
3735 
3736 
3737 
3738 char* fapint_check_kiss_callsign(char* input)
3739 {
3740  unsigned int matchcount = 3;
3741  regmatch_t matches[matchcount];
3742 
3743  int len;
3744  char* tmp_str;
3745 
3746 
3747  if ( !input ) return NULL;
3748 
3749  if ( regexec(&fapint_regex_kiss_callsign, input, matchcount, (regmatch_t*)&matches, 0) == 0 )
3750  {
3751  /* Check ssid if given. */
3752  len = matches[2].rm_eo - matches[2].rm_so;
3753  if ( len > 0 )
3754  {
3755  tmp_str = malloc(len+1);
3756  if ( !tmp_str ) return NULL;
3757  memcpy(tmp_str, input+matches[2].rm_so, len);
3758  tmp_str[len] = 0;
3759  if ( atoi(tmp_str) < -15 )
3760  {
3761  free(tmp_str);
3762  return NULL;
3763  }
3764  free(tmp_str);
3765  }
3766 
3767  /* Combine as result. */
3768  len += matches[1].rm_eo - matches[1].rm_so;
3769  tmp_str = malloc(len+1);
3770  if ( !tmp_str ) return NULL;
3771  memcpy(tmp_str, input+matches[1].rm_so, matches[1].rm_eo - matches[1].rm_so);
3772  memcpy(tmp_str+matches[1].rm_eo, input+matches[2].rm_so, matches[2].rm_eo - matches[2].rm_so);
3773  tmp_str[len] = 0;
3774 
3775  return tmp_str;
3776  }
3777 
3778  return NULL;
3779 }
3780 
3781 
3782 
3783 /* Implementation-specific helpers for fap.c. */
3784 
3785 
3786 
3788 {
3789  fap_packet_t* result = malloc(sizeof(fap_packet_t));
3790  if ( !result ) return NULL;
3791 
3792  /* Prepare result object. */
3793  result->error_code = NULL;
3794  result->type = NULL;
3795 
3796  result->orig_packet = NULL;
3797  result->orig_packet_len = 0;
3798 
3799  result->header = NULL;
3800  result->body = NULL;
3801  result->body_len = 0;
3802  result->src_callsign = NULL;
3803  result->dst_callsign = NULL;
3804  result->path = NULL;
3805  result->path_len = 0;
3806 
3807  result->latitude = NULL;
3808  result->longitude = NULL;
3809  result->format = NULL;
3810  result->pos_resolution = NULL;
3811  result->pos_ambiguity = NULL;
3812  result->dao_datum_byte = 0;
3813 
3814  result->altitude = NULL;
3815  result->course = NULL;
3816  result->speed = NULL;
3817 
3818  result->symbol_table = 0;
3819  result->symbol_code = 0;
3820 
3821  result->messaging = NULL;
3822  result->destination = NULL;
3823  result->message = NULL;
3824  result->message_ack = NULL;
3825  result->message_nack = NULL;
3826  result->message_id = NULL;
3827  result->comment = NULL;
3828  result->comment_len = 0;
3829 
3830  result->object_or_item_name = NULL;
3831  result->alive = NULL;
3832 
3833  result->gps_fix_status = NULL;
3834  result->radio_range = NULL;
3835  result->phg = NULL;
3836  result->timestamp = NULL;
3837  result->raw_timestamp = NULL;
3838  result->nmea_checksum_ok = NULL;
3839 
3840  result->wx_report = NULL;
3841  result->telemetry = NULL;
3842 
3843  result->messagebits = NULL;
3844  result->status = NULL;
3845  result->status_len = 0;
3846  result->capabilities = NULL;
3847  result->capabilities_len = 0;
3848 
3849  /* Return results. */
3850  return result;
3851 }