diff options
author | Guido Günther <agx@sigxcpu.org> | 2023-12-05 20:05:16 +0100 |
---|---|---|
committer | Aleksander Morgado <aleksander@aleksander.es> | 2024-12-01 21:41:10 +0000 |
commit | c69a64c0cb5690f4435f83f17df7376f3a60a9cf (patch) | |
tree | 72cf78b1015d961db03891e859588ecf0fcf2495 /src | |
parent | 8cb68e87d85c32458a391353e1119af86c8a9fde (diff) |
cbm: Add parsing bits for cell broadcast messages
This allows to parse the CBMs parameters like channel, part number and
message text. We parse uncompressed GSM7 and UCS2 encodings as
described in 3GPP TS 23.038.
Signed-off-by: Guido Günther <agx@sigxcpu.org>
Diffstat (limited to 'src')
-rw-r--r-- | src/meson.build | 1 | ||||
-rw-r--r-- | src/mm-cbm-part.c | 225 | ||||
-rw-r--r-- | src/mm-cbm-part.h | 69 | ||||
-rw-r--r-- | src/tests/meson.build | 3 | ||||
-rw-r--r-- | src/tests/test-cbm-part.c | 247 |
5 files changed, 544 insertions, 1 deletions
diff --git a/src/meson.build b/src/meson.build index 67b6edeb..01c5e12c 100644 --- a/src/meson.build +++ b/src/meson.build @@ -43,6 +43,7 @@ enums_sources += custom_target( ) sources = files( + 'mm-cbm-part.c', 'mm-charsets.c', 'mm-error-helpers.c', 'mm-log.c', diff --git a/src/mm-cbm-part.c b/src/mm-cbm-part.c new file mode 100644 index 00000000..34bbfa55 --- /dev/null +++ b/src/mm-cbm-part.c @@ -0,0 +1,225 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * 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: + * + * Copyright (C) 2024 Guido Günther <agx@sigxcpu.org> + */ + +#include <glib.h> + +#include <ModemManager.h> +#define _LIBMM_INSIDE_MM +#include <libmm-glib.h> + +#include "mm-common-helpers.h" +#include "mm-helper-enums-types.h" +#include "mm-cbm-part.h" +#include "mm-charsets.h" +#include "mm-log.h" +#include "mm-sms-part-3gpp.h" + +#define CBS_DATA_CODING_GROUP_MASK 0b11110000 +#define CBS_DATA_CODING_LANG_GSM7 0b00000000 +#define CBS_DATA_CODING_GSM7 0b00010000 +#define CBS_DATA_CODING_UCS2 0b00010001 +#define CBS_DATA_CODING_GENERAL_NO_CLASS 0b01000000 +#define CBS_DATA_CODING_GENERAL_CLASS 0b01010000 +#define CBS_DATA_CODING_GENERAL_CHARSET_MASK 0b00001100 +#define CBS_DATA_CODING_GENERAL_GSM7 0b00000000 +#define CBS_DATA_CODING_GENERAL_8BIT 0b00000100 +#define CBS_DATA_CODING_GENERAL_UCS2 0b00001000 +#define CBS_DATA_CODING_UDH 0b10010000 + +struct _MMCbmPart { + guint16 serial; + guint16 channel; + + guint8 num_parts; + guint8 part_num; + + gchar *text; + MMSmsEncoding encoding; +}; + + +MMCbmPart * +mm_cbm_part_new_from_pdu (const gchar *hexpdu, + gpointer log_object, + GError **error) +{ + g_autofree guint8 *pdu = NULL; + gsize pdu_len; + + /* Convert PDU from hex to binary */ + pdu = mm_utils_hexstr2bin (hexpdu, -1, &pdu_len, error); + if (!pdu) { + g_prefix_error (error, "Couldn't convert 3GPP PDU from hex to binary: "); + return NULL; + } + + return mm_cbm_part_new_from_binary_pdu (pdu, pdu_len, log_object, error); +} + +MMCbmPart * +mm_cbm_part_new_from_binary_pdu (const guint8 *pdu, + gsize pdu_len, + gpointer log_object, + GError **error) +{ + MMCbmPart *cbm_part; + MMCbmGeoScope scope; + guint offset = 0; + guint16 serial, group; + int len; + g_autofree gchar *text = NULL; + + cbm_part = mm_cbm_part_new (); + + mm_obj_dbg (log_object, "parsing CBM..."); + +#define PDU_SIZE_CHECK(required_size, check_descr_str) \ + if (pdu_len < required_size) { \ + g_set_error (error, \ + MM_CORE_ERROR, \ + MM_CORE_ERROR_FAILED, \ + "PDU too short, %s: %" G_GSIZE_FORMAT " < %u", \ + check_descr_str, \ + pdu_len, \ + required_size); \ + mm_cbm_part_free (cbm_part); \ + return NULL; \ + } + + /* Serial number (2 bytes) */ + PDU_SIZE_CHECK (offset + 2, "cannot read serial number"); + serial = pdu[offset] << 8 | pdu[offset+1]; + scope = CBM_SERIAL_GEO_SCOPE (serial); + switch (scope) { + case MM_CBM_GEO_SCOPE_CELL_NORMAL: + mm_obj_dbg (log_object, " normal cell cbm scope"); + break; + case MM_CBM_GEO_SCOPE_PLMN: + mm_obj_dbg (log_object, " plmn cbm scope"); + break; + case MM_CBM_GEO_SCOPE_AREA: + mm_obj_dbg (log_object, " area cbm scope"); + break; + case MM_CBM_GEO_SCOPE_CELL_IMMEDIATE: + mm_obj_dbg (log_object, " immediate cell cbm scope"); + break; + default: + mm_cbm_part_free (cbm_part); + g_set_error (error, + MM_CORE_ERROR, + MM_CORE_ERROR_FAILED, + "Unhandled cbm message scope: 0x%02x", + scope); + return NULL; + } + cbm_part->serial = serial; + offset+=2; + + /* Channel / Message identifier */ + PDU_SIZE_CHECK (offset + 2, "cannot read channel"); + cbm_part->channel = pdu[offset] << 8 | pdu[offset+1]; + offset+=2; + + PDU_SIZE_CHECK (offset + 1, "cannot read encoding scheme"); + group = pdu[offset] & CBS_DATA_CODING_GROUP_MASK; + /* Order matches 3GPP TS 23.038 Chapter 5 */ + if (group == CBS_DATA_CODING_LANG_GSM7) { + cbm_part->encoding = MM_SMS_ENCODING_GSM7; + } else if (pdu[offset] == CBS_DATA_CODING_GSM7) { + PDU_SIZE_CHECK (offset + 4, "cannot skip lang"); + offset+=3; + cbm_part->encoding = MM_SMS_ENCODING_GSM7; + } else if (pdu[offset] == CBS_DATA_CODING_UCS2) { + PDU_SIZE_CHECK (offset + 3, "cannot skip lang"); + offset+=2; + cbm_part->encoding = MM_SMS_ENCODING_UCS2; + } else if ((group == CBS_DATA_CODING_GENERAL_CLASS) || + (group == CBS_DATA_CODING_GENERAL_NO_CLASS) || + (group == CBS_DATA_CODING_UDH)) { + guint16 charset = pdu[offset] & CBS_DATA_CODING_GENERAL_CHARSET_MASK; + /* We don't handle compression or 8 bit data */ + if (charset == CBS_DATA_CODING_GENERAL_GSM7) + cbm_part->encoding = MM_SMS_ENCODING_GSM7; + else if (charset == CBS_DATA_CODING_GENERAL_UCS2) + cbm_part->encoding = MM_SMS_ENCODING_UCS2; + } else { + mm_cbm_part_free (cbm_part); + g_set_error (error, + MM_CORE_ERROR, + MM_CORE_ERROR_FAILED, + "Unhandled cbm message encoding: 0x%02x", + pdu[offset]); + return NULL; + } + offset++; + + PDU_SIZE_CHECK (offset + 1, "cannot read page parameter"); + cbm_part->num_parts = (pdu[offset] & 0x0F); + cbm_part->part_num = (pdu[offset] & 0xF0) >> 4; + offset++; + + switch (cbm_part->encoding) { + case MM_SMS_ENCODING_GSM7: + len = ((pdu_len - offset) * 8) / 7; + break; + case MM_SMS_ENCODING_UCS2: + len = pdu_len - offset; + break; + case MM_SMS_ENCODING_8BIT: + case MM_SMS_ENCODING_UNKNOWN: + default: + g_assert_not_reached (); + } + PDU_SIZE_CHECK (offset + 1, "cannot read message text"); + text = mm_sms_decode_text (&pdu[offset], + len, + cbm_part->encoding, + 0, + log_object, + error); + if (!text) { + mm_cbm_part_free (cbm_part); + return NULL; + } + cbm_part->text = g_steal_pointer (&text); + + return cbm_part; +} + +MMCbmPart * +mm_cbm_part_new (void) +{ + return g_slice_new0 (MMCbmPart); +} + +void +mm_cbm_part_free (MMCbmPart *part) +{ + g_clear_pointer (&part->text, g_free); + g_slice_free (MMCbmPart, part); +} + +#define PART_GET_FUNC(type, name) \ + type \ + mm_cbm_part_get_##name (MMCbmPart *self) \ + { \ + return self->name; \ + } + +PART_GET_FUNC (guint, part_num) +PART_GET_FUNC (guint, num_parts) +PART_GET_FUNC (const char *, text) +PART_GET_FUNC (guint16, channel) +PART_GET_FUNC (guint16, serial) diff --git a/src/mm-cbm-part.h b/src/mm-cbm-part.h new file mode 100644 index 00000000..f942ab0c --- /dev/null +++ b/src/mm-cbm-part.h @@ -0,0 +1,69 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * 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: + * + * Copyright (C) 2024 Guido Günther <agx@sigxcpu.org> + */ + +#ifndef MM_CBM_PART_H +#define MM_CBM_PART_H + +#include <glib.h> +#include <ModemManager.h> + +#include "mm-sms-part.h" + +/* Serial number per ETSI TS 123 041 */ +#define CBM_SERIAL_GEO_SCOPE(serial) (((serial) & 0xC000) >> 14) +#define CBM_SERIAL_MESSAGE_CODE(serial) (((serial) & 0x0FF0) >> 4) +#define CBM_SERIAL_MESSAGE_CODE_UPDATE(serial) ((serial) & 0x000F) +#define CBM_SERIAL_MESSAGE_CODE_ALERT(serial) (!!((serial) & 0x2000)) +#define CBM_SERIAL_MESSAGE_CODE_POPUP(serial) (!!((serial) & 0x1000)) + +/** + * MMCbmGeoScope: + * @MM_CBM_GEO_SCOPE_CELL_IMMEDIATE: cell wide, immediate display + * @MM_CBM_GEO_SCOPE_PLMN: PLMN wide, normal display + * @MM_CBM_GEO_SCOPE_AREA: area wide, normal display + * @MM_CBM_GEO_SCOPE_CELL_NORMAL: cell wide, normal display + * + * The geographical area of which a CBM is unique and whether to display + * it immediately to the user. + */ +typedef enum _MMCbmGeoScope { + MM_CBM_GEO_SCOPE_CELL_IMMEDIATE = 0, + MM_CBM_GEO_SCOPE_PLMN = 1, + MM_CBM_GEO_SCOPE_AREA = 2, + MM_CBM_GEO_SCOPE_CELL_NORMAL = 3, +} MMCbmGeoScope; + + +typedef struct _MMCbmPart MMCbmPart; + +MMCbmPart *mm_cbm_part_new_from_pdu (const gchar *hexpdu, + gpointer log_object, + GError **error); +MMCbmPart *mm_cbm_part_new_from_binary_pdu (const guint8 *pdu, + gsize pdu_len, + gpointer log_object, + GError **error); + +MMCbmPart *mm_cbm_part_new (void); +void mm_cbm_part_free (MMCbmPart *part); + +guint mm_cbm_part_get_part_num (MMCbmPart *part); +guint mm_cbm_part_get_num_parts (MMCbmPart *part); +const char *mm_cbm_part_get_text (MMCbmPart *part); + +guint16 mm_cbm_part_get_serial (MMCbmPart *part); +guint16 mm_cbm_part_get_channel (MMCbmPart *part); + +#endif diff --git a/src/tests/meson.build b/src/tests/meson.build index dc6ee3fb..b303ff5d 100644 --- a/src/tests/meson.build +++ b/src/tests/meson.build @@ -3,6 +3,7 @@ test_units = { 'at-serial-port': libport_dep, + 'cbm-part': libhelpers_dep, 'charsets': libhelpers_dep, 'error-helpers': libhelpers_dep, 'kernel-device-helpers': libkerneldevice_dep, @@ -51,4 +52,4 @@ if get_option('fuzzer') link_args : '-fsanitize=fuzzer', ) endforeach -endif
\ No newline at end of file +endif diff --git a/src/tests/test-cbm-part.c b/src/tests/test-cbm-part.c new file mode 100644 index 00000000..7981018b --- /dev/null +++ b/src/tests/test-cbm-part.c @@ -0,0 +1,247 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * 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: + * + * Copyright (C) 2024 Guido Günther <agx@sigxcpu.org> + */ + +#include <glib.h> +#include <glib-object.h> +#include <string.h> +#include <stdio.h> +#include <locale.h> + +#define _LIBMM_INSIDE_MM +#include <libmm-glib.h> + +#include "mm-modem-helpers.h" +#include "mm-cbm-part.h" +#include "mm-charsets.h" +#include "mm-log-test.h" + +static void +test_cbm_ca (void) +{ + g_autoptr(GError) err = NULL; + MMCbmPart *part; + guint16 serial; + + static const guint8 pdu[] = { + 0x67, 0x60, 0x11, 0x12, 0x0F, 0x16, + 0x54, 0x74, 0x7A, 0x0E, 0x4A, 0xCF, 0x41, 0x61, + 0x10, 0xBD, 0x3C, 0xA7, 0x83, 0xDE, 0x66, 0x10, + 0x1D, 0x5D, 0x06, 0x3D, 0xDD, 0xF4, 0xB0, 0x3C, + 0xFD, 0x06, 0x05, 0xD9, 0x65, 0x39, 0x1D, 0x24, + 0x2D, 0x87, 0xC9, 0x79, 0xD0, 0x34, 0x3F, 0xA7, + 0x97, 0xDB, 0x2E, 0x10, 0x15, 0x5D, 0x96, 0x97, + 0x41, 0xE9, 0x39, 0xC8, 0xFD, 0x06, 0x91, 0xC3, + 0xEE, 0x73, 0x59, 0x0E, 0xA2, 0xBF, 0x41, 0xF9, + 0x77, 0x5D, 0x0E, 0x42, 0x97, 0xC3, 0x6C, 0x3A, + 0x1A, 0xF4, 0x96, 0x83, 0xE6, 0x61, 0x73, 0x99, + 0x9E, 0x07 + }; + + part = mm_cbm_part_new_from_binary_pdu (pdu, G_N_ELEMENTS (pdu), NULL, &err); + g_assert_no_error (err); + g_assert_nonnull (part); + + serial = mm_cbm_part_get_serial (part); + g_assert_cmpuint (CBM_SERIAL_GEO_SCOPE (serial), ==, MM_CBM_GEO_SCOPE_PLMN); + g_assert_true (CBM_SERIAL_MESSAGE_CODE_ALERT (serial)); + g_assert_false (CBM_SERIAL_MESSAGE_CODE_POPUP (serial)); + g_assert_cmpuint (CBM_SERIAL_MESSAGE_CODE (serial), ==, 0x76); + g_assert_cmpuint (CBM_SERIAL_MESSAGE_CODE_UPDATE (serial), ==, 0); + + /* CA: Emergency alert */ + g_assert_cmpuint (mm_cbm_part_get_channel (part), ==, 4370); + + g_assert_cmpuint (mm_cbm_part_get_num_parts (part), ==, 6); + g_assert_cmpuint (mm_cbm_part_get_part_num (part), ==, 1); + + g_assert_cmpstr (mm_cbm_part_get_text (part), ==, + "This is a test of the Ontario Alert Ready System. There is no danger to your health or safety" ); +} + +static void +test_cbm_ucs2 (void) +{ + g_autoptr(GError) err = NULL; + MMCbmPart *part; + guint16 serial; + + static const guint8 pdu [] = { + 0x63, 0x40, 0x00, 0x32, 0x59, 0x14, + 0x00, 0x20, 0x04, 0x1f, 0x04, 0x40, 0x04, 0x3e, + 0x04, 0x42, 0x04, 0x4f, 0x04, 0x33, 0x04, 0x3e, + 0x04, 0x3c, 0x00, 0x20, 0x04, 0x34, 0x04, 0x3d, + 0x04, 0x4f, 0x00, 0x20, 0x04, 0x54, 0x00, 0x20, + 0x04, 0x32, 0x04, 0x38, 0x04, 0x41, 0x04, 0x3e, + 0x04, 0x3a, 0x04, 0x30, 0x00, 0x20, 0x04, 0x56, + 0x04, 0x3c, 0x04, 0x3e, 0x04, 0x32, 0x04, 0x56, + 0x04, 0x40, 0x04, 0x3d, 0x04, 0x56, 0x04, 0x41, + 0x04, 0x42, 0x04, 0x4c, 0x00, 0x20, 0x04, 0x40, + 0x04, 0x30, 0x04, 0x3a, 0x04, 0x35, 0x04, 0x42, + 0x04, 0x3d, 0x16, 0x01, 0x00, 0x00}; + + part = mm_cbm_part_new_from_binary_pdu (pdu, G_N_ELEMENTS (pdu), NULL, &err); + g_assert_no_error (err); + g_assert_nonnull (part); + + serial = mm_cbm_part_get_serial (part); + g_assert_cmpuint (CBM_SERIAL_GEO_SCOPE (serial), ==, MM_CBM_GEO_SCOPE_PLMN); + g_assert_true (CBM_SERIAL_MESSAGE_CODE_ALERT (serial)); + g_assert_false (CBM_SERIAL_MESSAGE_CODE_POPUP (serial)); + g_assert_cmpuint (CBM_SERIAL_MESSAGE_CODE (serial), ==, 0x34); + g_assert_cmpuint (CBM_SERIAL_MESSAGE_CODE_UPDATE (serial), ==, 0); + + g_assert_cmpuint (mm_cbm_part_get_channel (part), ==, 50); + + g_assert_cmpuint (mm_cbm_part_get_num_parts (part), ==, 4); + g_assert_cmpuint (mm_cbm_part_get_part_num (part), ==, 1); + + g_assert_cmpstr (mm_cbm_part_get_text (part), ==, + " Протягом дня є висока імовірність ракетнᘁ"); +} + + +static void +test_cbm_eu (void) +{ + g_autoptr(GError) err = NULL; + MMCbmPart *part; + guint16 serial; + + static const guint8 pdu[] = { + 0x40, 0xC0, 0x11, 0x1F, 0x01, 0x13, + 0xD4, 0xE2, 0x94, 0x0A, 0x0A, 0x32, 0x8B, 0x52, + 0x2A, 0x0B, 0xE4, 0x0C, 0x52, 0x93, 0x4F, 0xE7, + 0x35, 0x49, 0x2C, 0x82, 0x82, 0xCC, 0xA2, 0x94, + 0x0A, 0x22, 0x06, 0xB3, 0x20, 0x19, 0x4C, 0x26, + 0x03, 0x51, 0xD1, 0x75, 0x90, 0x0C, 0x26, 0x93, + 0xBD, 0x62, 0xB2, 0x17, 0x0C, 0x07, 0x6A, 0x81, + 0x62, 0x30, 0x5D, 0x2D, 0x07, 0x0A, 0xB7, 0x41, + 0x2D, 0x10, 0xB5, 0x3C, 0xA7, 0x83, 0xC2, 0xEC, + 0xB2, 0x9C, 0x0E, 0x6A, 0x81, 0xCC, 0x6F, 0x39, + 0x88, 0x58, 0xAE, 0xD3, 0xE7, 0x63, 0x34, 0x3B, + 0xEC, 0x06, + }; + + part = mm_cbm_part_new_from_binary_pdu (pdu, G_N_ELEMENTS (pdu), NULL, &err); + g_assert_no_error (err); + g_assert_nonnull (part); + + serial = mm_cbm_part_get_serial (part); + g_assert_cmpuint (CBM_SERIAL_GEO_SCOPE (serial), ==, MM_CBM_GEO_SCOPE_PLMN); + g_assert_false (CBM_SERIAL_MESSAGE_CODE_ALERT (serial)); + g_assert_false (CBM_SERIAL_MESSAGE_CODE_POPUP (serial)); + g_assert_cmpuint (CBM_SERIAL_MESSAGE_CODE (serial), ==, 0x0C); + g_assert_cmpuint (CBM_SERIAL_MESSAGE_CODE_UPDATE (serial), ==, 0); + + /* DE: Emergency alert */ + g_assert_cmpuint (mm_cbm_part_get_channel (part), ==, 4383); + + g_assert_cmpuint (mm_cbm_part_get_num_parts (part), ==, 3); + g_assert_cmpuint (mm_cbm_part_get_part_num (part), ==, 1); + + g_assert_cmpstr (mm_cbm_part_get_text (part), ==, + "TEST ALERT, NATIONWIDE ALERT DAY 2022 Thu 2022/12/08 - 10:59 am - Test alert - for Deutschlan"); +} + +static void +parse_cbm (const char *str, MMCbmPart **part) +{ + g_autoptr(GRegex) r = mm_3gpp_cbm_regex_get (); + g_autoptr(GMatchInfo) match_info = NULL; + g_autoptr(GError) err = NULL; + g_autofree char *pdu = NULL; + + g_assert_true (g_regex_match (r, str, 0, &match_info)); + g_assert_true (g_match_info_matches (match_info)); + + pdu = g_match_info_fetch (match_info, 2); + g_assert (pdu); + + *part = mm_cbm_part_new_from_pdu (pdu, NULL, &err); + g_assert_no_error (err); + g_assert (*part); +} + +static void +test_cbm_nl_2023 (void) +{ + MMCbmPart *part; + guint16 serial; + + parse_cbm ("\r\n+CBM: 88\r\n46A0111305134E662BC82ECBE92018AD1593B56430D90C1493E960301D885A9C528545697288A4BA40C432E86D2FCBD1E53419740F87E5F331BA7EA783D465103DAD2697DD7390FBFD26CFD3F47A989E2ECF41F67418E404\r\n", &part); + serial = mm_cbm_part_get_serial (part); + g_assert_cmpuint (CBM_SERIAL_GEO_SCOPE (serial), ==, MM_CBM_GEO_SCOPE_PLMN); + g_assert_false (CBM_SERIAL_MESSAGE_CODE_ALERT (serial)); + g_assert_false (CBM_SERIAL_MESSAGE_CODE_POPUP (serial)); + g_assert_cmpuint (CBM_SERIAL_MESSAGE_CODE (serial), ==, 0x6A); + g_assert_cmpuint (CBM_SERIAL_MESSAGE_CODE_UPDATE (serial), ==, 0); + /* NL: NL-Alert */ + g_assert_cmpuint (mm_cbm_part_get_channel (part), ==, 4371); + g_assert_cmpuint (mm_cbm_part_get_num_parts (part), ==, 3); + g_assert_cmpuint (mm_cbm_part_get_part_num (part), ==, 1); + g_assert_cmpstr (mm_cbm_part_get_text (part), ==, + "NL-Alert 04-12-2023 12:00: TESTBERICHT. De overheid waarschuwt je tijdens noodsituaties via N"); + mm_cbm_part_free (part); + + parse_cbm ("\r\n+CBM: 88\r\n46A011130523CC56905D96D35D206519C42E97E7741039EC06DDC37490BA0C6ABFCB7410F95D7683CA6ED03D1C9683D46550BB5C9683D26EF35BDE0ED3D365D03AEC06D9D36E72D9ED02A9542A10B538A5829AC5E9347804\r\n", &part); + serial = mm_cbm_part_get_serial (part); + g_assert_cmpuint (CBM_SERIAL_GEO_SCOPE (serial), ==, MM_CBM_GEO_SCOPE_PLMN); + g_assert_false (CBM_SERIAL_MESSAGE_CODE_ALERT (serial)); + g_assert_false (CBM_SERIAL_MESSAGE_CODE_POPUP (serial)); + g_assert_cmpuint (CBM_SERIAL_MESSAGE_CODE (serial), ==, 0x6A); + g_assert_cmpuint (CBM_SERIAL_MESSAGE_CODE_UPDATE (serial), ==, 0); + g_assert_cmpuint (mm_cbm_part_get_channel (part), ==, 4371); + g_assert_cmpuint (mm_cbm_part_get_num_parts (part), ==, 3); + g_assert_cmpuint (mm_cbm_part_get_part_num (part), ==, 2); + g_assert_cmpstr (mm_cbm_part_get_text (part), ==, + "L-Alert. Je leest dan wat je moet doen en waar je meer informatie kan vinden. *** TEST MESSAG"); + mm_cbm_part_free (part); + + parse_cbm ("\r\n+CBM: 65\r\n46A0111305334590B34C4797E5ECB09B3C071DDFF6B2DCDD2EBBE920685DCC4E8F41D7B0DC9D769F41D3FC9C5E6EBB40CE37283CA6A7DF6E90BC1CAFA7E565B2AB\r\n", &part); + serial = mm_cbm_part_get_serial (part); + g_assert_cmpuint (CBM_SERIAL_GEO_SCOPE (serial), ==, MM_CBM_GEO_SCOPE_PLMN); + g_assert_false (CBM_SERIAL_MESSAGE_CODE_ALERT (serial)); + g_assert_false (CBM_SERIAL_MESSAGE_CODE_POPUP (serial)); + g_assert_cmpuint (CBM_SERIAL_MESSAGE_CODE (serial), ==, 0x6A); + g_assert_cmpuint (CBM_SERIAL_MESSAGE_CODE_UPDATE (serial), ==, 0); + g_assert_cmpuint (mm_cbm_part_get_channel (part), ==, 4371); + g_assert_cmpuint (mm_cbm_part_get_num_parts (part), ==, 3); + g_assert_cmpuint (mm_cbm_part_get_part_num (part), ==, 3); + g_assert_cmpstr (mm_cbm_part_get_text (part), ==, + "E Netherlands Government Public Warning System. No action required." ); + mm_cbm_part_free (part); +} + +int main (int argc, char **argv) +{ + setlocale (LC_ALL, ""); + + g_test_init (&argc, &argv, NULL); + + /* First part of ontario alert: */ + /* https://gitlab.freedesktop.org/mobile-broadband/ModemManager/-/issues/253#note_1161764 */ + g_test_add_func ("/MM/CBM/PDU-Parser/CBM-CA", test_cbm_ca); + /* UCS2 message: */ + /* https://github.com/the-modem-distro/meta-qcom/blob/9d17dfa55599fe4708806a6f4103fee6cc2830f8/recipes-modem/openqti/files/src/chat_helpers.c#L416 */ + g_test_add_func ("/MM/CBM/PDU-Parser/UCS2", test_cbm_ucs2); + /* First part of EU alert: */ + /* https://source.puri.sm/Librem5/OS-issues/-/issues/303 */ + g_test_add_func ("/MM/CBM/PDU-Parser/CBM-EU", test_cbm_eu); + /* 2023 NL alert: */ + /* https://gitlab.freedesktop.org/mobile-broadband/ModemManager/-/issues/253#note_2192474 */ + g_test_add_func ("/MM/CBM/PDU-Parser/CBM-NL", test_cbm_nl_2023); + + return g_test_run (); +} |