Translation update done using Pootle.
[gammu.git] / tests / pdu-decode.c
blobb3f354bbd502feec2d29a191700bd2b67ab3d069
1 /*
2 * Very simple PDU decoder, just parses header and is independent to
3 * Gammu library. It is used for verification of Gammu test - anything
4 * this fails to process should also fail in Gammu.
5 */
7 #include <stdlib.h>
8 #include <stdio.h>
9 #include <string.h>
10 #include <ctype.h>
12 #define BUFFER_SIZE 16384
14 /**
15 * Converts hex digit to number, returns -1 on failure.
17 int hexdigit2number(const char digit)
19 if (digit >= '0' && digit <= '9') {
20 return digit - '0';
22 if (digit >= 'a' && digit <= 'f') {
23 return 0xa + digit - 'a';
25 if (digit >= 'A' && digit <= 'F') {
26 return 0xa + digit - 'A';
28 printf("%c is not a digit!\n", digit);
29 return -1;
32 /**
33 * Converts hex string of arbitrary length to number, returns -1 on
34 * failure.
36 int hex2number(const char *buffer, const size_t len)
38 int result = 0, tmp;
39 size_t pos;
41 for (pos = 0; pos < len; pos++) {
42 result = result << 4;
43 tmp = hexdigit2number(buffer[pos]);
44 if (tmp < 0)
45 return tmp;
46 result += tmp;
48 return result;
51 /**
52 * Reads single number encoded in PDU.
54 int pdu_get_number(const char *buffer, const int semioctet)
56 int length;
57 int type;
58 char *out;
59 int i;
61 length = hex2number(buffer, 2);
62 if (semioctet) {
63 if (length % 2)
64 length++;
65 length = length / 2 + 1;
67 printf("Number length = %d\n", length);
69 if (length == 0)
70 return 2;
72 type = hex2number(buffer + 2, 2);
73 printf("Number type = %d\n", type);
75 out = (char *)malloc((2 * length) + 1);
76 if (out == NULL)
77 return -1;
78 memset(out, 0, 2 * length);
80 for (i = 0; i < (length - 1) * 2; i++) {
81 if (!isxdigit((int)buffer[4 + i])) {
82 printf("Non hex digit in PDU (%s)!\n", buffer + 4 + i);
83 free(out);
84 return -1;
87 if (i % 2 == 0) {
88 out[i + 1] = buffer[4 + i];
89 if (out[i + 1] == 'F') {
90 out[i + 1] = '\0';
92 } else {
93 out[i - 1] = buffer[4 + i];
96 printf("Number = %s\n", out);
97 free(out);
99 return (length * 2) + 2;
103 * Parses timestamp from PDU.
105 int pdu_get_timestamp(const char *buffer)
107 int i;
109 for (i = 0; i < 14; i++) {
110 if (!isxdigit((int)buffer[i]))
111 return -1;
114 printf("Date: %d-%d-%d %d:%d:%d TZ=%d\n",
115 hex2number(buffer + 0, 2),
116 hex2number(buffer + 2, 2), hex2number(buffer + 4, 2), hex2number(buffer + 6, 2), hex2number(buffer + 8, 2), hex2number(buffer + 10, 2), hex2number(buffer + 12, 2)
119 return 14;
123 * Decodes textual PDU.
125 int pdu_decode(const char *buffer)
127 /* Values */
128 int type;
129 int mr;
130 /* Status variables */
131 int pos = 0, ret;
132 /* Message content */
133 int submit = 0, deliver = 0, report = 0;
134 int vpf = 0;
135 int rp = 0;
136 int udh = 0;
137 int pid = 0;
138 int dcs = 0;
139 int vp = 0;
140 int udhl = 0;
141 int ud;
142 int i;
144 /* SMSC number */
145 ret = pdu_get_number(buffer + pos, 0);
146 if (ret < 0)
147 return ret;
148 pos += ret;
150 /* Message type */
151 type = hex2number(buffer + pos, 2);
152 if (type < 0)
153 return type;
154 pos += 2;
155 printf("Message type: %02x - ", type);
157 switch (type & 0x3) {
158 case 0:
159 printf("Deliver");
160 deliver = 1;
161 break;
162 case 1:
163 printf("Submit");
164 submit = 1;
165 break;
166 case 2:
167 printf("Status report\n");
168 report = 1;
169 break;
170 case 3:
171 printf("Reserved\n");
172 return -1;
174 if (submit || deliver) {
175 if (type & (1 << 7)) {
176 rp = 1;
178 if (type & (1 << 6)) {
179 udh = 1;
182 if (rp) {
183 printf(", Reply path set");
185 if (udh) {
186 printf(", UDH included");
188 if (submit) {
189 switch (type & (0x3 << 3)) {
190 case 0:
191 printf(", No VP");
192 break;
193 case 1:
194 printf(", Reserved VP!\n");
195 return -1;
196 case 2:
197 printf(", Relative VP");
198 vpf = 2;
199 break;
200 case 3:
201 printf(", Absolute VP");
202 vpf = 3;
203 break;
206 printf("\n");
208 /* Message reference (for submit) */
209 if (submit || report) {
210 mr = hex2number(buffer + pos, 2);
211 if (mr < 0)
212 return mr;
213 pos += 2;
214 printf("MR = 0x%02X\n", mr);
217 /* Address (sender for deliver, receiver for submit, recipient
218 * for report) */
219 ret = pdu_get_number(buffer + pos, 1);
220 if (ret < 0)
221 return ret;
222 pos += ret;
224 if (report) {
225 /* Timestamp */
226 ret = pdu_get_timestamp(buffer + pos);
227 if (ret < 0)
228 return ret;
229 pos += ret;
231 /* SMSC timestamp */
232 ret = pdu_get_timestamp(buffer + pos);
233 if (ret < 0)
234 return ret;
235 pos += ret;
237 if (submit || deliver) {
238 /* PID */
239 pid = hex2number(buffer + pos, 2);
240 if (pid < 0)
241 return pid;
242 pos += 2;
243 printf("PID = 0x%02X\n", pid);
245 /* DCS */
246 dcs = hex2number(buffer + pos, 2);
247 if (dcs < 0)
248 return dcs;
249 pos += 2;
250 printf("DCS = 0x%02X\n", dcs);
252 if (submit) {
253 /* Validity */
254 if (vpf == 2 || vpf == 0) {
255 vp = hex2number(buffer + pos, 2);
256 if (vp < 0)
257 return vp;
258 pos += 2;
259 printf("VP = 0x%02X\n", vp);
260 } else if (vpf == 3) {
261 ret = pdu_get_timestamp(buffer + pos);
262 if (ret < 0)
263 return ret;
264 pos += ret;
267 if (deliver) {
268 /* SMSC timestamp */
269 ret = pdu_get_timestamp(buffer + pos);
270 if (ret < 0)
271 return ret;
272 pos += ret;
274 if (submit || deliver) {
275 /* UD */
276 udhl = hex2number(buffer + pos, 2);
277 if (udhl < 0)
278 return udhl;
279 pos += 2;
280 printf("UDL = 0x%02X\n", udhl);
281 /* GSM 03.40 section 9.2.3.10 (TP-Data-Coding-Scheme) and GSM 03.38 section 4 */
282 if ((((dcs & 0xC0) == 0) && ((dcs == 0) || ((dcs & 0x2C) == 0x00) || ((dcs & 0x2C) == 0x20))) ||
283 ((((dcs & 0xF0) == 0xC0) || ((dcs & 0xF0) == 0xD0)) && ((dcs & 4) != 4)) || (((dcs & 0xF0) == 0xF0) && ((dcs & 8) != 8) && ((dcs & 4) == 0))) {
284 if ((udhl * 7) % 8 != 0) {
285 udhl = (udhl * 7) / 8;
286 udhl++;
287 } else {
288 udhl = (udhl * 7) / 8;
290 printf("UDL[adjusted] = 0x%02X\n", udhl);
292 printf("data = ");
293 for (i = 0; i < udhl; i++) {
294 ud = hex2number(buffer + pos, 2);
295 if (ud < 0) {
296 printf("\nData too short!\n");
297 return ud;
299 pos += 2;
300 printf("%02X", ud);
302 printf("\n");
305 if (buffer[pos] != '\r' && buffer[pos] != '\n' && buffer[pos] != '\0') {
306 printf("Did not reach end: %s\n", buffer + pos);
307 return 1;
310 return 0;
313 int main(int argc, char **argv)
315 char buffer[BUFFER_SIZE];
316 char *pos;
317 FILE *f;
318 size_t len;
320 /* Check parameters */
321 if (argc != 2) {
322 printf("Not enough parameters!\nUsage: pdu-decode comm.dump\n");
323 return 1;
326 /* Open file */
327 f = fopen(argv[1], "r");
328 if (f == NULL) {
329 printf("Could not open %s\n", argv[1]);
330 return 1;
333 /* Read data */
334 len = fread(buffer, 1, sizeof(buffer) - 1, f);
335 if (!feof(f)) {
336 printf("Could not read whole file %s\n", argv[1]);
337 fclose(f);
338 return 1;
340 /* Zero terminate data */
341 buffer[len] = 0;
343 /* Close file */
344 fclose(f);
346 pos = strchr(buffer, '\n');
347 if (pos == NULL)
348 return 2;
349 pos++;
351 pos = strchr(pos, '\n');
352 if (pos == NULL)
353 return 2;
354 pos++;
356 if (pdu_decode(pos) < 0)
357 return 3;
359 return 0;
362 /* Editor configuration
363 * vim: noexpandtab sw=8 ts=8 sts=8 tw=72: