diff options
-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 (); +} |