FreeCalypso > hg > freecalypso-hwlab
comparison simtool/pbupdate.c @ 111:5bfb5a7262c1
fc-simtool: pb-update command implemented
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Tue, 26 Jan 2021 03:22:26 +0000 |
parents | |
children | 06e2d5c60cbd |
comparison
equal
deleted
inserted
replaced
110:a6de34816297 | 111:5bfb5a7262c1 |
---|---|
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 <pcsclite.h> | |
12 #include <winscard.h> | |
13 #include "globals.h" | |
14 | |
15 static u_char gsm7_encode_table[256] = { | |
16 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 0x00 */ | |
17 0xFF, 0xFF, '\n', 0xFF, 0xFF, '\r', 0xFF, 0xFF, | |
18 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 0x10 */ | |
19 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, | |
20 ' ', '!', '"', '#', 0x02, '%', '&', 0x27, /* 0x20 */ | |
21 '(', ')', '*', '+', ',', '-', '.', '/', | |
22 '0', '1', '2', '3', '4', '5', '6', '7', /* 0x30 */ | |
23 '8', '9', ':', ';', '<', '=', '>', '?', | |
24 0x00, 'A', 'B', 'C', 'D', 'E', 'F', 'G', /* 0x40 */ | |
25 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', | |
26 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', /* 0x50 */ | |
27 'X', 'Y', 'Z', 0xBC, 0xAF, 0xBE, 0x94, 0x11, | |
28 0xFF, 'a', 'b', 'c', 'd', 'e', 'f', 'g', /* 0x60 */ | |
29 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', | |
30 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', /* 0x70 */ | |
31 'x', 'y', 'z', 0xA8, 0xC0, 0xA9, 0xBD, 0xFF, | |
32 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 0x80 */ | |
33 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, | |
34 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 0x90 */ | |
35 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, | |
36 0xFF, 0x40, 0xFF, 0x01, 0x24, 0x03, 0xFF, 0x5F, /* 0xA0 */ | |
37 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, | |
38 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 0xB0 */ | |
39 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x60, | |
40 0xFF, 0xFF, 0xFF, 0xFF, 0x5B, 0x0E, 0x1C, 0x09, /* 0xC0 */ | |
41 0xFF, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, | |
42 0xFF, 0x5D, 0xFF, 0xFF, 0xFF, 0xFF, 0x5C, 0xFF, /* 0xD0 */ | |
43 0x0B, 0xFF, 0xFF, 0xFF, 0x5E, 0xFF, 0xFF, 0x1E, | |
44 0x7F, 0xFF, 0xFF, 0xFF, 0x7B, 0x0F, 0x1D, 0xFF, /* 0xE0 */ | |
45 0x04, 0x05, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xFF, | |
46 0xFF, 0x7D, 0x08, 0xFF, 0xFF, 0xFF, 0x7C, 0xFF, /* 0xF0 */ | |
47 0x0C, 0x06, 0xFF, 0xFF, 0x7E, 0xFF, 0xFF, 0xFF | |
48 }; | |
49 | |
50 static | |
51 digit_char_to_gsm(ch) | |
52 { | |
53 switch (ch) { | |
54 case '0': | |
55 case '1': | |
56 case '2': | |
57 case '3': | |
58 case '4': | |
59 case '5': | |
60 case '6': | |
61 case '7': | |
62 case '8': | |
63 case '9': | |
64 return (ch - '0'); | |
65 case '*': | |
66 return 0xA; | |
67 case '#': | |
68 return 0xB; | |
69 case 'a': | |
70 case 'b': | |
71 case 'c': | |
72 return (ch - 'a' + 0xC); | |
73 case 'A': | |
74 case 'B': | |
75 case 'C': | |
76 return (ch - 'A' + 0xC); | |
77 } | |
78 return (-1); | |
79 } | |
80 | |
81 static void | |
82 pack_digit_bytes(digits, dest, num_digit_bytes) | |
83 u_char *digits, *dest; | |
84 unsigned num_digit_bytes; | |
85 { | |
86 u_char *sp, *dp; | |
87 unsigned n; | |
88 | |
89 sp = digits; | |
90 dp = dest; | |
91 for (n = 0; n < num_digit_bytes; n++) { | |
92 *dp++ = sp[0] | (sp[1] << 4); | |
93 sp += 2; | |
94 } | |
95 } | |
96 | |
97 static char * | |
98 decode_qstring_alpha(cp, record, filename_for_errs, lineno_for_errs) | |
99 char *cp, *filename_for_errs; | |
100 u_char *record; | |
101 { | |
102 unsigned maxlen, acclen, nadd; | |
103 int c; | |
104 | |
105 maxlen = curfile_record_len - 14; | |
106 for (acclen = 0; ; ) { | |
107 if (*cp == '\0') { | |
108 unterm_qstring: fprintf(stderr, | |
109 "%s line %d: unterminated quoted string\n", | |
110 filename_for_errs, lineno_for_errs); | |
111 return(0); | |
112 } | |
113 if (*cp == '"') | |
114 break; | |
115 c = *cp++; | |
116 if (c == '\\') { | |
117 if (*cp == '\0') | |
118 goto unterm_qstring; | |
119 c = *cp++; | |
120 switch (c) { | |
121 case 'n': | |
122 c = '\n'; | |
123 break; | |
124 case 'r': | |
125 c = '\r'; | |
126 break; | |
127 case '"': | |
128 case '\\': | |
129 break; | |
130 default: | |
131 fprintf(stderr, | |
132 "%s line %d: non-understood backslash escape\n", | |
133 filename_for_errs, lineno_for_errs); | |
134 return(0); | |
135 } | |
136 } | |
137 c = gsm7_encode_table[c]; | |
138 if (c == 0xFF) { | |
139 fprintf(stderr, | |
140 "%s line %d: character in quoted string cannot be encoded in GSM7\n", | |
141 filename_for_errs, lineno_for_errs); | |
142 return(0); | |
143 } | |
144 if (c & 0x80) | |
145 nadd = 2; | |
146 else | |
147 nadd = 1; | |
148 if (acclen + nadd > maxlen) { | |
149 fprintf(stderr, | |
150 "%s line %d: alpha tag string is longer than SIM limit\n", | |
151 filename_for_errs, lineno_for_errs); | |
152 return(0); | |
153 } | |
154 if (c & 0x80) | |
155 record[acclen++] = 0x1B; | |
156 record[acclen++] = c & 0x7F; | |
157 } | |
158 return(cp + 1); | |
159 } | |
160 | |
161 static char * | |
162 decode_hex_alpha(cp, record, filename_for_errs, lineno_for_errs) | |
163 char *cp, *filename_for_errs; | |
164 u_char *record; | |
165 { | |
166 unsigned maxlen, acclen; | |
167 | |
168 maxlen = curfile_record_len - 14; | |
169 for (acclen = 0; ; ) { | |
170 if (!isxdigit(cp[0]) || !isxdigit(cp[1])) | |
171 break; | |
172 if (acclen >= maxlen) { | |
173 fprintf(stderr, | |
174 "%s line %d: alpha tag string is longer than SIM limit\n", | |
175 filename_for_errs, lineno_for_errs); | |
176 return(0); | |
177 } | |
178 record[acclen++] = (decode_hex_digit(cp[0]) << 4) | | |
179 decode_hex_digit(cp[1]); | |
180 cp += 2; | |
181 } | |
182 return(cp); | |
183 } | |
184 | |
185 static | |
186 process_record(line, filename_for_errs, lineno_for_errs) | |
187 char *line, *filename_for_errs; | |
188 { | |
189 unsigned recno; | |
190 u_char record[255], *fixp; | |
191 u_char digits[20]; | |
192 unsigned ndigits, num_digit_bytes; | |
193 char *cp; | |
194 int c; | |
195 | |
196 recno = strtoul(line+1, 0, 10); | |
197 if (recno < 1 || recno > curfile_record_count) { | |
198 fprintf(stderr, "%s line %d: record number is out of range\n", | |
199 filename_for_errs, lineno_for_errs); | |
200 return(-1); | |
201 } | |
202 cp = line + 1; | |
203 while (isdigit(*cp)) | |
204 cp++; | |
205 if (*cp++ != ':') { | |
206 inv_syntax: fprintf(stderr, "%s line %d: invalid syntax\n", | |
207 filename_for_errs, lineno_for_errs); | |
208 return(-1); | |
209 } | |
210 while (isspace(*cp)) | |
211 cp++; | |
212 memset(record, 0xFF, curfile_record_len); | |
213 fixp = record + curfile_record_len - 14; | |
214 if (digit_char_to_gsm(*cp) < 0) | |
215 goto inv_syntax; | |
216 for (ndigits = 0; ; ndigits++) { | |
217 c = digit_char_to_gsm(*cp); | |
218 if (c < 0) | |
219 break; | |
220 cp++; | |
221 if (ndigits >= 20) { | |
222 fprintf(stderr, "%s line %d: too many number digits\n", | |
223 filename_for_errs, lineno_for_errs); | |
224 return(-1); | |
225 } | |
226 digits[ndigits] = c; | |
227 } | |
228 if (ndigits & 1) | |
229 digits[ndigits++] = 0xF; | |
230 num_digit_bytes = ndigits >> 1; | |
231 fixp[0] = num_digit_bytes + 1; | |
232 pack_digit_bytes(digits, fixp + 2, num_digit_bytes); | |
233 if (*cp++ != ',') | |
234 goto inv_syntax; | |
235 if (cp[0] != '0' || cp[1] != 'x' && cp[1] != 'X' || !isxdigit(cp[2]) || | |
236 !isxdigit(cp[3]) || !isspace(cp[4])) | |
237 goto inv_syntax; | |
238 fixp[1] = strtoul(cp, 0, 16); | |
239 cp += 5; | |
240 while (isspace(*cp)) | |
241 cp++; | |
242 if (!strncasecmp(cp, "CCP=", 4)) { | |
243 cp += 4; | |
244 fixp[12] = strtoul(cp, 0, 0); | |
245 while (*cp && !isspace(*cp)) | |
246 cp++; | |
247 while (isspace(*cp)) | |
248 cp++; | |
249 } | |
250 if (!strncasecmp(cp, "EXT=", 4)) { | |
251 cp += 4; | |
252 fixp[13] = strtoul(cp, 0, 0); | |
253 while (*cp && !isspace(*cp)) | |
254 cp++; | |
255 while (isspace(*cp)) | |
256 cp++; | |
257 } | |
258 if (*cp == '"') { | |
259 cp++; | |
260 cp = decode_qstring_alpha(cp, record, filename_for_errs, | |
261 lineno_for_errs); | |
262 if (!cp) | |
263 return(-1); | |
264 } else if (!strncasecmp(cp, "HEX", 3)) { | |
265 cp += 3; | |
266 while (isspace(*cp)) | |
267 cp++; | |
268 cp = decode_hex_alpha(cp, record, filename_for_errs, | |
269 lineno_for_errs); | |
270 if (!cp) | |
271 return(-1); | |
272 } else | |
273 goto inv_syntax; | |
274 while (isspace(*cp)) | |
275 cp++; | |
276 if (*cp) | |
277 goto inv_syntax; | |
278 return update_rec_op(recno, 0x04, record, curfile_record_len); | |
279 } | |
280 | |
281 cmd_pb_update(argc, argv) | |
282 char **argv; | |
283 { | |
284 int rc; | |
285 FILE *inf; | |
286 int lineno; | |
287 char linebuf[1024]; | |
288 | |
289 rc = phonebook_op_common(argv[1]); | |
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, argv[2], lineno); | |
308 if (rc < 0) { | |
309 fclose(inf); | |
310 return(rc); | |
311 } | |
312 } | |
313 fclose(inf); | |
314 return(0); | |
315 } |