Cosmetics, fixed headers, comment style
[hayes-ril.git] / at.c
1 /*
2  * This file is part of hayes-ril.
3  *
4  * Copyright (C) 2012 Paul Kocialkowski <contact@paulk.fr>
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 #include <string.h>
20 #include <ctype.h>
21
22 #define LOG_TAG "RIL-AT"
23 #include <utils/Log.h>
24
25 #include <hayes-ril.h>
26
27 int at_strings_compare(char *major, char *minor)
28 {
29         if(strncmp(major, minor, strlen(major)) == 0)
30                 return 1;
31         else
32                 return 0;
33 }
34
35 void at_string_clean(char *string, int length)
36 {
37         int i=0;
38
39         for(i=length-1; i >= 0 ; i--) {
40                 if(!isprint(string[i]))
41                         string[i] = '\0';
42         }
43 }
44
45 int at_line_parse_status(char *data, int length, char **error_p)
46 {
47         // TODO: defined rc, fill error_p
48
49         *error_p = NULL;
50
51         if(at_strings_compare("OK", data))
52                 return 1;
53
54         if(at_strings_compare("CONNECT", data))
55                 return 2;
56
57         if(at_strings_compare("ERROR", data))
58                 return -1;
59
60         // TODO: Other error codes
61
62         // TODO: undefined magic
63         return 0;
64 }
65
66 int at_line_parse_command_data(char *data, int length, char **response_command, char **response_data)
67 {
68         char *string = NULL;
69         int string_length = 0;
70         int close_your_eyes = 0;
71         int mark = 0;
72         int i;
73
74
75         for(i=0 ; i < length ; i++) {
76                 if(data[i] == ':' && mark == 0) {
77                         if(i > 0) {
78                                 data[i] = '\0';
79
80                                 string_length = i + 1;
81                                 string = strndup(data, string_length);
82
83                                 if(!isprint(string[0])) {
84                                         free(string);
85                                 } else {
86                                         *response_command = string;
87                                 }
88
89                                 mark = i + 1;
90                         }
91
92                         while(isspace(data[i+1])) {
93                                 mark = i + 2;
94                                 i++;
95                         }
96                 }
97
98                 if(data[i] == '"') {
99                         if(close_your_eyes & AT_PARSE_DOUBLE_QUOTE)
100                                 close_your_eyes &= ~AT_PARSE_DOUBLE_QUOTE;
101                         else
102                                 close_your_eyes |= AT_PARSE_DOUBLE_QUOTE;
103                 }
104
105                 if(data[i] == '\'') {
106                         if(close_your_eyes & AT_PARSE_SINGLE_QUOTE)
107                                 close_your_eyes &= ~AT_PARSE_SINGLE_QUOTE;
108                         else
109                                 close_your_eyes |= AT_PARSE_SINGLE_QUOTE;
110                 }
111
112                 // Found = or ? outside of any quotes: assume no data
113                 if(!close_your_eyes && (data[i] == '=' || data[i] == '?') && mark == 0) {
114                         data[i] = '\0';
115
116                         string_length = i + 1;
117                         string = strndup(data, string_length);
118
119                         if(!isprint(string[0])) {
120                                 free(string);
121                         } else {
122                                 *response_command = string;
123                         }
124
125                         return 0;
126                 }
127         }
128
129
130         if(length - mark > 0) {
131                 string_length = length - mark;
132                 string = strndup(data + mark, string_length);
133
134                 if(mark == 0) {
135                         *response_command = string;
136                         return 0;
137                 } else {
138                         *response_data = string;
139                         return string_length;
140                 }
141         }
142
143         return 0;
144 }
145
146 int at_responses_process_line(struct at_response ***responses_p, int responses_count, char *data, int length)
147 {
148         struct at_response **responses = NULL;
149
150         char *response_command = NULL;
151         char *response_data = NULL;
152         int response_data_length = 0;
153         char *response_error = NULL;
154         int response_status = 0;
155
156         char **response_previous_data = NULL;
157         int response_data_count = 0;
158
159         int index = -1;
160         int count = 0;
161         int i;
162
163         if(responses_p == NULL || data == NULL || length < 0) {
164                 LOGE("Failed to process AT response: wrong arguments!");
165                 return 0;
166         }
167
168         responses = *responses_p;
169
170         // Parse status
171         response_status = at_line_parse_status(data, length, &response_error);
172
173         if(response_status != 0) {
174                 if(responses_count > 0 && responses != NULL) {
175                         for(i=responses_count-1 ; i >= 0; i--) {
176                                 if(responses[i]->status == 0) {
177                                         responses[i]->status = response_status;
178                                         responses[i]->error = response_error;
179
180                                         // Do not alloc a new response
181                                         if(index == -1)
182                                                 index = i;
183                                 }
184                         }
185                 }
186
187                 // Alloc a new response
188                 if(index == -1) {
189                         // Index is the request index in the requests array
190                         index = responses_count;
191                         // Count is the total count of requests in the array
192                         count = index + 1;
193
194                         // Alloc the array with the new size
195                         *responses_p = malloc(sizeof(struct at_response *) * count);
196
197                         // Copy and free previous data
198                         if(responses != NULL) {
199                                 memcpy(*responses_p, responses, sizeof(struct at_response *) * responses_count);
200                                 free(responses);
201                         }
202
203                         responses = *responses_p;
204
205                         // Alloc new structure and copy obtained data
206                         responses[index] = calloc(1, sizeof(struct at_response));
207                         responses[index]->status = response_status;
208                         responses[index]->error = response_error;
209                 }
210         } else {
211                 // Parse command and data
212                 response_data_length = at_line_parse_command_data(data, length, &response_command, &response_data);
213
214                 if(response_command == NULL) {
215                         LOGE("Failed to parse command!");
216                         return responses_count;
217                 }
218
219                 at_string_clean(response_command, strlen(response_command) + 1);
220
221                 if(responses_count > 0 && responses != NULL) {
222                         for(i=responses_count-1 ; i >= 0; i--) {
223                                 if(responses[i]->command != NULL) {
224                                         if(strcmp(responses[i]->command, response_command) == 0)
225                                                 // Do not alloc a new response
226                                                 index = i;
227                                 }
228                         }
229                 }
230
231                 // Alloc a new response
232                 if(index == -1) {
233                         // Index is the request index in the requests array
234                         index = responses_count;
235                         // Count is the total count of requests in the array
236                         count = index + 1;
237
238                         // Alloc the array with the new size
239                         *responses_p = malloc(sizeof(struct at_response *) * count);
240
241                         // Copy and free previous data
242                         if(responses != NULL) {
243                                 memcpy(*responses_p, responses, sizeof(struct at_response *) * responses_count);
244                                 free(responses);
245                         }
246
247                         responses = *responses_p;
248
249                         // Alloc new structure and copy obtained data
250                         responses[index] = calloc(1, sizeof(struct at_response));
251                         responses[index]->command = response_command;
252                 }
253
254                 if(response_data_length > 0 && response_data != NULL) {
255                         at_string_clean(response_data, response_data_length);
256
257                         response_previous_data = responses[index]->data;
258
259                         // Data count is the total count of elements in the request data
260                         response_data_count = responses[index]->data_count + 1;
261
262                         // Alloc the array with the new size
263                         responses[index]->data = malloc(sizeof(char *) * response_data_count);
264
265                         // Copy and free previous data
266                         if(response_previous_data != NULL) {
267                                 memcpy(responses[index]->data, response_previous_data, sizeof(char *) * responses[index]->data_count);
268                                 free(response_previous_data);
269                         }
270
271                         responses[index]->data_count = response_data_count;
272                         responses[index]->data[response_data_count - 1] = response_data;
273                 }
274         }
275
276         return count > responses_count ? count : responses_count;
277 }
278
279 int at_responses_process(struct at_response ***responses_p, char *data, int length)
280 {
281         int responses_count = 0;
282         int count = 0;
283
284         char *string = NULL;
285         int string_length = 0;
286         int mark = 0;
287         int i;
288
289         if(responses_p == NULL || data == NULL || length < 0) {
290                 LOGE("Failed to process AT response: wrong arguments!");
291                 return 0;
292         }
293
294         for(i=0 ; i < length ; i++) {
295                 if(data[i] == '\r' || data[i] == ';') {
296                         if(i - mark > 0) {
297                                 data[i] = '\0';
298
299                                 string_length = i - mark + 1;
300                                 string = strndup(data + mark, string_length);
301
302                                 if(!isprint(string[0])) {
303                                         free(string);
304                                 }
305                                 else {
306                                         count = at_responses_process_line(responses_p, responses_count, string, string_length);
307                                         if(count > responses_count)
308                                                 responses_count = count;
309
310                                         free(string);
311                                 }
312
313                                 mark = i + 1;
314                         }
315
316                         while(isspace(data[i+1])) {
317                                 mark = i + 2;
318                                 i++;
319                         }
320                 }
321         }
322
323         if(length - mark > 0) {
324                 for(i=mark ; i < length ; i++)
325                         if(!isprint(data[i]))
326                                 break;
327
328                 if(i - mark > 0) {
329                         string_length = i - mark + 1;
330                         string = calloc(1, string_length);
331
332                         memcpy(string, data + mark, string_length - 1);
333                         string[string_length - 1] = '\0';
334
335                         count = at_responses_process_line(responses_p, responses_count, string , string_length);
336                         if(count > responses_count)
337                                 responses_count = count;
338
339                         free(string);
340                 }
341         }
342
343         return responses_count;
344 }
345
346 void at_responses_dump(struct at_response **responses, int responses_count)
347 {
348         int i;
349
350         LOGD("== AT RESPONSES DUMP ==\n");
351         for(i=0 ; i < responses_count ; i++) {
352                 LOGD("#%d command=%s status=%d error=%s\n", i, responses[i]->command, responses[i]->status, responses[i]->error);
353                 if(responses[i]->data_count > 0) {
354                         int j;
355                         for(j=0 ; j < responses[i]->data_count ; j++) {
356                                 LOGD("    #%d data='%s'\n", j, responses[i]->data[j]);
357                         }
358                 }
359         }
360 }
361
362 void at_responses_free(struct at_response **responses, int responses_count)
363 {
364         int i, j;
365
366         for(i=0 ; i < responses_count ; i++) {
367                 if(responses[i]->data_count > 0 && responses[i]->data != NULL) {
368                         for(j=0 ; j < responses[i]->data_count ; j++) {
369                                 if(responses[i]->data[j] != NULL) {
370                                         free(responses[i]->data[j]);
371                                         responses[i]->data[j] = NULL;
372                                 }
373                         }
374
375                         free(responses[i]->data);
376                         responses[i]->data_count = 0;
377                 }
378
379                 if(responses[i]->command != NULL) {
380                         free(responses[i]->command);
381                         responses[i]->command = NULL;
382                 }
383
384                 if(responses[i]->error != NULL) {
385                         free(responses[i]->error);
386                         responses[i]->error = NULL;
387                 }
388         }
389 }