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