FreeCalypso > hg > freecalypso-hwlab
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 } |