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 }