• Main Page
  • Data Structures
  • Files
  • File List
  • Globals

src/helpers.c

Go to the documentation of this file.
00001 /* $Id: helpers.c 200 2011-05-22 16:42:29Z oh2gve $
00002  *
00003  * Copyright 2005, 2006, 2007, 2008, 2009, 2010 Tapio Sokura
00004  * Copyright 2007, 2008, 2009, 2010 Heikki Hannikainen
00005  *
00006  * Perl-to-C modifications
00007  * Copyright 2009, 2010, 2011 Tapio Aaltonen
00008  *
00009  * This file is part of libfap.
00010  *
00011  * Libfap is free software; you can redistribute it and/or modify it under the
00012  * terms of either:
00013  *
00014  * a) the GNU General Public License as published by the Free Software
00015  * Foundation; either version 1, or (at your option) any later
00016  * version, or
00017  * 
00018  * b) the "Artistic License". 
00019  * 
00020  * Both licenses can be found in the licenses directory of this source code
00021  * package.
00022  *
00023  * APRS is a registered trademark of APRS Software and Bob Bruninga, WB4APR.
00024 */
00025 
00033 #include "helpers.h"
00034 #include "helpers2.h"
00035 #include "regs.h"
00036 #ifdef HAVE_CONFIG_H
00037 #include <config.h>
00038 #endif
00039 
00040 #include <stdlib.h>
00041 #include <stdio.h>
00042 #include <string.h>
00043 #include <stdint.h>
00044 #include <regex.h>
00045 #include <ctype.h>
00046 #include <math.h>
00047 
00048 
00049 
00050 int fapint_parse_header(fap_packet_t* packet, short const is_ax25)
00051 {
00052         int i, len, startpos, retval = 1;
00053         char* rest = NULL;
00054         char* tmp = NULL;
00055         char buf_10b[10];
00056         fapint_llist_item_t* path;
00057         int path_len;
00058         fapint_llist_item_t* current_elem;
00059         short seenq = 0;
00060         
00061         unsigned int const matchcount = 3;
00062         regmatch_t matches[matchcount];
00063         
00064         /* Separate source callsign and the rest. */
00065         if ( regexec(&fapint_regex_header, packet->header, matchcount, (regmatch_t*)&matches, 0) == 0 )
00066         {
00067                 /* Save (and validate if we're AX.25) the callsign. */
00068                 tmp = malloc(matches[1].rm_eo+1);
00069                 if ( !tmp ) return 0;
00070                 memcpy(tmp, packet->header, matches[1].rm_eo);
00071                 tmp[matches[1].rm_eo] = 0;
00072                 if ( is_ax25 )
00073                 {
00074                         packet->src_callsign = fap_check_ax25_call(tmp, 0);
00075                         free(tmp);
00076                         if ( !packet->src_callsign )
00077                         {
00078                                 packet->error_code = malloc(sizeof(fap_error_code_t));
00079                                 if ( packet->error_code ) *packet->error_code = fapSRCCALL_NOAX25;
00080                                 retval = 0;
00081                         }
00082                 }
00083                 else
00084                 {
00085                         packet->src_callsign = tmp;
00086                 }
00087                 
00088                 /* Save the rest of the header also 0-terminated string. */
00089                 len = matches[2].rm_eo - matches[2].rm_so;
00090                 rest = malloc(len+1);
00091                 if ( !rest ) return 0;
00092                 memcpy(rest, packet->header + matches[2].rm_so, len);
00093                 rest[len] = 0;
00094         }
00095         else
00096         {
00097                 packet->error_code = malloc(sizeof(fap_error_code_t));
00098                 if ( packet->error_code ) *packet->error_code = fapSRCCALL_BADCHARS;
00099                 retval = 0;
00100         }
00101         if ( !retval )
00102         {
00103                 if ( rest ) free(rest);
00104                 return 0;
00105         }
00106         
00107         /* Find path elements. */
00108         len = 0;
00109         startpos = 0;
00110         path = NULL;
00111         path_len = -1;
00112         current_elem = NULL;
00113         tmp = NULL;
00114         for ( i = 0; i < strlen(rest); ++i )
00115         {
00116                 tmp = NULL;
00117                 
00118                 /* Look for element boundary. */
00119                 if ( rest[i] == ',' )
00120                 {
00121                         /* Found a bound, let's create a copy of the element it ends. */
00122                         len = i - startpos;
00123                         tmp = malloc(len+1);
00124                         if ( !tmp )
00125                         {
00126                                 retval = 0;
00127                                 break;
00128                         }
00129                         memcpy(tmp, rest+startpos, len);
00130                         tmp[len] = 0;
00131                         
00132                         /* Start to look for next element. */
00133                         startpos = i + 1;
00134                 }
00135                 else if ( i+1 == strlen(rest) )
00136                 {
00137                         /* We're at the end, save the last element. */
00138                         len = i+1 - startpos;
00139                         tmp = malloc(len+1);
00140                         if ( !tmp )
00141                         {
00142                                 retval = 0;
00143                                 break;
00144                         }
00145                         memcpy(tmp, rest+startpos, len);
00146                         tmp[len] = 0;
00147                 }
00148                 
00149                 /* Check if we found something. */
00150                 if ( tmp )
00151                 {
00152                         /* Create list item. */
00153                         if ( path == NULL )
00154                         {
00155                                 path = malloc(sizeof(fapint_llist_item_t));
00156                                 if ( !path )
00157                                 {
00158                                         retval = 0;
00159                                         break;
00160                                 }
00161                                 current_elem = path;
00162                         }
00163                         else
00164                         {
00165                                 current_elem->next = malloc(sizeof(fapint_llist_item_t));
00166                                 if ( !current_elem->next )
00167                                 {
00168                                         retval = 0;
00169                                         break;
00170                                 }
00171                                 current_elem = current_elem->next;
00172                         }
00173                         current_elem->next = NULL;
00174                         current_elem->text = tmp;
00175                         
00176                         ++path_len;
00177                 }
00178         }
00179         if ( !retval )
00180         {
00181                 if ( tmp ) free(tmp);
00182                 fapint_clear_llist(path);
00183                 free(rest);
00184                 return 0;
00185         }
00186         
00187         /* Check that we got at least destination callsign. */
00188         if ( !path )
00189         {
00190                 /* Found nothing. */
00191                 packet->error_code = malloc(sizeof(fap_error_code_t));
00192                 if ( packet->error_code ) *packet->error_code = fapDSTCALL_NONE;
00193                 fapint_clear_llist(path);
00194                 free(rest);
00195                 return 0;
00196         }
00197 
00198         /* Validate dst call. We are strict here, there should be no need to use
00199          * a non-AX.25 compatible destination callsigns in the APRS-IS. */
00200         packet->dst_callsign = fap_check_ax25_call(path->text, 0);
00201         if ( !packet->dst_callsign )
00202         {
00203                 packet->error_code = malloc(sizeof(fap_error_code_t));
00204                 if ( packet->error_code ) *packet->error_code = fapDSTCALL_NOAX25;
00205                 fapint_clear_llist(path);
00206                 free(rest);
00207                 return 0;
00208         }
00209 
00210         /* If in AX.25 mode, check that path length is valid. */
00211         if ( is_ax25 && path_len > MAX_DIGIS )
00212         {
00213                 packet->error_code = malloc(sizeof(fap_error_code_t));
00214                 if ( packet->error_code ) *packet->error_code = fapDSTPATH_TOOMANY;
00215                 fapint_clear_llist(path);
00216                 free(rest);
00217                 return 0;
00218         }
00219 
00220         /* Validate path elements, saving them while going. */
00221         packet->path = calloc(path_len, sizeof(char*));
00222         if ( !packet->path )
00223         {
00224                 fapint_clear_llist(path);
00225                 free(rest);
00226         }
00227         for ( i = 0; i < path_len; ++i ) packet->path[i] = NULL;
00228         i = 0;
00229         current_elem = path->next;
00230         while ( current_elem != NULL )
00231         {
00232                 /* First we validate the element in a relaxed, APRS-IS-compatible way. */
00233                 if ( regexec(&fapint_regex_digicall, current_elem->text, matchcount, (regmatch_t*)&matches, 0) == 0 )
00234                 {
00235                         /* Check if we need to be AX.25-strict. */
00236                         if ( is_ax25 )
00237                         {
00238                                 /* Create a copy the element without the has-been-repeated flag. */
00239                                 memset(buf_10b, 0, 10);
00240                                 memcpy(buf_10b, current_elem->text, matches[1].rm_eo);
00241                                 
00242                                 /* Validate it in AX.25-way. */
00243                                 tmp = fap_check_ax25_call(buf_10b, 1);
00244                                 if ( !tmp )
00245                                 {
00246                                         packet->error_code = malloc(sizeof(fap_error_code_t));
00247                                         if ( packet->error_code ) *packet->error_code = fapDIGICALL_NOAX25;
00248                                         retval = 0;
00249                                         break;
00250                                 }
00251                                 free(tmp);
00252                         }
00253                         
00254                         /* Save the callsign as originally given. */
00255                         len = strlen(current_elem->text);
00256                         packet->path[i] = malloc(len+1);
00257                         if ( !packet->path[i] )
00258                         {
00259                                 retval = 0;
00260                                 break;
00261                         }
00262                         strcpy(packet->path[i], current_elem->text);
00263                         
00264                         /* Check if this element was a q-construct. */
00265                         if ( !seenq && current_elem->text[0] == 'q' ) seenq = 1;
00266                 }
00267                 /* This includes accepting IPv6 addresses after q-construct. */
00268                 else if ( seenq && regexec(&fapint_regex_digicallv6, current_elem->text, 0, NULL, 0) == 0 )
00269                 {
00270                         /* Save the callsign as originally given. */
00271                         len = strlen(current_elem->text);
00272                         packet->path[i] = malloc(len+1);
00273                         if ( !packet->path[i] )
00274                         {
00275                                 retval = 0;
00276                                 break;
00277                         }
00278                         strcpy(packet->path[i], current_elem->text);
00279                 }
00280                 else
00281                 {
00282                         packet->error_code = malloc(sizeof(fap_error_code_t));
00283                         if ( packet->error_code ) *packet->error_code = fapDIGICALL_BADCHARS;
00284                         retval = 0;
00285                         break;
00286                 }            
00287                 
00288                 /* Get next element. */
00289                 current_elem = current_elem->next;
00290                 ++i;
00291         }
00292         if ( !retval )
00293         {
00294                 fapint_clear_llist(path);
00295                 for ( len = 0; len <= i; ++len ) { free(packet->path[len]); }
00296                 free(packet->path);
00297                 packet->path = NULL;
00298                 free(rest);
00299                 return 0;
00300         }
00301         packet->path_len = path_len;
00302 
00303         /* Header parsed. */
00304         fapint_clear_llist(path);
00305         free(rest);
00306         return 1;
00307 }
00308 
00309 
00310 
00311 int fapint_parse_mice(fap_packet_t* packet, char const* input, unsigned int const input_len)
00312 {
00313         int len, error, i, lon;
00314         unsigned int tmp_us;
00315         char *rest, *tmp_str;
00316         char dstcall[7], latitude[7], buf_6b[6], longitude[6];
00317         double speed, course_speed, course_speed_tmp, course;
00318         char dao[3];
00319 
00320         unsigned int const matchcount = 3;
00321         regmatch_t matches[matchcount];
00322 
00323         /* Body must be at least 8 chars long. Destination callsign must exist. */
00324         if ( input_len < 8 || packet->dst_callsign == NULL )
00325         {
00326                 packet->error_code = malloc(sizeof(fap_error_code_t));
00327                 if ( packet->error_code ) *packet->error_code = fapMICE_SHORT;
00328                 return 0;
00329         }
00330 
00331         /* Create copy of dst call without ssid. */
00332         memset(dstcall, 0, 7);
00333         for ( i = 0; i < strlen(packet->dst_callsign) && i < 6; ++i )
00334         {
00335                 if ( packet->dst_callsign[i] == '-' ) break;
00336                 dstcall[i] = packet->dst_callsign[i];
00337         }
00338         if ( strlen(dstcall) != 6 )
00339         {
00340                 packet->error_code = malloc(sizeof(fap_error_code_t));
00341                 if ( packet->error_code ) *packet->error_code = fapMICE_SHORT;
00342                 return 0;
00343         }
00344 
00345         /* Validate target call. */
00346         if ( regexec(&fapint_regex_mice_dstcall, dstcall, 0, NULL, 0) != 0 )
00347         {
00348                 /* A-K characters are not used in the last 3 characters and MNO are never used. */
00349                 packet->error_code = malloc(sizeof(fap_error_code_t));
00350                 if ( packet->error_code ) *packet->error_code = fapMICE_INV;
00351                 return 0;
00352         }
00353         
00354         /* Get symbol table. */
00355         packet->symbol_table = input[7];
00356 
00357         /* Validate body. */
00358         /* "^[\x26-\x7f][\x26-\x61][\x1c-\x7f]{2}[\x1c-\x7d][\x1c-\x7f][\x21-\x7b\x7d][\/\\A-Z0-9]" */
00359         error = 0;
00360         if ( input[0] < 0x26 || (unsigned char)input[0] > 0x7f ) error = 1;
00361         if ( input[1] < 0x26 || input[1] > 0x61 ) error = 1;
00362         if ( input[2] < 0x1c || (unsigned char)input[2] > 0x7f ) error = 1;
00363         if ( input[3] < 0x1c || (unsigned char)input[3] > 0x7f ) error = 1;
00364         if ( input[4] < 0x1c || input[4] > 0x7d ) error = 1;
00365         if ( input[5] < 0x1c || (unsigned char)input[5] > 0x7f ) error = 1;
00366         if ( input[6] != 0x7d && (input[6] < 0x21 || input[6] > 0x7b) ) error = 1;
00367         if ( error || regexec(&fapint_regex_mice_body, input+7, 0, NULL, 0) != 0 )
00368         {
00369                 packet->error_code = malloc(sizeof(fap_error_code_t));
00370                 if ( packet->error_code )
00371                 {
00372                         /* Validate symbol table. */
00373                         if ( ( packet->symbol_table == '/' ) ||
00374                              ( packet->symbol_table == '\\' ) ||
00375                              ( packet->symbol_table >= 'A' && packet->symbol_table <= 'Z' ) ||
00376                              isdigit(packet->symbol_table) )
00377                         {
00378                                 // It's okay, we have some other error.
00379                                 *packet->error_code = fapMICE_INV_INFO;
00380                         }
00381                         else
00382                         {
00383                                 // It's not okay.
00384                                 *packet->error_code = fapSYM_INV_TABLE;
00385                         }
00386                 }
00387                 return 0;
00388         }
00389         
00390         /* Store pos format. */
00391         packet->format = malloc(sizeof(fap_pos_format_t));
00392         if ( !packet->format )
00393         {
00394                 return 0;
00395         }
00396         *packet->format = fapPOS_MICE;
00397         
00398         /* Start process from the target call to find latitude, message bits, N/S
00399          * and W/E indicators and long. offset. */
00400         
00401         /* First create a translated copy to find latitude. */
00402         memset(latitude, 0, 7);
00403         for ( i = 0; i < 6; ++i )
00404         {
00405                 if ( dstcall[i] >= 'A' && dstcall[i] <= 'J' )
00406                 {
00407                         /* A-J -> 0-9 */
00408                         latitude[i] = dstcall[i] - 17;
00409                 }
00410                 else if ( dstcall[i] >= 'P' && dstcall[i] <= 'Y' )
00411                 {
00412                         /* P-Y -> 0-9 */
00413                         latitude[i] = dstcall[i] - 32;
00414                 }
00415                 else if ( dstcall[i] == 'K' || dstcall[i] == 'L' || dstcall[i] == 'Z' )
00416                 {
00417                         /* pos amb */
00418                         latitude[i] = '_';
00419                 }
00420                 else
00421                 {
00422                         latitude[i] = dstcall[i];
00423                 }
00424         }
00425         
00426         /* Check the amount of position ambiguity. */
00427         packet->pos_ambiguity = malloc(sizeof(unsigned int));
00428         if ( !packet->pos_ambiguity ) return 0;
00429         if ( regexec(&fapint_regex_mice_amb, latitude, matchcount, (regmatch_t*)&matches, 0) != 0 )
00430         {
00431                 packet->error_code = malloc(sizeof(fap_error_code_t));
00432                 if ( packet->error_code ) *packet->error_code = fapMICE_AMB_LARGE;
00433                 return 0;
00434         }
00435         *packet->pos_ambiguity = matches[2].rm_eo - matches[2].rm_so;
00436         
00437         /* Validate ambiguity. */
00438         if ( *packet->pos_ambiguity > 4 )
00439         {
00440                 packet->error_code = malloc(sizeof(fap_error_code_t));
00441                 if ( packet->error_code ) *packet->error_code = fapMICE_AMB_INV;
00442                 return 0;
00443         }
00444   
00445         /* Calculate position resolution. */
00446         packet->pos_resolution = malloc(sizeof(double));
00447         if ( !packet->pos_resolution ) return 0;
00448         *packet->pos_resolution = fapint_get_pos_resolution(2 - *packet->pos_ambiguity);
00449         
00450         /* Convert the latitude to the midvalue if position ambiguity is used. */
00451         if ( *packet->pos_ambiguity >= 4 )
00452         {
00453                 /* The minute is between 0 and 60, so the midpoint is 30. */
00454                 tmp_str = strchr(latitude, '_');
00455                 *tmp_str = '3';
00456         }
00457         else
00458         {
00459                 /* First digit is changed to 5. */
00460                 if ( (tmp_str = strchr(latitude, '_')) != NULL )
00461                 {
00462                         *tmp_str = '5';
00463                 }
00464         }
00465         
00466         /* Remaining digits are changed to 0. */
00467         while ( (tmp_str = strchr(latitude, '_')) != NULL )
00468         {
00469                 *tmp_str = '0';
00470         }
00471         
00472         /* Convert latitude degrees into number and save it. */
00473         buf_6b[0] = latitude[0]; buf_6b[1] = latitude[1];
00474         buf_6b[2] = 0;
00475         packet->latitude = malloc(sizeof(double));
00476         if ( !packet->latitude ) return 0;
00477         *packet->latitude = atof(buf_6b);
00478         
00479         /* Same for minutes. */
00480         buf_6b[0] = latitude[2]; buf_6b[1] = latitude[3];
00481         buf_6b[2] = '.';
00482         buf_6b[3] = latitude[4]; buf_6b[4] = latitude[5];
00483         buf_6b[5] = 0;
00484         *packet->latitude += atof(buf_6b)/60;
00485 
00486         /* Check the north/south direction and correct the latitude if necessary. */
00487         if ( dstcall[3] <= 0x4c )
00488         {
00489                 *packet->latitude = 0 - *packet->latitude;
00490         }
00491 
00492         /* Get the message bits. 1 is standard one-bit and 2 is custom one-bit. */
00493         packet->messagebits = malloc(4);
00494         if ( !packet->messagebits ) return 0;
00495         for ( i = 0; i < 3; ++i )
00496         {
00497                 if ( (dstcall[i] >= '0' && dstcall[i] <= '9') || dstcall[i] == 'L' )
00498                 {
00499                         packet->messagebits[i] = '0';
00500                 }
00501                 else if ( dstcall[i] >= 'P' && dstcall[i] <= 'Z' )
00502                 {
00503                         packet->messagebits[i] = '1';
00504                 }
00505                 else if ( dstcall[i] >= 'A' && dstcall[i] <= 'K' )
00506                 {
00507                         packet->messagebits[i] = '2';
00508                 }
00509         }
00510         packet->messagebits[3] = 0;
00511         
00512         /* Decode the longitude, the first three bytes of the body after the data
00513          * type indicator. First longitude degrees, remember the longitude offset. */
00514         lon = input[0] - 28;
00515         if ( dstcall[4] >= 0x50 )
00516         {
00517                 lon += 100;
00518         }
00519         if ( lon >= 180 && lon <= 189 )
00520         {
00521                 lon -= 80;
00522         }
00523         else if ( lon >= 190 && lon <= 199 )
00524         {
00525                 lon -= 190;
00526         }
00527         packet->longitude = malloc(sizeof(double));
00528         if ( !packet->longitude ) return 0;
00529         *packet->longitude = lon;
00530         
00531         /* Get longitude minutes. */
00532         memset(longitude, 0, 6);
00533         lon = input[1] - 28;
00534         if ( lon >= 60 )
00535         {
00536                 lon -= 60;
00537         }
00538         sprintf(longitude, "%02d.%02d", lon, input[2] - 28);
00539         
00540         /* Apply pos amb and save. */
00541         if ( *packet->pos_ambiguity == 4 )
00542         {
00543                 /* Minutes are not used. */
00544                 *packet->longitude += 0.5;
00545         }
00546         else if ( *packet->pos_ambiguity == 3 )
00547         {
00548                 /* 1 minute digit is used. */
00549                 tmp_str = malloc(3);
00550                 tmp_str[0] = longitude[0]; tmp_str[1] = '5'; tmp_str[2] = 0;
00551                 *packet->longitude += atof(tmp_str)/60;
00552                 free(tmp_str);
00553         }
00554         else if ( *packet->pos_ambiguity == 2 )
00555         {
00556                 /* Whole minutes are used. */
00557                 memset(buf_6b, 0, 6);
00558                 buf_6b[0] = longitude[0];
00559                 buf_6b[1] = longitude[1];
00560                 buf_6b[2] = '.';
00561                 buf_6b[3] = '5';
00562                 *packet->longitude += atof(buf_6b)/60;
00563         }
00564         else if ( *packet->pos_ambiguity == 1 )
00565         {
00566                 /* Whole minutes and 1 decimal are used. */
00567                 longitude[4] = '5';
00568                 *packet->longitude += atof(longitude)/60;
00569         }
00570         else if ( *packet->pos_ambiguity == 0 )
00571         {
00572                 *packet->longitude += atof(longitude)/60;
00573         }
00574         else
00575         {
00576                 packet->error_code = malloc(sizeof(fap_error_code_t));
00577                 if ( packet->error_code ) *packet->error_code = fapMICE_AMB_ODD;
00578                 return 0;
00579         }
00580         
00581         /* Check E/W sign. */
00582         if ( dstcall[5] >= 0x50 )
00583         {
00584                 *packet->longitude = 0 - *packet->longitude;
00585         }
00586 
00587         /* Now onto speed and course. */
00588         speed = (input[3] - 28) * 10;
00589         course_speed = input[4] - 28;
00590         course_speed_tmp = floor(course_speed / 10);
00591         speed += course_speed_tmp;
00592         course_speed -= course_speed_tmp * 10;
00593         course = 100 * course_speed;
00594         course += input[5] - 28;
00595         
00596         /* Some adjustment. */
00597         if ( speed >= 800 )
00598         {
00599                 speed -= 800;
00600         }
00601         if ( course >= 400 )
00602         {
00603                 course -= 400;
00604         }
00605   
00606         /* Save values. */
00607         packet->speed = malloc(sizeof(double));
00608         if ( !packet->speed ) return 0;
00609         *packet->speed = speed * KNOT_TO_KMH;
00610         if ( course >= 0 )
00611         {
00612                 packet->course = malloc(sizeof(unsigned int));
00613                 if ( !packet->course ) return 0;
00614                 *packet->course = course;
00615         }
00616         
00617         /* Save symbol code. */
00618         packet->symbol_code = input[6];
00619         
00620         /* If there's something left, create working copy of it. */
00621         if ( (len = input_len - 8) > 0 )
00622         {
00623                 rest = malloc(len);
00624                 memcpy(rest, input+8, len);
00625         }
00626         else
00627         {
00628                 /* Nothing left, we're ok and out. */
00629                 return 1;
00630         }
00631         
00632         /* Check for possible altitude. Altitude is base-91 coded and in format
00633          * "xxx}" where x are the base-91 digits in meters, origin is 10000 meters
00634          * below sea. */
00635         for ( i = 0; i+3 < len; ++i )
00636         {
00637                 /* Check for possible altitude digit. */
00638                 if ( rest[i] >= 0x21 && rest[i] <= 0x7b )
00639                 {
00640                         /* Check remaining digits for altitudeness. */
00641                         if ( (rest[i+1] >= 0x21 && rest[i+1] <= 0x7b) &&
00642                                   (rest[i+2] >= 0x21 && rest[i+2] <= 0x7b) &&
00643                                   rest[i+3] == '}' )
00644                         {
00645                                 /* Save altitude. */
00646                                 packet->altitude = malloc(sizeof(double));
00647                                 if ( !packet->altitude )
00648                                 {
00649                                         free(rest);
00650                                         return 0;
00651                                 }
00652                                 *packet->altitude = ( (rest[i] - 33) * pow(91,2) +
00653                                                                      (rest[i+1] - 33) * 91 +
00654                                                                      (rest[i+2] - 33) ) - 10000;
00655                                 /* Remove altitude. */
00656                                 tmp_str = fapint_remove_part(rest, len, i, i+4, &tmp_us);
00657                                 free(rest);
00658                                 rest = tmp_str;
00659                                 len = tmp_us;
00660                                 /* We're done. */
00661                                 break;
00662                         }
00663                 }
00664         }
00665 
00666         /* If we still hafe stuff left, check for !DAO!, take the last occurrence (per recommendation). */
00667         if ( len > 0 )
00668         {
00669                 for ( i = len-1; i >= 0 ; --i )
00670                 {
00671                         if ( i + 4 < len && rest[i] == '!' &&
00672                                   0x21 <= rest[i+1] && rest[i+1] <= 0x7b &&
00673                                   0x20 <= rest[i+2] && rest[i+2] <= 0x7b &&
00674                                   0x20 <= rest[i+3] && rest[i+3] <= 0x7b &&
00675                                   rest[i+4] == '!' )
00676                         {
00677                                 memcpy(dao, rest+i+1, 3);
00678                                 /* Validate and save dao. */
00679                                 if ( fapint_parse_dao(packet, dao) )
00680                                 {
00681                                         /* Remove !DAO!. */
00682                                         tmp_str = fapint_remove_part(rest, len, i, i+5, &tmp_us);
00683                                         free(rest);
00684                                         rest = tmp_str;
00685                                         len = tmp_us;
00686                                         break;
00687                                 }
00688                         }
00689                 }
00690         }
00691 
00692         /* Check for base-91 comment telemetry. */
00693         /*fapint_parse_comment_telemetry(packet, &rest, &len);*/
00694         
00695         /* If there's something left, save it as a comment. */
00696         if ( len > 0 )
00697         {
00698                 packet->comment = rest;
00699                 packet->comment_len = len;
00700         }
00701         
00702         return 1;
00703 }
00704 
00705 
00706 time_t fapint_parse_timestamp(char const* input)
00707 {
00708         char buf_3b[3];
00709         unsigned int first, second, third;
00710         char type;
00711         struct tm now_struct, fwd_struct, back_struct, *tmp_struct;
00712         time_t now, fwd, back, result;
00713         
00714         unsigned int const matchcount = 5;
00715         regmatch_t matches[matchcount];
00716 
00717 
00718         /* Validate input. */
00719         if ( !input )
00720         {
00721                 return 0;
00722         }
00723         if ( regexec(&fapint_regex_timestamp, input, matchcount, (regmatch_t*)&matches, 0) == 0 )
00724         {
00725                 buf_3b[2] = 0;
00726                 /* Get three numbers. */
00727                 memcpy(buf_3b, input+matches[1].rm_so, 2);
00728                 first = atoi(buf_3b);
00729                 memcpy(buf_3b, input+matches[2].rm_so, 2);
00730                 second = atoi(buf_3b);
00731                 memcpy(buf_3b, input+matches[3].rm_so, 2);
00732                 third = atoi(buf_3b);
00733                 
00734                 /* Get type flag. */
00735                 type = input[matches[4].rm_so];
00736         }
00737         else
00738         {
00739                 return 0;
00740         }
00741         
00742         /* Continue based on stamp type. */
00743         if ( type == 'h' )
00744         {
00745                 /* HMS in UTC -format, check for valid time. */
00746                 if ( first > 23 || second > 59 || third > 59 )
00747                 {
00748                         return 0;
00749                 }
00750                 
00751                 /* Convert into unixtime. */
00752                 now = time(NULL);
00753                 tmp_struct = gmtime(&now);
00754                 memcpy((struct tm*)&now_struct, tmp_struct, sizeof(struct tm));
00755                 now_struct.tm_sec = third;
00756                 now_struct.tm_min = second;
00757                 now_struct.tm_hour = first-1;
00758                 result = mktime((struct tm*)&now_struct);
00759                 
00760                 /* If the time is more than about one hour into the future, roll the
00761                         timestamp one day backwards. */
00762                 if ( now + 3900 < result )
00763                 {
00764                         result -= 86400;
00765                 }
00766                 /* If the time is more than about 23 hours into the past, roll the
00767                         timestamp one day forwards. */
00768                 else if ( now - 82500 > result )
00769                 {
00770                         result += 86400;
00771                 }
00772                 return result;
00773         }
00774         else if ( type == 'z' || type == '/' )
00775         {
00776                 /* DHM in UTC (z) or local(/). Always intepret local to mean local to this computer. */
00777                 if ( first < 1 || first > 31 || second > 23 || third > 59 )
00778                 {
00779                         return 0;
00780                 }
00781                 
00782                 /* If time is under about 12 hours into the future, go there.
00783                         Otherwise get the first matching time in the past. */
00784 
00785                 /* Form the possible timestamps. */
00786                 
00787                 /* This month. */
00788                 now = time(NULL);
00789                 if ( type == 'z' )
00790                 {
00791                         tmp_struct = gmtime(&now);
00792                 }
00793                 else
00794                 {
00795                         tmp_struct = localtime(&now);
00796                 }
00797                 memcpy((struct tm*)&now_struct, tmp_struct, sizeof(struct tm));
00798                 now_struct.tm_mday = first;
00799                 now_struct.tm_hour = second-1;
00800                 now_struct.tm_min = third;
00801                 now_struct.tm_sec = 0;
00802                 now = mktime((struct tm*)&now_struct);
00803 
00804                 /* Next month. */
00805                 memcpy((struct tm*)&fwd_struct, tmp_struct, sizeof(struct tm));
00806                 fwd_struct.tm_mon += 1;
00807                 fwd_struct.tm_mday = first;
00808                 fwd_struct.tm_hour = second-1;
00809                 fwd_struct.tm_min = third;
00810                 fwd_struct.tm_sec = 0;
00811                 fwd = mktime((struct tm*)&fwd_struct);
00812                 
00813                 /* Previous month. */
00814                 memcpy((struct tm*)&back_struct, tmp_struct, sizeof(struct tm));
00815                 if ( back_struct.tm_mon == 0 )
00816                 {
00817                         back_struct.tm_mon = 11;
00818                         back_struct.tm_year -= 1;
00819                 }
00820                 else
00821                 {
00822                         back_struct.tm_mon -= 1;
00823                 }
00824                 back_struct.tm_mday = first;
00825                 back_struct.tm_hour = second-1;
00826                 back_struct.tm_min = third;
00827                 back_struct.tm_sec = 0;
00828                 back = mktime((struct tm*)&back_struct);
00829                 
00830                 /* Select the timestamp to use. Pick the timestamp that is largest,
00831                         but under about 12 hours from current time. */
00832                 if ( fwd - now < 43400 )
00833                 {
00834                         result = fwd;
00835                 }
00836                 else if ( now - time(NULL) < 43400 )
00837                 {
00838                         result = now;
00839                 }
00840                 else
00841                 {
00842                         result = back;
00843                 }
00844                 
00845                 return result;
00846          }
00847                 
00848         return 0;
00849 }
00850 
00851 
00852 int fapint_parse_compressed(fap_packet_t* packet, char const* input)
00853 {
00854         int i;
00855         char symboltable, symbolcode;
00856         char lat[4], lon[4];
00857         char c1, s1, comptype;
00858         char cs;
00859         
00860         /* Validate compressed position and things. */
00861         if ( strlen(input) < 13 )
00862         {
00863                 packet->error_code = malloc(sizeof(fap_error_code_t));
00864                 if ( packet->error_code ) *packet->error_code = fapCOMP_INV;
00865                 return 0;
00866         }
00867         if ( !(  
00868                         (input[0] >= 'A' && input[0] <= 'Z') ||
00869                         (input[0] >= 'a' && input[0] <= 'j') ||
00870                         input[0] == '/' ||
00871                         input[0] == '\\')
00872                 )
00873         {
00874                 packet->error_code = malloc(sizeof(fap_error_code_t));
00875                 if ( packet->error_code ) *packet->error_code = fapCOMP_INV;
00876                 return 0;
00877         }
00878         for ( i = 1; i <= 8; ++i )
00879         {
00880                 if ( input[i] < 0x21 || input[i] > 0x7b )
00881                 {
00882                         packet->error_code = malloc(sizeof(fap_error_code_t));
00883                         if ( packet->error_code ) *packet->error_code = fapCOMP_INV;
00884                         return 0;
00885                 }
00886         }
00887         if ( input[9] != 0x7d && (input[9] < 0x21 || input[9] > 0x7b) )
00888         {
00889                 packet->error_code = malloc(sizeof(fap_error_code_t));
00890                 if ( packet->error_code ) *packet->error_code = fapCOMP_INV;
00891                 return 0;
00892         }
00893         for ( i = 10; i <= 12; ++i )
00894         {
00895                 if ( input[i] < 0x20 || input[i] > 0x7b )
00896                 {
00897                         packet->error_code = malloc(sizeof(fap_error_code_t));
00898                         if ( packet->error_code ) *packet->error_code = fapCOMP_INV;
00899                         return 0;
00900                 }
00901         }
00902         
00903         /* Store pos format. */
00904         packet->format = malloc(sizeof(fap_pos_format_t));
00905         if ( !packet->format )
00906         {
00907                 return 0;
00908         }
00909         *packet->format = fapPOS_COMPRESSED;
00910         
00911         /* Get symbol. */
00912         symboltable = input[0];
00913         symbolcode = input[9];
00914         
00915         /* Get position. */
00916         for ( i = 0; i < 4; ++i )
00917         {
00918                 lat[i] = input[i+1] - 33;
00919                 lon[i] = input[i+5] - 33;
00920         }
00921         
00922         /* Get other data. */
00923         c1 = input[10] - 33;
00924         s1 = input[11] - 33;
00925         comptype = input[12] - 33;
00926         
00927         /* Save symbol table. Table chars (a-j) are converted to numbers 0-9. */
00928         if ( symboltable >= 'a' && symboltable <= 'j' )
00929         {
00930                 symboltable -= 81;
00931         }
00932         packet->symbol_table = symboltable;
00933         
00934         /* Save symbol code as is. */
00935         packet->symbol_code = symbolcode;
00936         
00937 
00938         /* Calculate position. */
00939         packet->latitude = malloc(sizeof(double));
00940         if ( !packet->latitude ) return 0;
00941         *packet->latitude = 90 - ( (lat[0] * pow(91,3) + lat[1] * pow(91,2) + lat[2] * 91 + lat[3]) / 380926);
00942         packet->longitude = malloc(sizeof(double));
00943         if ( !packet->latitude ) return 0;
00944         *packet->longitude = -180 + ( (lon[0] * pow(91,3) + lon[1] * pow(91,2) + lon[2] * 91 + lon[3]) / 190463);
00945         
00946         /* Save best-case position resolution in meters: 1852 meters * 60 minutes in a degree * 180 degrees / 91^4. */
00947         packet->pos_resolution = malloc(sizeof(double));
00948         if ( !packet->pos_resolution ) return 0;
00949         *packet->pos_resolution = 0.291;
00950         
00951         /* GPS fix status, only if csT is used. */
00952         if ( c1 != -1 )
00953         {
00954                 packet->gps_fix_status = malloc(sizeof(short));
00955                 if ( !packet->gps_fix_status ) return 0;
00956                 if ( (comptype & 0x20) == 0x20 )
00957                 {
00958                         *packet->gps_fix_status = 1;
00959                 }
00960                 else
00961                 {
00962                         *packet->gps_fix_status = 0;
00963                 }
00964         }
00965 
00966         /* Check the compression type, if GPGGA, then the cs bytes are altitude.
00967          * Otherwise try to decode it as course and speed and finally as radio range.
00968          * If c is space, then csT is not used. Also require that s is not a space. */
00969         if ( c1 == -1 || s1 == -1 )
00970         {
00971                 /* csT not used. */
00972         }
00973         else if ( (comptype & 0x18) == 0x10 )
00974         {
00975                 /* cs is altitude. */
00976                 cs = c1 * 91 + s1;
00977                 packet->altitude = malloc(sizeof(double));
00978                 if ( !packet->altitude ) return 0;
00979                 /* Convert directly to meters. */
00980                 *packet->altitude = pow(1.002, cs) * 0.3048;
00981         }
00982         else if ( c1 >= 0 && c1 <= 89 )
00983         {
00984                 packet->course = malloc(sizeof(unsigned int));
00985                 if ( !packet->course ) return 0;
00986                 if ( c1 == 0 )
00987                 {
00988                         /* Special case of north, APRS spec uses zero for unknown and 360 for north.
00989                          * So remember to convert north here. */
00990                         *packet->course = 360;
00991                 }
00992                 else
00993                 {
00994                         *packet->course = c1 * 4;
00995                 }
00996                 /* Convert directly to km/h. */
00997                 packet->speed = malloc(sizeof(double));
00998                 if ( !packet->speed ) return 0;
00999                 *packet->speed = ( pow(1.08, s1) - 1 ) * KNOT_TO_KMH;
01000         }
01001         else if ( c1 == 90 )
01002         {
01003                 /* Convert directly to km. */
01004                 packet->radio_range = malloc(sizeof(unsigned int));
01005                 if ( !packet->radio_range ) return 0;
01006                 *packet->radio_range = 2 * pow(1.08, s1) * MPH_TO_KMH;
01007         }
01008         
01009         return 1;
01010 }
01011 
01012 
01013 int fapint_parse_normal(fap_packet_t* packet, char const* input)
01014 {
01015         char sind, wind;
01016         short is_south = 0;
01017         short is_west = 0;
01018         char lat_deg[3], lat_min[6], lon_deg[4], lon_min[6], tmp_5b[5];
01019         double lat, lon;
01020         
01021         unsigned int const matchcount = 9;
01022         regmatch_t matches[matchcount];
01023 
01024         
01025         /* Check length. */
01026         if ( strlen(input) < 19 )
01027         {
01028                 packet->error_code = malloc(sizeof(fap_error_code_t));
01029                 if ( packet->error_code ) *packet->error_code = fapLOC_SHORT;
01030                 return 0;
01031         }
01032         
01033         /* Save pos format. */
01034         packet->format = malloc(sizeof(fap_pos_format_t));
01035         if ( !packet->format )
01036         {
01037                 return 0;
01038         }
01039         *packet->format = fapPOS_UNCOMPRESSED;
01040         
01041         /* Validate. */
01042         if ( regexec(&fapint_regex_normalpos, input, matchcount, (regmatch_t*)&matches, 0) != 0 )
01043         {
01044                 packet->error_code = malloc(sizeof(fap_error_code_t));
01045                 if ( packet->error_code ) *packet->error_code = fapLOC_INV;
01046                 return 0;
01047         }
01048         if ( input[18] != 0x7d && (input[18] < 0x21 || input[18] > 0x7b) )
01049         {
01050                 packet->error_code = malloc(sizeof(fap_error_code_t));
01051                 if ( packet->error_code ) *packet->error_code = fapLOC_INV;
01052                 return 0;
01053         }
01054         
01055         /* Save hemisphere info. */
01056         sind = toupper(input[matches[3].rm_so]);
01057         wind = toupper(input[matches[7].rm_so]);
01058         
01059         /* Save symbol table and code. */
01060         packet->symbol_table = input[matches[4].rm_so];
01061         packet->symbol_code = input[18];
01062 
01063         /* Save position numbers as NULL-terminated strings. */
01064         memset(lat_deg, 0, 3);
01065         memcpy(lat_deg, input+matches[1].rm_so, 2);
01066         memset(lat_min, 0, 6);
01067         memcpy(lat_min, input+matches[2].rm_so, 5);
01068         memset(lon_deg, 0, 4);
01069         memcpy(lon_deg, input+matches[5].rm_so, 3);
01070         memset(lon_min, 0, 6);
01071         memcpy(lon_min, input+matches[6].rm_so, 5);
01072         
01073         /* Validate symbol table. */
01074         if ( ( packet->symbol_table == '/' ) ||
01075              ( packet->symbol_table == '\\' ) ||
01076              ( packet->symbol_table >= 'A' && packet->symbol_table <= 'Z' ) ||
01077              isdigit(packet->symbol_table) )
01078         {
01079                 // It's okay.
01080         }
01081         else
01082         {
01083                 // It's not.
01084                 packet->error_code = malloc(sizeof(fap_error_code_t));
01085                 if ( packet->error_code ) *packet->error_code = fapSYM_INV_TABLE;
01086                 return 0;
01087         }       
01088         
01089         /* Convert hemisphere indicators to numbers. */
01090         if ( sind == 'S' ) is_south = 1;
01091         if ( wind == 'W' ) is_west = 1;
01092 
01093         /* Convert degrees to numbers and check them. */
01094         lat = atoi(lat_deg);
01095         lon = atoi(lon_deg);
01096         if ( lat > 89 || lon > 179 )
01097         {
01098                 packet->error_code = malloc(sizeof(fap_error_code_t));
01099                 if ( packet->error_code ) *packet->error_code = fapLOC_LARGE;
01100                 return 0;
01101         }
01102         
01103         /* Prepare to parse position ambiguity. */
01104         packet->pos_ambiguity = malloc(sizeof(unsigned int));
01105         if ( !packet->pos_ambiguity ) return 0;
01106         
01107         /* First task is to create a copy without the decimal separator. */
01108         tmp_5b[0] = lat_min[0];
01109         tmp_5b[1] = lat_min[1];
01110         tmp_5b[2] = lat_min[3];
01111         tmp_5b[3] = lat_min[4];
01112         tmp_5b[4] = 0;
01113         
01114         /* Calculate ambiguity, which is the amount of spaces at the end. */
01115         if ( regexec(&fapint_regex_normalamb, tmp_5b, matchcount, (regmatch_t*)&matches, 0) != 0 )
01116         {
01117                 packet->error_code = malloc(sizeof(fap_error_code_t));
01118                 if ( packet->error_code ) *packet->error_code = fapLOC_AMB_INV;
01119                 return 0;
01120         }
01121         *packet->pos_ambiguity = matches[2].rm_eo - matches[2].rm_so;
01122         
01123         /* Continue depending on amount of position ambiguity. */
01124         packet->latitude = malloc(sizeof(double));
01125         packet->longitude = malloc(sizeof(double));
01126         if ( !packet->latitude || !packet->longitude ) return 0;
01127         switch ( *packet->pos_ambiguity )
01128         {
01129                 case 0:
01130                         /* Validate longitude and save values. */
01131                         if ( strchr(lon_min, ' ') != NULL )
01132                         {
01133                                 packet->error_code = malloc(sizeof(fap_error_code_t));
01134                                 if ( packet->error_code ) *packet->error_code = fapLOC_AMB_INV;
01135                                 return 0;
01136                         }
01137                         else
01138                         {
01139                           *packet->latitude = lat + atof(lat_min)/60;
01140                           *packet->longitude = lon + atof(lon_min)/60;
01141                         }
01142                         break;
01143                 case 4:
01144                         /* Disregard the minutes and add 0.5 to the degree values. */
01145                         *packet->latitude = lat + 0.5;
01146                         *packet->longitude = lon + 0.5;
01147                         break;
01148                 case 1:
01149                 case 2:
01150                         /* Blank digits are just ignored. */
01151                         *packet->latitude = lat + atof(lat_min)/60;
01152                         *packet->longitude = lon + atof(lon_min)/60;
01153                         break;
01154                 case 3:
01155                         /* Single minute digit is set to 5, minute decimals are ignored. */
01156                         lat_min[1] = '5';
01157                         memset(lat_min+2, 0, 4);
01158                         lon_min[1] = '5';
01159                         memset(lon_min+2, 0, 4);
01160                         *packet->latitude = lat + atof(lat_min)/60;
01161                         *packet->longitude = lon + atof(lon_min)/60;
01162                         break;
01163                 default:
01164                         packet->error_code = malloc(sizeof(fap_error_code_t));
01165                         if ( packet->error_code ) *packet->error_code = fapLOC_AMB_INV;
01166                         return 0;
01167         }
01168 
01169         /* Apply hemisphere indicators. */
01170         if ( is_south )
01171         {
01172                 *packet->latitude = 0 - *packet->latitude;
01173         }
01174         if ( is_west )
01175         {
01176                 *packet->longitude = 0 - *packet->longitude;
01177         }
01178         
01179         /* Calculate position resolution based on position ambiguity. */
01180         packet->pos_resolution = malloc(sizeof(double));
01181         if ( !packet->pos_resolution ) return 0;
01182         *packet->pos_resolution = fapint_get_pos_resolution(2 - *packet->pos_ambiguity);
01183         
01184         return 1;
01185 }
01186 
01187 
01188 
01189 void fapint_parse_comment(fap_packet_t* packet, char const* input, unsigned int const input_len)
01190 {
01191         char course[4], speed[4], range[5], altitude[7], dao[3];
01192         int i, tmp_s;
01193         char* tmp_str, *rest = NULL;
01194         unsigned int rest_len = 0, tmp_us;
01195 
01196         unsigned int const matchcount = 2;
01197         regmatch_t matches[matchcount];
01198         
01199         
01200         /* First check the possible APRS data extension, immediately following the
01201                 packet. Then check for PHG. */
01202         if ( input_len >= 7 )
01203         {
01204                 /* Look for data. */
01205                 if ( regexec(&fapint_regex_comment, input, 0, NULL, 0) == 0 )
01206                 {
01207                         /* Get and validate course, if not already available. 0 stands for invalid. */
01208                         if ( !packet->course )
01209                         {
01210                                 memcpy(course, input, 3);
01211                                 course[3] = 0;
01212                                 packet->course = malloc(sizeof(unsigned int));
01213                                 if ( !packet->course ) return;
01214                                 *packet->course = 0;
01215                                 if ( isdigit(course[0]) && isdigit(course[1]) && isdigit(course[2]) )
01216                                 {
01217                                         tmp_s = atoi(course);
01218                                         if ( tmp_s >= 1 && tmp_s <= 360 )
01219                                         {
01220                                                 /* It's valid, let's save it. */
01221                                                 *packet->course = tmp_s;
01222                                         }
01223                                 }
01224                         }
01225                         
01226                         /* Get and validate speed, if not available already. */
01227                         if ( !packet->speed )
01228                         {
01229                                 /* There's no speed value for invalid, so we leave it unallocated by default. */
01230                                 memcpy(speed, input+4, 3);
01231                                 speed[3] = 0;
01232                                 if ( isdigit(speed[0]) && isdigit(speed[1]) && isdigit(speed[2]) )
01233                                 {
01234                                         tmp_s = atoi(&speed[0]);
01235                                         packet->speed = malloc(sizeof(double));
01236                                         if ( !packet->speed ) return;
01237                                         *packet->speed = tmp_s * KNOT_TO_KMH;
01238                                 }
01239                         }
01240                         
01241                         /* Save the rest. */
01242                         rest = fapint_remove_part(input, input_len, 0, 7, &rest_len);
01243                 }
01244                 /* Look for PHGR. */
01245                 else if ( regexec(&fapint_regex_phgr, input, 0, NULL, 0) == 0 &&
01246                                          input[4] >= 0x30 && input[4] <= 0x7e )
01247                 {
01248                         /* Save PHGR. */
01249                         packet->phg = malloc(6);
01250                         if ( !packet->phg ) return;
01251                         memcpy(packet->phg, input+3, 5);
01252                         packet->phg[5] = 0;
01253                         
01254                         /* Save the rest. */
01255                         rest = fapint_remove_part(input, input_len, 0, 8, &rest_len);
01256                 }
01257                 /* Look for PHG. */
01258                 else if ( regexec(&fapint_regex_phg, input, 0, NULL, 0) == 0 &&
01259                                          input[4] >= 0x30 && input[4] <= 0x7e )
01260                 {
01261                         /* Save PHG. */
01262                         packet->phg = malloc(5);
01263                         if ( !packet->phg ) return;
01264                         memcpy(packet->phg, input+3, 4);
01265                         packet->phg[4] = 0;
01266                         
01267                         /* Save the rest. */
01268                         rest = fapint_remove_part(input, input_len, 0, 7, &rest_len);
01269                 }
01270                 /* Look for RNG. */
01271                 else if ( regexec(&fapint_regex_rng, input, 0, NULL, 0) == 0 )
01272                 {
01273                         /* Save and validate range. There's no invalid range value. */
01274                         memcpy(range, input+3, 4);
01275                         range[4] = 0;
01276                         tmp_s = atoi(range);
01277                         packet->radio_range = malloc(sizeof(unsigned int));
01278                         if ( !packet->radio_range ) return;
01279                         *packet->radio_range = tmp_s * MPH_TO_KMH;
01280                  
01281                         /* Save the rest. */
01282                         rest = fapint_remove_part(input, input_len, 0, 7, &rest_len);
01283                 }
01284                 else
01285                 {
01286                         rest = malloc(input_len+1);
01287                         if ( !rest ) return;
01288                         memcpy(rest, input, input_len);
01289                         rest_len = input_len;
01290                         rest[rest_len] = 0;
01291                 }
01292         }
01293         else if ( input_len > 0 )
01294         {
01295                 rest = malloc(input_len+1);
01296                 if ( !rest ) return;
01297                 memcpy(rest, input, input_len);
01298                 rest_len = input_len;
01299                 rest[rest_len] = 0;
01300         }
01301         
01302         /* Check if we still have something left. */
01303         if ( rest_len > 0 )
01304         {
01305                 /* Check for optional altitude anywhere in the comment, take the first occurrence. */
01306                 if ( regexec(&fapint_regex_altitude, rest, matchcount, (regmatch_t*)&matches, 0) == 0 )
01307                 {
01308                         /* Save altitude, if not already there. */
01309                         if ( !packet->altitude )
01310                         {
01311                                 memcpy(altitude, rest+matches[1].rm_so, 6);
01312                                 altitude[6] = 0;
01313                                 tmp_s = atoi(altitude);
01314                                 packet->altitude = malloc(sizeof(double));
01315                                 *packet->altitude = tmp_s * FT_TO_M;
01316                         }
01317                 
01318                         /* Remove altitude. */
01319                         tmp_str = fapint_remove_part(rest, rest_len, matches[1].rm_so-3, matches[1].rm_eo, &tmp_us);
01320                         free(rest);
01321                         rest = tmp_str;
01322                         rest_len = tmp_us;
01323                 }
01324         }
01325                 
01326         /* If we still hafe stuff left, check for !DAO!, take the last occurrence (per recommendation). */
01327         if ( rest_len > 0 )
01328         {
01329                 for ( i = rest_len-1; i >= 0 ; --i )
01330                 {
01331                         if ( i + 4 < rest_len && rest[i] == '!' &&
01332                                   0x21 <= rest[i+1] && rest[i+1] <= 0x7b &&
01333                                   0x20 <= rest[i+2] && rest[i+2] <= 0x7b &&
01334                                   0x20 <= rest[i+3] && rest[i+3] <= 0x7b &&
01335                                   rest[i+4] == '!' )
01336                         {
01337                                 memcpy(dao, rest+i+1, 3);
01338                                 /* Validate and save dao. */
01339                                 if ( fapint_parse_dao(packet, dao) )
01340                                 {
01341                                         /* Remove !DAO!. */
01342                                         tmp_str = fapint_remove_part(rest, rest_len, i, i+5, &tmp_us);
01343                                         free(rest);
01344                                         rest = tmp_str;
01345                                         rest_len = tmp_us;
01346                                         break;
01347                                 }
01348                         }
01349                 }
01350         }
01351         
01352         /* Check for base-91 comment telemetry. */
01353         /*fapint_parse_comment_telemetry(packet, &rest, &rest_len);*/
01354         
01355         /* If there's something left, save it as a comment. */
01356         if ( rest_len > 0 )
01357         {
01358                 packet->comment = rest;
01359                 packet->comment_len = rest_len;
01360         }
01361 }
01362 
01363 
01364 
01365 int fapint_parse_nmea(fap_packet_t* packet, char const* input, unsigned int const input_len)
01366 {
01367         char* rest;
01368         unsigned int rest_len;
01369         int i, len, retval = 1;
01370 
01371         char* checksum_area;
01372         char checksum_given_str[3];
01373         long int checksum_given;
01374         long int checksum_calculated = 0;
01375         
01376         fapint_llist_item_t* nmea_field_list = NULL, *current_elem = NULL;
01377         char** nmea_fields = NULL;
01378         unsigned int nmea_field_count;
01379         char* tmp_str;
01380         
01381         char buf_3b[3];
01382         unsigned int year, month, day, hours, mins, secs;
01383         struct tm timestamp;
01384         
01385         unsigned int const matchcount = 5;
01386         regmatch_t matches[matchcount];
01387         
01388         /* Create working copy of input with no trailing white spaces. */
01389         for ( i = input_len-1; i >= 0; ++i )
01390         {
01391                 if ( !isspace(input[i]) )
01392                 {
01393                         break;
01394                 }
01395         }
01396         rest_len = i+1;
01397         
01398         if ( rest_len > 0 )
01399         {
01400                 rest = malloc(rest_len+1);
01401                 if ( !rest ) return 0;
01402                 memcpy(rest, input, rest_len);
01403                 rest[rest_len] = 0;
01404         }
01405         else
01406         {
01407                 return 0;
01408         }
01409         
01410         /* Verify first, if it is provided. */
01411         if ( regexec(&fapint_regex_nmea_chksum, rest, matchcount, (regmatch_t*)&matches, 0) == 0 )
01412         {
01413                 len = matches[1].rm_eo - matches[1].rm_so;
01414                 checksum_area = malloc(len+1);
01415                 if ( !checksum_area )
01416                 {
01417                         free(rest);
01418                         return 0;
01419                 }
01420                 memcpy(checksum_area, rest+matches[1].rm_so, len);
01421                 checksum_area[len] = 0;
01422                 
01423                 checksum_given_str[0] = rest[matches[2].rm_so];
01424                 checksum_given_str[1] = rest[matches[2].rm_so+1];
01425                 checksum_given_str[2] = 0;
01426                 checksum_given = strtol(checksum_given_str, NULL, 16);
01427                 
01428                 for ( i = 0; i < strlen(checksum_area); ++i )
01429                 {
01430                         checksum_calculated ^= checksum_area[i];
01431                 }
01432                 free(checksum_area);
01433                 
01434                 if ( checksum_given != checksum_calculated )
01435                 {
01436                         packet->error_code = malloc(sizeof(fap_error_code_t));
01437                         if ( packet->error_code ) *packet->error_code = fapNMEA_INV_CKSUM;
01438                         free(rest);
01439                         return 0;
01440                 }
01441                 
01442                 /* Make a note of the existance of a checksum. */
01443                 packet->nmea_checksum_ok = malloc(sizeof(short));
01444                 if ( !packet->nmea_checksum_ok )
01445                 {
01446                         free(rest);
01447                         return 0;
01448                 }
01449                 *packet->nmea_checksum_ok = 1;
01450         
01451                 /* Remove checksum. */
01452                 rest = fapint_remove_part(rest, rest_len, matches[2].rm_so-1, matches[2].rm_eo, &rest_len);
01453         }
01454         else
01455         {
01456                 printf("no checksum in (%s)", rest);
01457         }
01458         
01459         /* Format is NMEA. */
01460         packet->format = malloc(sizeof(fap_pos_format_t));
01461         if ( !packet->format )
01462         {
01463                 free(rest);
01464                 return 0;
01465         }
01466         *packet->format = fapPOS_NMEA;
01467 
01468         /* Use a dot as a default symbol if one is not defined in the destination callsign. */
01469         if ( !fapint_parse_symbol_from_dst_callsign(packet) )
01470         {
01471           packet->symbol_table = '/';
01472           packet->symbol_code = '/';
01473         }
01474         
01475         /* Split to NMEA fields. */
01476         tmp_str = strtok(rest, ",");
01477         nmea_field_count = 0;
01478         while ( tmp_str != NULL )
01479         {
01480                 /* Create new element. */
01481                 if ( !nmea_field_list )
01482                 {
01483                         nmea_field_list = malloc(sizeof(fapint_llist_item_t));
01484                         if ( !nmea_field_list ) return 0;
01485                         current_elem = nmea_field_list;
01486                 }
01487                 else
01488                 {
01489                         current_elem->next = malloc(sizeof(fapint_llist_item_t));
01490                         if ( !current_elem->next )
01491                         {
01492                                 retval = 0;
01493                                 break;
01494                         }
01495                         current_elem = current_elem->next;
01496                 }
01497                 current_elem->next = NULL;
01498 
01499                 /* Save element. */
01500                 current_elem->text = malloc(strlen(tmp_str)+1);
01501                 if ( !current_elem->text )
01502                 {
01503                         retval = 0;
01504                         break;
01505                 }
01506                 strcpy(current_elem->text, tmp_str);
01507                 nmea_field_count++;
01508 
01509                 /* Try to get next. */
01510                 tmp_str = strtok(NULL, ",");
01511         }
01512         if ( !retval )
01513         {
01514                 fapint_clear_llist(nmea_field_list);
01515                 free(rest);
01516                 return 0;
01517         }
01518 
01519         /* Collect NMEA fields into an array. */
01520         do
01521         {
01522                 if ( !nmea_field_count )
01523                 {
01524                         packet->error_code = malloc(sizeof(fap_error_code_t));
01525                         if ( packet->error_code ) *packet->error_code = fapNMEA_NOFIELDS;
01526                         retval = 0;
01527                         break;
01528                 }
01529                 else
01530                 {
01531                         nmea_fields = calloc(nmea_field_count, sizeof(char*));
01532                         if ( !nmea_fields )
01533                         {
01534                                 retval = 0;
01535                                 break;
01536                         }
01537                         for ( i = 0; i < nmea_field_count; ++i ) nmea_fields[i] = NULL;
01538                         current_elem = nmea_field_list;
01539                         i = 0;
01540                         while ( current_elem != NULL )
01541                         {
01542                                 nmea_fields[i] = malloc(strlen(current_elem->text)+1);
01543                                 if ( !nmea_fields[i] )
01544                                 {
01545                                         retval = 0;
01546                                         break;
01547                                 }
01548                                 strcpy(nmea_fields[i], current_elem->text);
01549                                 current_elem = current_elem->next;
01550                                 i++;
01551                         }
01552                 }
01553         }
01554         while ( 0 );
01555         fapint_clear_llist(nmea_field_list);
01556         if ( !retval )
01557         {
01558                 free(nmea_fields);
01559                 free(rest);
01560                 return 0;
01561         }
01562         
01563         
01564         /* Now check the sentence type and get as much info as we can (want). */
01565         while ( retval )
01566         {
01567                 if ( strcmp(nmea_fields[0], "GPRMC") == 0 )
01568                 {
01569                         /* We want at least 10 fields. */
01570                         if ( nmea_field_count < 10 )
01571                         {
01572                                 packet->error_code = malloc(sizeof(fap_error_code_t));
01573                                 if ( packet->error_code ) *packet->error_code = fapGPRMC_FEWFIELDS;
01574                                 retval = 0;
01575                                 break;
01576                         }
01577                 
01578                         /* Check for fix. */
01579                         if ( strcmp(nmea_fields[2], "A" ) != 0 )
01580                         {
01581                                 packet->error_code = malloc(sizeof(fap_error_code_t));
01582                                 if ( packet->error_code ) *packet->error_code = fapGPRMC_NOFIX;
01583                                 retval = 0;
01584                                 break;
01585                         }
01586                         
01587                         /* Check and get timestamp. */
01588                         if ( regexec(&fapint_regex_nmea_time, nmea_fields[1], matchcount, (regmatch_t*)&matches, 0) == 0 )
01589                         {
01590                                 buf_3b[2] = 0;
01591                                 memcpy(buf_3b, nmea_fields[1]+matches[1].rm_so, 2);
01592                                 hours = atoi(buf_3b);
01593                                 memcpy(buf_3b, nmea_fields[1]+matches[2].rm_so, 2);
01594                                 mins = atoi(buf_3b);
01595                                 memcpy(buf_3b, nmea_fields[1]+matches[3].rm_so, 2);
01596                                 secs = atoi(buf_3b);
01597                                 
01598                                 if ( hours > 23 || mins > 59 || secs > 59 )
01599                                 {
01600                                         packet->error_code = malloc(sizeof(fap_error_code_t));
01601                                         if ( packet->error_code ) *packet->error_code = fapGPRMC_INV_TIME;
01602                                         retval = 0;
01603                                         break;
01604                                 }
01605                         }
01606                         else
01607                         {
01608                                 packet->error_code = malloc(sizeof(fap_error_code_t));
01609                                 if ( packet->error_code ) *packet->error_code = fapGPRMC_INV_TIME;
01610                                 retval = 0;
01611                                 break;
01612                         }
01613                         
01614                         /* Check and get date. */
01615                         if ( regexec(&fapint_regex_nmea_date, nmea_fields[9], matchcount, (regmatch_t*)&matches, 0) == 0 )
01616                         {
01617                                 buf_3b[2] = 0;
01618                                 memcpy(buf_3b, nmea_fields[9]+matches[1].rm_so, 2);
01619                                 day = atoi(buf_3b);
01620                                 memcpy(buf_3b, nmea_fields[9]+matches[2].rm_so, 2);
01621                                 month = atoi(buf_3b);
01622                                 memcpy(buf_3b, nmea_fields[9]+matches[3].rm_so, 2);
01623                                 year = atoi(buf_3b);
01624                                 
01625                                 /* Check the date for validity. Assume years 0-69 are 21st
01626                                         century and years 70-99 are 20th century. */
01627                                 if ( year < 70 )
01628                                 {
01629                                         year += 2000;
01630                                 }
01631                                 else
01632                                 {
01633                                         year += 1900;
01634                                 }
01635                                 if ( !fapint_check_date(year, month, day) )
01636                                 {
01637                                         packet->error_code = malloc(sizeof(fap_error_code_t));
01638                                         if ( packet->error_code ) *packet->error_code = fapGPRMC_INV_DATE;
01639                                         retval = 0;
01640                                         break;
01641                                 }
01642                         }
01643                         else
01644                         {
01645                                 packet->error_code = malloc(sizeof(fap_error_code_t));
01646                                 if ( packet->error_code ) *packet->error_code = fapGPRMC_INV_DATE;
01647                                 retval = 0;
01648                                 break;
01649                         }
01650                         
01651                         /* Save date and time. We can only handle 32-bit unix timestamps,
01652                                 so we need to check for non-representable years. */
01653                         if ( year >= 2038 || year < 1970 )
01654                         {
01655                                 packet->error_code = malloc(sizeof(fap_error_code_t));
01656                                 if ( packet->error_code ) *packet->error_code = fapGPRMC_DATE_OUT;
01657                                 retval = 0;
01658                                 break;
01659                         }
01660                         else
01661                         {
01662                                 timestamp.tm_sec = secs;
01663                                 timestamp.tm_min = mins;
01664                                 timestamp.tm_hour = hours;
01665                                 timestamp.tm_mday = day;
01666                                 timestamp.tm_mon = month-1;
01667                                 timestamp.tm_year = year-1900;
01668                                 timestamp.tm_isdst = 0;
01669                                 packet->timestamp = malloc(sizeof(time_t));
01670                                 if ( !packet->timestamp )
01671                                 {
01672                                         retval = 0;
01673                                         break;
01674                                 }
01675                                 *packet->timestamp = (time_t)mktime(&timestamp) - (time_t)timezone;
01676                         }
01677                         
01678                         /* Get speed, if available. */
01679                         if ( regexec(&fapint_regex_nmea_specou, nmea_fields[7], matchcount, (regmatch_t*)&matches, 0) == 0 )
01680                         {
01681                                 len = matches[1].rm_eo - matches[1].rm_so;
01682                                 tmp_str = malloc(len+1);
01683                                 if ( !tmp_str )
01684                                 {
01685                                         retval = 0;
01686                                         break;
01687                                 }
01688                                 memcpy(tmp_str, nmea_fields[7]+matches[1].rm_so, len);
01689                                 tmp_str[len] = 0;
01690                                 
01691                                 packet->speed = malloc(sizeof(double));
01692                                 if ( !packet->speed )
01693                                 {
01694                                         retval = 0;
01695                                         break;
01696                                 }
01697                                 *packet->speed = atof(tmp_str) * KNOT_TO_KMH;
01698                                 free(tmp_str); tmp_str = NULL;
01699                         }
01700                         
01701                         /* Get course, if available. */
01702                         if ( regexec(&fapint_regex_nmea_specou, nmea_fields[8], matchcount, (regmatch_t*)&matches, 0) == 0 )
01703                         {
01704                                 len = matches[1].rm_eo - matches[1].rm_so;
01705                                 tmp_str = malloc(len+1);
01706                                 if ( !tmp_str )
01707                                 {
01708                                         retval = 0;
01709                                         break;
01710                                 }
01711                                 memcpy(tmp_str, nmea_fields[8]+matches[1].rm_so, len);
01712                                 tmp_str[len] = 0;
01713                                 
01714                                 packet->course = malloc(sizeof(unsigned int));
01715                                 if ( !packet->course )
01716                                 {
01717                                         retval = 0;
01718                                         break;
01719                                 }
01720                                 *packet->course = atof(tmp_str) + 0.5;
01721                                 free(tmp_str); tmp_str = NULL;
01722                                 
01723                                 /* If zero, set to 360 because in APRS zero means invalid course... */
01724                                 if ( *packet->course == 0 )
01725                                 {
01726                                         *packet->course = 360;
01727                                 }
01728                                 else if ( *packet->course > 360 )
01729                                 {
01730                                         *packet->course = 0;
01731                                 }
01732                         }
01733                         
01734                         /* Get latitude and longitude. */
01735                         if ( !fapint_get_nmea_latlon(packet, nmea_fields[3], nmea_fields[4]) )
01736                         {
01737                                 retval = 0;
01738                                 break;
01739                         }
01740                         if ( !fapint_get_nmea_latlon(packet, nmea_fields[5], nmea_fields[6]) )
01741                         {
01742                                 retval = 0;
01743                                 break;
01744                         }
01745                         
01746                         /* We have everything we want, return. */
01747                         break;
01748                 }
01749                 else if ( strcmp(nmea_fields[0], "GPGGA") == 0 )
01750                 {
01751                         /* We want at least 11 fields. */
01752                         if ( nmea_field_count < 11 )
01753                         {
01754                                 packet->error_code = malloc(sizeof(fap_error_code_t));
01755                                 if ( packet->error_code ) *packet->error_code = fapGPGGA_FEWFIELDS;
01756                                 retval = 0;
01757                                 break;
01758                         }
01759                 
01760                         /* Check for fix. */
01761                         if ( regexec(&fapint_regex_nmea_fix, nmea_fields[6], matchcount, (regmatch_t*)&matches, 0) == 0 )
01762                         {
01763                                 len = matches[1].rm_eo - matches[1].rm_so;
01764                                 tmp_str = malloc(len+1);
01765                                 if ( tmp_str )
01766                                 {
01767                                         retval = 0;
01768                                         break;
01769                                 }
01770                                 memcpy(tmp_str, nmea_fields[8]+matches[1].rm_so, len);
01771                                 tmp_str[len] = 0;
01772                                 if ( atoi(tmp_str) < 1 )
01773                                 {
01774                                         free(tmp_str);
01775                                         packet->error_code = malloc(sizeof(fap_error_code_t));
01776                                         if ( packet->error_code ) *packet->error_code = fapGPGGA_NOFIX;
01777                                         retval = 0;
01778                                         break;
01779                                 }
01780                                 free(tmp_str); tmp_str = NULL;
01781                         }
01782                         else
01783                         {
01784                                 packet->error_code = malloc(sizeof(fap_error_code_t));
01785                                 if ( packet->error_code ) *packet->error_code = fapGPGGA_NOFIX;
01786                                 retval = 0;
01787                                 break;
01788                         }
01789                         
01790                         /* Use the APRS time parsing routines to check the time and convert
01791                                 it to timestamp. But before that, remove a possible decimal
01792                                 part. */
01793                         if ( strlen(nmea_fields[1]) < 6 )
01794                         {
01795                                 packet->error_code = malloc(sizeof(fap_error_code_t));
01796                                 if ( packet->error_code ) *packet->error_code = fapTIMESTAMP_INV_GPGGA;
01797                                 retval = 0;
01798                                 break;
01799                         }
01800                         tmp_str = malloc(8);
01801                         if ( !tmp_str )
01802                         {
01803                                 retval = 0;
01804                                 break;
01805                         }
01806                         memcpy(tmp_str, nmea_fields[1], 6);
01807                         tmp_str[6] = 'h';
01808                         tmp_str[7] = 0;
01809                         packet->timestamp = malloc(sizeof(time_t));
01810                         if ( !packet->timestamp )
01811                         {
01812                                 retval = 0;
01813                                 break;
01814                         }
01815                         *packet->timestamp = fapint_parse_timestamp(tmp_str);
01816                         free(tmp_str); tmp_str = NULL;
01817                         if ( *packet->timestamp == 0 )
01818                         {
01819                                 packet->error_code = malloc(sizeof(fap_error_code_t));
01820                                 if ( packet->error_code ) *packet->error_code = fapTIMESTAMP_INV_GPGGA;
01821                                 retval = 0;
01822                                 break;
01823                         }
01824                         
01825                         /* Latitude and longitude. */
01826                         if ( !fapint_get_nmea_latlon(packet, nmea_fields[2], nmea_fields[3]) )
01827                         {
01828                                 retval = 0;
01829                                 break;
01830                         }
01831                         if ( !fapint_get_nmea_latlon(packet, nmea_fields[4], nmea_fields[5]) )
01832                         {
01833                                 retval = 0;
01834                                 break;
01835                         }
01836                         
01837                         /* Altitude, only meters are accepted. */
01838                         if ( strcmp(nmea_fields[0], "M") == 0 &&
01839                                   regexec(&fapint_regex_nmea_altitude, nmea_fields[9], matchcount, (regmatch_t*)&matches, 0) == 0 )
01840                         {
01841                                 len = matches[1].rm_eo - matches[1].rm_so;
01842                                 tmp_str = malloc(len+1);
01843                                 if ( !tmp_str )
01844                                 {
01845                                         retval = 0;
01846                                         break;
01847                                 }
01848                                 memcpy(tmp_str, nmea_fields[8]+matches[1].rm_so, len);
01849                                 tmp_str[len] = 0;
01850                                 packet->altitude = malloc(sizeof(double));
01851                                 if ( !packet->altitude )
01852                                 {
01853                                         retval = 0;
01854                                         break;
01855                                 }
01856                                 *packet->altitude = atoi(tmp_str);
01857                                 free(tmp_str); tmp_str = NULL;
01858                         }
01859                         
01860                         /* Ok. */
01861                         break;
01862                 }
01863                 else if ( strcmp(nmea_fields[0], "GPGLL") == 0 )
01864                 {
01865                         /* We want at least 5 fields. */
01866                         if ( nmea_field_count < 5 )
01867                         {
01868                                 packet->error_code = malloc(sizeof(fap_error_code_t));
01869                                 if ( packet->error_code ) *packet->error_code = fapGPGLL_FEWFIELDS;
01870                                 retval = 0;
01871                                 break;
01872                         }
01873                         
01874                         /* Latitude and longitude. */
01875                         if ( !fapint_get_nmea_latlon(packet, nmea_fields[1], nmea_fields[2]) )
01876                         {
01877                                 retval = 0;
01878                                 break;
01879                         }
01880                         if ( !fapint_get_nmea_latlon(packet, nmea_fields[3], nmea_fields[4]) )
01881                         {
01882                                 retval = 0;
01883                                 break;
01884                         }
01885                         
01886                         /* Use the APRS time parsing routines to check the time and convert
01887                                 it to timestamp. But before that, remove a possible decimal
01888                                 part. */
01889                         if ( nmea_field_count >= 6 && strlen(nmea_fields[5]) >= 6 )
01890                         {
01891                                 tmp_str = malloc(8);
01892                                 if ( !tmp_str )
01893                                 {
01894                                         retval = 0;
01895                                         break;
01896                                 }
01897                                 memcpy(tmp_str, nmea_fields[5], 6);
01898                                 tmp_str[6] = 'h';
01899                                 tmp_str[7] = 0;
01900                                 packet->timestamp = malloc(sizeof(time_t));
01901                                 if ( !packet->timestamp )
01902                                 {
01903                                         retval = 0;
01904                                         break;
01905                                 }
01906                                 *packet->timestamp = fapint_parse_timestamp(tmp_str);
01907                                 free(tmp_str); tmp_str = NULL;
01908                                 if ( *packet->timestamp == 0 )
01909                                 {
01910                                         packet->error_code = malloc(sizeof(fap_error_code_t));
01911                                         if ( packet->error_code ) *packet->error_code = fapTIMESTAMP_INV_GPGLL;
01912                                         retval = 0;
01913                                         break;
01914                                 }
01915                         }
01916                         
01917                         /* Check if fix validity is available. */
01918                         if ( nmea_field_count >= 7 )
01919                         {
01920                                 if ( strcmp(nmea_fields[0], "GPGLL") == 0 )
01921                                 {
01922                                         packet->error_code = malloc(sizeof(fap_error_code_t));
01923                                         if ( packet->error_code ) *packet->error_code = fapGPGLL_NOFIX;
01924                                         retval = 0;
01925                                         break;
01926                                 }
01927                         }
01928                         
01929                         /* Ok. */
01930                         break;
01931                 }
01932                 else
01933                 {
01934                         packet->error_code = malloc(sizeof(fap_error_code_t));
01935                         if ( packet->error_code ) *packet->error_code = fapNMEA_UNSUPP;
01936                         retval = 0;
01937                 }
01938                 break;
01939         }
01940 
01941 
01942         for ( i = 0; i < nmea_field_count; ++i )
01943         {
01944                 free(nmea_fields[i]);
01945         }
01946         if ( tmp_str ) free(tmp_str);
01947         if ( nmea_fields ) free(nmea_fields);
01948         free(rest);
01949         return retval;
01950 }
01951 
01952 
01953 
01954 int fapint_parse_object(fap_packet_t* packet, char const* input, unsigned int const input_len)
01955 {
01956         int i;
01957 
01958         /* Validate object length. At least 31 non-null chars are needed. */
01959         if ( strlen(input) < 31 )
01960         {
01961                 packet->error_code = malloc(sizeof(fap_error_code_t));
01962                 if ( packet->error_code ) *packet->error_code = fapOBJ_SHORT;
01963                 return 0;
01964         }
01965         
01966         /* Validate and store object name. */
01967         for ( i = 1; i < 10; ++i )
01968         {
01969                 if ( input[i] < 0x20 || input[i] > 0x7e )
01970                 {
01971                         packet->error_code = malloc(sizeof(fap_error_code_t));
01972                         if ( packet->error_code ) *packet->error_code = fapOBJ_INV;
01973                         return 0;
01974                 }
01975         }
01976         packet->object_or_item_name = malloc(10);
01977         if ( !packet->object_or_item_name ) return 0;
01978         memcpy(packet->object_or_item_name, input+1, 9);
01979         packet->object_or_item_name[9] = 0;
01980         
01981         /* Validate and store object status. */
01982         if ( input[i] == '*' )
01983         {
01984                 packet->alive = malloc(sizeof(int));
01985                 if ( !packet->alive ) return 0;
01986                 *packet->alive = 1;
01987         }
01988         else if ( input[i] == '_' )
01989         {
01990                 packet->alive = malloc(sizeof(int));
01991                 if ( !packet->alive ) return 0;
01992                 *packet->alive = 0;
01993         }
01994         else
01995         {
01996                 packet->error_code = malloc(sizeof(fap_error_code_t));
01997                 if ( packet->error_code ) *packet->error_code = fapOBJ_INV;
01998                 return 0;
01999         }
02000         
02001         /* Validate and store timestamp. */
02002         packet->timestamp = malloc(sizeof(time_t));
02003         if ( !packet->timestamp ) return 0;
02004         *packet->timestamp = fapint_parse_timestamp(input+11);
02005         if ( *packet->timestamp == 0)
02006         {
02007                 packet->error_code = malloc(sizeof(fap_error_code_t));
02008                 if ( packet->error_code ) *packet->error_code = fapTIMESTAMP_INV_OBJ;
02009                 return 0;
02010         }
02011         
02012         /* Check location type. */
02013         i = 18;
02014         if ( input[i] == '/' || input[i] == '\\' ||
02015                   (input[i] >= 'A' && input[i] <= 'Z') ||
02016                   (input[i] >= 'a' && input[i] <= 'j')
02017                 )
02018         {
02019                 /* It's compressed. */
02020                 if ( !fapint_parse_compressed(packet, input+i) )
02021                 {
02022                         return 0;
02023                 }
02024                 i += 13;
02025         }
02026         else if ( isdigit(input[i]) )
02027         {
02028                 /* It's normal. */
02029                 if ( !fapint_parse_normal(packet, input+i) )
02030                 {
02031                         return 0;
02032                 }
02033                 i += 19;
02034         }
02035         else
02036         {
02037                 packet->error_code = malloc(sizeof(fap_error_code_t));
02038                 if ( packet->error_code ) *packet->error_code = fapOBJ_DEC_ERR;
02039                 return 0;
02040         }
02041                 
02042         /* 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..) */
02043         if ( packet->symbol_code != '_' )
02044         {
02045                 fapint_parse_comment(packet, (char*)input+i, input_len-i);
02046         }
02047         else
02048         {
02049                 fapint_parse_wx(packet, (char*)input+i, input_len-i);
02050         }
02051         
02052         return 1;
02053 }
02054 
02055 
02056 int fapint_parse_item(fap_packet_t* packet, char const* input, unsigned int const input_len)
02057 {
02058         int len, i;
02059 
02060         /* Check length. */
02061         if ( input_len < 18 )
02062         {
02063                 packet->error_code = malloc(sizeof(fap_error_code_t));
02064                 if ( packet->error_code ) *packet->error_code = fapITEM_SHORT;
02065                 return 0;
02066         }
02067         
02068         /* Validate item bytes up to location. */
02069         if ( input[0] != ')' )
02070         {
02071                 packet->error_code = malloc(sizeof(fap_error_code_t));
02072                 if ( packet->error_code ) *packet->error_code = fapITEM_INV;
02073                 return 0;
02074         }
02075         len = 0;
02076         for ( i = 1; i <= 9; ++i )
02077         {
02078                 if ( input[i] == 0x20 ||
02079                           (input[i] >= 0x22 && input[i] <= 0x5e) ||
02080                           (input[i] >= 0x60 && input[i] <= 0x7e) )
02081                 {
02082                         len = i;
02083                 }
02084                 else
02085                 {
02086                         break;
02087                 }
02088         }
02089         if ( input[i] == '!' )
02090         {
02091                 packet->alive = malloc(sizeof(int));
02092                 if ( !packet->alive ) return 0;
02093                 *packet->alive = 1;
02094         }
02095         else if ( input[i] == '_' )
02096         {
02097                 packet->alive = malloc(sizeof(int));
02098                 if ( !packet->alive ) return 0;
02099                 *packet->alive = 0;
02100         }
02101         else
02102         {
02103                 packet->error_code = malloc(sizeof(fap_error_code_t));
02104                 if ( packet->error_code ) *packet->error_code = fapITEM_INV;
02105                 return 0;
02106         }
02107         
02108         /* Save item name with null termination. */
02109         packet->object_or_item_name = malloc(len+1);
02110         if ( !packet->object_or_item_name ) return 0;
02111         memcpy(packet->object_or_item_name, input+1, len);
02112         packet->object_or_item_name[len] = 0;
02113         
02114         /* Check location type. */
02115         i = len + 2;
02116         if ( input[i] == '/' || input[i] == '\\' ||
02117                   (input[i] >= 'A' && input[i] <= 'Z') ||
02118                   (input[i] >= 'a' && input[i] <= 'j')
02119                 )
02120         {
02121                 /* It's compressed. */
02122                 if ( !fapint_parse_compressed(packet, input+i) )
02123                 {
02124                         return 0;
02125                 }
02126                 i += 13;
02127         }
02128         else if ( isdigit(input[i]) )
02129         {
02130                 /* It's normal. */
02131                 if ( !fapint_parse_normal(packet, input+i) )
02132                 {
02133                         return 0;
02134                 }
02135                 i += 19;
02136         }
02137         else
02138         {
02139                 packet->error_code = malloc(sizeof(fap_error_code_t));
02140                 if ( packet->error_code ) *packet->error_code = fapITEM_DEC_ERR;
02141                 return 0;
02142         }
02143                 
02144         /* 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..) */
02145         if ( packet->symbol_code != '_' )
02146         {
02147                 fapint_parse_comment(packet, (char*)input+i, input_len-i);
02148         }   
02149 
02150         return 1;
02151 }
02152 
02153 
02154 int fapint_parse_message(fap_packet_t* packet, char const* input, unsigned int const input_len)
02155 {
02156         int i, len;
02157         char* tmp;
02158         short skipping_spaces = 1;
02159                                         
02160         unsigned int const matchcount = 3;
02161         regmatch_t matches[matchcount];
02162 
02163 
02164         /* Check length. */
02165         if ( input_len < 12 )
02166         {
02167                 packet->error_code = malloc(sizeof(fap_error_code_t));
02168                 if ( packet->error_code ) *packet->error_code = fapMSG_INV;
02169                 return 0;
02170         }
02171         
02172         /* Validate and save destination. */
02173         if ( regexec(&fapint_regex_mes_dst, input, matchcount, (regmatch_t*)&matches, 0) == 0 )
02174         {
02175                 /* Get length and strip trailing spaces. */
02176                 len = matches[1].rm_eo - matches[1].rm_so;
02177                 for ( i = matches[1].rm_eo-1; i > 0; --i )
02178                 {
02179                         if ( input[i] == ' ' )
02180                         {
02181                                 --len;
02182                         }
02183                         else
02184                         {
02185                                 break;
02186                         }
02187                 }
02188 
02189                 /* Save with null-termination. */
02190                 packet->destination = malloc(len+1);
02191                 if ( !packet->destination ) return 0;
02192                 memcpy(packet->destination, input+matches[1].rm_so, len);
02193                 packet->destination[len] = 0;
02194         }
02195         else
02196         {
02197                 packet->error_code = malloc(sizeof(fap_error_code_t));
02198                 if ( packet->error_code ) *packet->error_code = fapMSG_INV;
02199                 return 0;
02200         }
02201         
02202         /* Find message length. */
02203         len = 0;
02204         for ( i = 11; i < input_len; ++i )
02205         {
02206                 if ( (input[i] >= 0x20 && input[i] <= 0x7e) || ((unsigned char)input[i] >= 0x80 && (unsigned char)input[i] <= 0xfe) )
02207                 {
02208                         len = i - 10;
02209                 }
02210                 else
02211                 {
02212                         break;
02213                 }
02214         }
02215         if ( len == 0 )
02216         {
02217                 packet->error_code = malloc(sizeof(fap_error_code_t));
02218                 if ( packet->error_code ) *packet->error_code = fapMSG_INV;
02219                 return 0;
02220         }
02221         
02222         /* Save message. */
02223         packet->message = malloc(len+1);
02224         if ( !packet->message ) return 0;
02225         memcpy(packet->message, input+11, len);
02226         packet->message[len] = 0;
02227         
02228         /* Check if message is an ack, save id if it is. */
02229         if ( regexec(&fapint_regex_mes_ack, packet->message, matchcount, (regmatch_t*)&matches, 0) == 0 )
02230         {
02231                 len = matches[1].rm_eo - matches[1].rm_so;
02232                 packet->message_ack = malloc(len+1);
02233                 if ( !packet->message_ack ) return 0;
02234                 memcpy(packet->message_ack, packet->message+matches[1].rm_so, len);
02235                 packet->message_ack[len] = 0;
02236         }
02237 
02238         /* Check if message is a nack, save id if it is. */
02239         if ( regexec(&fapint_regex_mes_nack, packet->message, matchcount, (regmatch_t*)&matches, 0) == 0 )
02240         {
02241                 len = matches[1].rm_eo - matches[1].rm_so;
02242                 packet->message_nack = malloc(len+1);
02243                 if ( !packet->message_nack ) return 0;
02244                 memcpy(packet->message_nack, packet->message+matches[1].rm_so, len);
02245                 packet->message_nack[len] = 0;
02246         }
02247         
02248         /* Separate message-id from the body, if present. */
02249         len = 0;
02250         for ( i = strlen(packet->message)-1; i >= 0 ; i-- )
02251         {
02252                 if ( skipping_spaces && !isspace(packet->message[i]) )
02253                 {
02254                         /* Last non-space char of the id. */
02255                         skipping_spaces = 0;
02256                 }
02257                 else if ( skipping_spaces )
02258                 {
02259                         continue;
02260                 }
02261                 
02262                 /* New char of id. First check that it can be part of id. */
02263                 if ( !(isalnum(packet->message[i]) || packet->message[i] == '{') )
02264                 {
02265                         break;
02266                 }
02267                 
02268                 /* Check that we're not too long yet. */
02269                 len++;
02270                 if ( len > 6 )
02271                 {
02272                         break;
02273                 }
02274                 
02275                 /* Check if id starts here. */
02276                 if ( packet->message[i] == '{' )
02277                 {
02278                         /* Create copy of message without the id. */
02279                         tmp = packet->message;
02280                         packet->message = malloc(i+1);
02281                         if ( !packet->message )
02282                         {
02283                                 free(tmp);
02284                                 return 0;
02285                         }
02286                         memcpy(packet->message, tmp, i);
02287                         packet->message[i] = 0;
02288                 
02289                         /* Save message id. */
02290                         packet->message_id = malloc(len+1);
02291                         if ( !packet->message_id )
02292                         {
02293                                 free(tmp);
02294                                 return 0;
02295                         }
02296                         memcpy(packet->message_id, tmp+i+1, len);
02297                         packet->message_id[len] = 0;
02298                         
02299                         /* Get rid of the old message. */
02300                         free(tmp);
02301 
02302                         break;
02303                 }
02304         }
02305         
02306         /* Catch telemetry messages. */
02307         if ( strcmp(packet->src_callsign, packet->destination) == 0 &&
02308                   ( strstr(packet->message, "BITS.") != NULL ||
02309                          strstr(packet->message, "PARM.") != NULL ||
02310                          strstr(packet->message, "UNIT.") != NULL ||
02311                          strstr(packet->message, "EQNS.") != NULL
02312                   )
02313                 )
02314         {
02315                 if ( packet->type == NULL )
02316                 {
02317                         packet->type = malloc(sizeof(fap_packet_type_t));
02318                         if ( !packet->type ) return 0;
02319                 }
02320                 *packet->type = fapTELEMETRY_MESSAGE;
02321         }
02322         
02323         return 1;
02324 }
02325 
02326 int fapint_parse_capabilities(fap_packet_t* packet, char const* input, unsigned int const input_len)
02327 {
02328         fapint_llist_item_t* caps = NULL;
02329         int cap_count = 0;
02330         fapint_llist_item_t* current_elem = NULL;
02331 
02332         char* tmp_str, *sepa;
02333         int cap_len, cap_startpos, i, retval = 1;
02334         unsigned int foo, saved, sepa_pos;
02335 
02336         /* Find capabilities. */
02337         cap_startpos = 0;
02338         for ( i = 0; i < input_len; ++i )
02339         {
02340                 tmp_str = NULL;
02341                 
02342                 /* Look for element boundary. */
02343                 if ( input[i] == ',' )
02344                 {
02345                         /* Found a bound, let's create a copy of the capability it ends. */
02346                         cap_len = i - cap_startpos;
02347                         tmp_str = malloc(cap_len+1);
02348                         if ( !tmp_str )
02349                         {
02350                                 retval = 0;
02351                                 break;
02352                         }
02353                         memcpy(tmp_str, input+cap_startpos, cap_len);
02354                         tmp_str[cap_len] = 0;
02355                         
02356                         /* Start to look for next element. */
02357                         cap_startpos = i + 1;
02358                 }
02359                 else if ( i+1 == input_len )
02360                 {
02361                         /* We're at the end, save the last element. */
02362                         cap_len = i+1 - cap_startpos;
02363                         tmp_str = malloc(cap_len+1);
02364                         if ( !tmp_str )
02365                         {
02366                                 retval = 0;
02367                                 break;
02368                         }
02369                         memcpy(tmp_str, input+cap_startpos, cap_len);
02370                         tmp_str[cap_len] = 0;
02371                 }
02372                 
02373                 /* Check if we found something. */
02374                 if ( tmp_str )
02375                 {
02376                         /* Create list item. */
02377                         if ( caps == NULL )
02378                         {
02379                                 caps = malloc(sizeof(fapint_llist_item_t));
02380                                 if ( !caps )
02381                                 {
02382                                         retval = 0;
02383                                         break;
02384                                 }
02385                                 current_elem = caps;
02386                         }
02387                         else
02388                         {
02389                                 current_elem->next = malloc(sizeof(fapint_llist_item_t));
02390                                 if ( !current_elem->next )
02391                                 {
02392                                         retval = 0;
02393                                         break;
02394                                 }
02395                                 current_elem = current_elem->next;
02396                         }
02397                         current_elem->next = NULL;
02398                         current_elem->text = tmp_str;
02399                         
02400                         ++cap_count;
02401                 }
02402         }
02403         if ( !retval )
02404         {
02405                 fapint_clear_llist(caps);
02406                 return 0;
02407         }
02408         
02409         /* At least one capability is needed for the packet to be valid. */
02410         if ( cap_count == 0 )
02411         {
02412                 return 0;
02413         }
02414         
02415         /* Save capabilites. */
02416         packet->capabilities = calloc(cap_count*2, sizeof(char*));
02417         if ( !packet->capabilities )
02418         {
02419                 fapint_clear_llist(caps);
02420                 return 0;
02421         }
02422         for ( i = 0; i < cap_count; ++i ) packet->capabilities[i] = NULL;
02423         packet->capabilities_len = cap_count;
02424         i = 0;
02425         current_elem = caps;
02426         while ( current_elem != NULL )
02427         {
02428                 saved = 0;
02429                 /* Find value splitpos. */
02430                 if ( (sepa = strchr(current_elem->text, '=')) != NULL )
02431                 {
02432                         sepa_pos = sepa - current_elem->text - 1;
02433                         /* Check that splitpos is not first or last char. */
02434                         if ( sepa_pos < input_len )
02435                         {
02436                                 packet->capabilities[i] = fapint_remove_part(current_elem->text, strlen(current_elem->text), sepa_pos, strlen(current_elem->text), &foo);
02437                                 packet->capabilities[i+1] = fapint_remove_part(current_elem->text, strlen(current_elem->text), 0, sepa_pos+2, &foo);
02438                                 saved = 1;
02439                         }
02440                 }
02441                 
02442                 /* If the cap was not yet saved, save it without value. */
02443                 if ( !saved )
02444                 {
02445                         packet->capabilities[i] = malloc(strlen(current_elem->text)+1);
02446                         if ( !packet->capabilities[i] )
02447                         {
02448                                 retval = 0;
02449                                 break;
02450                         }
02451                         strcpy(packet->capabilities[i], current_elem->text);
02452                         packet->capabilities[i+1] = NULL;
02453                 }
02454                 
02455                 /* Get next element. */
02456                 current_elem = current_elem->next;
02457                 i += 2;
02458         }
02459         fapint_clear_llist(caps);
02460         
02461         return retval;
02462 }
02463 
02464 
02465 
02466 int fapint_parse_status(fap_packet_t* packet, char const* input, unsigned int const input_len)
02467 {
02468         short has_timestamp = 0;
02469         int i;
02470 
02471         /* Check for timestamp. */
02472         if ( input_len > 6 )
02473         {
02474                 has_timestamp = 1;
02475                 for ( i = 0; i < 6; ++i )
02476                 {
02477                         if ( !isdigit(input[i]) )
02478                         {
02479                                 has_timestamp = 0;
02480                                 break;
02481                         }
02482                 }
02483                 if ( input[6] != 'z' )
02484                 {
02485                         has_timestamp = 0;
02486                 }
02487         }
02488         
02489         /* Save rest as status. */
02490         if ( has_timestamp )
02491         {
02492                 packet->timestamp = malloc(sizeof(time_t));
02493                 if ( !packet->timestamp ) return 0;
02494                 *packet->timestamp = fapint_parse_timestamp(input);
02495                 if ( *packet->timestamp == 0 )
02496                 {
02497                         packet->error_code = malloc(sizeof(fap_error_code_t));
02498                         if ( packet->error_code ) *packet->error_code = fapTIMESTAMP_INV_STA;
02499                         return 0;
02500                 }
02501                 packet->status = fapint_remove_part(input, input_len, 0, 7, &packet->status_len);
02502         }
02503         else
02504         {
02505                 packet->status = malloc(input_len);
02506                 if ( !packet->status ) return 0;
02507                 memcpy(packet->status, input, input_len);
02508                 packet->status_len = input_len;
02509         }
02510         
02511         return 1;
02512 }
02513 
02514 
02515 
02516 int fapint_parse_wx(fap_packet_t* packet, char const* input, unsigned int const input_len)
02517 {
02518         char wind_dir[4], wind_speed[4], *wind_gust = NULL, *temp = NULL;
02519         char buf_5b[6];
02520         int len, retval = 1;
02521         char* rest = NULL, *tmp_str;
02522         unsigned int rest_len, tmp_us;
02523         
02524         unsigned int const matchcount = 5;
02525         regmatch_t matches[matchcount];
02526         
02527         /* Check that we have something to look at. */
02528         if ( !packet || !input || !input_len )
02529         {
02530                 return 0;
02531         }
02532         
02533         /* Initialize result vars. */
02534         memset(wind_dir, 0, 4);
02535         memset(wind_speed, 0, 4);
02536         
02537         /* Look for wind and temperature. Remaining bytes are copied to report var. */
02538         if ( regexec(&fapint_regex_wx1, input, matchcount, (regmatch_t*)&matches, 0) == 0 )
02539         {
02540                 memcpy(wind_dir, input+matches[1].rm_so, 3);
02541                 wind_dir[3] = 0;
02542 
02543                 memcpy(wind_speed, input+matches[2].rm_so, 3);
02544                 wind_speed[3] = 0;
02545 
02546                 len = matches[3].rm_eo - matches[3].rm_so;
02547                 wind_gust = malloc(len+1);
02548                 if ( !wind_gust ) return 0;
02549                 memcpy(wind_gust, input+matches[3].rm_so, len);
02550                 wind_gust[len] = 0;
02551 
02552                 len = matches[4].rm_eo - matches[4].rm_so;
02553                 temp = malloc(len+1);
02554                 if ( !temp )
02555                 {
02556                         free(wind_gust);
02557                         return 0;
02558                 }
02559                 memcpy(temp, input+matches[4].rm_so, len);
02560                 temp[len] = 0;
02561 
02562                 rest = fapint_remove_part(input, input_len, 0, matches[4].rm_eo, &rest_len);
02563         }
02564         else if ( regexec(&fapint_regex_wx2, input, 5, matches, 0) == 0 )
02565         {
02566                 memcpy(wind_dir, input+matches[1].rm_so, 3);
02567                 wind_dir[3] = 0;
02568 
02569                 memcpy(wind_speed, input+matches[2].rm_so, 3);
02570                 wind_speed[3] = 0;
02571 
02572                 len = matches[3].rm_eo - matches[3].rm_so;
02573                 wind_gust = malloc(len+1);
02574                 if ( !wind_gust ) return 0;
02575                 memcpy(wind_gust, input+matches[3].rm_so, len);
02576                 wind_gust[len] = 0;
02577 
02578                 len = matches[4].rm_eo - matches[4].rm_so;
02579                 temp = malloc(len+1);
02580                 if ( !temp )
02581                 {
02582                         free(wind_gust);
02583                         return 0;
02584                 }
02585                 memcpy(temp, input+matches[4].rm_so, len);
02586                 temp[len] = 0;
02587 
02588                 rest = fapint_remove_part(input, input_len, 0, matches[4].rm_eo, &rest_len);
02589         }
02590         else if ( regexec(&fapint_regex_wx3, input, 4, matches, 0) == 0 )
02591         {
02592                 memcpy(wind_dir, input+matches[1].rm_so, 3);
02593                 wind_dir[3] = 0;
02594 
02595                 memcpy(wind_speed, input+matches[2].rm_so, 3);
02596                 wind_speed[3] = 0;
02597 
02598                 len = matches[3].rm_eo - matches[3].rm_so;
02599                 wind_gust = malloc(len+1);
02600                 if ( !wind_gust ) return 0;
02601                 memcpy(wind_gust, input+matches[3].rm_so, len);
02602                 wind_gust[len] = 0;
02603 
02604                 rest = fapint_remove_part(input, input_len, 0, matches[3].rm_eo, &rest_len);
02605         }
02606         else if ( regexec(&fapint_regex_wx4, input, 4, matches, 0) == 0 )
02607         {
02608                 memcpy(wind_dir, input+matches[1].rm_so, 3);
02609                 wind_dir[3] = 0;
02610 
02611                 memcpy(wind_speed, input+matches[2].rm_so, 3);
02612                 wind_speed[3] = 0;
02613 
02614                 len = matches[3].rm_eo - matches[3].rm_so;
02615                 wind_gust = malloc(len+1);
02616                 if ( !wind_gust ) return 0;
02617                 memcpy(wind_gust, input+matches[3].rm_so, len);
02618                 wind_gust[len] = 0;
02619 
02620                 rest = fapint_remove_part(input, input_len, 0, matches[3].rm_eo, &rest_len);
02621         }
02622         else if ( regexec(&fapint_regex_wx5, input, 3, matches, 0) == 0 )
02623         {
02624                 len = matches[1].rm_eo - matches[1].rm_so;
02625                 wind_gust = malloc(len+1);
02626                 if ( !wind_gust ) return 0;
02627                 memcpy(wind_gust, input+matches[1].rm_so, len);
02628                 wind_gust[len] = 0;
02629                 
02630                 len = matches[2].rm_eo - matches[2].rm_so;
02631                 temp = malloc(len+1);
02632                 if ( !temp )
02633                 {
02634                         free(wind_gust);
02635                         return 0;
02636                 }
02637                 memcpy(temp, input+matches[2].rm_so, len);
02638                 temp[len] = 0;
02639                 
02640                 rest = fapint_remove_part(input, input_len, 0, matches[2].rm_eo, &rest_len);
02641         }
02642         else
02643         {
02644                 return 0;
02645         }
02646         
02647         if ( temp == NULL && rest_len > 0 && regexec(&fapint_regex_wx5, rest, matchcount, (regmatch_t*)&matches, 0) == 0 )
02648         {
02649                 len = matches[1].rm_eo - matches[1].rm_so;
02650                 temp = malloc(len+1);
02651                 if ( !temp )
02652                 {
02653                         if ( wind_gust ) free(wind_gust);
02654                         free(rest);
02655                         return 0;
02656                 }
02657                 memcpy(temp, rest+matches[1].rm_so, len);
02658                 temp[len] = 0;
02659 
02660                 tmp_str = fapint_remove_part(rest, rest_len, matches[1].rm_so-1, matches[1].rm_eo, &tmp_us);
02661                 free(rest);
02662                 rest = tmp_str;
02663                 rest_len = tmp_us;
02664         }
02665         
02666         /* Prepare to get results. */
02667         packet->wx_report = malloc(sizeof(fap_wx_report_t));
02668         if ( !packet->wx_report )
02669         {
02670                 if ( wind_gust ) free(wind_gust);
02671                 if ( temp ) free(temp);
02672                 if ( rest ) free(rest);
02673                 return 0;
02674         }
02675         fapint_init_wx_report(packet->wx_report);
02676 
02677         /* Save values. */
02678         do
02679         {
02680                 if ( fapint_is_number(wind_gust) )
02681                 {
02682                         packet->wx_report->wind_gust = malloc(sizeof(double));
02683                         if ( !packet->wx_report->wind_gust )
02684                         {
02685                                 retval = 0;
02686                                 break;
02687                         }
02688                         *packet->wx_report->wind_gust = atof(wind_gust) * MPH_TO_MS;
02689                 }
02690                 if ( fapint_is_number(wind_dir) )
02691                 {
02692                         packet->wx_report->wind_dir = malloc(sizeof(int));
02693                         if ( !packet->wx_report->wind_dir )
02694                         {
02695                                 retval = 0;
02696                                 break;
02697                         }
02698                         *packet->wx_report->wind_dir = atoi(wind_dir);
02699                 }
02700                 if ( fapint_is_number(wind_speed) )
02701                 {
02702                         packet->wx_report->wind_speed = malloc(sizeof(double));
02703                         if ( !packet->wx_report->wind_speed )
02704                         {
02705                                 retval = 0;
02706                                 break;
02707                         }
02708                         *packet->wx_report->wind_speed = atof(wind_speed) * MPH_TO_MS;
02709                 }
02710                 if ( fapint_is_number(temp) )
02711                 {
02712                         packet->wx_report->temp = malloc(sizeof(double));
02713                         if ( !packet->wx_report->temp )
02714                         {
02715                                 retval = 0;
02716                                 break;
02717                         }
02718                         *packet->wx_report->temp = FAHRENHEIT_TO_CELCIUS(atof(temp));
02719                 }
02720         } while ( 0 );
02721         if ( wind_gust )
02722         {
02723                 free(wind_gust);
02724                 wind_gust = NULL;
02725         }
02726         if ( temp )
02727         {
02728                 free(temp);
02729                 temp = NULL;
02730         }
02731         if ( !retval )
02732         {
02733                 free(rest);
02734                 return 0;
02735         }
02736         
02737         /* Then some rain values. */
02738         do
02739         {
02740                 if ( rest_len > 0 && regexec(&fapint_regex_wx_r1, rest, matchcount, (regmatch_t*)&matches, 0) == 0 )
02741                 {
02742                         len = matches[1].rm_eo - matches[1].rm_so;
02743                         memset(buf_5b, 0, 6);
02744                         memcpy(buf_5b, rest+matches[1].rm_so, len);
02745                         packet->wx_report->rain_1h = malloc(sizeof(double));
02746                         if ( !packet->wx_report->rain_1h )
02747                         {
02748                                 retval = 0;
02749                                 break;
02750                         }
02751                         *packet->wx_report->rain_1h = atof(buf_5b) * HINCH_TO_MM;
02752 
02753                         tmp_str = fapint_remove_part(rest, rest_len, matches[1].rm_so-1, matches[1].rm_eo, &tmp_us);
02754                         free(rest);
02755                         rest = tmp_str;
02756                         rest_len = tmp_us;
02757                 }
02758                 if ( rest_len > 0 && regexec(&fapint_regex_wx_r24, rest, 2, matches, 0) == 0 )
02759                 {
02760                         len = matches[1].rm_eo - matches[1].rm_so;
02761                         memset(buf_5b, 0, 4);
02762                         memcpy(buf_5b, rest+matches[1].rm_so, len);
02763                         packet->wx_report->rain_24h = malloc(sizeof(double));
02764                         if ( !packet->wx_report->rain_24h )
02765                         {
02766                                 retval = 0;
02767                                 break;
02768                         }
02769                         *packet->wx_report->rain_24h = atof(buf_5b) * HINCH_TO_MM;
02770                 
02771                         tmp_str = fapint_remove_part(rest, rest_len, matches[1].rm_so-1, matches[1].rm_eo, &tmp_us);
02772                         free(rest);
02773                         rest = tmp_str;
02774                         rest_len = tmp_us;
02775                 }
02776                 if ( rest_len > 0 && regexec(&fapint_regex_wx_rami, rest, 2, matches, 0) == 0 )
02777                 {
02778                         len = matches[1].rm_eo - matches[1].rm_so;
02779                         memset(buf_5b, 0, 4);
02780                         memcpy(buf_5b, rest+matches[1].rm_so, len);
02781                         packet->wx_report->rain_midnight = malloc(sizeof(double));
02782                         if ( !packet->wx_report->rain_midnight )
02783                         {
02784                                 retval = 0;
02785                                 break;
02786                         }
02787                         *packet->wx_report->rain_midnight = atof(buf_5b) * HINCH_TO_MM;
02788 
02789                         tmp_str = fapint_remove_part(rest, rest_len, matches[1].rm_so-1, matches[1].rm_eo, &tmp_us);
02790                         free(rest);
02791                         rest = tmp_str;
02792                         rest_len = tmp_us;
02793                 }
02794         } while ( 0 );
02795         if ( !retval )
02796         {
02797                 free(rest);
02798                 return 0;
02799         }
02800         
02801         /* Humidity. */
02802         if ( rest_len > 0 && regexec(&fapint_regex_wx_humi, rest, 2, matches, 0) == 0 )
02803         {
02804                 len = matches[1].rm_eo - matches[1].rm_so;
02805                 memset(buf_5b, 0, 6);
02806                 memcpy(buf_5b, rest+matches[1].rm_so, len);
02807                 if ( (tmp_us = atoi(buf_5b)) <= 100 )
02808                 {
02809                         packet->wx_report->humidity = malloc(sizeof(unsigned int));
02810                         if ( !packet->wx_report->humidity )
02811                         {
02812                                 free(rest);
02813                                 return 0;
02814                         }
02815                         if ( tmp_us == 0 ) tmp_us = 100;
02816                         *packet->wx_report->humidity = tmp_us;
02817                 }
02818                 
02819                 tmp_str = fapint_remove_part(rest, rest_len, matches[1].rm_so-1, matches[1].rm_eo, &tmp_us);
02820                 free(rest);
02821                 rest = tmp_str;
02822                 rest_len = tmp_us;
02823         }
02824         
02825         /* Pressure. */
02826         if ( rest_len > 0 && regexec(&fapint_regex_wx_pres, rest, 2, matches, 0) == 0 )
02827         {
02828                 len = matches[1].rm_eo - matches[1].rm_so;
02829                 memset(buf_5b, 0, 6);
02830                 memcpy(buf_5b, rest+matches[1].rm_so, len);
02831                 packet->wx_report->pressure = malloc(sizeof(double));
02832                 if ( !packet->wx_report->pressure )
02833                 {
02834                         free(rest);
02835                         return 0;
02836                 }
02837                 *packet->wx_report->pressure = atoi(buf_5b)/10.0; // tenths of mbars to mbars
02838                 
02839                 tmp_str = fapint_remove_part(rest, rest_len, matches[1].rm_so-1, matches[1].rm_eo, &tmp_us);
02840                 free(rest);
02841                 rest = tmp_str;
02842                 rest_len = tmp_us;
02843         }
02844         
02845         /* Luminosity. */
02846         if ( rest_len > 0 && regexec(&fapint_regex_wx_lumi, rest, 3, matches, 0) == 0 )
02847         {
02848                 len = matches[2].rm_eo - matches[2].rm_so;
02849                 memset(buf_5b, 0, 6);
02850                 memcpy(buf_5b, rest+matches[2].rm_so, len);
02851                 packet->wx_report->luminosity = malloc(sizeof(unsigned int));
02852                 if ( !packet->wx_report->luminosity )
02853                 {
02854                         free(rest);
02855                         return 0;
02856                 }
02857                 *packet->wx_report->luminosity = atoi(buf_5b);
02858                 if ( input[matches[1].rm_so] == 'l' )
02859                 {
02860                         *packet->wx_report->luminosity += 1000;
02861                 }
02862                 
02863                 tmp_str = fapint_remove_part(rest, rest_len, matches[1].rm_so, matches[2].rm_eo, &tmp_us);
02864                 free(rest);
02865                 rest = tmp_str;
02866                 rest_len = tmp_us;
02867         }
02868         
02869         /* What? */
02870         if ( rest_len > 0 && regexec(&fapint_regex_wx_what, rest, 2, matches, 0) == 0 )
02871         {
02872                 tmp_str = fapint_remove_part(rest, rest_len, matches[1].rm_so-1, matches[1].rm_eo, &tmp_us);
02873                 free(rest);
02874                 rest = tmp_str;
02875                 rest_len = tmp_us;
02876         }
02877         
02878         /* Snowfall. */
02879         if ( rest_len > 0 && regexec(&fapint_regex_wx_snow, rest, 2, matches, 0) == 0 )
02880         {
02881                 len = matches[1].rm_eo - matches[1].rm_so;
02882                 if ( len > 5 ) len = 5;
02883                 memset(buf_5b, 0, 6);
02884                 memcpy(buf_5b, rest+matches[1].rm_so, len);
02885                 packet->wx_report->snow_24h = malloc(sizeof(double));
02886                 if ( !packet->wx_report->snow_24h )
02887                 {
02888                         free(rest);
02889                         return 0;
02890                 }
02891                 *packet->wx_report->snow_24h = atof(buf_5b) * HINCH_TO_MM;
02892                 
02893                 tmp_str = fapint_remove_part(rest, rest_len, matches[1].rm_so-1, matches[1].rm_eo, &tmp_us);
02894                 free(rest);
02895                 rest = tmp_str;
02896                 rest_len = tmp_us;
02897         }
02898         
02899         /* Raw rain counter. */
02900         if ( rest_len > 0 && regexec(&fapint_regex_wx_rrc, rest, 2, matches, 0) == 0 )
02901         {
02902                 tmp_str = fapint_remove_part(rest, rest_len, matches[1].rm_so-1, matches[1].rm_eo, &tmp_us);
02903                 free(rest);
02904                 rest = tmp_str;
02905                 rest_len = tmp_us;
02906         }
02907         
02908         /* Remove any remaining known report parts. */
02909         if ( rest_len > 0 && regexec(&fapint_regex_wx_any, rest, 2, matches, 0) == 0 )
02910         {
02911                 tmp_str = fapint_remove_part(rest, rest_len, matches[1].rm_so, matches[1].rm_eo, &tmp_us);
02912                 free(rest);
02913                 rest = tmp_str;
02914                 rest_len = tmp_us;
02915         }
02916         
02917         /* If there's still something left, we can't know what it is. We do some guesswork nevertheless. */
02918         
02919         /* Check if it could be wx software id. */
02920         if ( rest_len > 0 && regexec(&fapint_regex_wx_soft, rest, 0, NULL, 0) == 0 )
02921         {
02922                 packet->wx_report->soft = rest;
02923         }
02924         /* If not, it is propaby a comment. */
02925         else if ( rest_len > 0 && packet->comment == NULL )
02926         {
02927                 packet->comment = rest;
02928                 packet->comment_len = rest_len;
02929         }
02930         else
02931         {
02932                 free(rest);
02933         }
02934 
02935         return 1;
02936 }
02937 
02938 
02939 
02940 int fapint_parse_telemetry(fap_packet_t* packet, char const* input)
02941 {
02942         unsigned int matchcount = 13;
02943         regmatch_t matches[matchcount];
02944         
02945         char* tmp_str;
02946         int len1, len2;
02947         
02948         /* Check params. */
02949         if ( !packet || !input )
02950         {
02951                 return 0;
02952         }
02953         
02954         if ( regexec(&fapint_regex_telemetry, input, matchcount, (regmatch_t*)&matches, 0) == 0 )
02955         {
02956                 /* Initialize results. */
02957                 packet->telemetry = malloc(sizeof(fap_telemetry_t));
02958                 if ( !packet->telemetry ) return 0;
02959                 fapint_init_telemetry_report(packet->telemetry);
02960                 
02961                 /* seq */
02962                 len1 = matches[1].rm_eo - matches[1].rm_so;
02963                 tmp_str = malloc(len1+1);
02964                 if ( !tmp_str ) return 0;
02965                 memcpy(tmp_str, input+matches[1].rm_so, len1);
02966                 tmp_str[len1] = 0;
02967                 packet->telemetry->seq = atoi(tmp_str);
02968                 free(tmp_str);
02969                 
02970                 /* val1 */
02971                 len1 = matches[2].rm_eo - matches[2].rm_so;
02972                 len2 = matches[3].rm_eo - matches[3].rm_so;
02973                 tmp_str = malloc(len1+len2+1);
02974                 if ( !tmp_str ) return 0;
02975                 memcpy(tmp_str, input+matches[2].rm_so, len1);
02976                 memcpy(tmp_str+len1, input+matches[3].rm_so, len2);
02977                 tmp_str[len1+len2] = 0;
02978                 packet->telemetry->val1 = atof(tmp_str);
02979                 free(tmp_str);
02980 
02981                 /* val2 */
02982                 len1 = matches[4].rm_eo - matches[4].rm_so;
02983                 len2 = matches[5].rm_eo - matches[5].rm_so;
02984                 tmp_str = malloc(len1+len2+1);
02985                 if ( !tmp_str ) return 0;
02986                 memcpy(tmp_str, input+matches[4].rm_so, len1);
02987                 memcpy(tmp_str+len1, input+matches[5].rm_so, len2);
02988                 tmp_str[len1+len2] = 0;
02989                 packet->telemetry->val2 = atof(tmp_str);
02990                 free(tmp_str);
02991                 
02992                 /* val3 */
02993                 len1 = matches[6].rm_eo - matches[6].rm_so;
02994                 len2 = matches[7].rm_eo - matches[7].rm_so;
02995                 tmp_str = malloc(len1+len2+1);
02996                 if ( !tmp_str ) return 0;
02997                 memcpy(tmp_str, input+matches[6].rm_so, len1);
02998                 memcpy(tmp_str+len1, input+matches[7].rm_so, len2);
02999                 tmp_str[len1+len2] = 0;
03000                 packet->telemetry->val3 = atof(tmp_str);
03001                 free(tmp_str);
03002 
03003                 /* val4 */
03004                 len1 = matches[8].rm_eo - matches[8].rm_so;
03005                 len2 = matches[9].rm_eo - matches[9].rm_so;
03006                 tmp_str = malloc(len1+len2+1);
03007                 if ( !tmp_str ) return 0;
03008                 memcpy(tmp_str, input+matches[8].rm_so, len1);
03009                 memcpy(tmp_str+len1, input+matches[9].rm_so, len2);
03010                 tmp_str[len1+len2] = 0;
03011                 packet->telemetry->val4 = atof(tmp_str);
03012                 free(tmp_str);
03013 
03014                 /* val5 */
03015                 len1 = matches[10].rm_eo - matches[10].rm_so;
03016                 len2 = matches[11].rm_eo - matches[11].rm_so;
03017                 tmp_str = malloc(len1+len2+1);
03018                 if ( !tmp_str ) return 0;
03019                 memcpy(tmp_str, input+matches[10].rm_so, len1);
03020                 memcpy(tmp_str+len1, input+matches[11].rm_so, len2);
03021                 tmp_str[len1+len2] = 0;
03022                 packet->telemetry->val5 = atof(tmp_str);
03023                 free(tmp_str);
03024 
03025                 /* bits */
03026                 len1 = matches[12].rm_eo - matches[12].rm_so;
03027                 memcpy(packet->telemetry->bits, input+matches[12].rm_so, len1);
03028         }
03029         else
03030         {
03031                 packet->error_code = malloc(sizeof(fap_error_code_t));
03032                 if ( packet->error_code ) *packet->error_code = fapTLM_INV;
03033                 return 0;
03034         }
03035         
03036         return 1;
03037 }
03038 
03039 
03040 
03041 int fapint_parse_wx_peet_logging(fap_packet_t* packet, char const* input)
03042 {
03043         fapint_llist_item_t* parts, *current_elem;
03044         unsigned int part_count;
03045 
03046         int i, retval = 1;
03047 
03048         unsigned int matchcount = 2;
03049         regmatch_t matches[matchcount];
03050         
03051         
03052         /* Split report into parts. */
03053         parts = NULL;
03054         current_elem = NULL;
03055         part_count = 0;
03056         i = 0;
03057         while ( regexec(&fapint_regex_peet_splitter, input+i, matchcount, matches, 0) == 0 )
03058         {
03059                 if ( !parts )
03060                 {
03061                         parts = malloc(sizeof(fapint_llist_item_t));
03062                         if ( !parts )
03063                         {
03064                                 retval = 0;
03065                                 break;
03066                         }
03067                         current_elem = parts;
03068                 }
03069                 else
03070                 {
03071                         current_elem->next = malloc(sizeof(fapint_llist_item_t));
03072                         if ( !current_elem->next )
03073                         {
03074                                 retval = 0;
03075                                 break;
03076                         }
03077                         current_elem = current_elem->next;
03078                 }
03079                 current_elem->next = NULL;
03080                 if ( input[i+matches[1].rm_so] != '-' )
03081                 {
03082                         current_elem->text = malloc(5);
03083                         memcpy(current_elem->text, input+i+matches[1].rm_so, 4);
03084                         current_elem->text[4] = 0;
03085                 }
03086                 else
03087                 {
03088                         current_elem->text = NULL;
03089                 }
03090                 part_count++;
03091                 
03092                 /* Prepare for next element. */
03093                 i += 4;
03094                 if ( i >= strlen(input) ) break;
03095         }
03096         if ( !retval || !part_count )
03097         {
03098                 fapint_clear_llist(parts);
03099                 return 0;
03100         }
03101         
03102         /* Prepare to return results. */
03103         packet->wx_report = malloc(sizeof(fap_wx_report_t));
03104         if ( !packet->wx_report )
03105         {
03106                 fapint_clear_llist(parts);
03107                 return 0;
03108         }
03109         fapint_init_wx_report(packet->wx_report);
03110         
03111         /* Check parts one at a time. */
03112         do
03113         {
03114                 current_elem = parts;
03115                 
03116                 /* instant wind speed */
03117                 if ( current_elem->text )
03118                 {
03119                         packet->wx_report->wind_speed = malloc(sizeof(double));
03120                         if ( !packet->wx_report->wind_speed )
03121                         {
03122                                 retval = 0;
03123                                 break;
03124                         }
03125                         *packet->wx_report->wind_speed = strtol(current_elem->text, NULL, 16) * KMH_TO_MS / 10.0;
03126                 }
03127                 current_elem = current_elem->next;
03128         
03129                 /* wind direction */
03130                 if ( current_elem )
03131                 {
03132                         if ( current_elem->text )
03133                         {
03134                                 packet->wx_report->wind_dir = malloc(sizeof(unsigned int));
03135                                 if ( !packet->wx_report->wind_dir )
03136                                 {
03137                                         retval = 0;
03138                                         break;
03139                                 }
03140                                 *packet->wx_report->wind_dir = floor(strtol(current_elem->text, NULL, 16) * 1.41176 + 0.5);
03141                         }
03142                         current_elem = current_elem->next;
03143                 }
03144                 else
03145                 {
03146                         break;
03147                 }
03148                 
03149                 /* temperature */
03150                 if ( current_elem )
03151                 {
03152                         if ( current_elem->text )
03153                         {
03154                                 packet->wx_report->temp = malloc(sizeof(double));
03155                                 if ( !packet->wx_report->temp )
03156                                 {
03157                                         retval = 0;
03158                                         break;
03159                                 }
03160                                 *packet->wx_report->temp = FAHRENHEIT_TO_CELCIUS(strtol(current_elem->text, NULL, 16)/10.0);
03161                         }
03162                         current_elem = current_elem->next;
03163                 }
03164                 else
03165                 {
03166                         break;
03167                 }
03168                 
03169                 /* rain since midnight */
03170                 if ( current_elem )
03171                 {
03172                         if ( current_elem->text )
03173                         {
03174                                 packet->wx_report->rain_midnight = malloc(sizeof(double));
03175                                 if ( !packet->wx_report->rain_midnight )
03176                                 {
03177                                         retval = 0;
03178                                         break;
03179                                 }
03180                                 *packet->wx_report->rain_midnight = strtol(current_elem->text, NULL, 16) * HINCH_TO_MM;
03181                         }
03182                         current_elem = current_elem->next;
03183                 }
03184                 else
03185                 {
03186                         break;
03187                 }
03188                 
03189                 /* pressure */
03190                 if ( current_elem )
03191                 {
03192                         if ( current_elem->text )
03193                         {
03194                                 packet->wx_report->pressure = malloc(sizeof(double));
03195                                 if ( !packet->wx_report->pressure )
03196                                 {
03197                                         retval = 0;
03198                                         break;
03199                                 }
03200                                 *packet->wx_report->pressure = strtol(current_elem->text, NULL, 16) / 10.0;
03201                         }
03202                         current_elem = current_elem->next;
03203                 }
03204                 else
03205                 {
03206                         break;
03207                 }
03208                 
03209                 /* inside temperature */
03210                 if ( current_elem )
03211                 {
03212                         if ( current_elem->text )
03213                         {
03214                                 packet->wx_report->temp_in = malloc(sizeof(double));
03215                                 if ( !packet->wx_report->temp_in )
03216                                 {
03217                                         retval = 0;
03218                                         break;
03219                                 }
03220                                 *packet->wx_report->temp_in = FAHRENHEIT_TO_CELCIUS(strtol(current_elem->text, NULL, 16)/10.0);
03221                         }
03222                         current_elem = current_elem->next;
03223                 }
03224                 else
03225                 {
03226                         break;
03227                 }
03228                 
03229                 /* humidity */
03230                 if ( current_elem )
03231                 {
03232                         if ( current_elem->text )
03233                         {
03234                                 packet->wx_report->humidity = malloc(sizeof(unsigned int));
03235                                 if ( !packet->wx_report->humidity )
03236                                 {
03237                                         retval = 0;
03238                                         break;
03239                                 }
03240                                 *packet->wx_report->humidity = strtol(current_elem->text, NULL, 16)/10.0;
03241                         }
03242                         current_elem = current_elem->next;
03243                 }
03244                 else
03245                 {
03246                         break;
03247                 }
03248                 
03249                 /* inside humidity */
03250                 if ( current_elem )
03251                 {
03252                         if ( current_elem->text )
03253                         {
03254                                 packet->wx_report->humidity_in = malloc(sizeof(unsigned int));
03255                                 if ( !packet->wx_report->humidity_in )
03256                                 {
03257                                         retval = 0;
03258                                         break;
03259                                 }
03260                                 *packet->wx_report->humidity_in = strtol(current_elem->text, NULL, 16)/10.0;
03261                         }
03262                         current_elem = current_elem->next;
03263                 }
03264                 else
03265                 {
03266                         break;
03267                 }
03268                 
03269                 /* date */
03270                 if ( current_elem )
03271                 {
03272                         current_elem = current_elem->next;
03273                 }
03274                 else
03275                 {
03276                         break;
03277                 }
03278                 
03279                 /* time */
03280                 if ( current_elem )
03281                 {
03282                         current_elem = current_elem->next;
03283                 }
03284                 else
03285                 {
03286                         break;
03287                 }
03288 
03289                 /* rain since midnight (again?) */
03290                 if ( current_elem )
03291                 {
03292                         if ( current_elem->text )
03293                         {
03294                                 *packet->wx_report->rain_midnight = strtol(current_elem->text, NULL, 16) * HINCH_TO_MM;
03295                         }
03296                         current_elem = current_elem->next;
03297 
03298                 /* avg wind speed */
03299                 if ( current_elem->text )
03300                 {
03301                         *packet->wx_report->wind_speed = strtol(current_elem->text, NULL, 16) * KMH_TO_MS / 10.0;
03302                 }
03303                 current_elem = current_elem->next;
03304                 }
03305                 
03306         } while ( 0 );  
03307         fapint_clear_llist(parts);
03308         
03309         return retval;
03310 }
03311 
03312 
03313 
03314 int fapint_parse_wx_peet_packet(fap_packet_t* packet, char const* input)
03315 {
03316         fapint_llist_item_t* parts, *current_elem;
03317         unsigned int part_count;
03318 
03319         int i, retval = 1;
03320         int16_t temp;
03321 
03322         unsigned int matchcount = 2;
03323         regmatch_t matches[matchcount];
03324         
03325         
03326         /* Split report into parts. */
03327         parts = NULL;
03328         current_elem = NULL;
03329         part_count = 0;
03330         i = 0;
03331         while ( regexec(&fapint_regex_peet_splitter, input+i, matchcount, matches, 0) == 0 )
03332         {
03333                 if ( !parts )
03334                 {
03335                         parts = malloc(sizeof(fapint_llist_item_t));
03336                         if ( !parts ) return 0;
03337                         current_elem = parts;
03338                 }
03339                 else
03340                 {
03341                         current_elem->next = malloc(sizeof(fapint_llist_item_t));
03342                         if ( !current_elem->next )
03343                         {
03344                                 retval = 0;
03345                                 break;
03346                         }
03347                         current_elem = current_elem->next;
03348                 }
03349                 current_elem->next = NULL;
03350                 if ( input[i+matches[1].rm_so] != '-' )
03351                 {
03352                         current_elem->text = malloc(5);
03353                         if ( !current_elem->text )
03354                         {
03355                                 retval = 0;
03356                                 break;
03357                         }
03358                         memcpy(current_elem->text, input+i+matches[1].rm_so, 4);
03359                         current_elem->text[4] = 0;
03360                 }
03361                 else
03362                 {
03363                         current_elem->text = NULL;
03364                 }
03365                 part_count++;
03366                 
03367                 /* Prepare for next element. */
03368                 i += 4;
03369                 if ( i >= strlen(input) ) break;
03370         }
03371         if ( !retval || !part_count )
03372         {
03373                 fapint_clear_llist(parts);
03374                 return 0;
03375         }
03376         
03377         /* Prepare to return results. */
03378         packet->wx_report = malloc(sizeof(fap_wx_report_t));
03379         if ( !packet->wx_report )
03380         {
03381                 fapint_clear_llist(parts);
03382                 return 0;
03383         }
03384         fapint_init_wx_report(packet->wx_report);
03385         
03386         /* Check parts one at a time. */
03387         do
03388         {
03389                 current_elem = parts;
03390                 
03391                 /* wind gust */
03392                 if ( current_elem->text )
03393                 {
03394                         packet->wx_report->wind_gust = malloc(sizeof(double));
03395                         if ( !packet->wx_report->wind_gust )
03396                         {
03397                                 retval = 0;
03398                                 break;
03399                         }
03400                         *packet->wx_report->wind_gust = strtol(current_elem->text, NULL, 16) * KMH_TO_MS / 10.0;
03401                 }
03402                 current_elem = current_elem->next;
03403         
03404                 /* wind direction */
03405                 if ( current_elem )
03406                 {
03407                         if ( current_elem->text )
03408                         {
03409                                 packet->wx_report->wind_dir = malloc(sizeof(unsigned int));
03410                                 if ( !packet->wx_report->wind_dir )
03411                                 {
03412                                         retval = 0;
03413                                         break;
03414                                 }
03415                                 *packet->wx_report->wind_dir = floor(strtol(current_elem->text, NULL, 16) * 1.41176 + 0.5);
03416                         }
03417                         current_elem = current_elem->next;
03418                 }
03419                 else
03420                 {
03421                         break;
03422                 }
03423                 
03424                 /* temperature */
03425                 if ( current_elem )
03426                 {
03427                         if ( current_elem->text )
03428                         {
03429                                 packet->wx_report->temp = malloc(sizeof(double));
03430                                 if ( !packet->wx_report->temp )
03431                                 {
03432                                         retval = 0;
03433                                         break;
03434                                 }
03435                                 temp = strtol(current_elem->text, NULL, 16);
03436                                 *packet->wx_report->temp = FAHRENHEIT_TO_CELCIUS(temp/10.0);
03437                         }
03438                         current_elem = current_elem->next;
03439                 }
03440                 else
03441                 {
03442                         break;
03443                 }
03444                 
03445                 /* rain since midnight */
03446                 if ( current_elem )
03447                 {
03448                         if ( current_elem->text )
03449                         {
03450                                 packet->wx_report->rain_midnight = malloc(sizeof(double));
03451                                 if ( !packet->wx_report->rain_midnight )
03452                                 {
03453                                         retval = 0;
03454                                         break;
03455                                 }
03456                                 *packet->wx_report->rain_midnight = strtol(current_elem->text, NULL, 16) * HINCH_TO_MM;
03457                         }
03458                         current_elem = current_elem->next;
03459                 }
03460                 else
03461                 {
03462                         break;
03463                 }
03464                 
03465                 /* pressure */
03466                 if ( current_elem )
03467                 {
03468                         if ( current_elem->text )
03469                         {
03470                                 packet->wx_report->pressure = malloc(sizeof(double));
03471                                 if ( !packet->wx_report->pressure )
03472                                 {
03473                                         retval = 0;
03474                                         break;
03475                                 }
03476                                 *packet->wx_report->pressure = strtol(current_elem->text, NULL, 16) / 10.0;
03477                         }
03478                         current_elem = current_elem->next;
03479                 }
03480                 else
03481                 {
03482                         break;
03483                 }
03484                 
03485                 /* barometer delta */
03486                 if ( current_elem )
03487                 {
03488                         current_elem = current_elem->next;
03489                 }
03490                 else
03491                 {
03492                         break;
03493                 }
03494                 
03495                 /* barometer corr. factor */
03496                 if ( current_elem )
03497                 {
03498                         current_elem = current_elem->next;
03499                 }
03500                 else
03501                 {
03502                         break;
03503                 }
03504 
03505                 /* barometer corr. factor */
03506                 if ( current_elem )
03507                 {
03508                         current_elem = current_elem->next;
03509                 }
03510                 else
03511                 {
03512                         break;
03513                 }
03514                 
03515                 /* humidity */
03516                 if ( current_elem )
03517                 {
03518                         if ( current_elem->text )
03519                         {
03520                                 packet->wx_report->humidity = malloc(sizeof(unsigned int));
03521                                 if ( !packet->wx_report->humidity )
03522                                 {
03523                                         retval = 0;
03524                                         break;
03525                                 }
03526                                 *packet->wx_report->humidity = strtol(current_elem->text, NULL, 16)/10.0;
03527                         }
03528                         current_elem = current_elem->next;
03529                 }
03530                 else
03531                 {
03532                         break;
03533                 }
03534                 
03535                 /* date */
03536                 if ( current_elem )
03537                 {
03538                         current_elem = current_elem->next;
03539                 }
03540                 else
03541                 {
03542                         break;
03543                 }
03544                 
03545                 /* time */
03546                 if ( current_elem )
03547                 {
03548                         current_elem = current_elem->next;
03549                 }
03550                 else
03551                 {
03552                         break;
03553                 }
03554                 
03555                 /* rain since midnight */
03556                 if ( current_elem )
03557                 {
03558                         if ( current_elem->text )
03559                         {
03560                                 *packet->wx_report->rain_midnight = strtol(current_elem->text, NULL, 16) * HINCH_TO_MM;
03561                         }
03562                         current_elem = current_elem->next;
03563                 }
03564                 else
03565                 {
03566                         break;
03567                 }
03568 
03569                 /* wind speed */
03570                 if ( current_elem )
03571                 {
03572                         if ( current_elem->text )
03573                         {
03574                                 packet->wx_report->wind_speed = malloc(sizeof(double));
03575                                 if ( !packet->wx_report->wind_speed )
03576                                 {
03577                                         retval = 0;
03578                                         break;
03579                                 }
03580                                 *packet->wx_report->wind_speed = strtol(current_elem->text, NULL, 16) * KMH_TO_MS / 10.0;
03581                         }
03582                         current_elem = current_elem->next;
03583                 }
03584                 else
03585                 {
03586                         break;
03587                 }
03588                 /* That's all folks. */
03589                 break;
03590         } while ( 0 );
03591         fapint_clear_llist(parts);
03592 
03593         return retval;
03594 }
03595 
03596 
03597 
03598 int fapint_parse_dao(fap_packet_t* packet, char input[3])
03599 {
03600         double lon_off = 0.0, lat_off = 0.0;
03601 
03602         /* Datum character is the first character and also defines how the rest is interpreted. */
03603         if ( 'A' <= input[0] && input[0] <= 'Z' && isdigit(input[1]) && isdigit(input[2]) )
03604         {
03605                 /* Human readable. */
03606                 packet->dao_datum_byte = input[0];
03607                 if ( packet->pos_resolution == NULL )
03608                 {
03609                         packet->pos_resolution = malloc(sizeof(double));
03610                         if ( !packet->pos_resolution ) return 0;
03611                 }
03612                 *packet->pos_resolution = fapint_get_pos_resolution(3);
03613                 lat_off = (input[1]-48.0) * 0.001 / 60.0;
03614                 lon_off = (input[2]-48.0) * 0.001 / 60.0;
03615         }
03616         else if ( 'a' <= input[0] && input[0] <= 'z' &&
03617                   0x21 <= input[1] && input[1] <= 0x7b &&
03618                   0x21 <= input[2] && input[2] <= 0x7b )
03619         {
03620                 /* Base-91. */
03621                 packet->dao_datum_byte = toupper(input[0]); /* Save in uppercase. */
03622                 if ( packet->pos_resolution == NULL )
03623                 {
03624                         packet->pos_resolution = malloc(sizeof(double));
03625                         if ( !packet->pos_resolution ) return 0;
03626                 }
03627                 *packet->pos_resolution = fapint_get_pos_resolution(4);
03628                 /* Scale base-91. */
03629                 lat_off = (input[1]-33.0)/91.0 * 0.01 / 60.0;
03630                 lon_off = (input[2]-33.0)/91.0 * 0.01 / 60.0;
03631         }
03632         else if ( 0x21 <= input[0] && input[0] <= 0x7b &&
03633                   input[1] == ' ' && input[2] == ' ' )
03634         {
03635                 /* Only datum information, no lat/lon digits. */
03636                 if ( 'a' <= input[0] && input[0] <= 'z' )
03637                 {
03638                         packet->dao_datum_byte = toupper(input[0]);
03639                 }
03640                 else
03641                 {
03642                         packet->dao_datum_byte = input[0];
03643                 }    
03644         }
03645         else
03646         {
03647                 /* Invalid !DAO! */
03648                 return 0;
03649         }
03650         
03651         /* Cautiously check N/S and E/W. */
03652         if ( packet->latitude )
03653         {
03654                 if ( *packet->latitude < 0 )
03655                 {
03656                         *packet->latitude -= lat_off;
03657                 }
03658                 else
03659                 {
03660                         *packet->latitude += lat_off;
03661                 }
03662         }
03663         if ( packet->longitude )
03664         {
03665                 if ( *packet->longitude < 0 )
03666                 {
03667                         *packet->longitude -= lon_off;
03668                 }
03669                 else
03670                 {
03671                         *packet->longitude += lon_off;
03672                 }      
03673         }
03674         
03675         return 1;
03676 }
03677 
03678 
03679 
03680 char* fapint_check_kiss_callsign(char* input)
03681 {
03682         unsigned int matchcount = 3;
03683         regmatch_t matches[matchcount];
03684         
03685         int len;
03686         char* tmp_str;
03687         
03688         
03689         if ( !input ) return NULL;
03690         
03691         if ( regexec(&fapint_regex_kiss_callsign, input, matchcount, (regmatch_t*)&matches, 0) == 0 )
03692         {
03693                 /* Check ssid if given. */
03694                 len = matches[2].rm_eo - matches[2].rm_so;
03695                 if ( len > 0 )
03696                 {
03697                         tmp_str = malloc(len+1);
03698                         if ( !tmp_str ) return NULL;
03699                         memcpy(tmp_str, input+matches[2].rm_so, len);
03700                         tmp_str[len] = 0;
03701                         if ( atoi(tmp_str) < -15 )
03702                         {
03703                                 free(tmp_str);
03704                                 return NULL;
03705                         }
03706                         free(tmp_str);
03707                 }
03708                 
03709                 /* Combine as result. */
03710                 len += matches[1].rm_eo - matches[1].rm_so;
03711                 tmp_str = malloc(len+1);
03712                 if ( !tmp_str ) return NULL;
03713                 memcpy(tmp_str, input+matches[1].rm_so, matches[1].rm_eo - matches[1].rm_so);
03714                 memcpy(tmp_str+matches[1].rm_eo, input+matches[2].rm_so, matches[2].rm_eo - matches[2].rm_so);
03715                 tmp_str[len] = 0;
03716                 
03717                 return tmp_str;
03718         }
03719         
03720         return NULL;
03721 }
03722 
03723 
03724 
03725 /* Implementation-specific helpers for fap.c. */
03726 
03727 
03728 
03729 fap_packet_t* fapint_create_packet()
03730 {
03731         fap_packet_t* result = malloc(sizeof(fap_packet_t));
03732         if ( !result ) return NULL;
03733 
03734         /* Prepare result object. */
03735         result->error_code = NULL;
03736         result->type = NULL;
03737         
03738         result->orig_packet = NULL;
03739         result->orig_packet_len = 0;
03740 
03741         result->header = NULL;
03742         result->body = NULL;  
03743         result->body_len = 0; 
03744         result->src_callsign = NULL;
03745         result->dst_callsign = NULL;
03746         result->path = NULL; 
03747         result->path_len = 0;
03748         
03749         result->latitude = NULL;    
03750         result->longitude = NULL;
03751         result->format = NULL;
03752         result->pos_resolution = NULL;
03753         result->pos_ambiguity = NULL;
03754         result->dao_datum_byte = 0;
03755         
03756         result->altitude = NULL;
03757         result->course = NULL;  
03758         result->speed = NULL;   
03759 
03760         result->symbol_table = 0;
03761         result->symbol_code = 0; 
03762         
03763         result->messaging = NULL;
03764         result->destination = NULL;
03765         result->message = NULL;
03766         result->message_ack = NULL;
03767         result->message_nack = NULL;
03768         result->message_id = NULL;
03769         result->comment = NULL;
03770         result->comment_len = 0;
03771         
03772         result->object_or_item_name = NULL;
03773         result->alive = NULL;
03774 
03775         result->gps_fix_status = NULL;
03776         result->radio_range = NULL;
03777         result->phg = NULL;
03778         result->timestamp = NULL;
03779         result->nmea_checksum_ok = NULL;
03780         
03781         result->wx_report = NULL;
03782         result->telemetry = NULL;
03783 
03784         result->messagebits = NULL;
03785         result->status = NULL;
03786         result->status_len = 0;
03787         result->capabilities = NULL;
03788         result->capabilities_len = 0;
03789         
03790         /* Return results. */
03791         return result;
03792 }

Generated on Wed Dec 21 2011 23:04:42 for libfap by  doxygen 1.7.1