From 30869c7afc5517eaf9f5a31bd21274215a4c5225 Mon Sep 17 00:00:00 2001
From: wb2osz <wb2osz@comcast.net>
Date: Mon, 4 Jul 2022 02:11:55 +0100
Subject: [PATCH] Issues 405 & 406 and other improvements in message
 interpretation.

---
 src/decode_aprs.c | 98 +++++++++++++++++++++++++++++++----------------
 1 file changed, 65 insertions(+), 33 deletions(-)

diff --git a/src/decode_aprs.c b/src/decode_aprs.c
index 26e87cc..dfb87a4 100644
--- a/src/decode_aprs.c
+++ b/src/decode_aprs.c
@@ -174,10 +174,10 @@ void decode_aprs (decode_aprs_t *A, packet_t pp, int quiet, int third_party)
 	A->g_quiet = quiet;
 
 	if (isprint(*pinfo)) {
-	  snprintf (A->g_data_type_desc, sizeof(A->g_data_type_desc), "Unknown APRS Data Type Indicator \"%c\"", *pinfo);
+	  snprintf (A->g_data_type_desc, sizeof(A->g_data_type_desc), "ERROR!!!  Unknown APRS Data Type Indicator \"%c\"", *pinfo);
 	}
 	else {
-	  snprintf (A->g_data_type_desc, sizeof(A->g_data_type_desc), "ERROR!!! Unknown APRS Data Type Indicator: unprintable 0x%02x", *pinfo);
+	  snprintf (A->g_data_type_desc, sizeof(A->g_data_type_desc), "ERROR!!!  Unknown APRS Data Type Indicator: unprintable 0x%02x", *pinfo);
 	}
 
 	A->g_symbol_table = '/';	/* Default to primary table. */
@@ -303,7 +303,7 @@ void decode_aprs (decode_aprs_t *A, packet_t pp, int quiet, int third_party)
 
 	      if (strncmp((char*)pinfo, "!!", 2) == 0)
 	      {
-		aprs_ultimeter (A, (char*)pinfo, info_len);
+		aprs_ultimeter (A, (char*)pinfo, info_len);		// TODO: produce obsolete error.
 	      }
 	      else
 	      {	     
@@ -312,7 +312,7 @@ void decode_aprs (decode_aprs_t *A, packet_t pp, int quiet, int third_party)
 	      break;
 
 
-	    //case '#':		/* Peet Bros U-II Weather station */
+	    //case '#':		/* Peet Bros U-II Weather station */		// TODO: produce obsolete error.
 	    //case '*':		/* Peet Bros U-II Weather station */
 	      //break;
 		
@@ -320,7 +320,7 @@ void decode_aprs (decode_aprs_t *A, packet_t pp, int quiet, int third_party)
 		
 	      if (strncmp((char*)pinfo, "$ULTW", 5) == 0)
 	      {
-		aprs_ultimeter (A, (char*)pinfo, info_len);
+		aprs_ultimeter (A, (char*)pinfo, info_len);		// TODO: produce obsolete error.
 	      }
 	      else
 	      {
@@ -536,7 +536,13 @@ void decode_aprs_print (decode_aprs_t *A) {
 	  snprintf (rng, sizeof(rng), ", range=%.1f", A->g_range);
 	  strlcat (stemp, rng, sizeof(stemp));
 	}
-	text_color_set(DW_COLOR_DECODED);
+
+	if (strncmp(stemp, "ERROR", 5) == 0) {
+	  text_color_set(DW_COLOR_ERROR);
+	}
+	else {
+	  text_color_set(DW_COLOR_DECODED);
+	}
 	dw_printf("%s\n", stemp);
 
 /*
@@ -556,7 +562,6 @@ void decode_aprs_print (decode_aprs_t *A) {
  * Any example was checked for each hemihemisphere using
  * http://www.amsat.org/cgi-bin/gridconv
  */
-// FIXME soften language about upper case.
 
 	if (strlen(A->g_maidenhead) > 0) {
 
@@ -1565,7 +1570,7 @@ static void aprs_mic_e (decode_aprs_t *A, packet_t pp, unsigned char *info, int
  * Purpose:	Decode "Message Format."
  *		The word message is used loosely all over the place, but it has a very specific meaning here.
  *
- * Inputs:	info 	- Pointer to Information field.
+ * Inputs:	info 	- Pointer to Information field.  Be carefull not to modify it here!
  *		ilen 	- Information field length.
  *		quiet	- suppress error messages.
  *
@@ -1609,7 +1614,7 @@ static void aprs_mic_e (decode_aprs_t *A, packet_t pp, unsigned char *info, int
  *
  *------------------------------------------------------------------*/
 
-static void aprs_message (decode_aprs_t *A, unsigned char *info, int ilen, int quiet) 
+static void aprs_message (decode_aprs_t *A, unsigned char *info, int ilen, int quiet)
 {
 
 	struct aprs_message_s {
@@ -1619,7 +1624,7 @@ static void aprs_message (decode_aprs_t *A, unsigned char *info, int ilen, int q
 	  char message[256-1-9-1];	/* Officially up to 67 characters for message text. */
 					/* Relaxing seemingly arbitrary restriction here; it doesn't need to fit on a punched card. */
 					/* Wouldn't surprise me if others did not pay attention to the limit. */
-					/* Optional { followed by 1-5 alphanumeric characters for message number */
+					/* Optional '{' followed by 1-5 alphanumeric characters for message number */
 
 					/* If the first character is '?' it is a Directed Station Query. */
 	} *p;
@@ -1751,6 +1756,16 @@ static void aprs_message (decode_aprs_t *A, unsigned char *info, int ilen, int q
 	      text_color_set(DW_COLOR_ERROR);
 	      dw_printf("ERROR: Message number is missing after \"ack\".\n");
 	  }
+
+	  // Xastir puts a carriage return on the end.
+	  char *p = strchr(A->g_message_number, '\r');
+	  if (p != NULL) {
+	      text_color_set(DW_COLOR_ERROR);
+	      dw_printf("The APRS protocol specification says nothing about a possible carriage return after the\n");
+	      dw_printf("message id.  Adding CR might prevent proper interoperability with with other applications.\n");
+	      *p = '\0';
+	  }
+ 
 	  if (strlen(A->g_message_number) >= 3 && A->g_message_number[2] == '}') A->g_message_number[2] = '\0';
 	  snprintf (A->g_data_type_desc, sizeof(A->g_data_type_desc), "\"%s\" ACKnowledged message number \"%s\" from \"%s\"", A->g_src, A->g_message_number, addressee);
 	  A->g_message_subtype = message_subtype_ack;
@@ -1765,6 +1780,16 @@ static void aprs_message (decode_aprs_t *A, unsigned char *info, int ilen, int q
 	      text_color_set(DW_COLOR_ERROR);
 	      dw_printf("ERROR: Message number is missing after \"rej\".\n");
 	  }
+
+	  // Xastir puts a carriage return on the end.
+	  char *p = strchr(A->g_message_number, '\r');
+	  if (p != NULL) {
+	      text_color_set(DW_COLOR_ERROR);
+	      dw_printf("The APRS protocol specification says nothing about a possible carriage return after the\n");
+	      dw_printf("message id.  Adding CR might prevent proper interoperability with with other applications.\n");
+	      *p = '\0';
+	  }
+
 	  if (strlen(A->g_message_number) >= 3 && A->g_message_number[2] == '}') A->g_message_number[2] = '\0';
 	  snprintf (A->g_data_type_desc, sizeof(A->g_data_type_desc), "\"%s\" REJected message number \"%s\" from \"%s\"", A->g_src, A->g_message_number, addressee);
 	  A->g_message_subtype = message_subtype_ack;
@@ -1788,13 +1813,23 @@ static void aprs_message (decode_aprs_t *A, unsigned char *info, int ilen, int q
 	  // Look for message number.
 	  char *pno = strchr(p->message, '{');
 	  if (pno != NULL) {
-	    *pno = '\0';
-	    int mlen = strlen(pno+1);
+	    strlcpy (A->g_message_number, pno+1, sizeof(A->g_message_number));
+
+	    // Xastir puts a carriage return on the end.
+	    char *p = strchr(A->g_message_number, '\r');
+	    if (p != NULL) {
+	        text_color_set(DW_COLOR_ERROR);
+	        dw_printf("The APRS protocol specification says nothing about a possible carriage return after the\n");
+	        dw_printf("message id.  Adding CR might prevent proper interoperability with with other applications.\n");
+	        *p = '\0';
+	    }
+
+	    int mlen = strlen(A->g_message_number);
 	    if (mlen < 1 || mlen > 5) {
 	      text_color_set(DW_COLOR_ERROR);
-	      dw_printf("Message number \"%s\" has length outside range of 1 to 5.\n", pno+1);
+	      dw_printf("Message number \"%s\" has length outside range of 1 to 5.\n", A->g_message_number);
 	    }
-	    strlcpy (A->g_message_number, pno+1, sizeof(A->g_message_number));
+
 	    // TODO: Complain if not alphanumeric.
 
 	    char ack[8] = "";
@@ -1824,6 +1859,11 @@ static void aprs_message (decode_aprs_t *A, unsigned char *info, int ilen, int q
 	  /* No location so don't use  process_comment () */
 
 	  strlcpy (A->g_comment, p->message, sizeof(A->g_comment));
+	  // Remove message number when displaying message text.
+	  pno = strchr(A->g_comment, '{');
+	  if (pno != NULL) {
+	    *pno = '\0';
+	  }
 	}
 
 }
@@ -3752,9 +3792,14 @@ time_t get_timestamp (decode_aprs_t *A, char *p)
  *		It is composed of:
  *			a pair of letters in range A to R.
  *			a pair of digits in range of 0 to 9.
- *			a pair of letters in range of A to X.
+ *			an optional pair of letters in range of A to X.
  *
- * 		The APRS spec says that all letters must be transmitted in upper case.
+ *		The spec says:
+ *				"All letters must be transmitted in upper case.
+ *				Letters may be received in upper case or lower case."
+ *
+ *		Typically the second set of letters is written in lower case.
+ *		An earlier version incorrectly produced an error if lower case found.
  *
  *
  * Examples from APRS spec:	
@@ -3775,25 +3820,10 @@ int get_maidenhead (decode_aprs_t *A, char *p)
 
 	  /* We have 4 characters matching the rule. */
 
-	  if (islower(p[0]) || islower(p[1])) {
-	    if ( ! A->g_quiet) {
-	      text_color_set(DW_COLOR_ERROR);
-	      dw_printf("Warning: Lower case letter in Maidenhead locator.  Specification requires upper case.\n");
-	    }	  
-	  }
-
 	  if (toupper(p[4]) >= 'A' && toupper(p[4]) <= 'X' &&
 	      toupper(p[5]) >= 'A' && toupper(p[5]) <= 'X') {
 
 	    /* We have 6 characters matching the rule. */
-
-	    if (islower(p[4]) || islower(p[5])) {
-	      if ( ! A->g_quiet) {
-	        text_color_set(DW_COLOR_ERROR);
-	        dw_printf("Warning: Lower case letter in Maidenhead locator.  Specification requires upper case.\n");	
-	      }	  
-	    }
-	  
 	    return 6;
 	  }
 	
@@ -4649,7 +4679,7 @@ static void process_comment (decode_aprs_t *A, char *pstart, int clen)
 	  int a = A->g_comment[match[0].rm_so+2];
 	  int o = A->g_comment[match[0].rm_so+3];
 
-	  dw_printf("DAO start=%d, end=%d\n", (int)(match[0].rm_so), (int)(match[0].rm_eo));
+	  //dw_printf("DAO start=%d, end=%d\n", (int)(match[0].rm_so), (int)(match[0].rm_eo));
 
 
 /*
@@ -5035,7 +5065,9 @@ int main (int argc, char *argv[])
 	    /* Try to process it. */
 
 	    text_color_set(DW_COLOR_REC);
-	    dw_printf("\n%s\n", stuff);	    
+	    dw_printf("\n");
+	    ax25_safe_print (stuff, -1, 0);
+	    dw_printf("\n");
 
 // Do we have monitor format, KISS, or AX.25 frame?