mirror of
https://github.com/Xastir/Xastir
synced 2026-08-13 17:46:16 -04:00
This PR adds configurable UTF-8 handling for APRS message traffic to
improve interoperability with modern clients such as APRSdroid.
It introduces a global config option that controls both:
- incoming message normalization for display in legacy Motif/Latin-1
UI paths
and
- outgoing message encoding so transmitted payloads can be UTF-8.
What changed:
- Added global runtime/config variable traffic_utf8_enabled.
- Persisted setting in xastir.cnf as TRAFFIC_UTF8 (load/save).
- Gated incoming conversion in message ingest/display code paths.
- Gated outgoing conversion in message output path.
- Updated unit-test stubs to include the new global symbol used by db.c
test links.
Behavior:
TRAFFIC_UTF8=1 (default):
Incoming: normalize UTF-8 message text for Latin-1 UI display.
Outgoing: encode Latin-1 UI input to UTF-8 before transmit.
TRAFFIC_UTF8=0:
Preserve legacy byte behavior (no UTF-8 parse/send conversions).
Closes #380
263 lines
6.8 KiB
C
263 lines
6.8 KiB
C
/*
|
|
*
|
|
* XASTIR, Amateur Station Tracking and Information Reporting
|
|
* Copyright (C) 2025-2026 The Xastir Group
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*
|
|
* Look at the README for more information on the program.
|
|
*/
|
|
|
|
/*
|
|
* Stub implementations for symbols referenced by util.o
|
|
* but not used by the unit tests.
|
|
*
|
|
* These stubs allow us to link with the real util.o for testing
|
|
* without pulling in the entire Xastir codebase.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <time.h>
|
|
#include "globals.h"
|
|
#include "database.h"
|
|
|
|
#include "tests/test_framework.h"
|
|
|
|
// define from xastir.h
|
|
#define MAX_LINE_SIZE 512
|
|
|
|
// global variables referenced but unused in tests so far:
|
|
int transmit_compressed_objects_items=0;
|
|
int object_tx_disable=0;
|
|
int transmit_disable=0;
|
|
int debug_level=0;
|
|
long center_longitude, center_latitude;
|
|
char dangerous_operation[200];
|
|
char my_long[MAX_LONG], my_lat[MAX_LAT];
|
|
char my_callsign[MAX_CALLSIGN+1]="TEST";
|
|
time_t OBJECT_rate=0l;
|
|
|
|
|
|
// These are cut/pasted out of test_db_stubs (duplicates removed)
|
|
int altnet = 0;
|
|
int track_case = 0;
|
|
int track_match = 0;
|
|
int track_station_on = 0;
|
|
char tracking_station_call[100] = "";
|
|
int trail_segment_distance = 0;
|
|
int trail_segment_time = 0;
|
|
int traffic_utf8_enabled = 1;
|
|
int transmit_now = 0;
|
|
int wait_to_redraw = 0;
|
|
void *da=NULL;
|
|
|
|
/* Widget and display related globals */
|
|
void *Display_ = NULL;
|
|
void *Display_data_dialog = NULL;
|
|
void *Display_data_text = NULL;
|
|
int Display_packet_data_mine_only = 0;
|
|
int Display_packet_data_type = 0;
|
|
void *LOGFILE_MESSAGE = NULL;
|
|
void *LOGFILE_WX_ALERT = NULL;
|
|
|
|
/* Screen coordinate globals */
|
|
long NW_corner_latitude = 0;
|
|
long NW_corner_longitude = 0;
|
|
long SE_corner_latitude = 0;
|
|
long SE_corner_longitude = 0;
|
|
long center_latitude = 0;
|
|
long center_longitude = 0;
|
|
|
|
/* Display selection globals */
|
|
void *Select_ = NULL;
|
|
time_t aircraft_sec_clear = 0;
|
|
|
|
/* Alert and message globals */
|
|
char altnet_call[MAX_CALLSIGN+1] = "";
|
|
int auto_reply = 0;
|
|
char auto_reply_message[256] = "";
|
|
|
|
/* Band open globals */
|
|
int bando_min = 0;
|
|
int bando_max = 0;
|
|
|
|
/* Device globals */
|
|
void *devices = NULL;
|
|
void *mw = NULL;
|
|
void *port_data = NULL;
|
|
int transmit_compressed_posit;
|
|
|
|
/* English units flag */
|
|
int english_units = 0;
|
|
|
|
/* Igate globals */
|
|
int igate_msgs_tx = 0;
|
|
int operate_as_an_igate = 0;
|
|
|
|
/* Data copy buffers */
|
|
char incoming_data_copy[1024] = "";
|
|
char incoming_data_copy_previous[1024] = "";
|
|
|
|
/* Locate station globals */
|
|
char locate_station_call[MAX_CALLSIGN+1] = "";
|
|
|
|
/* My station globals */
|
|
long my_last_altitude = 0;
|
|
time_t my_last_altitude_time = 0;
|
|
int my_last_course = 0;
|
|
int my_last_speed = 0;
|
|
int my_position_valid = 0;
|
|
int my_trail_diff_color = 0;
|
|
|
|
/* Proximity globals */
|
|
int prox_min = 0;
|
|
int prox_max = 0;
|
|
|
|
/* Redraw globals */
|
|
int redo_list = 0;
|
|
int redraw_on_new_data = 0;
|
|
|
|
/* Screen dimensions */
|
|
unsigned long scale_x = 0;
|
|
unsigned long scale_y = 0;
|
|
int screen_height = 0;
|
|
int screen_width = 0;
|
|
|
|
/* Station clear time globals */
|
|
time_t sec_clear = 0;
|
|
time_t sec_remove = 0;
|
|
|
|
/* Send message dialog lock */
|
|
void *send_message_dialog_lock = NULL;
|
|
|
|
/* Smart beaconing globals */
|
|
int smart_beaconing = 0;
|
|
int sb_POSIT_rate = 0;
|
|
int sb_current_heading = 0;
|
|
int sb_high_speed_limit = 0;
|
|
int sb_last_heading = 0;
|
|
int sb_low_speed_limit = 0;
|
|
int sb_posit_fast = 0;
|
|
int sb_posit_slow = 0;
|
|
int sb_turn_min = 0;
|
|
int sb_turn_slope = 0;
|
|
time_t sb_turn_time = 0;
|
|
|
|
/* Position timing globals */
|
|
time_t posit_last_time = 0;
|
|
time_t posit_next_time = 0;
|
|
|
|
|
|
/* Sound globals */
|
|
int sound_band_open_message = 0;
|
|
char sound_command[256] = "";
|
|
int sound_new_message = 0;
|
|
int sound_new_station = 0;
|
|
int sound_play_band_open_message;
|
|
int sound_play_new_message;
|
|
int sound_play_new_station;
|
|
int sound_play_prox_message;
|
|
int sound_prox_message = 0;
|
|
|
|
/* Festival speak globals */
|
|
int festival_speak_ID=0;
|
|
int festival_speak_new_station=0;
|
|
int festival_speak_proximity_alert=0;
|
|
int festival_speak_tracked_proximity_alert=0;
|
|
int festival_speak_band_opening=0;
|
|
int festival_speak_new_message_alert=0;
|
|
int festival_speak_new_message_body=0;
|
|
int festival_speak_new_weather_alert=0;
|
|
|
|
/* Station capability globals */
|
|
int show_only_station_capabilities = 0;
|
|
|
|
/* Trail color global */
|
|
int current_trail_color = 0;
|
|
|
|
/* Logging globals */
|
|
int log_wx_alert_data;
|
|
int log_message_data;
|
|
int read_file;
|
|
|
|
/* Conversion globals */
|
|
double cvt_kn2len; // from knots
|
|
double cvt_mi2len; // from miles
|
|
|
|
// stubs needed to get objects.c linked in:
|
|
STUB_IMPL(output_my_data);
|
|
STUB_IMPL(langcode);
|
|
STUB_IMPL(get_user_base_dir);
|
|
STUB_IMPL(statusline);
|
|
STUB_IMPL(ll_to_utm_ups);
|
|
STUB_IMPL(utm_ups_to_ll);
|
|
|
|
//stubs needed to get db.c linked in (duplicates removed):
|
|
STUB_IMPL(alert_build_list)
|
|
STUB_IMPL(alert_match)
|
|
STUB_IMPL(alert_on_alert_list)
|
|
STUB_IMPL(all_messages)
|
|
STUB_IMPL(bulletin_message_check)
|
|
STUB_IMPL(draw_area)
|
|
STUB_IMPL(draw_labeled_area)
|
|
STUB_IMPL(request_new_image)
|
|
STUB_IMPL(schedule_reboot)
|
|
STUB_IMPL(setup_message_data)
|
|
STUB_IMPL(sound_play)
|
|
STUB_IMPL(transmit_message_data)
|
|
STUB_IMPL(transmit_message_data_delayed)
|
|
STUB_IMPL(track_station)
|
|
STUB_IMPL(begin_critical_section)
|
|
STUB_IMPL(bulletin_data_add)
|
|
STUB_IMPL(check_popup_window)
|
|
STUB_IMPL(clear_acked_message)
|
|
STUB_IMPL(create_garmin_waypoint)
|
|
STUB_IMPL(decode_Peet_Bros)
|
|
STUB_IMPL(decode_U2000_L)
|
|
STUB_IMPL(decode_U2000_P)
|
|
STUB_IMPL(display_station)
|
|
STUB_IMPL(draw_trail)
|
|
STUB_IMPL(end_critical_section)
|
|
STUB_IMPL(fill_in_new_alert_entries)
|
|
STUB_IMPL(get_send_message_path)
|
|
STUB_IMPL(get_tactical_from_hash)
|
|
STUB_IMPL(insert_into_heard_queue)
|
|
STUB_IMPL(is_local_interface)
|
|
STUB_IMPL(is_network_interface)
|
|
STUB_IMPL(Locate_station)
|
|
STUB_IMPL(log_data)
|
|
STUB_IMPL(log_tactical_call)
|
|
STUB_IMPL(look_for_open_group_data)
|
|
STUB_IMPL(play_sound)
|
|
STUB_IMPL(popup_message)
|
|
STUB_IMPL(popup_message_always)
|
|
STUB_IMPL(port_write_string)
|
|
STUB_IMPL(SayText)
|
|
STUB_IMPL(send_agwpe_packet)
|
|
STUB_IMPL(send_ax25_frame)
|
|
STUB_IMPL(stations_types)
|
|
STUB_IMPL(output_igate_net)
|
|
STUB_IMPL(output_igate_rf)
|
|
STUB_IMPL(output_message)
|
|
STUB_IMPL(output_nws_igate_rf)
|
|
|
|
// Fake implementation of compute_current_DR_position, just returns
|
|
// position of station without dead reckoning.
|
|
void compute_current_DR_position(DataRow *p_station, long *x_long, long *y_lat)
|
|
{
|
|
*x_long = p_station->coord_lon;
|
|
*y_lat = p_station->coord_lat;
|
|
}
|