changeset 157:f064dbcc5f41

libutil split from libcommon
author Mychaela Falconia <falcon@freecalypso.org>
date Fri, 26 Feb 2021 20:19:58 +0000
parents 5f1f3f6fd865
children 3698c8192d2d
files Makefile libcommon/Makefile libcommon/alpha_decode.c libcommon/alpha_fromfile.c libcommon/alpha_valid.c libcommon/decimal_str.c libcommon/filesearch.c libcommon/gsm7_decode.c libcommon/gsm7_encode.c libcommon/gsm7_encode_table.c libcommon/gsm7_unpack.c libcommon/hexread.c libcommon/hexstr.c libcommon/number_decode.c libcommon/number_encode.c libcommon/pinentry.c libcommon/plmncodes.c libcommon/revnibbles.c libutil/Makefile libutil/alpha_decode.c libutil/alpha_fromfile.c libutil/alpha_valid.c libutil/decimal_str.c libutil/filesearch.c libutil/gsm7_decode.c libutil/gsm7_encode.c libutil/gsm7_encode_table.c libutil/gsm7_unpack.c libutil/hexread.c libutil/hexstr.c libutil/number_decode.c libutil/number_encode.c libutil/pinentry.c libutil/plmncodes.c libutil/revnibbles.c misc/Makefile simtool/Makefile uicc/Makefile
diffstat 38 files changed, 1027 insertions(+), 1015 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile	Thu Feb 25 20:55:10 2021 +0000
+++ b/Makefile	Fri Feb 26 20:19:58 2021 +0000
@@ -1,12 +1,12 @@
 PROGDIR=misc simtool uicc
-LIBDIR=	libcommon
+LIBDIR=	libcommon libutil
 SUBDIR=	${PROGDIR} ${LIBDIR}
 
 all:	${SUBDIR}
 
-misc:		libcommon
-simtool:	libcommon
-uicc:		libcommon
+misc:		libcommon libutil
+simtool:	libcommon libutil
+uicc:		libcommon libutil
 
 ${SUBDIR}: FRC
 	cd $@; ${MAKE} ${MFLAGS}
--- a/libcommon/Makefile	Thu Feb 25 20:55:10 2021 +0000
+++ b/libcommon/Makefile	Fri Feb 26 20:19:58 2021 +0000
@@ -1,11 +1,7 @@
 CC=	gcc
 CFLAGS=	-O2 -I/usr/include/PCSC
-OBJS=	alpha_decode.o alpha_fromfile.o alpha_valid.o apdu.o apducmd.o atr.o \
-	cardconnect.o chkblank.o decimal_str.o dumpdirfunc.o exit.o \
-	filesearch.o globalopts.o gsm7_decode.o gsm7_encode.o \
-	gsm7_encode_table.o gsm7_unpack.o hexdump.o hexread.o hexstr.o \
-	localcd.o names.o number_decode.o number_encode.o pinentry.o \
-	plmncodes.o revnibbles.o
+OBJS=	apdu.o apducmd.o atr.o cardconnect.o chkblank.o dumpdirfunc.o exit.o \
+	globalopts.o hexdump.o localcd.o names.o
 LIB=	libcommon.a
 
 all:	${LIB}
--- a/libcommon/alpha_decode.c	Thu Feb 25 20:55:10 2021 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,38 +0,0 @@
-/*
- * This module contains functions for decoding and displaying alpha fields
- * that exist in various SIM files.
- */
-
-#include <sys/types.h>
-#include <stdio.h>
-
-static void
-print_alpha_field_hex(data, nbytes, outf)
-	u_char *data;
-	unsigned nbytes;
-	FILE *outf;
-{
-	u_char *dp, *endp;
-
-	fputs("HEX ", outf);
-	dp = data;
-	endp = data + nbytes;
-	while (dp < endp)
-		fprintf(outf, "%02X", *dp++);
-}
-
-void
-print_alpha_field(data, nbytes, outf)
-	u_char *data;
-	unsigned nbytes;
-	FILE *outf;
-{
-	if (!nbytes) {
-		fputs("\"\"", outf);
-		return;
-	}
-	if (data[0] & 0x80)
-		print_alpha_field_hex(data, nbytes, outf);
-	else
-		print_gsm7_string_to_file(data, nbytes, outf);
-}
--- a/libcommon/alpha_fromfile.c	Thu Feb 25 20:55:10 2021 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,107 +0,0 @@
-/*
- * This module implements functions for parsing alpha tag strings
- * from input data files, to be used by commands like pb-update
- * and smsp-restore.
- */
-
-#include <sys/types.h>
-#include <ctype.h>
-#include <stdio.h>
-
-extern u_char gsm7_encode_table[256];
-
-char *
-alpha_from_file_qstring(cp, record, maxlen, filename_for_errs, lineno_for_errs)
-	char *cp, *filename_for_errs;
-	u_char *record;
-	unsigned maxlen;
-{
-	unsigned acclen, nadd;
-	int c;
-
-	for (acclen = 0; ; ) {
-		if (*cp == '\0') {
-unterm_qstring:		fprintf(stderr,
-				"%s line %d: unterminated quoted string\n",
-				filename_for_errs, lineno_for_errs);
-			return(0);
-		}
-		if (*cp == '"')
-			break;
-		c = *cp++;
-		if (c == '\\') {
-			if (*cp == '\0')
-				goto unterm_qstring;
-			c = *cp++;
-			if (c >= '0' && c <= '7' && isxdigit(*cp)) {
-				c = ((c - '0') << 4) | decode_hex_digit(*cp++);
-				goto bypass_encoding;
-			}
-			switch (c) {
-			case 'n':
-				c = '\n';
-				goto bypass_encoding;
-			case 'r':
-				c = '\r';
-				goto bypass_encoding;
-			case 'e':
-				c = 0x1B;
-				goto bypass_encoding;
-			case '"':
-			case '\\':
-				break;
-			default:
-				fprintf(stderr,
-				"%s line %d: non-understood backslash escape\n",
-					filename_for_errs, lineno_for_errs);
-				return(0);
-			}
-		}
-		c = gsm7_encode_table[c];
-		if (c == 0xFF) {
-			fprintf(stderr,
-	"%s line %d: character in quoted string cannot be encoded in GSM7\n",
-				filename_for_errs, lineno_for_errs);
-			return(0);
-		}
-bypass_encoding:
-		if (c & 0x80)
-			nadd = 2;
-		else
-			nadd = 1;
-		if (acclen + nadd > maxlen) {
-			fprintf(stderr,
-		"%s line %d: alpha tag string is longer than SIM limit\n",
-				filename_for_errs, lineno_for_errs);
-			return(0);
-		}
-		if (c & 0x80)
-			record[acclen++] = 0x1B;
-		record[acclen++] = c & 0x7F;
-	}
-	return(cp + 1);
-}
-
-char *
-alpha_from_file_hex(cp, record, maxlen, filename_for_errs, lineno_for_errs)
-	char *cp, *filename_for_errs;
-	u_char *record;
-	unsigned maxlen;
-{
-	unsigned acclen;
-
-	for (acclen = 0; ; ) {
-		if (!isxdigit(cp[0]) || !isxdigit(cp[1]))
-			break;
-		if (acclen >= maxlen) {
-			fprintf(stderr,
-		"%s line %d: alpha tag string is longer than SIM limit\n",
-				filename_for_errs, lineno_for_errs);
-			return(0);
-		}
-		record[acclen++] = (decode_hex_digit(cp[0]) << 4) |
-				    decode_hex_digit(cp[1]);
-		cp += 2;
-	}
-	return(cp);
-}
--- a/libcommon/alpha_valid.c	Thu Feb 25 20:55:10 2021 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,152 +0,0 @@
-/*
- * This module contains functions for validating alpha fields
- * that exist in various SIM files.
- */
-
-#include <sys/types.h>
-#include <string.h>
-#include <strings.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-static
-validate_classic_gsm(data, nbytes, textlenp)
-	u_char *data;
-	unsigned nbytes, *textlenp;
-{
-	u_char *dp;
-	unsigned n;
-
-	dp = data;
-	for (n = 0; n < nbytes; n++) {
-		if (*dp == 0xFF)
-			break;
-		if (*dp & 0x80)
-			return(-1);
-		dp++;
-	}
-	if (textlenp)
-		*textlenp = n;
-	for (; n < nbytes; n++)
-		if (*dp++ != 0xFF)
-			return(-1);
-	return(0);
-}
-
-static
-validate_ucs2_80(data, nbytes, textlenp)
-	u_char *data;
-	unsigned nbytes, *textlenp;
-{
-	u_char *dp, *endp;
-
-	if (nbytes < 3)
-		return(-1);
-	dp = data + 1;
-	endp = data + nbytes;
-	while (dp < endp) {
-		if (dp + 1 == endp) {
-			if (*dp != 0xFF)
-				return(-1);
-			if (textlenp)
-				*textlenp = dp - data;
-			return(0);
-		}
-		if (dp[0] == 0xFF && dp[1] == 0xFF)
-			break;
-		dp += 2;
-	}
-	if (textlenp)
-		*textlenp = dp - data;
-	while (dp < endp)
-		if (*dp++ != 0xFF)
-			return(-1);
-	return(0);
-}
-
-static
-validate_ucs2_81(data, nbytes, textlenp)
-	u_char *data;
-	unsigned nbytes, *textlenp;
-{
-	u_char *dp, *endp;
-	unsigned textlen;
-
-	if (nbytes < 4)
-		return(-1);
-	if (!data[1])
-		return(-1);
-	textlen = data[1] + 3;
-	if (textlen > nbytes)
-		return(-1);
-	if (textlenp)
-		*textlenp = textlen;
-	dp = data + textlen;
-	endp = data + nbytes;
-	while (dp < endp)
-		if (*dp++ != 0xFF)
-			return(-1);
-	return(0);
-}
-
-static
-validate_ucs2_82(data, nbytes, textlenp)
-	u_char *data;
-	unsigned nbytes, *textlenp;
-{
-	u_char *dp, *endp;
-	unsigned textlen;
-
-	if (nbytes < 5)
-		return(-1);
-	if (!data[1])
-		return(-1);
-	textlen = data[1] + 4;
-	if (textlen > nbytes)
-		return(-1);
-	if (textlenp)
-		*textlenp = textlen;
-	dp = data + textlen;
-	endp = data + nbytes;
-	while (dp < endp)
-		if (*dp++ != 0xFF)
-			return(-1);
-	return(0);
-}
-
-static
-validate_empty(data, nbytes, textlenp)
-	u_char *data;
-	unsigned nbytes, *textlenp;
-{
-	u_char *dp;
-	unsigned n;
-
-	dp = data;
-	for (n = 0; n < nbytes; n++)
-		if (*dp++ != 0xFF)
-			return(-1);
-	if (textlenp)
-		*textlenp = 0;
-	return(0);
-}
-
-validate_alpha_field(data, nbytes, textlenp)
-	u_char *data;
-	unsigned nbytes, *textlenp;
-{
-	if (data[0] < 0x80)
-		return validate_classic_gsm(data, nbytes, textlenp);
-	switch (data[0]) {
-	case 0x80:
-		return validate_ucs2_80(data, nbytes, textlenp);
-	case 0x81:
-		return validate_ucs2_81(data, nbytes, textlenp);
-	case 0x82:
-		return validate_ucs2_82(data, nbytes, textlenp);
-	case 0xFF:
-		return validate_empty(data, nbytes, textlenp);
-	default:
-		return -1;
-	}
-}
--- a/libcommon/decimal_str.c	Thu Feb 25 20:55:10 2021 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-/*
- * This module implements some functions for initial parsing of decimal
- * string arguments, intended for implementation of commands like
- * write-iccid and write-imsi.
- */
-
-#include <sys/types.h>
-#include <ctype.h>
-#include <stdio.h>
-
-parse_decimal_string_arg(arg, dest, maxdigits)
-	char *arg;
-	u_char *dest;
-	unsigned maxdigits;
-{
-	unsigned n, ndig;
-
-	if (!*arg) {
-		fprintf(stderr,
-			"error: empty argument given for decimal string\n");
-		return(-1);
-	}
-	for (n = 0; *arg; ) {
-		if (!isdigit(*arg)) {
-			fprintf(stderr,
-			"error: non-digit char in decimal string argument\n");
-			return(-1);
-		}
-		if (n >= maxdigits) {
-			fprintf(stderr,
-			"error: decimal string exceeds limit of %u digits\n",
-				maxdigits);
-			return(-1);
-		}
-		dest[n++] = *arg++ - '0';
-	}
-	ndig = n;
-	while (n < maxdigits)
-		dest[n++] = 0xF;
-	return ndig;
-}
-
-pack_reversed_nibbles(nibbles, bytes, nbytes)
-	u_char *nibbles, *bytes;
-	unsigned nbytes;
-{
-	u_char *sp, *dp;
-	unsigned n;
-
-	sp = nibbles;
-	dp = bytes;
-	for (n = 0; n < nbytes; n++) {
-		*dp++ = sp[0] | (sp[1] << 4);
-		sp += 2;
-	}
-}
--- a/libcommon/filesearch.c	Thu Feb 25 20:55:10 2021 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,27 +0,0 @@
-/*
- * This module implements the function that searches for files
- * in a dedicated directory for SIM programming scripts.
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <strings.h>
-
-static char script_install_dir[] = "/opt/freecalypso/sim-scripts";
-
-FILE *
-open_script_input_file(req_filename)
-	char *req_filename;
-{
-	char pathbuf[256];
-	FILE *f;
-
-	if (!index(req_filename, '/') && strlen(req_filename) < 128) {
-		sprintf(pathbuf, "%s/%s", script_install_dir, req_filename);
-		f = fopen(pathbuf, "r");
-		if (f)
-			return f;
-	}
-	f = fopen(req_filename, "r");
-	return f;
-}
--- a/libcommon/gsm7_decode.c	Thu Feb 25 20:55:10 2021 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,88 +0,0 @@
-/*
- * This module contains functions for decoding GSM7 strings
- * that exist in various SIM files.
- */
-
-#include <sys/types.h>
-#include <stdio.h>
-
-static char gsm7_decode_table[128] = {
-	'@', 0,   '$',  0,   0,   0,    0,   0,
-	0,   0,   '\n', 0,   0,   '\r', 0,   0,
-	0,   '_', 0,    0,   0,   0,    0,   0,
-	0,   0,   0,    0,   0,   0,    0,   0,
-	' ', '!', '"',  '#', 0,   '%',  '&', 0x27,
-	'(', ')', '*',  '+', ',', '-',  '.', '/',
-	'0', '1', '2',  '3', '4', '5',  '6', '7',
-	'8', '9', ':',  ';', '<', '=',  '>', '?',
-	0,   'A', 'B',  'C', 'D', 'E',  'F', 'G',
-	'H', 'I', 'J',  'K', 'L', 'M',  'N', 'O',
-	'P', 'Q', 'R',  'S', 'T', 'U',  'V', 'W',
-	'X', 'Y', 'Z',  0,   0,   0,    0,   0,
-	0,   'a', 'b',  'c', 'd', 'e',  'f', 'g',
-	'h', 'i', 'j',  'k', 'l', 'm',  'n', 'o',
-	'p', 'q', 'r',  's', 't', 'u',  'v', 'w',
-	'x', 'y', 'z',  0,   0,   0,    0,   0
-};
-
-static char gsm7ext_decode_table[128] = {
-	0,   0, 0, 0, 0,   0, 0, 0, 0,   0,   0, 0, 0,   0,   0,   0,
-	0,   0, 0, 0, '^', 0, 0, 0, 0,   0,   0, 0, 0,   0,   0,   0,
-	0,   0, 0, 0, 0,   0, 0, 0, '{', '}', 0, 0, 0,   0,   0,   '\\',
-	0,   0, 0, 0, 0,   0, 0, 0, 0,   0,   0, 0, '[', '~', ']', 0,
-	'|', 0, 0, 0, 0,   0, 0, 0, 0,   0,   0, 0, 0,   0,   0,   0,
-	0,   0, 0, 0, 0,   0, 0, 0, 0,   0,   0, 0, 0,   0,   0,   0,
-	0,   0, 0, 0, 0,   0, 0, 0, 0,   0,   0, 0, 0,   0,   0,   0,
-	0,   0, 0, 0, 0,   0, 0, 0, 0,   0,   0, 0, 0,   0,   0,   0
-};
-
-void
-print_gsm7_string_to_file(data, nbytes, outf)
-	u_char *data;
-	unsigned nbytes;
-	FILE *outf;
-{
-	u_char *dp, *endp;
-	int b, c;
-
-	dp = data;
-	endp = data + nbytes;
-	putc('"', outf);
-	while (dp < endp) {
-		b = *dp++;
-		if (b == 0x1B) {
-			if (dp >= endp || *dp == 0x1B || *dp == '\n' ||
-			    *dp == '\r') {
-				putc('\\', outf);
-				putc('e', outf);
-				continue;
-			}
-			b = *dp++;
-			c = gsm7ext_decode_table[b];
-			if (!c) {
-				fprintf(outf, "\\e\\%02X", b);
-				continue;
-			}
-		} else {
-			c = gsm7_decode_table[b];
-			if (!c) {
-				fprintf(outf, "\\%02X", b);
-				continue;
-			}
-		}
-		if (c == '\n') {
-			putc('\\', outf);
-			putc('n', outf);
-			continue;
-		}
-		if (c == '\r') {
-			putc('\\', outf);
-			putc('r', outf);
-			continue;
-		}
-		if (c == '"' || c == '\\')
-			putc('\\', outf);
-		putc(c, outf);
-	}
-	putc('"', outf);
-}
--- a/libcommon/gsm7_encode.c	Thu Feb 25 20:55:10 2021 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,76 +0,0 @@
-/*
- * This module implements functions for parsing quoted string
- * arguments intended for GSM7 string encoding, and actually
- * encoding them into GSM7 binary strings.
- */
-
-#include <sys/types.h>
-#include <ctype.h>
-#include <stdio.h>
-
-extern u_char gsm7_encode_table[256];
-
-qstring_arg_to_gsm7(arg, record, maxlen)
-	char *arg;
-	u_char *record;
-	unsigned maxlen;
-{
-	unsigned acclen, nadd;
-	char *cp;
-	int c;
-
-	cp = arg;
-	for (acclen = 0; *cp; ) {
-		c = *cp++;
-		if (c == '\\') {
-			if (*cp == '\0') {
-				fprintf(stderr,
-					"error: dangling backslash escape\n");
-				return(-1);
-			}
-			c = *cp++;
-			if (c >= '0' && c <= '7' && isxdigit(*cp)) {
-				c = ((c - '0') << 4) | decode_hex_digit(*cp++);
-				goto bypass_encoding;
-			}
-			switch (c) {
-			case 'n':
-				c = '\n';
-				goto bypass_encoding;
-			case 'r':
-				c = '\r';
-				goto bypass_encoding;
-			case 'e':
-				c = 0x1B;
-				goto bypass_encoding;
-			case '"':
-			case '\\':
-				break;
-			default:
-				fprintf(stderr,
-				"error: non-understood backslash escape\n");
-				return(-1);
-			}
-		}
-		c = gsm7_encode_table[c];
-		if (c == 0xFF) {
-			fprintf(stderr,
-	"error: character in alpha tag string cannot be encoded in GSM7\n");
-			return(-1);
-		}
-bypass_encoding:
-		if (c & 0x80)
-			nadd = 2;
-		else
-			nadd = 1;
-		if (acclen + nadd > maxlen) {
-			fprintf(stderr,
-			"error: alpha tag string is longer than SIM limit\n");
-			return(-1);
-		}
-		if (c & 0x80)
-			record[acclen++] = 0x1B;
-		record[acclen++] = c & 0x7F;
-	}
-	return(acclen);
-}
--- a/libcommon/gsm7_encode_table.c	Thu Feb 25 20:55:10 2021 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-/*
- * This library module contains the table for encoding from ISO 8859-1
- * into the GSM 7-bit default alphabet (03.38 or 23.038).  High bit set
- * in the output indicates escape encoding, used for ASCII characters
- * [\]^ and {|}~.  0xFF indicates invalid chars.
- */
-
-#include <sys/types.h>
-
-u_char gsm7_encode_table[256] = {
-	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,	/* 0x00 */
-	0xFF, 0xFF, '\n', 0xFF, 0xFF, '\r', 0xFF, 0xFF,
-	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,	/* 0x10 */
-	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-	' ',  '!',  '"',  '#',  0x02, '%',  '&',  0x27,	/* 0x20 */
-	'(',  ')',  '*',  '+',  ',',  '-',  '.',  '/',
-	'0',  '1',  '2',  '3',  '4',  '5',  '6',  '7',	/* 0x30 */
-	'8',  '9',  ':',  ';',  '<',  '=',  '>',  '?',
-	0x00, 'A',  'B',  'C',  'D',  'E',  'F',  'G',	/* 0x40 */
-	'H',  'I',  'J',  'K',  'L',  'M',  'N',  'O',
-	'P',  'Q',  'R',  'S',  'T',  'U',  'V',  'W',	/* 0x50 */
-	'X',  'Y',  'Z',  0xBC, 0xAF, 0xBE, 0x94, 0x11,
-	0xFF, 'a',  'b',  'c',  'd',  'e',  'f',  'g',	/* 0x60 */
-	'h',  'i',  'j',  'k',  'l',  'm',  'n',  'o',
-	'p',  'q',  'r',  's',  't',  'u',  'v',  'w',	/* 0x70 */
-	'x',  'y',  'z',  0xA8, 0xC0, 0xA9, 0xBD, 0xFF,
-	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,	/* 0x80 */
-	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,	/* 0x90 */
-	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-	0xFF, 0x40, 0xFF, 0x01, 0x24, 0x03, 0xFF, 0x5F,	/* 0xA0 */
-	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,	/* 0xB0 */
-	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x60,
-	0xFF, 0xFF, 0xFF, 0xFF, 0x5B, 0x0E, 0x1C, 0x09,	/* 0xC0 */
-	0xFF, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-	0xFF, 0x5D, 0xFF, 0xFF, 0xFF, 0xFF, 0x5C, 0xFF,	/* 0xD0 */
-	0x0B, 0xFF, 0xFF, 0xFF, 0x5E, 0xFF, 0xFF, 0x1E,
-	0x7F, 0xFF, 0xFF, 0xFF, 0x7B, 0x0F, 0x1D, 0xFF,	/* 0xE0 */
-	0x04, 0x05, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xFF,
-	0xFF, 0x7D, 0x08, 0xFF, 0xFF, 0xFF, 0x7C, 0xFF,	/* 0xF0 */
-	0x0C, 0x06, 0xFF, 0xFF, 0x7E, 0xFF, 0xFF, 0xFF
-};
--- a/libcommon/gsm7_unpack.c	Thu Feb 25 20:55:10 2021 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,22 +0,0 @@
-/*
- * This library module implements unpacking of GSM 7-bit data
- * from packed octets.
- */
-
-#include <sys/types.h>
-
-static u_char shift[8] = {0, 7, 6, 5, 4, 3, 2, 1};
-
-gsm7_unpack(inbuf, outbuf, nseptets)
-	u_char *inbuf, *outbuf;
-	unsigned nseptets;
-{
-	u_char *inp = inbuf, *outp = outbuf;
-	unsigned n;
-
-	for (n = 0; n < nseptets; n++) {
-		*outp++ = (((inp[1] << 8) | inp[0]) >> shift[n&7]) & 0x7F;
-		if (n & 7)
-			inp++;
-	}
-}
--- a/libcommon/hexread.c	Thu Feb 25 20:55:10 2021 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,57 +0,0 @@
-/*
- * This module contains the function for reading hex files,
- * to be used in the implementation of manual write commands.
- */
-
-#include <sys/types.h>
-#include <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-extern FILE *open_script_input_file();
-
-read_hex_data_file(filename, databuf, maxlen)
-	char *filename;
-	u_char *databuf;
-	unsigned maxlen;
-{
-	FILE *inf;
-	unsigned count;
-	int c, c2;
-
-	inf = open_script_input_file(filename);
-	if (!inf) {
-		perror(filename);
-		return(-1);
-	}
-	for (count = 0; ; count++) {
-		do
-			c = getc(inf);
-		while (isspace(c));
-		if (c < 0)
-			break;
-		if (!isxdigit(c)) {
-inv_input:		fprintf(stderr, "%s: invalid hex file input\n",
-				filename);
-			fclose(inf);
-			return(-1);
-		}
-		c2 = getc(inf);
-		if (!isxdigit(c2))
-			goto inv_input;
-		if (count >= maxlen) {
-			fprintf(stderr, "%s: hex input data is too long\n",
-				filename);
-			fclose(inf);
-			return(-1);
-		}
-		databuf[count] = (decode_hex_digit(c) << 4) |
-				 decode_hex_digit(c2);
-	}
-	fclose(inf);
-	if (!count) {
-		fprintf(stderr, "%s: no hex data input found\n", filename);
-		return(-1);
-	}
-	return(count);
-}
--- a/libcommon/hexstr.c	Thu Feb 25 20:55:10 2021 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,52 +0,0 @@
-/*
- * This module contains the function for decoding hex strings.
- */
-
-#include <sys/types.h>
-#include <ctype.h>
-#include <string.h>
-#include <strings.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-decode_hex_digit(c)
-{
-	if (c >= '0' && c <= '9')
-		return(c - '0');
-	if (c >= 'A' && c <= 'F')
-		return(c - 'A' + 10);
-	if (c >= 'a' && c <= 'f')
-		return(c - 'a' + 10);
-	return(-1);
-}
-
-decode_hex_data_from_string(arg, databuf, minlen, maxlen)
-	char *arg;
-	u_char *databuf;
-	unsigned minlen, maxlen;
-{
-	unsigned count;
-
-	for (count = 0; ; count++) {
-		while (isspace(*arg))
-			arg++;
-		if (!*arg)
-			break;
-		if (!isxdigit(arg[0]) || !isxdigit(arg[1])) {
-			fprintf(stderr, "error: invalid hex string input\n");
-			return(-1);
-		}
-		if (count >= maxlen) {
-			fprintf(stderr, "error: hex string is too long\n");
-			return(-1);
-		}
-		databuf[count] = (decode_hex_digit(arg[0]) << 4) |
-				 decode_hex_digit(arg[1]);
-		arg += 2;
-	}
-	if (count < minlen) {
-		fprintf(stderr, "error: hex string is too short\n");
-		return(-1);
-	}
-	return(count);
-}
--- a/libcommon/number_decode.c	Thu Feb 25 20:55:10 2021 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +0,0 @@
-/*
- * This module implements functions for decoding phone numbers.
- */
-
-#include <sys/types.h>
-
-static char gsm_address_digits[16] =
-	{'0','1','2','3','4','5','6','7','8','9','*','#','a','b','c','?'};
-
-decode_phone_number(data, nbytes, out)
-	u_char *data;
-	unsigned nbytes;
-	char *out;
-{
-	u_char *dp, *endp;
-	int c;
-
-	dp = data;
-	endp = data + nbytes;
-	while (dp < endp) {
-		c = *dp & 0xF;
-		if (c == 0xF)
-			return(-1);
-		*out++ = gsm_address_digits[c];
-		c = *dp >> 4;
-		if (c == 0xF) {
-			if (dp + 1 == endp)
-				break;
-			else
-				return(-1);
-		}
-		*out++ = gsm_address_digits[c];
-		dp++;
-	}
-	*out = '\0';
-	return(0);
-}
-
-decode_address_digits(inbuf, outbuf, ndigits)
-	u_char *inbuf;
-	char *outbuf;
-	unsigned ndigits;
-{
-	u_char *inp = inbuf;
-	char *outp = outbuf;
-	unsigned n = 0, b;
-
-	while (n < ndigits) {
-		b = *inp++;
-		*outp++ = gsm_address_digits[b & 0xF];
-		n++;
-		if (n >= ndigits)
-			break;
-		*outp++ = gsm_address_digits[b >> 4];
-		n++;
-	}
-	*outp = '\0';
-}
--- a/libcommon/number_encode.c	Thu Feb 25 20:55:10 2021 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,104 +0,0 @@
-/*
- * This module implements functions for encoding phone numbers.
- */
-
-#include <sys/types.h>
-#include <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-digit_char_to_gsm(ch)
-{
-	switch (ch) {
-	case '0':
-	case '1':
-	case '2':
-	case '3':
-	case '4':
-	case '5':
-	case '6':
-	case '7':
-	case '8':
-	case '9':
-		return (ch - '0');
-	case '*':
-		return 0xA;
-	case '#':
-		return 0xB;
-	case 'a':
-	case 'b':
-	case 'c':
-		return (ch - 'a' + 0xC);
-	case 'A':
-	case 'B':
-	case 'C':
-		return (ch - 'A' + 0xC);
-	}
-	return (-1);
-}
-
-void
-pack_digit_bytes(digits, dest, num_digit_bytes)
-	u_char *digits, *dest;
-	unsigned num_digit_bytes;
-{
-	u_char *sp, *dp;
-	unsigned n;
-
-	sp = digits;
-	dp = dest;
-	for (n = 0; n < num_digit_bytes; n++) {
-		*dp++ = sp[0] | (sp[1] << 4);
-		sp += 2;
-	}
-}
-
-encode_phone_number_arg(arg, fixp, mode)
-	char *arg;
-	u_char *fixp;
-{
-	u_char digits[20];
-	unsigned ndigits, num_digit_bytes;
-	char *cp, *endp;
-	int c;
-
-	cp = arg;
-	if (*cp == '+') {
-		fixp[1] = 0x91;
-		cp++;
-	} else
-		fixp[1] = 0x81;
-	if (digit_char_to_gsm(*cp) < 0) {
-inv_arg:	fprintf(stderr, "error: invalid phone number argument\n");
-		return(-1);
-	}
-	for (ndigits = 0; ; ndigits++) {
-		c = digit_char_to_gsm(*cp);
-		if (c < 0)
-			break;
-		cp++;
-		if (ndigits >= 20) {
-			fprintf(stderr, "error: too many number digits\n");
-			return(-1);
-		}
-		digits[ndigits] = c;
-	}
-	if (mode)
-		fixp[0] = ndigits;
-	if (ndigits & 1)
-		digits[ndigits++] = 0xF;
-	num_digit_bytes = ndigits >> 1;
-	if (!mode)
-		fixp[0] = num_digit_bytes + 1;
-	pack_digit_bytes(digits, fixp + 2, num_digit_bytes);
-	if (*cp == ',') {
-		cp++;
-		if (!isdigit(*cp))
-			goto inv_arg;
-		fixp[1] = strtoul(cp, &endp, 0);
-		if (*endp)
-			goto inv_arg;
-	} else if (*cp)
-		goto inv_arg;
-	return(0);
-}
--- a/libcommon/pinentry.c	Thu Feb 25 20:55:10 2021 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,28 +0,0 @@
-#include <sys/types.h>
-#include <ctype.h>
-#include <stdio.h>
-
-encode_pin_entry(arg, dest)
-	char *arg;
-	u_char *dest;
-{
-	unsigned n;
-
-	n = 0;
-	while (*arg) {
-		if (!isdigit(*arg)) {
-			fprintf(stderr,
-			"error: PIN argument contains a non-digit character\n");
-			return(-1);
-		}
-		if (n >= 8) {
-			fprintf(stderr, "error: PIN argument is too long\n");
-			return(-1);
-		}
-		*dest++ = *arg++;
-		n++;
-	}
-	for (; n < 8; n++)
-		*dest++ = 0xFF;
-	return(0);
-}
--- a/libcommon/plmncodes.c	Thu Feb 25 20:55:10 2021 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,60 +0,0 @@
-/*
- * This module implements some functions for working with MCC-MNC PLMN codes.
- */
-
-#include <sys/types.h>
-#include <ctype.h>
-#include <stdio.h>
-
-decode_plmn_3bytes(bin, asc, space_pad)
-	u_char *bin;
-	char *asc;
-{
-	asc[0] = encode_hex_digit(bin[0] & 0xF);
-	asc[1] = encode_hex_digit(bin[0] >> 4);
-	asc[2] = encode_hex_digit(bin[1] & 0xF);
-	asc[3] = '-';
-	asc[4] = encode_hex_digit(bin[2] & 0xF);
-	asc[5] = encode_hex_digit(bin[2] >> 4);
-	asc[6] = encode_hex_digit(bin[1] >> 4);
-	asc[7] = '\0';
-	if (asc[6] == 'F') {
-		if (space_pad)
-			asc[6] = ' ';
-		else
-			asc[6] = '\0';
-	}
-}
-
-encode_plmn_3bytes(asc, bin)
-	char *asc;
-	u_char *bin;
-{
-	u_char mcc[3], mnc[3];
-
-	if (!isxdigit(asc[0]) || !isxdigit(asc[1]) || !isxdigit(asc[2])) {
-inv:		fprintf(stderr, "error: invalid MCC-MNC argument\n");
-		return(-1);
-	}
-	mcc[0] = decode_hex_digit(asc[0]);
-	mcc[1] = decode_hex_digit(asc[1]);
-	mcc[2] = decode_hex_digit(asc[2]);
-	asc += 3;
-	if (*asc == '-')
-		asc++;
-	if (!isxdigit(asc[0]) || !isxdigit(asc[1]))
-		goto inv;
-	mnc[0] = decode_hex_digit(asc[0]);
-	mnc[1] = decode_hex_digit(asc[1]);
-	asc += 2;
-	if (*asc == '\0')
-		mnc[2] = 0xF;
-	else if (isxdigit(asc[0]) && asc[1] == '\0')
-		mnc[2] = decode_hex_digit(*asc);
-	else
-		goto inv;
-	bin[0] = (mcc[1] << 4) | mcc[0];
-	bin[1] = (mnc[2] << 4) | mcc[2];
-	bin[2] = (mnc[1] << 4) | mnc[0];
-	return(0);
-}
--- a/libcommon/revnibbles.c	Thu Feb 25 20:55:10 2021 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,34 +0,0 @@
-/*
- * This module implements some reversed-nibbles parsing functions.
- */
-
-#include <sys/types.h>
-
-encode_hex_digit(d)
-	unsigned d;
-{
-	if (d <= 9)
-		return(d + '0');
-	else
-		return(d - 10 + 'A');
-}
-
-decode_reversed_nibbles(bytes, nbytes, dest)
-	u_char *bytes;
-	unsigned nbytes;
-	char *dest;
-{
-	u_char *sp;
-	char *dp;
-	unsigned n, c;
-
-	sp = bytes;
-	dp = dest;
-	for (n = 0; n < nbytes; n++) {
-		c = *sp & 0xF;
-		*dp++ = encode_hex_digit(c);
-		c = *sp >> 4;
-		*dp++ = encode_hex_digit(c);
-		sp++;
-	}
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libutil/Makefile	Fri Feb 26 20:19:58 2021 +0000
@@ -0,0 +1,16 @@
+CC=	gcc
+CFLAGS=	-O2
+OBJS=	alpha_decode.o alpha_fromfile.o alpha_valid.o decimal_str.o \
+	filesearch.o gsm7_decode.o gsm7_encode.o gsm7_encode_table.o \
+	gsm7_unpack.o hexread.o hexstr.o number_decode.o number_encode.o \
+	pinentry.o plmncodes.o revnibbles.o
+LIB=	libutil.a
+
+all:	${LIB}
+
+${LIB}:	${OBJS}
+	ar rcu $@ ${OBJS}
+	ranlib $@
+
+clean:
+	rm -f *.[oa] errs
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libutil/alpha_decode.c	Fri Feb 26 20:19:58 2021 +0000
@@ -0,0 +1,38 @@
+/*
+ * This module contains functions for decoding and displaying alpha fields
+ * that exist in various SIM files.
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+
+static void
+print_alpha_field_hex(data, nbytes, outf)
+	u_char *data;
+	unsigned nbytes;
+	FILE *outf;
+{
+	u_char *dp, *endp;
+
+	fputs("HEX ", outf);
+	dp = data;
+	endp = data + nbytes;
+	while (dp < endp)
+		fprintf(outf, "%02X", *dp++);
+}
+
+void
+print_alpha_field(data, nbytes, outf)
+	u_char *data;
+	unsigned nbytes;
+	FILE *outf;
+{
+	if (!nbytes) {
+		fputs("\"\"", outf);
+		return;
+	}
+	if (data[0] & 0x80)
+		print_alpha_field_hex(data, nbytes, outf);
+	else
+		print_gsm7_string_to_file(data, nbytes, outf);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libutil/alpha_fromfile.c	Fri Feb 26 20:19:58 2021 +0000
@@ -0,0 +1,107 @@
+/*
+ * This module implements functions for parsing alpha tag strings
+ * from input data files, to be used by commands like pb-update
+ * and smsp-restore.
+ */
+
+#include <sys/types.h>
+#include <ctype.h>
+#include <stdio.h>
+
+extern u_char gsm7_encode_table[256];
+
+char *
+alpha_from_file_qstring(cp, record, maxlen, filename_for_errs, lineno_for_errs)
+	char *cp, *filename_for_errs;
+	u_char *record;
+	unsigned maxlen;
+{
+	unsigned acclen, nadd;
+	int c;
+
+	for (acclen = 0; ; ) {
+		if (*cp == '\0') {
+unterm_qstring:		fprintf(stderr,
+				"%s line %d: unterminated quoted string\n",
+				filename_for_errs, lineno_for_errs);
+			return(0);
+		}
+		if (*cp == '"')
+			break;
+		c = *cp++;
+		if (c == '\\') {
+			if (*cp == '\0')
+				goto unterm_qstring;
+			c = *cp++;
+			if (c >= '0' && c <= '7' && isxdigit(*cp)) {
+				c = ((c - '0') << 4) | decode_hex_digit(*cp++);
+				goto bypass_encoding;
+			}
+			switch (c) {
+			case 'n':
+				c = '\n';
+				goto bypass_encoding;
+			case 'r':
+				c = '\r';
+				goto bypass_encoding;
+			case 'e':
+				c = 0x1B;
+				goto bypass_encoding;
+			case '"':
+			case '\\':
+				break;
+			default:
+				fprintf(stderr,
+				"%s line %d: non-understood backslash escape\n",
+					filename_for_errs, lineno_for_errs);
+				return(0);
+			}
+		}
+		c = gsm7_encode_table[c];
+		if (c == 0xFF) {
+			fprintf(stderr,
+	"%s line %d: character in quoted string cannot be encoded in GSM7\n",
+				filename_for_errs, lineno_for_errs);
+			return(0);
+		}
+bypass_encoding:
+		if (c & 0x80)
+			nadd = 2;
+		else
+			nadd = 1;
+		if (acclen + nadd > maxlen) {
+			fprintf(stderr,
+		"%s line %d: alpha tag string is longer than SIM limit\n",
+				filename_for_errs, lineno_for_errs);
+			return(0);
+		}
+		if (c & 0x80)
+			record[acclen++] = 0x1B;
+		record[acclen++] = c & 0x7F;
+	}
+	return(cp + 1);
+}
+
+char *
+alpha_from_file_hex(cp, record, maxlen, filename_for_errs, lineno_for_errs)
+	char *cp, *filename_for_errs;
+	u_char *record;
+	unsigned maxlen;
+{
+	unsigned acclen;
+
+	for (acclen = 0; ; ) {
+		if (!isxdigit(cp[0]) || !isxdigit(cp[1]))
+			break;
+		if (acclen >= maxlen) {
+			fprintf(stderr,
+		"%s line %d: alpha tag string is longer than SIM limit\n",
+				filename_for_errs, lineno_for_errs);
+			return(0);
+		}
+		record[acclen++] = (decode_hex_digit(cp[0]) << 4) |
+				    decode_hex_digit(cp[1]);
+		cp += 2;
+	}
+	return(cp);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libutil/alpha_valid.c	Fri Feb 26 20:19:58 2021 +0000
@@ -0,0 +1,152 @@
+/*
+ * This module contains functions for validating alpha fields
+ * that exist in various SIM files.
+ */
+
+#include <sys/types.h>
+#include <string.h>
+#include <strings.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static
+validate_classic_gsm(data, nbytes, textlenp)
+	u_char *data;
+	unsigned nbytes, *textlenp;
+{
+	u_char *dp;
+	unsigned n;
+
+	dp = data;
+	for (n = 0; n < nbytes; n++) {
+		if (*dp == 0xFF)
+			break;
+		if (*dp & 0x80)
+			return(-1);
+		dp++;
+	}
+	if (textlenp)
+		*textlenp = n;
+	for (; n < nbytes; n++)
+		if (*dp++ != 0xFF)
+			return(-1);
+	return(0);
+}
+
+static
+validate_ucs2_80(data, nbytes, textlenp)
+	u_char *data;
+	unsigned nbytes, *textlenp;
+{
+	u_char *dp, *endp;
+
+	if (nbytes < 3)
+		return(-1);
+	dp = data + 1;
+	endp = data + nbytes;
+	while (dp < endp) {
+		if (dp + 1 == endp) {
+			if (*dp != 0xFF)
+				return(-1);
+			if (textlenp)
+				*textlenp = dp - data;
+			return(0);
+		}
+		if (dp[0] == 0xFF && dp[1] == 0xFF)
+			break;
+		dp += 2;
+	}
+	if (textlenp)
+		*textlenp = dp - data;
+	while (dp < endp)
+		if (*dp++ != 0xFF)
+			return(-1);
+	return(0);
+}
+
+static
+validate_ucs2_81(data, nbytes, textlenp)
+	u_char *data;
+	unsigned nbytes, *textlenp;
+{
+	u_char *dp, *endp;
+	unsigned textlen;
+
+	if (nbytes < 4)
+		return(-1);
+	if (!data[1])
+		return(-1);
+	textlen = data[1] + 3;
+	if (textlen > nbytes)
+		return(-1);
+	if (textlenp)
+		*textlenp = textlen;
+	dp = data + textlen;
+	endp = data + nbytes;
+	while (dp < endp)
+		if (*dp++ != 0xFF)
+			return(-1);
+	return(0);
+}
+
+static
+validate_ucs2_82(data, nbytes, textlenp)
+	u_char *data;
+	unsigned nbytes, *textlenp;
+{
+	u_char *dp, *endp;
+	unsigned textlen;
+
+	if (nbytes < 5)
+		return(-1);
+	if (!data[1])
+		return(-1);
+	textlen = data[1] + 4;
+	if (textlen > nbytes)
+		return(-1);
+	if (textlenp)
+		*textlenp = textlen;
+	dp = data + textlen;
+	endp = data + nbytes;
+	while (dp < endp)
+		if (*dp++ != 0xFF)
+			return(-1);
+	return(0);
+}
+
+static
+validate_empty(data, nbytes, textlenp)
+	u_char *data;
+	unsigned nbytes, *textlenp;
+{
+	u_char *dp;
+	unsigned n;
+
+	dp = data;
+	for (n = 0; n < nbytes; n++)
+		if (*dp++ != 0xFF)
+			return(-1);
+	if (textlenp)
+		*textlenp = 0;
+	return(0);
+}
+
+validate_alpha_field(data, nbytes, textlenp)
+	u_char *data;
+	unsigned nbytes, *textlenp;
+{
+	if (data[0] < 0x80)
+		return validate_classic_gsm(data, nbytes, textlenp);
+	switch (data[0]) {
+	case 0x80:
+		return validate_ucs2_80(data, nbytes, textlenp);
+	case 0x81:
+		return validate_ucs2_81(data, nbytes, textlenp);
+	case 0x82:
+		return validate_ucs2_82(data, nbytes, textlenp);
+	case 0xFF:
+		return validate_empty(data, nbytes, textlenp);
+	default:
+		return -1;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libutil/decimal_str.c	Fri Feb 26 20:19:58 2021 +0000
@@ -0,0 +1,56 @@
+/*
+ * This module implements some functions for initial parsing of decimal
+ * string arguments, intended for implementation of commands like
+ * write-iccid and write-imsi.
+ */
+
+#include <sys/types.h>
+#include <ctype.h>
+#include <stdio.h>
+
+parse_decimal_string_arg(arg, dest, maxdigits)
+	char *arg;
+	u_char *dest;
+	unsigned maxdigits;
+{
+	unsigned n, ndig;
+
+	if (!*arg) {
+		fprintf(stderr,
+			"error: empty argument given for decimal string\n");
+		return(-1);
+	}
+	for (n = 0; *arg; ) {
+		if (!isdigit(*arg)) {
+			fprintf(stderr,
+			"error: non-digit char in decimal string argument\n");
+			return(-1);
+		}
+		if (n >= maxdigits) {
+			fprintf(stderr,
+			"error: decimal string exceeds limit of %u digits\n",
+				maxdigits);
+			return(-1);
+		}
+		dest[n++] = *arg++ - '0';
+	}
+	ndig = n;
+	while (n < maxdigits)
+		dest[n++] = 0xF;
+	return ndig;
+}
+
+pack_reversed_nibbles(nibbles, bytes, nbytes)
+	u_char *nibbles, *bytes;
+	unsigned nbytes;
+{
+	u_char *sp, *dp;
+	unsigned n;
+
+	sp = nibbles;
+	dp = bytes;
+	for (n = 0; n < nbytes; n++) {
+		*dp++ = sp[0] | (sp[1] << 4);
+		sp += 2;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libutil/filesearch.c	Fri Feb 26 20:19:58 2021 +0000
@@ -0,0 +1,27 @@
+/*
+ * This module implements the function that searches for files
+ * in a dedicated directory for SIM programming scripts.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+
+static char script_install_dir[] = "/opt/freecalypso/sim-scripts";
+
+FILE *
+open_script_input_file(req_filename)
+	char *req_filename;
+{
+	char pathbuf[256];
+	FILE *f;
+
+	if (!index(req_filename, '/') && strlen(req_filename) < 128) {
+		sprintf(pathbuf, "%s/%s", script_install_dir, req_filename);
+		f = fopen(pathbuf, "r");
+		if (f)
+			return f;
+	}
+	f = fopen(req_filename, "r");
+	return f;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libutil/gsm7_decode.c	Fri Feb 26 20:19:58 2021 +0000
@@ -0,0 +1,88 @@
+/*
+ * This module contains functions for decoding GSM7 strings
+ * that exist in various SIM files.
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+
+static char gsm7_decode_table[128] = {
+	'@', 0,   '$',  0,   0,   0,    0,   0,
+	0,   0,   '\n', 0,   0,   '\r', 0,   0,
+	0,   '_', 0,    0,   0,   0,    0,   0,
+	0,   0,   0,    0,   0,   0,    0,   0,
+	' ', '!', '"',  '#', 0,   '%',  '&', 0x27,
+	'(', ')', '*',  '+', ',', '-',  '.', '/',
+	'0', '1', '2',  '3', '4', '5',  '6', '7',
+	'8', '9', ':',  ';', '<', '=',  '>', '?',
+	0,   'A', 'B',  'C', 'D', 'E',  'F', 'G',
+	'H', 'I', 'J',  'K', 'L', 'M',  'N', 'O',
+	'P', 'Q', 'R',  'S', 'T', 'U',  'V', 'W',
+	'X', 'Y', 'Z',  0,   0,   0,    0,   0,
+	0,   'a', 'b',  'c', 'd', 'e',  'f', 'g',
+	'h', 'i', 'j',  'k', 'l', 'm',  'n', 'o',
+	'p', 'q', 'r',  's', 't', 'u',  'v', 'w',
+	'x', 'y', 'z',  0,   0,   0,    0,   0
+};
+
+static char gsm7ext_decode_table[128] = {
+	0,   0, 0, 0, 0,   0, 0, 0, 0,   0,   0, 0, 0,   0,   0,   0,
+	0,   0, 0, 0, '^', 0, 0, 0, 0,   0,   0, 0, 0,   0,   0,   0,
+	0,   0, 0, 0, 0,   0, 0, 0, '{', '}', 0, 0, 0,   0,   0,   '\\',
+	0,   0, 0, 0, 0,   0, 0, 0, 0,   0,   0, 0, '[', '~', ']', 0,
+	'|', 0, 0, 0, 0,   0, 0, 0, 0,   0,   0, 0, 0,   0,   0,   0,
+	0,   0, 0, 0, 0,   0, 0, 0, 0,   0,   0, 0, 0,   0,   0,   0,
+	0,   0, 0, 0, 0,   0, 0, 0, 0,   0,   0, 0, 0,   0,   0,   0,
+	0,   0, 0, 0, 0,   0, 0, 0, 0,   0,   0, 0, 0,   0,   0,   0
+};
+
+void
+print_gsm7_string_to_file(data, nbytes, outf)
+	u_char *data;
+	unsigned nbytes;
+	FILE *outf;
+{
+	u_char *dp, *endp;
+	int b, c;
+
+	dp = data;
+	endp = data + nbytes;
+	putc('"', outf);
+	while (dp < endp) {
+		b = *dp++;
+		if (b == 0x1B) {
+			if (dp >= endp || *dp == 0x1B || *dp == '\n' ||
+			    *dp == '\r') {
+				putc('\\', outf);
+				putc('e', outf);
+				continue;
+			}
+			b = *dp++;
+			c = gsm7ext_decode_table[b];
+			if (!c) {
+				fprintf(outf, "\\e\\%02X", b);
+				continue;
+			}
+		} else {
+			c = gsm7_decode_table[b];
+			if (!c) {
+				fprintf(outf, "\\%02X", b);
+				continue;
+			}
+		}
+		if (c == '\n') {
+			putc('\\', outf);
+			putc('n', outf);
+			continue;
+		}
+		if (c == '\r') {
+			putc('\\', outf);
+			putc('r', outf);
+			continue;
+		}
+		if (c == '"' || c == '\\')
+			putc('\\', outf);
+		putc(c, outf);
+	}
+	putc('"', outf);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libutil/gsm7_encode.c	Fri Feb 26 20:19:58 2021 +0000
@@ -0,0 +1,76 @@
+/*
+ * This module implements functions for parsing quoted string
+ * arguments intended for GSM7 string encoding, and actually
+ * encoding them into GSM7 binary strings.
+ */
+
+#include <sys/types.h>
+#include <ctype.h>
+#include <stdio.h>
+
+extern u_char gsm7_encode_table[256];
+
+qstring_arg_to_gsm7(arg, record, maxlen)
+	char *arg;
+	u_char *record;
+	unsigned maxlen;
+{
+	unsigned acclen, nadd;
+	char *cp;
+	int c;
+
+	cp = arg;
+	for (acclen = 0; *cp; ) {
+		c = *cp++;
+		if (c == '\\') {
+			if (*cp == '\0') {
+				fprintf(stderr,
+					"error: dangling backslash escape\n");
+				return(-1);
+			}
+			c = *cp++;
+			if (c >= '0' && c <= '7' && isxdigit(*cp)) {
+				c = ((c - '0') << 4) | decode_hex_digit(*cp++);
+				goto bypass_encoding;
+			}
+			switch (c) {
+			case 'n':
+				c = '\n';
+				goto bypass_encoding;
+			case 'r':
+				c = '\r';
+				goto bypass_encoding;
+			case 'e':
+				c = 0x1B;
+				goto bypass_encoding;
+			case '"':
+			case '\\':
+				break;
+			default:
+				fprintf(stderr,
+				"error: non-understood backslash escape\n");
+				return(-1);
+			}
+		}
+		c = gsm7_encode_table[c];
+		if (c == 0xFF) {
+			fprintf(stderr,
+	"error: character in alpha tag string cannot be encoded in GSM7\n");
+			return(-1);
+		}
+bypass_encoding:
+		if (c & 0x80)
+			nadd = 2;
+		else
+			nadd = 1;
+		if (acclen + nadd > maxlen) {
+			fprintf(stderr,
+			"error: alpha tag string is longer than SIM limit\n");
+			return(-1);
+		}
+		if (c & 0x80)
+			record[acclen++] = 0x1B;
+		record[acclen++] = c & 0x7F;
+	}
+	return(acclen);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libutil/gsm7_encode_table.c	Fri Feb 26 20:19:58 2021 +0000
@@ -0,0 +1,43 @@
+/*
+ * This library module contains the table for encoding from ISO 8859-1
+ * into the GSM 7-bit default alphabet (03.38 or 23.038).  High bit set
+ * in the output indicates escape encoding, used for ASCII characters
+ * [\]^ and {|}~.  0xFF indicates invalid chars.
+ */
+
+#include <sys/types.h>
+
+u_char gsm7_encode_table[256] = {
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,	/* 0x00 */
+	0xFF, 0xFF, '\n', 0xFF, 0xFF, '\r', 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,	/* 0x10 */
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	' ',  '!',  '"',  '#',  0x02, '%',  '&',  0x27,	/* 0x20 */
+	'(',  ')',  '*',  '+',  ',',  '-',  '.',  '/',
+	'0',  '1',  '2',  '3',  '4',  '5',  '6',  '7',	/* 0x30 */
+	'8',  '9',  ':',  ';',  '<',  '=',  '>',  '?',
+	0x00, 'A',  'B',  'C',  'D',  'E',  'F',  'G',	/* 0x40 */
+	'H',  'I',  'J',  'K',  'L',  'M',  'N',  'O',
+	'P',  'Q',  'R',  'S',  'T',  'U',  'V',  'W',	/* 0x50 */
+	'X',  'Y',  'Z',  0xBC, 0xAF, 0xBE, 0x94, 0x11,
+	0xFF, 'a',  'b',  'c',  'd',  'e',  'f',  'g',	/* 0x60 */
+	'h',  'i',  'j',  'k',  'l',  'm',  'n',  'o',
+	'p',  'q',  'r',  's',  't',  'u',  'v',  'w',	/* 0x70 */
+	'x',  'y',  'z',  0xA8, 0xC0, 0xA9, 0xBD, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,	/* 0x80 */
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,	/* 0x90 */
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0x40, 0xFF, 0x01, 0x24, 0x03, 0xFF, 0x5F,	/* 0xA0 */
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,	/* 0xB0 */
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x60,
+	0xFF, 0xFF, 0xFF, 0xFF, 0x5B, 0x0E, 0x1C, 0x09,	/* 0xC0 */
+	0xFF, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0x5D, 0xFF, 0xFF, 0xFF, 0xFF, 0x5C, 0xFF,	/* 0xD0 */
+	0x0B, 0xFF, 0xFF, 0xFF, 0x5E, 0xFF, 0xFF, 0x1E,
+	0x7F, 0xFF, 0xFF, 0xFF, 0x7B, 0x0F, 0x1D, 0xFF,	/* 0xE0 */
+	0x04, 0x05, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xFF,
+	0xFF, 0x7D, 0x08, 0xFF, 0xFF, 0xFF, 0x7C, 0xFF,	/* 0xF0 */
+	0x0C, 0x06, 0xFF, 0xFF, 0x7E, 0xFF, 0xFF, 0xFF
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libutil/gsm7_unpack.c	Fri Feb 26 20:19:58 2021 +0000
@@ -0,0 +1,22 @@
+/*
+ * This library module implements unpacking of GSM 7-bit data
+ * from packed octets.
+ */
+
+#include <sys/types.h>
+
+static u_char shift[8] = {0, 7, 6, 5, 4, 3, 2, 1};
+
+gsm7_unpack(inbuf, outbuf, nseptets)
+	u_char *inbuf, *outbuf;
+	unsigned nseptets;
+{
+	u_char *inp = inbuf, *outp = outbuf;
+	unsigned n;
+
+	for (n = 0; n < nseptets; n++) {
+		*outp++ = (((inp[1] << 8) | inp[0]) >> shift[n&7]) & 0x7F;
+		if (n & 7)
+			inp++;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libutil/hexread.c	Fri Feb 26 20:19:58 2021 +0000
@@ -0,0 +1,57 @@
+/*
+ * This module contains the function for reading hex files,
+ * to be used in the implementation of manual write commands.
+ */
+
+#include <sys/types.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+extern FILE *open_script_input_file();
+
+read_hex_data_file(filename, databuf, maxlen)
+	char *filename;
+	u_char *databuf;
+	unsigned maxlen;
+{
+	FILE *inf;
+	unsigned count;
+	int c, c2;
+
+	inf = open_script_input_file(filename);
+	if (!inf) {
+		perror(filename);
+		return(-1);
+	}
+	for (count = 0; ; count++) {
+		do
+			c = getc(inf);
+		while (isspace(c));
+		if (c < 0)
+			break;
+		if (!isxdigit(c)) {
+inv_input:		fprintf(stderr, "%s: invalid hex file input\n",
+				filename);
+			fclose(inf);
+			return(-1);
+		}
+		c2 = getc(inf);
+		if (!isxdigit(c2))
+			goto inv_input;
+		if (count >= maxlen) {
+			fprintf(stderr, "%s: hex input data is too long\n",
+				filename);
+			fclose(inf);
+			return(-1);
+		}
+		databuf[count] = (decode_hex_digit(c) << 4) |
+				 decode_hex_digit(c2);
+	}
+	fclose(inf);
+	if (!count) {
+		fprintf(stderr, "%s: no hex data input found\n", filename);
+		return(-1);
+	}
+	return(count);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libutil/hexstr.c	Fri Feb 26 20:19:58 2021 +0000
@@ -0,0 +1,52 @@
+/*
+ * This module contains the function for decoding hex strings.
+ */
+
+#include <sys/types.h>
+#include <ctype.h>
+#include <string.h>
+#include <strings.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+decode_hex_digit(c)
+{
+	if (c >= '0' && c <= '9')
+		return(c - '0');
+	if (c >= 'A' && c <= 'F')
+		return(c - 'A' + 10);
+	if (c >= 'a' && c <= 'f')
+		return(c - 'a' + 10);
+	return(-1);
+}
+
+decode_hex_data_from_string(arg, databuf, minlen, maxlen)
+	char *arg;
+	u_char *databuf;
+	unsigned minlen, maxlen;
+{
+	unsigned count;
+
+	for (count = 0; ; count++) {
+		while (isspace(*arg))
+			arg++;
+		if (!*arg)
+			break;
+		if (!isxdigit(arg[0]) || !isxdigit(arg[1])) {
+			fprintf(stderr, "error: invalid hex string input\n");
+			return(-1);
+		}
+		if (count >= maxlen) {
+			fprintf(stderr, "error: hex string is too long\n");
+			return(-1);
+		}
+		databuf[count] = (decode_hex_digit(arg[0]) << 4) |
+				 decode_hex_digit(arg[1]);
+		arg += 2;
+	}
+	if (count < minlen) {
+		fprintf(stderr, "error: hex string is too short\n");
+		return(-1);
+	}
+	return(count);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libutil/number_decode.c	Fri Feb 26 20:19:58 2021 +0000
@@ -0,0 +1,58 @@
+/*
+ * This module implements functions for decoding phone numbers.
+ */
+
+#include <sys/types.h>
+
+static char gsm_address_digits[16] =
+	{'0','1','2','3','4','5','6','7','8','9','*','#','a','b','c','?'};
+
+decode_phone_number(data, nbytes, out)
+	u_char *data;
+	unsigned nbytes;
+	char *out;
+{
+	u_char *dp, *endp;
+	int c;
+
+	dp = data;
+	endp = data + nbytes;
+	while (dp < endp) {
+		c = *dp & 0xF;
+		if (c == 0xF)
+			return(-1);
+		*out++ = gsm_address_digits[c];
+		c = *dp >> 4;
+		if (c == 0xF) {
+			if (dp + 1 == endp)
+				break;
+			else
+				return(-1);
+		}
+		*out++ = gsm_address_digits[c];
+		dp++;
+	}
+	*out = '\0';
+	return(0);
+}
+
+decode_address_digits(inbuf, outbuf, ndigits)
+	u_char *inbuf;
+	char *outbuf;
+	unsigned ndigits;
+{
+	u_char *inp = inbuf;
+	char *outp = outbuf;
+	unsigned n = 0, b;
+
+	while (n < ndigits) {
+		b = *inp++;
+		*outp++ = gsm_address_digits[b & 0xF];
+		n++;
+		if (n >= ndigits)
+			break;
+		*outp++ = gsm_address_digits[b >> 4];
+		n++;
+	}
+	*outp = '\0';
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libutil/number_encode.c	Fri Feb 26 20:19:58 2021 +0000
@@ -0,0 +1,104 @@
+/*
+ * This module implements functions for encoding phone numbers.
+ */
+
+#include <sys/types.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+digit_char_to_gsm(ch)
+{
+	switch (ch) {
+	case '0':
+	case '1':
+	case '2':
+	case '3':
+	case '4':
+	case '5':
+	case '6':
+	case '7':
+	case '8':
+	case '9':
+		return (ch - '0');
+	case '*':
+		return 0xA;
+	case '#':
+		return 0xB;
+	case 'a':
+	case 'b':
+	case 'c':
+		return (ch - 'a' + 0xC);
+	case 'A':
+	case 'B':
+	case 'C':
+		return (ch - 'A' + 0xC);
+	}
+	return (-1);
+}
+
+void
+pack_digit_bytes(digits, dest, num_digit_bytes)
+	u_char *digits, *dest;
+	unsigned num_digit_bytes;
+{
+	u_char *sp, *dp;
+	unsigned n;
+
+	sp = digits;
+	dp = dest;
+	for (n = 0; n < num_digit_bytes; n++) {
+		*dp++ = sp[0] | (sp[1] << 4);
+		sp += 2;
+	}
+}
+
+encode_phone_number_arg(arg, fixp, mode)
+	char *arg;
+	u_char *fixp;
+{
+	u_char digits[20];
+	unsigned ndigits, num_digit_bytes;
+	char *cp, *endp;
+	int c;
+
+	cp = arg;
+	if (*cp == '+') {
+		fixp[1] = 0x91;
+		cp++;
+	} else
+		fixp[1] = 0x81;
+	if (digit_char_to_gsm(*cp) < 0) {
+inv_arg:	fprintf(stderr, "error: invalid phone number argument\n");
+		return(-1);
+	}
+	for (ndigits = 0; ; ndigits++) {
+		c = digit_char_to_gsm(*cp);
+		if (c < 0)
+			break;
+		cp++;
+		if (ndigits >= 20) {
+			fprintf(stderr, "error: too many number digits\n");
+			return(-1);
+		}
+		digits[ndigits] = c;
+	}
+	if (mode)
+		fixp[0] = ndigits;
+	if (ndigits & 1)
+		digits[ndigits++] = 0xF;
+	num_digit_bytes = ndigits >> 1;
+	if (!mode)
+		fixp[0] = num_digit_bytes + 1;
+	pack_digit_bytes(digits, fixp + 2, num_digit_bytes);
+	if (*cp == ',') {
+		cp++;
+		if (!isdigit(*cp))
+			goto inv_arg;
+		fixp[1] = strtoul(cp, &endp, 0);
+		if (*endp)
+			goto inv_arg;
+	} else if (*cp)
+		goto inv_arg;
+	return(0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libutil/pinentry.c	Fri Feb 26 20:19:58 2021 +0000
@@ -0,0 +1,28 @@
+#include <sys/types.h>
+#include <ctype.h>
+#include <stdio.h>
+
+encode_pin_entry(arg, dest)
+	char *arg;
+	u_char *dest;
+{
+	unsigned n;
+
+	n = 0;
+	while (*arg) {
+		if (!isdigit(*arg)) {
+			fprintf(stderr,
+			"error: PIN argument contains a non-digit character\n");
+			return(-1);
+		}
+		if (n >= 8) {
+			fprintf(stderr, "error: PIN argument is too long\n");
+			return(-1);
+		}
+		*dest++ = *arg++;
+		n++;
+	}
+	for (; n < 8; n++)
+		*dest++ = 0xFF;
+	return(0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libutil/plmncodes.c	Fri Feb 26 20:19:58 2021 +0000
@@ -0,0 +1,60 @@
+/*
+ * This module implements some functions for working with MCC-MNC PLMN codes.
+ */
+
+#include <sys/types.h>
+#include <ctype.h>
+#include <stdio.h>
+
+decode_plmn_3bytes(bin, asc, space_pad)
+	u_char *bin;
+	char *asc;
+{
+	asc[0] = encode_hex_digit(bin[0] & 0xF);
+	asc[1] = encode_hex_digit(bin[0] >> 4);
+	asc[2] = encode_hex_digit(bin[1] & 0xF);
+	asc[3] = '-';
+	asc[4] = encode_hex_digit(bin[2] & 0xF);
+	asc[5] = encode_hex_digit(bin[2] >> 4);
+	asc[6] = encode_hex_digit(bin[1] >> 4);
+	asc[7] = '\0';
+	if (asc[6] == 'F') {
+		if (space_pad)
+			asc[6] = ' ';
+		else
+			asc[6] = '\0';
+	}
+}
+
+encode_plmn_3bytes(asc, bin)
+	char *asc;
+	u_char *bin;
+{
+	u_char mcc[3], mnc[3];
+
+	if (!isxdigit(asc[0]) || !isxdigit(asc[1]) || !isxdigit(asc[2])) {
+inv:		fprintf(stderr, "error: invalid MCC-MNC argument\n");
+		return(-1);
+	}
+	mcc[0] = decode_hex_digit(asc[0]);
+	mcc[1] = decode_hex_digit(asc[1]);
+	mcc[2] = decode_hex_digit(asc[2]);
+	asc += 3;
+	if (*asc == '-')
+		asc++;
+	if (!isxdigit(asc[0]) || !isxdigit(asc[1]))
+		goto inv;
+	mnc[0] = decode_hex_digit(asc[0]);
+	mnc[1] = decode_hex_digit(asc[1]);
+	asc += 2;
+	if (*asc == '\0')
+		mnc[2] = 0xF;
+	else if (isxdigit(asc[0]) && asc[1] == '\0')
+		mnc[2] = decode_hex_digit(*asc);
+	else
+		goto inv;
+	bin[0] = (mcc[1] << 4) | mcc[0];
+	bin[1] = (mnc[2] << 4) | mcc[2];
+	bin[2] = (mnc[1] << 4) | mnc[0];
+	return(0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libutil/revnibbles.c	Fri Feb 26 20:19:58 2021 +0000
@@ -0,0 +1,34 @@
+/*
+ * This module implements some reversed-nibbles parsing functions.
+ */
+
+#include <sys/types.h>
+
+encode_hex_digit(d)
+	unsigned d;
+{
+	if (d <= 9)
+		return(d + '0');
+	else
+		return(d - 10 + 'A');
+}
+
+decode_reversed_nibbles(bytes, nbytes, dest)
+	u_char *bytes;
+	unsigned nbytes;
+	char *dest;
+{
+	u_char *sp;
+	char *dp;
+	unsigned n, c;
+
+	sp = bytes;
+	dp = dest;
+	for (n = 0; n < nbytes; n++) {
+		c = *sp & 0xF;
+		*dp++ = encode_hex_digit(c);
+		c = *sp >> 4;
+		*dp++ = encode_hex_digit(c);
+		sp++;
+	}
+}
--- a/misc/Makefile	Thu Feb 25 20:55:10 2021 +0000
+++ b/misc/Makefile	Fri Feb 26 20:19:58 2021 +0000
@@ -1,7 +1,7 @@
 CC=	gcc
 CFLAGS=	-O2 -I/usr/include/PCSC -I../libcommon
 PROGS=	fc-pcsc-atr fc-pcsc-list
-LIBS=	../libcommon/libcommon.a
+LIBS=	../libcommon/libcommon.a ../libutil/libutil.a
 INSTBIN=/opt/freecalypso/bin
 
 all:	${PROGS}
--- a/simtool/Makefile	Thu Feb 25 20:55:10 2021 +0000
+++ b/simtool/Makefile	Fri Feb 26 20:19:58 2021 +0000
@@ -8,7 +8,7 @@
 	restorebin.o savebin.o script.o select.o smserase.o smsp_common.o \
 	smsp_dump.o smsp_erase.o smsp_restore.o smsp_set.o sstlist.o stktest.o \
 	sysmo.o telsum.o usersum.o writecmd.o writeops.o
-LIBS=	../libcommon/libcommon.a
+LIBS=	../libcommon/libcommon.a ../libutil/libutil.a
 INSTBIN=/opt/freecalypso/bin
 
 all:	${PROG}
--- a/uicc/Makefile	Thu Feb 25 20:55:10 2021 +0000
+++ b/uicc/Makefile	Fri Feb 26 20:19:58 2021 +0000
@@ -3,7 +3,7 @@
 PROG=	fc-uicc-tool
 OBJS=	bfsearch.o createfile.o dispatch.o dumpdir.o getresp.o hlread.o main.o \
 	pins.o readcmd.o readops.o script.o select.o writecmd.o writeops.o
-LIBS=	../libcommon/libcommon.a
+LIBS=	../libcommon/libcommon.a ../libutil/libutil.a
 INSTBIN=/opt/freecalypso/bin
 
 all:	${PROG}