comparison uicc/pbupdate.c @ 146:ce2a880ab704

fc-uicc-tool: pb-update commands ported over
author Mychaela Falconia <falcon@freecalypso.org>
date Sat, 06 Feb 2021 02:45:29 +0000
parents
children
comparison
equal deleted inserted replaced
145:14dee03e9675 146:ce2a880ab704
1 /*
2 * This module implements the pb-update command.
3 */
4
5 #include <sys/types.h>
6 #include <ctype.h>
7 #include <string.h>
8 #include <strings.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11
12 static u_char gsm7_encode_table[256] = {
13 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 0x00 */
14 0xFF, 0xFF, '\n', 0xFF, 0xFF, '\r', 0xFF, 0xFF,
15 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 0x10 */
16 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
17 ' ', '!', '"', '#', 0x02, '%', '&', 0x27, /* 0x20 */
18 '(', ')', '*', '+', ',', '-', '.', '/',
19 '0', '1', '2', '3', '4', '5', '6', '7', /* 0x30 */
20 '8', '9', ':', ';', '<', '=', '>', '?',
21 0x00, 'A', 'B', 'C', 'D', 'E', 'F', 'G', /* 0x40 */
22 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
23 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', /* 0x50 */
24 'X', 'Y', 'Z', 0xBC, 0xAF, 0xBE, 0x94, 0x11,
25 0xFF, 'a', 'b', 'c', 'd', 'e', 'f', 'g', /* 0x60 */
26 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
27 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', /* 0x70 */
28 'x', 'y', 'z', 0xA8, 0xC0, 0xA9, 0xBD, 0xFF,
29 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 0x80 */
30 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
31 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 0x90 */
32 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
33 0xFF, 0x40, 0xFF, 0x01, 0x24, 0x03, 0xFF, 0x5F, /* 0xA0 */
34 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
35 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 0xB0 */
36 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x60,
37 0xFF, 0xFF, 0xFF, 0xFF, 0x5B, 0x0E, 0x1C, 0x09, /* 0xC0 */
38 0xFF, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
39 0xFF, 0x5D, 0xFF, 0xFF, 0xFF, 0xFF, 0x5C, 0xFF, /* 0xD0 */
40 0x0B, 0xFF, 0xFF, 0xFF, 0x5E, 0xFF, 0xFF, 0x1E,
41 0x7F, 0xFF, 0xFF, 0xFF, 0x7B, 0x0F, 0x1D, 0xFF, /* 0xE0 */
42 0x04, 0x05, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xFF,
43 0xFF, 0x7D, 0x08, 0xFF, 0xFF, 0xFF, 0x7C, 0xFF, /* 0xF0 */
44 0x0C, 0x06, 0xFF, 0xFF, 0x7E, 0xFF, 0xFF, 0xFF
45 };
46
47 static
48 digit_char_to_gsm(ch)
49 {
50 switch (ch) {
51 case '0':
52 case '1':
53 case '2':
54 case '3':
55 case '4':
56 case '5':
57 case '6':
58 case '7':
59 case '8':
60 case '9':
61 return (ch - '0');
62 case '*':
63 return 0xA;
64 case '#':
65 return 0xB;
66 case 'a':
67 case 'b':
68 case 'c':
69 return (ch - 'a' + 0xC);
70 case 'A':
71 case 'B':
72 case 'C':
73 return (ch - 'A' + 0xC);
74 }
75 return (-1);
76 }
77
78 static void
79 pack_digit_bytes(digits, dest, num_digit_bytes)
80 u_char *digits, *dest;
81 unsigned num_digit_bytes;
82 {
83 u_char *sp, *dp;
84 unsigned n;
85
86 sp = digits;
87 dp = dest;
88 for (n = 0; n < num_digit_bytes; n++) {
89 *dp++ = sp[0] | (sp[1] << 4);
90 sp += 2;
91 }
92 }
93
94 static char *
95 decode_qstring_alpha(cp, record, maxlen, filename_for_errs, lineno_for_errs)
96 char *cp, *filename_for_errs;
97 u_char *record;
98 unsigned maxlen;
99 {
100 unsigned acclen, nadd;
101 int c;
102
103 for (acclen = 0; ; ) {
104 if (*cp == '\0') {
105 unterm_qstring: fprintf(stderr,
106 "%s line %d: unterminated quoted string\n",
107 filename_for_errs, lineno_for_errs);
108 return(0);
109 }
110 if (*cp == '"')
111 break;
112 c = *cp++;
113 if (c == '\\') {
114 if (*cp == '\0')
115 goto unterm_qstring;
116 c = *cp++;
117 switch (c) {
118 case 'n':
119 c = '\n';
120 break;
121 case 'r':
122 c = '\r';
123 break;
124 case '"':
125 case '\\':
126 break;
127 default:
128 fprintf(stderr,
129 "%s line %d: non-understood backslash escape\n",
130 filename_for_errs, lineno_for_errs);
131 return(0);
132 }
133 }
134 c = gsm7_encode_table[c];
135 if (c == 0xFF) {
136 fprintf(stderr,
137 "%s line %d: character in quoted string cannot be encoded in GSM7\n",
138 filename_for_errs, lineno_for_errs);
139 return(0);
140 }
141 if (c & 0x80)
142 nadd = 2;
143 else
144 nadd = 1;
145 if (acclen + nadd > maxlen) {
146 fprintf(stderr,
147 "%s line %d: alpha tag string is longer than SIM limit\n",
148 filename_for_errs, lineno_for_errs);
149 return(0);
150 }
151 if (c & 0x80)
152 record[acclen++] = 0x1B;
153 record[acclen++] = c & 0x7F;
154 }
155 return(cp + 1);
156 }
157
158 static char *
159 decode_hex_alpha(cp, record, maxlen, filename_for_errs, lineno_for_errs)
160 char *cp, *filename_for_errs;
161 u_char *record;
162 unsigned maxlen;
163 {
164 unsigned acclen;
165
166 for (acclen = 0; ; ) {
167 if (!isxdigit(cp[0]) || !isxdigit(cp[1]))
168 break;
169 if (acclen >= maxlen) {
170 fprintf(stderr,
171 "%s line %d: alpha tag string is longer than SIM limit\n",
172 filename_for_errs, lineno_for_errs);
173 return(0);
174 }
175 record[acclen++] = (decode_hex_digit(cp[0]) << 4) |
176 decode_hex_digit(cp[1]);
177 cp += 2;
178 }
179 return(cp);
180 }
181
182 static
183 process_record(line, pb_record_len, pb_record_count, filename_for_errs,
184 lineno_for_errs)
185 char *line, *filename_for_errs;
186 unsigned pb_record_len, pb_record_count;
187 {
188 unsigned recno;
189 u_char record[255], *fixp;
190 u_char digits[20];
191 unsigned ndigits, num_digit_bytes;
192 char *cp;
193 int c;
194
195 recno = strtoul(line+1, 0, 10);
196 if (recno < 1 || recno > pb_record_count) {
197 fprintf(stderr, "%s line %d: record number is out of range\n",
198 filename_for_errs, lineno_for_errs);
199 return(-1);
200 }
201 cp = line + 1;
202 while (isdigit(*cp))
203 cp++;
204 if (*cp++ != ':') {
205 inv_syntax: fprintf(stderr, "%s line %d: invalid syntax\n",
206 filename_for_errs, lineno_for_errs);
207 return(-1);
208 }
209 while (isspace(*cp))
210 cp++;
211 memset(record, 0xFF, pb_record_len);
212 fixp = record + pb_record_len - 14;
213 if (digit_char_to_gsm(*cp) < 0)
214 goto inv_syntax;
215 for (ndigits = 0; ; ndigits++) {
216 c = digit_char_to_gsm(*cp);
217 if (c < 0)
218 break;
219 cp++;
220 if (ndigits >= 20) {
221 fprintf(stderr, "%s line %d: too many number digits\n",
222 filename_for_errs, lineno_for_errs);
223 return(-1);
224 }
225 digits[ndigits] = c;
226 }
227 if (ndigits & 1)
228 digits[ndigits++] = 0xF;
229 num_digit_bytes = ndigits >> 1;
230 fixp[0] = num_digit_bytes + 1;
231 pack_digit_bytes(digits, fixp + 2, num_digit_bytes);
232 if (*cp++ != ',')
233 goto inv_syntax;
234 if (cp[0] != '0' || cp[1] != 'x' && cp[1] != 'X' || !isxdigit(cp[2]) ||
235 !isxdigit(cp[3]) || !isspace(cp[4]))
236 goto inv_syntax;
237 fixp[1] = strtoul(cp, 0, 16);
238 cp += 5;
239 while (isspace(*cp))
240 cp++;
241 if (!strncasecmp(cp, "CCP=", 4)) {
242 cp += 4;
243 fixp[12] = strtoul(cp, 0, 0);
244 while (*cp && !isspace(*cp))
245 cp++;
246 while (isspace(*cp))
247 cp++;
248 }
249 if (!strncasecmp(cp, "EXT=", 4)) {
250 cp += 4;
251 fixp[13] = strtoul(cp, 0, 0);
252 while (*cp && !isspace(*cp))
253 cp++;
254 while (isspace(*cp))
255 cp++;
256 }
257 if (*cp == '"') {
258 cp++;
259 cp = decode_qstring_alpha(cp, record, pb_record_len - 14,
260 filename_for_errs, lineno_for_errs);
261 if (!cp)
262 return(-1);
263 } else if (!strncasecmp(cp, "HEX", 3)) {
264 cp += 3;
265 while (isspace(*cp))
266 cp++;
267 cp = decode_hex_alpha(cp, record, pb_record_len - 14,
268 filename_for_errs, lineno_for_errs);
269 if (!cp)
270 return(-1);
271 } else
272 goto inv_syntax;
273 while (isspace(*cp))
274 cp++;
275 if (*cp)
276 goto inv_syntax;
277 return update_rec_op(recno, 0x04, record, pb_record_len);
278 }
279
280 cmd_pb_update(argc, argv)
281 char **argv;
282 {
283 int rc;
284 FILE *inf;
285 int lineno;
286 char linebuf[1024];
287 unsigned pb_record_len, pb_record_count;
288
289 rc = phonebook_op_common(argv[1], &pb_record_len, &pb_record_count);
290 if (rc < 0)
291 return(rc);
292 inf = fopen(argv[2], "r");
293 if (!inf) {
294 perror(argv[2]);
295 return(-1);
296 }
297 for (lineno = 1; fgets(linebuf, sizeof linebuf, inf); lineno++) {
298 if (!index(linebuf, '\n')) {
299 fprintf(stderr,
300 "%s line %d: too long or missing newline\n",
301 argv[2], lineno);
302 fclose(inf);
303 return(-1);
304 }
305 if (linebuf[0] != '#' || !isdigit(linebuf[1]))
306 continue;
307 rc = process_record(linebuf, pb_record_len, pb_record_count,
308 argv[2], lineno);
309 if (rc < 0) {
310 fclose(inf);
311 return(rc);
312 }
313 }
314 fclose(inf);
315 return(0);
316 }
317
318 static
319 decode_number_arg(arg, fixp)
320 char *arg;
321 u_char *fixp;
322 {
323 u_char digits[20];
324 unsigned ndigits, num_digit_bytes;
325 char *cp, *endp;
326 int c;
327
328 cp = arg;
329 if (*cp == '+') {
330 fixp[1] = 0x91;
331 cp++;
332 } else
333 fixp[1] = 0x81;
334 if (digit_char_to_gsm(*cp) < 0) {
335 inv_arg: fprintf(stderr, "error: invalid phone number argument\n");
336 return(-1);
337 }
338 for (ndigits = 0; ; ndigits++) {
339 c = digit_char_to_gsm(*cp);
340 if (c < 0)
341 break;
342 cp++;
343 if (ndigits >= 20) {
344 fprintf(stderr, "error: too many number digits\n");
345 return(-1);
346 }
347 digits[ndigits] = c;
348 }
349 if (ndigits & 1)
350 digits[ndigits++] = 0xF;
351 num_digit_bytes = ndigits >> 1;
352 fixp[0] = num_digit_bytes + 1;
353 pack_digit_bytes(digits, fixp + 2, num_digit_bytes);
354 if (*cp == ',') {
355 cp++;
356 if (!isdigit(*cp))
357 goto inv_arg;
358 fixp[1] = strtoul(cp, &endp, 0);
359 if (*endp)
360 goto inv_arg;
361 } else if (*cp)
362 goto inv_arg;
363 return(0);
364 }
365
366 static
367 decode_alphatag_arg(arg, record, maxlen)
368 char *arg;
369 u_char *record;
370 unsigned maxlen;
371 {
372 unsigned acclen, nadd;
373 char *cp;
374 int c;
375
376 cp = arg;
377 for (acclen = 0; *cp; ) {
378 c = *cp++;
379 if (c == '\\') {
380 if (*cp == '\0') {
381 fprintf(stderr,
382 "error: dangling backslash escape\n");
383 return(-1);
384 }
385 c = *cp++;
386 switch (c) {
387 case 'n':
388 c = '\n';
389 break;
390 case 'r':
391 c = '\r';
392 break;
393 case '"':
394 case '\\':
395 break;
396 default:
397 fprintf(stderr,
398 "error: non-understood backslash escape\n");
399 return(-1);
400 }
401 }
402 c = gsm7_encode_table[c];
403 if (c == 0xFF) {
404 fprintf(stderr,
405 "error: character in alpha tag string cannot be encoded in GSM7\n");
406 return(-1);
407 }
408 if (c & 0x80)
409 nadd = 2;
410 else
411 nadd = 1;
412 if (acclen + nadd > maxlen) {
413 fprintf(stderr,
414 "error: alpha tag string is longer than SIM limit\n");
415 return(-1);
416 }
417 if (c & 0x80)
418 record[acclen++] = 0x1B;
419 record[acclen++] = c & 0x7F;
420 }
421 return(0);
422 }
423
424 cmd_pb_update_imm(argc, argv)
425 char **argv;
426 {
427 int rc;
428 unsigned recno;
429 u_char record[255], *fixp;
430 unsigned pb_record_len, pb_record_count;
431
432 rc = phonebook_op_common(argv[1], &pb_record_len, &pb_record_count);
433 if (rc < 0)
434 return(rc);
435 recno = strtoul(argv[2], 0, 0);
436 if (recno < 1 || recno > pb_record_count) {
437 fprintf(stderr, "error: specified record number is invalid\n");
438 return(-1);
439 }
440 memset(record, 0xFF, pb_record_len);
441 fixp = record + pb_record_len - 14;
442 rc = decode_number_arg(argv[3], fixp);
443 if (rc < 0)
444 return(rc);
445 if (argv[4]) {
446 rc = decode_alphatag_arg(argv[4], record, pb_record_len - 14);
447 if (rc < 0)
448 return(rc);
449 }
450 return update_rec_op(recno, 0x04, record, pb_record_len);
451 }
452
453 static
454 decode_alphatag_arg_hex(arg, record, maxlen)
455 char *arg;
456 u_char *record;
457 unsigned maxlen;
458 {
459 unsigned acclen;
460
461 for (acclen = 0; ; acclen++) {
462 while (isspace(*arg))
463 arg++;
464 if (!*arg)
465 break;
466 if (!isxdigit(arg[0]) || !isxdigit(arg[1])) {
467 fprintf(stderr, "error: invalid hex string input\n");
468 return(-1);
469 }
470 if (acclen >= maxlen) {
471 fprintf(stderr,
472 "error: alpha tag string is longer than SIM limit\n");
473 return(-1);
474 }
475 record[acclen] = (decode_hex_digit(arg[0]) << 4) |
476 decode_hex_digit(arg[1]);
477 arg += 2;
478 }
479 return(0);
480 }
481
482 cmd_pb_update_imm_hex(argc, argv)
483 char **argv;
484 {
485 int rc;
486 unsigned recno;
487 u_char record[255], *fixp;
488 unsigned pb_record_len, pb_record_count;
489
490 rc = phonebook_op_common(argv[1], &pb_record_len, &pb_record_count);
491 if (rc < 0)
492 return(rc);
493 recno = strtoul(argv[2], 0, 0);
494 if (recno < 1 || recno > pb_record_count) {
495 fprintf(stderr, "error: specified record number is invalid\n");
496 return(-1);
497 }
498 memset(record, 0xFF, pb_record_len);
499 fixp = record + pb_record_len - 14;
500 rc = decode_number_arg(argv[3], fixp);
501 if (rc < 0)
502 return(rc);
503 rc = decode_alphatag_arg_hex(argv[4], record, pb_record_len - 14);
504 if (rc < 0)
505 return(rc);
506 return update_rec_op(recno, 0x04, record, pb_record_len);
507 }