FreeCalypso > hg > sms-coding-utils
changeset 29:aae078d9eaa6
immigrate sms-pdu-decode and pcm-sms-decode here
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Thu, 13 Jun 2024 02:39:21 +0000 |
parents | 6e925aa54727 |
children | d7571dc2fecc |
files | .hgignore Makefile decode/Makefile decode/pcm-sms-decode.c decode/pdu-common.c decode/sms-pdu-decode.c |
diffstat | 6 files changed, 593 insertions(+), 1 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgignore Thu Jun 13 02:32:11 2024 +0000 +++ b/.hgignore Thu Jun 13 02:39:21 2024 +0000 @@ -3,5 +3,7 @@ \.[oa]$ ^config\.defs$ +^decode/pcm-sms-decode$ +^decode/sms-pdu-decode$ ^enc-text/sms-encode-text$ ^gen-pdu/sms-gen-tpdu$
--- a/Makefile Thu Jun 13 02:32:11 2024 +0000 +++ b/Makefile Thu Jun 13 02:39:21 2024 +0000 @@ -1,10 +1,11 @@ -PROGDIR=enc-text gen-pdu scripts +PROGDIR=decode enc-text gen-pdu scripts LIBDIR= libcoding SUBDIR= ${PROGDIR} ${LIBDIR} DESTDIR= all: ${SUBDIR} +decode: libcoding enc-text: libcoding gen-pdu: libcoding
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/decode/Makefile Thu Jun 13 02:39:21 2024 +0000 @@ -0,0 +1,21 @@ +PROGS= pcm-sms-decode sms-pdu-decode +LIB= ../libcoding/libcoding.a +OBJS0= pcm-sms-decode.o pdu-common.o ${LIB} +OBJS1= pdu-common.o sms-pdu-decode.o ${LIB} + +include ../config.defs + +all: ${PROGS} + +pcm-sms-decode: ${OBJS0} + ${CC} ${CFLAGS} -o $@ ${OBJS0} + +sms-pdu-decode: ${OBJS1} + ${CC} ${CFLAGS} -o $@ ${OBJS1} + +install: + mkdir -p ${DESTDIR}${bindir} + install -c ${PROGS} ${DESTDIR}${bindir} + +clean: + rm -f ${PROGS} *.o *errs *.out
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/decode/pcm-sms-decode.c Thu Jun 13 02:39:21 2024 +0000 @@ -0,0 +1,78 @@ +#include <sys/types.h> +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <unistd.h> + +extern int ascii_ext_mode, global_hexdump_mode; +extern u_char pdu[176]; +extern unsigned pdu_length; + +static char *infname; +static FILE *inf; +static unsigned start_recno; + +static char *msgtype[4] = {"received", "received unread", "sent", + "stored unsent"}; + +static +process_cmdline(argc, argv) + char **argv; +{ + int c; + extern int optind; + + while ((c = getopt(argc, argv, "ehsu")) != EOF) + switch (c) { + case 'e': + ascii_ext_mode = 1; + continue; + case 'h': + global_hexdump_mode = 1; + continue; + case 's': + start_recno = 1; + continue; + case 'u': + ascii_ext_mode = 2; + continue; + default: + fprintf(stderr, "%s: invalid option\n", argv[0]); + exit(1); + } + if (argc != optind + 1) { + fprintf(stderr, "usage: %s [options] pcm-sms-binfile\n", + argv[0]); + exit(1); + } + infname = argv[optind]; +} + +main(argc, argv) + char **argv; +{ + u_char record[176]; + unsigned recno; + + process_cmdline(argc, argv); + inf = fopen(infname, "r"); + if (!inf) { + perror(infname); + exit(1); + } + pdu_length = 176; + for (recno = start_recno; fread(record, sizeof record, 1, inf); + recno++) { + if (record[0] & 1) { + printf("Record #%u is %s message:\n", recno, + msgtype[(record[0] >> 1) & 3]); + bcopy(record + 1, pdu, 175); + process_pdu(0, 1); + putchar('\n'); + } else + printf("Record #%u is empty\n\n", recno); + } + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/decode/pdu-common.c Thu Jun 13 02:39:21 2024 +0000 @@ -0,0 +1,391 @@ +#include <sys/types.h> +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> + +int ascii_ext_mode, global_hexdump_mode; + +u_char pdu[176]; +unsigned pdu_length; + +static u_char first_octet; +static unsigned pdu_ptr; +static int dcs_distilled; + +static +handle_sca() +{ + unsigned sca_len; + char digits[21]; + + sca_len = pdu[0]; + pdu_ptr = 1; + if (!sca_len) + return(0); + if (sca_len < 2 || sca_len > 11) { + printf("Decode-Error: invalid SCA length\n"); + return(-1); + } + if (pdu_ptr + sca_len > pdu_length) { + printf("Decode-Error: SCA goes past PDU end\n"); + return(-1); + } + pdu_ptr += sca_len; + decode_address_digits(pdu + 2, digits, sc_addr_ndigits(pdu)); + printf("SCA: %s%s (type 0x%02X)\n", pdu[1] == 0x91 ? "+" : "", digits, + pdu[1]); + return(0); +} + +static +handle_first_octet() +{ + if (pdu_ptr >= pdu_length) { + printf("Decode-Error: end of PDU before FO\n"); + return(-1); + } + first_octet = pdu[pdu_ptr++]; + printf("First-Octet: 0x%02X\n", first_octet); + return(0); +} + +static +handle_mr() +{ + if (pdu_ptr >= pdu_length) { + printf("Decode-Error: end of PDU before MR\n"); + return(-1); + } + printf("MR: 0x%02X\n", pdu[pdu_ptr++]); + return(0); +} + +static +handle_user_addr(direction) + char *direction; +{ + unsigned addr_field_len, alpha_nsep; + char digits[21]; + u_char alpha_gsm7[11]; + + if (pdu_ptr >= pdu_length) { + printf("Decode-Error: end of PDU before %s address\n", + direction); + return(-1); + } + if (pdu[pdu_ptr] > 20) { + printf("Decode-Error: %s address > 20 digits\n", direction); + return(-1); + } + addr_field_len = ((pdu[pdu_ptr] + 1) >> 1) + 2; + if (pdu_ptr + addr_field_len > pdu_length) { + printf("Decode-Error: %s address goes past PDU end\n", + direction); + return(-1); + } + if (!pdu[pdu_ptr]) + printf("%s: empty-addr (type 0x%02X)\n", direction, + pdu[pdu_ptr+1]); + else if ((pdu[pdu_ptr+1] & 0x70) == 0x50 && + alpha_addr_valid(pdu[pdu_ptr], &alpha_nsep)) { + gsm7_unpack(pdu + pdu_ptr + 2, alpha_gsm7, alpha_nsep); + printf("%s: ", direction); + print_gsm7_string_to_file(alpha_gsm7, alpha_nsep, stdout); + printf(" (type 0x%02X)\n", pdu[pdu_ptr+1]); + } else { + decode_address_digits(pdu + pdu_ptr + 2, digits, pdu[pdu_ptr]); + printf("%s: %s%s (type 0x%02X)\n", direction, + pdu[pdu_ptr+1] == 0x91 ? "+" : "", digits, + pdu[pdu_ptr+1]); + } + pdu_ptr += addr_field_len; + return(0); +} + +static +handle_pid() +{ + if (pdu_ptr >= pdu_length) { + printf("Decode-Error: end of PDU before PID\n"); + return(-1); + } + printf("PID: 0x%02X\n", pdu[pdu_ptr++]); + return(0); +} + +static +handle_dcs() +{ + u_char dcs; + char *strtype; + + if (pdu_ptr >= pdu_length) { + printf("Decode-Error: end of PDU before DCS\n"); + return(-1); + } + dcs = pdu[pdu_ptr++]; + dcs_distilled = sms_dcs_classify(dcs); + switch (dcs_distilled) { + case 7: + strtype = "7-bit"; + break; + case 8: + strtype = "raw octets"; + break; + case 9: + strtype = "compressed"; + break; + case 16: + strtype = "UCS-2"; + break; + } + printf("DCS: 0x%02X (%s)\n", dcs, strtype); + return(0); +} + +static +handle_scts() +{ + char str[21]; + + if (pdu_ptr + 7 > pdu_length) { + printf("Decode-Error: end of PDU before SCTS\n"); + return(-1); + } + gsm_timestamp_decode(pdu + pdu_ptr, str); + printf("SC-Timestamp: %s\n", str); + pdu_ptr += 7; + return(0); +} + +static +handle_vp_abs() +{ + char str[21]; + + if (pdu_ptr + 7 > pdu_length) { + printf("Decode-Error: end of PDU before VP-abs\n"); + return(-1); + } + gsm_timestamp_decode(pdu + pdu_ptr, str); + printf("VP-Absolute: %s\n", str); + pdu_ptr += 7; + return(0); +} + +static +handle_vp_rel() +{ + unsigned vprel, hours, min; + + if (pdu_ptr >= pdu_length) { + printf("Decode-Error: end of PDU before VP-rel\n"); + return(-1); + } + vprel = pdu[pdu_ptr++]; + if (vprel <= 143) { + min = (vprel + 1) * 5; + goto hhmm; + } else if (vprel <= 167) { + min = (vprel - 143) * 30 + 12 * 60; + goto hhmm; + } else if (vprel <= 196) { + printf("VP-Relative: %u days\n", vprel - 166); + return(0); + } else { + printf("VP-Relative: %u weeks\n", vprel - 192); + return(0); + } + +hhmm: hours = min / 60; + min %= 60; + printf("VP-Relative:"); + if (hours) + printf(" %u hour%s", hours, hours != 1 ? "s" : ""); + if (min) + printf(" %u min", min); + putchar('\n'); + return(0); +} + +static +handle_vp_enh() +{ + if (pdu_ptr + 7 > pdu_length) { + printf("Decode-Error: end of PDU before VP-enh\n"); + return(-1); + } + printf("VP-Enhanced: %02X %02X %02X %02X %02X %02X %02X\n", + pdu[pdu_ptr], pdu[pdu_ptr+1], pdu[pdu_ptr+2], pdu[pdu_ptr+3], + pdu[pdu_ptr+4], pdu[pdu_ptr+5], pdu[pdu_ptr+6]); + pdu_ptr += 7; + return(0); +} + +static +handle_vp() +{ + int rc; + + switch (first_octet & 0x18) { + case 0x00: + rc = 0; + break; + case 0x08: + rc = handle_vp_enh(); + break; + case 0x10: + rc = handle_vp_rel(); + break; + case 0x18: + rc = handle_vp_abs(); + break; + } + return(rc); +} + +process_pdu(require_exact_length, expect_sca) +{ + unsigned udl, udl_octets; + unsigned udhl, udh_octets, udh_chars, ud_chars; + u_char ud7[160], decode_buf[481]; + int do_hexdump; + unsigned decoded_len; + + if (expect_sca) { + if (handle_sca() < 0) + return(-1); + } else + pdu_ptr = 0; + if (handle_first_octet() < 0) + return(-1); + if (first_octet & 2) { + printf("Decode-Error: MTI not supported\n"); + return(-1); + } + if (first_octet & 1) { + if (handle_mr() < 0) + return(-1); + } + if (handle_user_addr(first_octet & 1 ? "To" : "From") < 0) + return(-1); + if (handle_pid() < 0) + return(-1); + if (handle_dcs() < 0) + return(-1); + if (first_octet & 1) { + if (handle_vp() < 0) + return(-1); + } else { + if (handle_scts() < 0) + return(-1); + } + if (pdu_ptr >= pdu_length) { + printf("Decode-Error: end of PDU before UDL\n"); + return(-1); + } + udl = pdu[pdu_ptr++]; + if (dcs_distilled == 7) { + if (udl > 160) { + printf("Decode-Error: UDL %u > 160\n", udl); + return(-1); + } + udl_octets = (udl * 7 + 7) / 8; + } else { + if (udl > 140) { + printf("Decode-Error: UDL %u > 140\n", udl); + return(-1); + } + udl_octets = udl; + } + if (require_exact_length && pdu_length - pdu_ptr != udl_octets) { + printf("Decode-Error: UD length in PDU %u != expected %u\n", + pdu_length - pdu_ptr, udl_octets); + return(-1); + } + if (first_octet & 0x40) { + if (!udl) { + printf("Decode-Error: UDHI set with UDL=0\n"); + return(-1); + } + udhl = pdu[pdu_ptr]; + udh_octets = udhl + 1; + if (udh_octets > udl_octets) { + printf("Decode-Error: UDHL exceeds UDL\n"); + return(-1); + } + printf("UDH-Length: %u\n", udhl); + if (dcs_distilled == 7) + udh_chars = (udh_octets * 8 + 6) / 7; + else + udh_chars = udh_octets; + } else { + udhl = 0; + udh_octets = 0; + udh_chars = 0; + } + if (udh_chars >= udl) { + ud_chars = 0; + printf("Length: 0\n"); + } else { + ud_chars = udl - udh_chars; + if (dcs_distilled == 7) + gsm7_unpack(pdu + pdu_ptr, ud7, udl); + if (global_hexdump_mode) + do_hexdump = 1; + else switch (dcs_distilled) { + case 7: + do_hexdump = 0; + break; + case 8: + case 9: + do_hexdump = 1; + break; + case 16: + if (ud_chars & 1) + do_hexdump = 1; + else + do_hexdump = 0; + break; + } + if (do_hexdump) + printf("Length: %u (raw)\n", ud_chars); + else { + switch (dcs_distilled) { + case 7: + gsm7_to_ascii_or_ext(ud7 + udh_chars, ud_chars, + decode_buf, &decoded_len, + ascii_ext_mode, 1); + break; + case 16: + ucs2_to_ascii_or_ext(pdu + pdu_ptr + udh_chars, + ud_chars, + decode_buf, &decoded_len, + ascii_ext_mode, 1); + break; + } + printf("Length: %u", ud_chars); + if (decoded_len != ud_chars) + printf("->%u", decoded_len); + putchar('\n'); + } + } + + if (udhl) { + printf("\nUDH:\n"); + msg_bits_hexdump(pdu + pdu_ptr + 1, udhl); + } + if (!ud_chars) + return(0); + putchar('\n'); + if (do_hexdump) { + if (dcs_distilled == 7) + msg_bits_hexdump(ud7 + udh_chars, ud_chars); + else + msg_bits_hexdump(pdu + pdu_ptr + udh_chars, ud_chars); + } else + puts(decode_buf); + return(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/decode/sms-pdu-decode.c Thu Jun 13 02:39:21 2024 +0000 @@ -0,0 +1,99 @@ +#include <sys/types.h> +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <unistd.h> + +extern int ascii_ext_mode, global_hexdump_mode; +extern u_char pdu[176]; +extern unsigned pdu_length; + +static char *infname; +static FILE *inf; +static int keep_raw_pdu, pdu_has_sca = 1; + +static char input_line[1024]; + +static +process_cmdline(argc, argv) + char **argv; +{ + int c; + extern int optind; + + while ((c = getopt(argc, argv, "ehnpu")) != EOF) + switch (c) { + case 'e': + ascii_ext_mode = 1; + continue; + case 'h': + global_hexdump_mode = 1; + continue; + case 'n': + pdu_has_sca = 0; + continue; + case 'p': + keep_raw_pdu = 1; + continue; + case 'u': + ascii_ext_mode = 2; + continue; + default: + fprintf(stderr, "%s: invalid option\n", argv[0]); + exit(1); + } + if (argc > optind) + infname = argv[optind]; +} + +static +swallow_empty_line() +{ + int c; + + c = getc(inf); + if (c != '\n') + ungetc(c, inf); +} + +main(argc, argv) + char **argv; +{ + char *nl; + int lineno, cc; + + process_cmdline(argc, argv); + if (infname) { + inf = fopen(infname, "r"); + if (!inf) { + perror(infname); + exit(1); + } + } else { + inf = stdin; + infname = "stdin"; + } + for (lineno = 1; fgets(input_line, sizeof input_line, inf); lineno++) { + nl = index(input_line, '\n'); + if (!nl) { + fprintf(stderr, "%s line %d: no newline\n", + infname, lineno); + exit(1); + } + *nl = '\0'; + cc = decode_hex_line(input_line, pdu, sizeof pdu); + if (cc <= 0) { + puts(input_line); + continue; + } + pdu_length = cc; + if (keep_raw_pdu) + printf("%s\n\n", input_line); + process_pdu(1, pdu_has_sca); + putchar('\n'); + swallow_empty_line(); + } + exit(0); +}