changeset 9:003660a57f99

new program sms-gen-tpdu
author Mychaela Falconia <falcon@freecalypso.org>
date Sat, 05 Aug 2023 07:43:45 +0000
parents 265b8103530c
children 17dd30989c0b
files .hgignore Makefile gen-pdu/Makefile gen-pdu/auto_scts.c gen-pdu/error.h gen-pdu/input.c gen-pdu/main.c gen-pdu/message.c gen-pdu/settings.c
diffstat 9 files changed, 496 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Sat Aug 05 06:40:50 2023 +0000
+++ b/.hgignore	Sat Aug 05 07:43:45 2023 +0000
@@ -3,3 +3,4 @@
 \.[oa]$
 
 ^enc-text/sms-encode-text$
+^gen-pdu/sms-gen-tpdu$
--- a/Makefile	Sat Aug 05 06:40:50 2023 +0000
+++ b/Makefile	Sat Aug 05 07:43:45 2023 +0000
@@ -1,6 +1,6 @@
 CC=	gcc
 CFLAGS=	-O2
-PROGDIR=enc-text
+PROGDIR=enc-text gen-pdu
 LIBDIR=	libcoding
 SUBDIR=	${PROGDIR} ${LIBDIR}
 
@@ -9,6 +9,7 @@
 all:	${SUBDIR}
 
 enc-text:	libcoding
+gen-pdu:	libcoding
 
 ${SUBDIR}: FRC
 	cd $@; ${MAKE} ${MFLAGS} CC=${CC} CFLAGS="${CFLAGS}"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gen-pdu/Makefile	Sat Aug 05 07:43:45 2023 +0000
@@ -0,0 +1,21 @@
+CC=	gcc
+CFLAGS=	-O2
+PROG=	sms-gen-tpdu
+OBJS=	auto_scts.o input.o main.o message.o settings.o
+LIBS=	../libcoding/libcoding.a
+
+INSTALL_PREFIX=	/opt/freecalypso
+
+INSTBIN=${INSTALL_PREFIX}/bin
+
+all:	${PROG}
+
+${PROG}:	${OBJS} ${LIBS}
+	${CC} ${CFLAGS} -o $@ ${OBJS} ${LIBS}
+
+install:	${PROG}
+	mkdir -p ${INSTBIN}
+	install -c ${PROG} ${INSTBIN}
+
+clean:
+	rm -f *.o *.out *errs ${PROG}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gen-pdu/auto_scts.c	Sat Aug 05 07:43:45 2023 +0000
@@ -0,0 +1,27 @@
+/*
+ * This module implements automatic generation of SC-Timestamp
+ * based on the current time.
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <time.h>
+
+extern u_char scts_buf[7];
+extern int scts_is_set;
+
+void
+set_auto_scts()
+{
+	time_t unixtime;
+	struct tm *tm;
+	char timestr[32];
+
+	time(&unixtime);
+	tm = localtime(&unixtime);
+	sprintf(timestr, "%02d/%02d/%02d,%02d:%02d:%02d%+03d",
+		tm->tm_year % 100, tm->tm_mon + 1, tm->tm_mday,
+		tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_gmtoff / (15*60));
+	encode_gsm_sms_abstime(timestr, scts_buf);
+	scts_is_set = 1;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gen-pdu/error.h	Sat Aug 05 07:43:45 2023 +0000
@@ -0,0 +1,3 @@
+/* some definitions for error handling */
+
+#define	ERR_PREFIX	"sms-gen-tpdu input line %d: "
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gen-pdu/input.c	Sat Aug 05 07:43:45 2023 +0000
@@ -0,0 +1,113 @@
+/*
+ * This module implements input handling for sms-gen-tpdu.
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include "error.h"
+
+extern char input_line[];
+extern int input_lineno;
+
+extern void set_sc_addr();
+extern void set_user_addr();
+extern void set_mr_byte();
+extern void set_pid_byte();
+extern void set_dcs();
+extern void set_scts();
+extern void cmd_msg_plain();
+extern void cmd_msg_udh();
+
+static struct cmdtab {
+	char *cmd;
+	int minargs;
+	int maxargs;
+	void (*func)();
+} cmdtab[] = {
+	{"sc-addr", 1, 1, set_sc_addr},
+	{"user-addr", 1, 1, set_user_addr},
+	{"mr", 1, 1, set_mr_byte},
+	{"pid", 1, 1, set_pid_byte},
+	{"dcs", 2, 2, set_dcs},
+	{"sc-ts", 1, 1, set_scts},
+	{"msg", 1, 1, cmd_msg_plain},
+	{"msg-udh", 1, 1, cmd_msg_udh},
+	/* table search terminator */
+	{0, 0, 0, 0}
+};
+
+void
+process_input_line()
+{
+	char *argv[10];
+	char *cp, **ap;
+	struct cmdtab *tp;
+
+	cp = index(input_line, '\n');
+	if (!cp) {
+		fprintf(stderr, ERR_PREFIX "missing newline\n", input_lineno);
+		exit(1);
+	}
+	for (cp = input_line; isspace(*cp); cp++)
+		;
+	if (*cp == '\0' || *cp == '#')
+		return;
+	argv[0] = cp;
+	while (*cp && !isspace(*cp))
+		cp++;
+	if (*cp)
+		*cp++ = '\0';
+	for (tp = cmdtab; tp->cmd; tp++)
+		if (!strcmp(tp->cmd, argv[0]))
+			break;
+	if (!tp->func) {
+		fprintf(stderr, ERR_PREFIX "invalid command \"%s\"\n",
+			input_lineno, argv[0]);
+		exit(1);
+	}
+	for (ap = argv + 1; ; ) {
+		while (isspace(*cp))
+			cp++;
+		if (!*cp || *cp == '#')
+			break;
+		if (ap - argv - 1 >= tp->maxargs) {
+			fprintf(stderr, ERR_PREFIX "too many arguments\n",
+				input_lineno);
+			exit(1);
+		}
+		if (*cp == '"') {
+			*ap++ = ++cp;
+			for (;;) {
+				if (!*cp) {
+unterm_qstring:				fprintf(stderr, ERR_PREFIX
+						"unterminated quoted string\n",
+						input_lineno);
+					exit(1);
+				}
+				if (*cp == '"')
+					break;
+				if (*cp++ == '\\') {
+					if (!*cp)
+						goto unterm_qstring;
+					cp++;
+				}
+			}
+			*cp++ = '\0';
+		} else {
+			*ap++ = cp;
+			while (*cp && !isspace(*cp))
+				cp++;
+			if (*cp)
+				*cp++ = '\0';
+		}
+	}
+	if (ap - argv - 1 < tp->minargs) {
+		fprintf(stderr, ERR_PREFIX "too few arguments\n", input_lineno);
+		exit(1);
+	}
+	*ap = 0;
+	tp->func(ap - argv, argv);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gen-pdu/main.c	Sat Aug 05 07:43:45 2023 +0000
@@ -0,0 +1,58 @@
+/*
+ * This C file is the main module for sms-gen-tpdu utility.
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+
+int dir_mo, include_sca;
+u_char sc_addr[12], user_addr[12];
+u_char mr_byte, pid_byte, dcs_byte;
+u_char scts_buf[7];
+int is_septet, scts_is_set;
+
+char input_line[512];
+int input_lineno;
+
+static void
+init_defaults()
+{
+	sc_addr[0] = 0;
+	user_addr[0] = 0;
+	user_addr[1] = 0x80;
+	mr_byte = 0xFF;
+	pid_byte = 0;
+	dcs_byte = 0;
+	is_septet = 1;
+}
+
+main(argc, argv)
+	char **argv;
+{
+	if (argc != 2) {
+usage:		fprintf(stderr, "usage: %s mo|mt|sc-mo|sc-mt\n", argv[0]);
+		exit(1);
+	}
+	if (!strcmp(argv[1], "mo")) {
+		dir_mo = 1;
+		include_sca = 0;
+	} else if (!strcmp(argv[1], "mt")) {
+		dir_mo = 0;
+		include_sca = 0;
+	} else if (!strcmp(argv[1], "sc-mo")) {
+		dir_mo = 1;
+		include_sca = 1;
+	} else if (!strcmp(argv[1], "sc-mt")) {
+		dir_mo = 0;
+		include_sca = 1;
+	} else
+		goto usage;
+	init_defaults();
+	for (input_lineno = 1; fgets(input_line, sizeof input_line, stdin);
+	     input_lineno++)
+		process_input_line();
+	exit(0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gen-pdu/message.c	Sat Aug 05 07:43:45 2023 +0000
@@ -0,0 +1,142 @@
+/*
+ * This module implements TPDU encoding of actual messages, after all
+ * settings have been captured.
+ */
+
+#include <sys/types.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include "error.h"
+
+extern int dir_mo, include_sca;
+extern u_char sc_addr[12], user_addr[12];
+extern u_char mr_byte, pid_byte, dcs_byte;
+extern u_char scts_buf[7];
+extern int is_septet, scts_is_set;
+
+extern int input_lineno;
+
+static void
+emit_first_octet(udhi)
+{
+	u_char fo;
+
+	if (dir_mo)
+		fo = 1;
+	else
+		fo = 0;
+	if (udhi)
+		fo |= 0x40;
+	printf("%02X", fo);
+}
+
+static void
+make_pdu(udl, ud_buf, ud_octets, udhi)
+	u_char *ud_buf;
+	unsigned udl, ud_octets;
+{
+	if (include_sca)
+		emit_hex_out(sc_addr, sc_addr[0] + 1, stdout);
+	emit_first_octet(udhi);
+	if (dir_mo)
+		printf("%02X", mr_byte);
+	emit_hex_out(user_addr, ((user_addr[0] + 1) >> 1) + 2, stdout);
+	printf("%02X", pid_byte);
+	printf("%02X", dcs_byte);
+	if (!dir_mo) {
+		if (!scts_is_set)
+			set_auto_scts();
+		emit_hex_out(scts_buf, 7, stdout);
+	}
+	printf("%02X", udl);
+	emit_hex_out(ud_buf, ud_octets, stdout);
+	putchar('\n');
+}
+
+static void
+cmd_msg_common(arg, udhi)
+	char *arg;
+{
+	u_char input[160], ud7[160], octbuf[140];
+	unsigned input_len, udhl, udhl1, udh_chars, plain_chars;
+	unsigned udl, udl_octets;
+
+	for (input_len = 0; ; input_len++) {
+		while (isspace(*arg))
+			arg++;
+		if (!*arg)
+			break;
+		if (!isxdigit(arg[0]) || !isxdigit(arg[1])) {
+			fprintf(stderr, ERR_PREFIX "invalid hex string\n",
+				input_lineno);
+			exit(1);
+		}
+		if (input_len >= 160) {
+toolong:		fprintf(stderr, ERR_PREFIX "hex string is too long\n",
+				input_lineno);
+			exit(1);
+		}
+		input[input_len] = (decode_hex_digit(arg[0]) << 4) |
+				    decode_hex_digit(arg[1]);
+		arg += 2;
+	}
+	if (!is_septet && input_len > 140)
+		goto toolong;
+	if (udhi) {
+		if (!input_len) {
+			fprintf(stderr, ERR_PREFIX
+				"empty message is invalid with UDHI\n",
+				input_lineno);
+			exit(1);
+		}
+		udhl = input[0];
+		udhl1 = udhl + 1;
+		if (udhl1 > input_len) {
+			fprintf(stderr, ERR_PREFIX "UDHL exceeds UD length\n",
+				input_lineno);
+			exit(1);
+		}
+	}
+	if (!is_septet) {
+		make_pdu(input_len, input, input_len, udhi);
+		return;
+	}
+	if (udhi)
+		udh_chars = (udhl1 * 8 + 6) / 7;
+	else {
+		udhl1 = 0;
+		udh_chars = 0;
+	}
+	plain_chars = input_len - udhl1;
+	udl = udh_chars + plain_chars;
+	if (udl > 160) {
+		fprintf(stderr, ERR_PREFIX
+			"message exceeds 160 septets after UDH\n",
+			input_lineno);
+		exit(1);
+	}
+	udl_octets = (udl * 7 + 7) / 8;
+	bzero(ud7, 160);
+	bcopy(input + udhl1, ud7 + udh_chars, plain_chars);
+	gsm7_pack(ud7, octbuf, udl_octets);
+	if (udhi)
+		bcopy(input, octbuf, udhl1);
+	make_pdu(udl, ud7, udl_octets, udhi);
+}
+
+void
+cmd_msg_plain(argc, argv)
+	char **argv;
+{
+	cmd_msg_common(argv[1], 0);
+}
+
+void
+cmd_msg_udh(argc, argv)
+	char **argv;
+{
+	cmd_msg_common(argv[1], 1);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gen-pdu/settings.c	Sat Aug 05 07:43:45 2023 +0000
@@ -0,0 +1,129 @@
+/*
+ * This module implements functions for various settings that come before
+ * msg or msg-udh lines.
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include "error.h"
+
+extern int dir_mo, include_sca;
+extern u_char sc_addr[12], user_addr[12];
+extern u_char mr_byte, pid_byte, dcs_byte;
+extern u_char scts_buf[7];
+extern int is_septet, scts_is_set;
+
+extern int input_lineno;
+
+void
+set_sc_addr(argc, argv)
+	char **argv;
+{
+	int rc;
+
+	if (!include_sca) {
+		fprintf(stderr, ERR_PREFIX
+			"sc-addr is not allowed in bare TPDU mode\n",
+			input_lineno);
+		exit(1);
+	}
+	rc = encode_phone_number_arg(argv[1], sc_addr, 0);
+	if (rc < 0) {
+		fprintf(stderr, ERR_PREFIX "invalid phone number argument\n",
+			input_lineno);
+		exit(1);
+	}
+}
+
+void
+set_user_addr(argc, argv)
+	char **argv;
+{
+	int rc;
+
+	rc = encode_phone_number_arg(argv[1], user_addr, 1);
+	if (rc < 0) {
+		fprintf(stderr, ERR_PREFIX "invalid phone number argument\n",
+			input_lineno);
+		exit(1);
+	}
+}
+
+void
+set_mr_byte(argc, argv)
+	char **argv;
+{
+	char *endp;
+
+	if (!dir_mo) {
+		fprintf(stderr, ERR_PREFIX "mr is not allowed in MT mode\n",
+			input_lineno);
+		exit(1);
+	}
+	mr_byte = strtoul(argv[1], &endp, 0);
+	if (*endp) {
+		fprintf(stderr, ERR_PREFIX "invalid byte value argument\n",
+			input_lineno);
+		exit(1);
+	}
+}
+
+void
+set_pid_byte(argc, argv)
+	char **argv;
+{
+	char *endp;
+
+	pid_byte = strtoul(argv[1], &endp, 0);
+	if (*endp) {
+		fprintf(stderr, ERR_PREFIX "invalid byte value argument\n",
+			input_lineno);
+		exit(1);
+	}
+}
+
+void
+set_dcs(argc, argv)
+	char **argv;
+{
+	char *endp;
+
+	dcs_byte = strtoul(argv[1], &endp, 0);
+	if (*endp) {
+		fprintf(stderr, ERR_PREFIX "invalid byte value argument\n",
+			input_lineno);
+		exit(1);
+	}
+	if (!strcmp(argv[2], "septet"))
+		is_septet = 1;
+	else if (!strcmp(argv[2], "octet"))
+		is_septet = 0;
+	else {
+		fprintf(stderr, ERR_PREFIX "invalid septet/octet mode kw\n",
+			input_lineno);
+		exit(1);
+	}
+}
+
+void
+set_scts(argc, argv)
+	char **argv;
+{
+	int rc;
+
+	if (dir_mo) {
+		fprintf(stderr, ERR_PREFIX "sc-ts is not allowed in MO mode\n",
+			input_lineno);
+		exit(1);
+	}
+	rc = encode_gsm_sms_abstime(argv[1], scts_buf);
+	if (rc < 0) {
+		fprintf(stderr, ERR_PREFIX "invalid timestamp argument\n",
+			input_lineno);
+		exit(1);
+	}
+	scts_is_set = 1;
+}