1 /*
2 
3   G N O K I I
4 
5   A Linux/Unix toolset and driver for the mobile phones.
6 
7   This file is part of gnokii.
8 
9   Gnokii is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; either version 2 of the License, or
12   (at your option) any later version.
13 
14   Gnokii is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18 
19   You should have received a copy of the GNU General Public License
20   along with gnokii; if not, write to the Free Software
21   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22 
23   Copyright (C) 2001      Manfred Jonsson <manfred.jonsson@gmx.de>
24   Copyright (C) 2002      Pavel Machek, Petr Cech
25   Copyright (C) 2002-2011 Pawel Kot
26   Copyright (C) 2002-2003 Ladis Michl
27   Copyright (C) 2002-2004 BORBELY Zoltan
28   Copyright (C) 2003-2004 Igor Popik
29   Copyright (C) 2004      Hugo Hass, Ron Yorston
30   Copyright (C) 2007      Jeremy Laine
31 
32   This file provides functions specific to generic AT command compatible
33   phones. See README for more details on supported mobile phones.
34 
35 */
36 
37 #include "config.h"
38 
39 #include <string.h>
40 #include <stdlib.h>
41 #include <ctype.h>
42 
43 #include "gnokii-internal.h"
44 #include "gnokii.h"
45 #include "phones/generic.h"
46 #include "phones/atgen.h"
47 #include "phones/atbosch.h"
48 #include "phones/ateric.h"
49 #include "phones/athuawei.h"
50 #include "phones/atmot.h"
51 #include "phones/atnok.h"
52 #include "phones/atsie.h"
53 #include "phones/atsoer.h"
54 #include "phones/atsam.h"
55 #include "phones/atsag.h"
56 #include "phones/atlg.h"
57 #include "links/atbus.h"
58 
59 static gn_error Initialise(gn_data *setupdata, struct gn_statemachine *state);
60 static gn_error Terminate(gn_data *data, struct gn_statemachine *state);
61 static gn_error Functions(gn_operation op, gn_data *data, struct gn_statemachine *state);
62 static gn_error Reply(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state);
63 static gn_error ReplyIdentify(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state);
64 static gn_error ReplyGetRFLevel(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state);
65 static gn_error ReplyGetBattery(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state);
66 static gn_error Parse_ReplyGetBattery(gn_data *data, struct gn_statemachine *state);
67 static gn_error ReplyReadPhonebook(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state);
68 static gn_error ReplyReadPhonebookExt(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state);
69 static gn_error ReplyMemoryStatus(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state);
70 static gn_error ReplyMemoryRange(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state);
71 static gn_error Parse_ReplyMemoryRange(gn_data *data, struct gn_statemachine *state);
72 static gn_error ReplyCallDivert(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state);
73 static gn_error ReplyGetPrompt(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state);
74 static gn_error ReplyGetSMSFolders(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state);
75 static gn_error ReplyGetSMSStatus(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state);
76 static gn_error ReplySendSMS(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state);
77 static gn_error ReplyGetSMS(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state);
78 /* static gn_error ReplyDeleteSMS(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state); */
79 static gn_error ReplyGetCharset(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state);
80 static gn_error ReplyGetSMSCenter(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state);
81 #ifdef SECURITY
82 static gn_error ReplyGetSecurityCodeStatus(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state);
83 #endif
84 static gn_error ReplyGetNetworkInfo(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state);
85 static gn_error ReplyRing(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state);
86 static gn_error ReplyGetDateTime(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state);
87 static gn_error ReplyGetActiveCalls(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state);
88 static gn_error ReplyIncomingSMS(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state);
89 static gn_error ReplyGetSMSMemorySize(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state);
90 
91 static gn_error AT_Identify(gn_data *data, struct gn_statemachine *state);
92 static gn_error AT_GetModel(gn_data *data, struct gn_statemachine *state);
93 static gn_error AT_GetRevision(gn_data *data, struct gn_statemachine *state);
94 static gn_error AT_GetIMEI(gn_data *data, struct gn_statemachine *state);
95 static gn_error AT_GetManufacturer(gn_data *data, struct gn_statemachine *state);
96 static gn_error AT_GetBattery(gn_data *data, struct gn_statemachine *state);
97 static gn_error AT_GetRFLevel(gn_data *data, struct gn_statemachine *state);
98 static gn_error AT_GetMemoryStatus(gn_data *data, struct gn_statemachine *state);
99 static gn_error AT_GetMemoryRange(gn_data *data, struct gn_statemachine *state);
100 static gn_error AT_ReadPhonebook(gn_data *data, struct gn_statemachine *state);
101 static gn_error AT_WritePhonebook(gn_data *data, struct gn_statemachine *state);
102 static gn_error AT_DeletePhonebook(gn_data *data, struct gn_statemachine *state);
103 static gn_error AT_ReadPhonebookExt(gn_data *data, struct gn_statemachine *state);
104 static gn_error AT_WritePhonebookExt(gn_data *data, struct gn_statemachine *state);
105 static gn_error AT_DeletePhonebookExt(gn_data *data, struct gn_statemachine *state);
106 static gn_error AT_CallDivert(gn_data *data, struct gn_statemachine *state);
107 static gn_error AT_SetPDUMode(gn_data *data, struct gn_statemachine *state);
108 static gn_error AT_GetSMSFolders(gn_data *data, struct gn_statemachine *state);
109 static gn_error AT_GetSMSFolderStatus(gn_data *data, struct gn_statemachine *state);
110 static gn_error AT_GetSMSStatus(gn_data *data, struct gn_statemachine *state);
111 static gn_error AT_SendSMS(gn_data *data, struct gn_statemachine *state);
112 static gn_error AT_SaveSMS(gn_data *data, struct gn_statemachine *state);
113 static gn_error AT_WriteSMS(gn_data *data, struct gn_statemachine *state, unsigned char *cmd);
114 static gn_error AT_GetSMS(gn_data *data, struct gn_statemachine *state);
115 static gn_error AT_DeleteSMS(gn_data *data, struct gn_statemachine *state);
116 static gn_error AT_GetCharset(gn_data *data, struct gn_statemachine *state);
117 static gn_error AT_SetCharset(gn_data *data, struct gn_statemachine *state);
118 static gn_error AT_GetSMSCenter(gn_data *data, struct gn_statemachine *state);
119 #ifdef SECURITY
120 static gn_error AT_EnterSecurityCode(gn_data *data, struct gn_statemachine *state);
121 static gn_error AT_GetSecurityCodeStatus(gn_data *data, struct gn_statemachine *state);
122 #endif
123 static gn_error AT_DialVoice(gn_data *data, struct gn_statemachine *state);
124 static gn_error AT_GetNetworkInfo(gn_data *data, struct gn_statemachine *state);
125 static gn_error AT_AnswerCall(gn_data *data, struct gn_statemachine *state);
126 static gn_error AT_CancelCall(gn_data *data, struct gn_statemachine *state);
127 static gn_error AT_SetCallNotification(gn_data *data, struct gn_statemachine *state);
128 static gn_error AT_SetDateTime(gn_data *data, struct gn_statemachine *state);
129 static gn_error AT_GetDateTime(gn_data *data, struct gn_statemachine *state);
130 static gn_error AT_PrepareDateTime(gn_data *data, struct gn_statemachine *state);
131 static gn_error AT_SendDTMF(gn_data *data, struct gn_statemachine *state);
132 static gn_error AT_GetActiveCalls(gn_data *data, struct gn_statemachine *state);
133 static gn_error AT_OnSMS(gn_data *data, struct gn_statemachine *state);
134 static gn_error AT_GetSMSMemorySize(gn_data *data, struct gn_statemachine *state);
135 
136 typedef struct {
137 	int gop;
138 	at_send_function_type sfunc;
139 	at_recv_function_type rfunc;
140 } at_function_init_type;
141 
142 /* Mobile phone information */
143 static at_function_init_type at_function_init[] = {
144 	{ GN_OP_Init,                  NULL,                     Reply },
145 	{ GN_OP_Terminate,             Terminate,                Reply },
146 	{ GN_OP_GetModel,              AT_GetModel,              ReplyIdentify },
147 	{ GN_OP_GetRevision,           AT_GetRevision,           ReplyIdentify },
148 	{ GN_OP_GetImei,               AT_GetIMEI,               ReplyIdentify },
149 	{ GN_OP_GetManufacturer,       AT_GetManufacturer,       ReplyIdentify },
150 	{ GN_OP_Identify,              AT_Identify,              ReplyIdentify },
151 	{ GN_OP_GetBatteryLevel,       AT_GetBattery,            ReplyGetBattery },
152 	{ GN_OP_GetPowersource,        AT_GetBattery,            ReplyGetBattery },
153 	{ GN_OP_GetRFLevel,            AT_GetRFLevel,            ReplyGetRFLevel },
154 	{ GN_OP_GetMemoryStatus,       AT_GetMemoryStatus,       ReplyMemoryStatus },
155 	{ GN_OP_AT_GetMemoryRange,     AT_GetMemoryRange,        ReplyMemoryRange },
156 	{ GN_OP_ReadPhonebook,         AT_ReadPhonebook,         ReplyReadPhonebook },
157 	{ GN_OP_WritePhonebook,        AT_WritePhonebook,        Reply },
158 	{ GN_OP_DeletePhonebook,       AT_DeletePhonebook,       Reply },
159 	{ GN_OP_CallDivert,            AT_CallDivert,            ReplyCallDivert },
160 	{ GN_OP_AT_SetPDUMode,         AT_SetPDUMode,            Reply },
161 	{ GN_OP_AT_Prompt,             NULL,                     ReplyGetPrompt },
162 	{ GN_OP_GetSMSFolders,         AT_GetSMSFolders,         ReplyGetSMSFolders },
163 	{ GN_OP_GetSMSFolderStatus,    AT_GetSMSFolderStatus,    Reply },
164 	{ GN_OP_GetSMSStatus,          AT_GetSMSStatus,          ReplyGetSMSStatus },
165 	{ GN_OP_SendSMS,               AT_SendSMS,               ReplySendSMS },
166 	{ GN_OP_SaveSMS,               AT_SaveSMS,               ReplySendSMS },
167 	{ GN_OP_GetSMS,                AT_GetSMS,                ReplyGetSMS },
168 	{ GN_OP_DeleteSMS,             AT_DeleteSMS,             Reply },
169 	{ GN_OP_AT_GetCharset,         AT_GetCharset,            ReplyGetCharset },
170 	{ GN_OP_AT_SetCharset,         AT_SetCharset,            Reply },
171 	{ GN_OP_GetSMSCenter,          AT_GetSMSCenter,          ReplyGetSMSCenter },
172 #ifdef SECURITY
173 	{ GN_OP_GetSecurityCodeStatus, AT_GetSecurityCodeStatus, ReplyGetSecurityCodeStatus },
174 	{ GN_OP_EnterSecurityCode,     AT_EnterSecurityCode,     Reply },
175 #endif
176 	{ GN_OP_MakeCall,              AT_DialVoice,             Reply },
177 	{ GN_OP_AnswerCall,            AT_AnswerCall,            Reply },
178 	{ GN_OP_CancelCall,            AT_CancelCall,            Reply },
179 	{ GN_OP_AT_Ring,               NULL,                     ReplyRing },
180 	{ GN_OP_SetCallNotification,   AT_SetCallNotification,   Reply },
181 	{ GN_OP_GetNetworkInfo,        AT_GetNetworkInfo,        ReplyGetNetworkInfo },
182 	{ GN_OP_SetDateTime,           AT_SetDateTime,           Reply },
183 	{ GN_OP_GetDateTime,           AT_GetDateTime,           ReplyGetDateTime },
184 	{ GN_OP_AT_PrepareDateTime,    AT_PrepareDateTime,       Reply },
185 	{ GN_OP_SendDTMF,              AT_SendDTMF,              Reply },
186 	{ GN_OP_GetActiveCalls,        AT_GetActiveCalls,        ReplyGetActiveCalls },
187 	{ GN_OP_OnSMS,                 AT_OnSMS,                 Reply },
188 	{ GN_OP_AT_IncomingSMS,        NULL,                     ReplyIncomingSMS },
189 	{ GN_OP_AT_GetSMSMemorySize,   AT_GetSMSMemorySize,      ReplyGetSMSMemorySize },
190 };
191 
192 /*
193  * Various functions that change default function registration.
194  */
register_extended_phonebook(struct gn_statemachine * state)195 static void register_extended_phonebook(struct gn_statemachine *state)
196 {
197 	at_insert_send_function(GN_OP_ReadPhonebook, AT_ReadPhonebookExt, state);
198 	at_insert_recv_function(GN_OP_ReadPhonebook, ReplyReadPhonebookExt, state);
199 	at_insert_send_function(GN_OP_WritePhonebook, AT_WritePhonebookExt, state);
200 	at_insert_send_function(GN_OP_DeletePhonebook, AT_DeletePhonebookExt, state);
201 }
202 
strip_quotes(char * s)203 char *strip_quotes(char *s)
204 {
205 	char *t;
206 
207 	if (*s == '"') {
208 		if ((t = strrchr(++s, '"'))) {
209 			*t = '\0';
210 		}
211 	}
212 
213 	return s;
214 }
215 
strip_brackets(char * s)216 static char *strip_brackets(char *s)
217 {
218 	char *t ;
219 
220 	if (*s == '(') {
221 		if ((t = strrchr(++s, ')'))) {
222 			*t = '\0';
223 		}
224 	}
225 
226 	return s;
227 }
228 
229 /*
230  * Compare the string passed in @tmpl with the echoed command passed in @req
231  * without the leading "AT" chars and the response passed in @resp and copy
232  * the response from @resp to @dest if one of the comparisons is successful,
233  * stripping the command prefix if present.
234  *
235  * Comparing both strings is needed to workaround some firmwares that reply
236  * to AT+GMM with +CGMM: or to AT+CGMM with +GMM:
237  *
238  * 1 is returned when tmpl matches req or resp. 0 is returned otherwise.
239  */
reply_simpletext(char * req,char * resp,const char * tmpl,char * dest,size_t maxlength)240 static int reply_simpletext(char *req, char *resp, const char *tmpl, char *dest, size_t maxlength)
241 {
242 	int i, n;
243 
244 	if (dest == NULL)
245 		return 0;
246 	n = strlen(tmpl);
247 	/* Subtract 2 to skip the trailing ": " (eg to match "+GMM" and "+GMM: ") */
248 	if ((strncmp(req, tmpl, n - 2) == 0) || (strncmp(resp, tmpl, n) == 0)) {
249 		/* Skip the prefix indicating to which command this response is responding, if present */
250 		i = 0;
251 		if (resp[i] == '+') {
252 			while (resp[i] && resp[i++] != ':')
253 				;
254 		}
255 		while (isspace(resp[i]))
256 			i++;
257 		snprintf(dest, maxlength, "%s", strip_quotes(resp + i));
258 		return 1;
259 	}
260 	return 0;
261 }
262 
263 gn_driver driver_at = {
264 	NULL,
265 	pgen_incoming_default,
266 	{
267 		"AT|AT-HW",		/* Supported models */
268 		99,			/* Max RF Level */
269 		0,			/* Min RF Level */
270 		GN_RF_CSQ,		/* RF level units */
271 		100,			/* Max Battery Level */
272 		0,			/* Min Battery Level */
273 		GN_BU_Percentage,	/* Battery level units */
274 		0,			/* Have date/time support */
275 		0,			/* Alarm supports time only */
276 		0,			/* Alarms available - FIXME */
277 		0, 0,			/* Startup logo size - FIXME */
278 		0, 0,			/* Op logo size */
279 		0, 0			/* Caller logo size */
280 	},
281 	Functions,
282 	NULL
283 };
284 
285 typedef struct {
286 	const char *str;
287 	at_charset charset;
288 } at_charset_map_t;
289 
290 static at_charset_map_t atcharsets[] = {
291 	{ "GSM",	AT_CHAR_GSM },
292 	{ "HEX",	AT_CHAR_HEXGSM },
293 	{ "UCS2",	AT_CHAR_UCS2 },
294 	{ NULL,		AT_CHAR_UNKNOWN },
295 };
296 
297 /*
298  * Help functions for extended phonebook handling.
299  */
extpb_scan_entry(at_driver_instance * drvinst,char * buffer,gn_phonebook_entry * entry,gn_phonebook_entry_type type,gn_phonebook_number_type number_type,int ext_str)300 static char *extpb_scan_entry(at_driver_instance *drvinst, char *buffer, gn_phonebook_entry *entry, gn_phonebook_entry_type type, gn_phonebook_number_type number_type, int ext_str)
301 {
302 	char *pos, *endpos;
303 	size_t len;
304 	int ix;
305 	if (!buffer)
306 		return NULL;
307 
308 	if (!(pos = strstr(buffer, ",\"")))
309 		return NULL;
310 	pos += 2;
311 
312 	if (ext_str) {
313 		if (!(endpos = strchr(pos, ',')))
314 			return NULL;
315 		*endpos = 0;
316 		len = atoi(pos);
317 		pos = endpos + 1;
318 		endpos = pos + len;
319 		*endpos = 0;
320 	} else {
321 		if (!(endpos = strstr(pos, "\",")))
322 			return NULL;
323 		*endpos = 0;
324 		len = strlen(pos);
325 	}
326 
327 	if (len > 0) {
328 		ix = entry->subentries_count++;
329 		entry->subentries[ix].entry_type = type;
330 		entry->subentries[ix].number_type = number_type;
331 		at_decode(drvinst->charset, entry->subentries[ix].data.number, pos, len, drvinst->ucs2_as_utf8);
332 		if (entry->number[0] == 0 && type == GN_PHONEBOOK_ENTRY_Number)
333 			snprintf(entry->number, sizeof(entry->number), "%s", entry->subentries[ix].data.number);
334 	}
335 
336 	return endpos + 1;
337 }
338 
extpb_find_subentry(gn_phonebook_entry * entry,gn_phonebook_entry_type type)339 static char *extpb_find_subentry(gn_phonebook_entry *entry, gn_phonebook_entry_type type)
340 {
341 	int i;
342 	for (i = 0; i < entry->subentries_count; ++i)
343 		if (entry->subentries[i].entry_type == type)
344 			return entry->subentries[i].data.number;
345 	return NULL;
346 }
347 
extpb_find_number_subentry(gn_phonebook_entry * entry,gn_phonebook_number_type type)348 static char *extpb_find_number_subentry(gn_phonebook_entry *entry, gn_phonebook_number_type type)
349 {
350 	int i;
351 	for (i = 0; i < entry->subentries_count; ++i)
352 		if (entry->subentries[i].entry_type == GN_PHONEBOOK_ENTRY_Number && entry->subentries[i].number_type == type)
353 			return entry->subentries[i].data.number;
354 	return NULL;
355 }
356 
Functions(gn_operation op,gn_data * data,struct gn_statemachine * state)357 static gn_error Functions(gn_operation op, gn_data *data, struct gn_statemachine *state)
358 {
359 	at_driver_instance *drvinst = AT_DRVINST(state);
360 	if (op == GN_OP_Init)
361 		return Initialise(data, state);
362 	if (drvinst && op == GN_OP_Terminate)
363 		return Terminate(data, state);
364 	if (!drvinst)
365 		return GN_ERR_INTERNALERROR;
366 	if ((op > GN_OP_Init) && (op < GN_OP_AT_Max))
367 		if (drvinst->functions[op])
368 			return (*(drvinst->functions[op]))(data, state);
369 	return GN_ERR_NOTIMPLEMENTED;
370 }
371 
372 /* Functions to encode and decode strings */
at_encode(at_charset charset,char * dst,size_t dst_len,const char * src,size_t len)373 size_t at_encode(at_charset charset, char *dst, size_t dst_len, const char *src, size_t len)
374 {
375 	size_t ret;
376 
377 	switch (charset) {
378 	case AT_CHAR_GSM:
379 		ret = char_ascii_encode(dst, dst_len, src, len);
380 		break;
381 	case AT_CHAR_HEXGSM:
382 		ret = char_hex_encode(dst, dst_len, src, len);
383 		break;
384 	case AT_CHAR_UCS2:
385 		ret = char_ucs2_encode(dst, dst_len, src, len);
386 		break;
387 	default:
388 		memcpy(dst, src, dst_len >= len ? len : dst_len);
389 		ret = len;
390 		break;
391 	}
392 	if (ret < dst_len)
393 		dst[ret] = '\0';
394 	return ret+1;
395 }
396 
at_decode(int charset,char * dst,char * src,int len,int ucs2_as_utf8)397 void at_decode(int charset, char *dst, char *src, int len, int ucs2_as_utf8)
398 {
399 	switch (charset) {
400 	/* char_*_decode() functions null terminate the strings */
401 	case AT_CHAR_GSM:
402 		char_default_alphabet_decode(dst, src, len);
403 		break;
404 	case AT_CHAR_HEXGSM:
405 		char_hex_decode(dst, src, len);
406 		break;
407 	case AT_CHAR_UCS2:
408 		if (ucs2_as_utf8)
409 			/* This function is defined in atsam.c */
410 			decode_ucs2_as_utf8(dst, src, len);
411 		else
412 			char_ucs2_decode(dst, src, len);
413 		break;
414 	default:
415 		memcpy(dst, src, len);
416 		dst[len] = 0;
417 		break;
418 	}
419 }
420 
421 /* Return the string representing the charset */
at_charset2str(at_charset charset)422 static const char *at_charset2str(at_charset charset)
423 {
424 	int i;
425 
426 	for (i = 0; atcharsets[i].str != NULL; i++) {
427 		if (atcharsets[i].charset == charset)
428 			return atcharsets[i].str;
429 	}
430 	return NULL;
431 }
432 
433 /* Set the requested charset as the current charset */
at_set_charset(gn_data * data,struct gn_statemachine * state,at_charset charset)434 gn_error at_set_charset(gn_data *data, struct gn_statemachine *state, at_charset charset)
435 {
436 	at_driver_instance *drvinst = AT_DRVINST(state);
437 	gn_data tmpdata;
438 	gn_error error;
439 
440 	if (drvinst->charset == charset)
441 		return GN_ERR_NONE;
442 
443 	/* load the available charsets if they're not already set */
444 	if (drvinst->availcharsets == 0) {
445 		error = sm_message_send(10, GN_OP_AT_GetCharset, "AT+CSCS=?\r", state);
446 		if (error)
447 			return error;
448 		gn_data_clear(&tmpdata);
449 		error = sm_block_no_retry(GN_OP_AT_GetCharset, &tmpdata, state);
450 	}
451 
452 	/* Try to set the requested charset if it's available */
453 	if (drvinst->availcharsets & charset) {
454 		const char *charset_s;
455 		char req[32];
456 
457 		charset_s = at_charset2str(charset);
458 		if (drvinst->encode_memory_type) {
459 			char charset_enc[16];
460 
461 			at_encode(drvinst->charset, charset_enc, sizeof(charset_enc), charset_s, strlen(charset_s));
462 			snprintf(req, sizeof(req), "AT+CSCS=\"%s\"\r", charset_enc);
463 		} else
464 			snprintf(req, sizeof(req), "AT+CSCS=\"%s\"\r", charset_s);
465 		error = sm_message_send(strlen(req), GN_OP_Init, req, state);
466 		if (error)
467 			return error;
468 		error = sm_block_no_retry(GN_OP_Init, &tmpdata, state);
469 		if (error)
470 			return error;
471 		drvinst->charset = charset;
472 	} else {
473 		error = GN_ERR_NOTSUPPORTED;
474 	}
475 
476 	return error;
477 }
478 
at_insert_recv_function(int type,at_recv_function_type func,struct gn_statemachine * state)479 at_recv_function_type at_insert_recv_function(int type, at_recv_function_type func, struct gn_statemachine *state)
480 {
481 	at_driver_instance *drvinst = AT_DRVINST(state);
482 	at_recv_function_type oldfunc;
483 	int i;
484 
485 	if (type >= GN_OP_AT_Max) {
486 		return (at_recv_function_type) -1;
487 	}
488 	if (drvinst->if_pos == 0) {
489 		drvinst->incoming_functions[0].message_type = type;
490 		drvinst->incoming_functions[0].functions = func;
491 		drvinst->if_pos++;
492 		return NULL;
493 	}
494 	for (i = 0; i < drvinst->if_pos; i++) {
495 		if (drvinst->incoming_functions[i].message_type == type) {
496 			oldfunc = drvinst->incoming_functions[i].functions;
497 			drvinst->incoming_functions[i].functions = func;
498 			return oldfunc;
499 		}
500 	}
501 	if (drvinst->if_pos < GN_OP_AT_Max-1) {
502 		drvinst->incoming_functions[drvinst->if_pos].message_type = type;
503 		drvinst->incoming_functions[drvinst->if_pos].functions = func;
504 		drvinst->if_pos++;
505 	}
506 	return NULL;
507 }
508 
at_insert_send_function(int type,at_send_function_type func,struct gn_statemachine * state)509 at_send_function_type at_insert_send_function(int type, at_send_function_type func, struct gn_statemachine *state)
510 {
511 	at_driver_instance *drvinst = AT_DRVINST(state);
512 	at_send_function_type f;
513 
514 	f = drvinst->functions[type];
515 	drvinst->functions[type] = func;
516 	return f;
517 }
518 
at_insert_manufacturer_error_function(at_error_function_type func,struct gn_statemachine * state)519 at_error_function_type at_insert_manufacturer_error_function(at_error_function_type func, struct gn_statemachine *state)
520 {
521 	at_driver_instance *drvinst = AT_DRVINST(state);
522 	at_error_function_type f;
523 
524 	f = drvinst->manufacturer_error;
525 	drvinst->manufacturer_error = func;
526 	return f;
527 }
528 
SoftReset(gn_data * data,struct gn_statemachine * state)529 static gn_error SoftReset(gn_data *data, struct gn_statemachine *state)
530 {
531 	if (sm_message_send(4, GN_OP_Init, "ATZ\r", state)) return GN_ERR_NOTREADY;
532 	return sm_block_no_retry(GN_OP_Init, data, state);
533 }
534 
SetEcho(gn_data * data,struct gn_statemachine * state)535 static gn_error SetEcho(gn_data *data, struct gn_statemachine *state)
536 {
537 	if (sm_message_send(5, GN_OP_Init, "ATE1\r", state)) return GN_ERR_NOTREADY;
538 	return sm_block_no_retry(GN_OP_Init, data, state);
539 }
540 
SetExtendedError(gn_data * data,struct gn_statemachine * state)541 static gn_error SetExtendedError(gn_data *data, struct gn_statemachine *state)
542 {
543 	if (sm_message_send(10, GN_OP_Init, "AT+CMEE=1\r", state)) return GN_ERR_NOTREADY;
544 	return sm_block_no_retry(GN_OP_Init, data, state);
545 }
546 
at_error_get(unsigned char * buffer,struct gn_statemachine * state)547 gn_error at_error_get(unsigned char *buffer, struct gn_statemachine *state)
548 {
549 	at_driver_instance *drvinst = AT_DRVINST(state);
550 	int code;
551 
552 	switch (buffer[0]) {
553 	case GN_AT_OK:
554 		return GN_ERR_NONE;
555 
556 	case GN_AT_ERROR:
557 		return GN_ERR_UNKNOWN;
558 
559 	case GN_AT_CMS:
560 		code = 256 * buffer[1] + buffer[2];
561 		switch (code) {
562 		case 300: return GN_ERR_FAILED;		/* ME failure */
563 		case 301: return GN_ERR_FAILED;		/* SMS service of ME reserved */
564 		case 302: return GN_ERR_FAILED;		/* operation not allowed */
565 		case 303: return GN_ERR_NOTSUPPORTED;	/* operation not supported */
566 		case 304: return GN_ERR_WRONGDATAFORMAT;/* invalid PDU mode parameter */
567 		case 305: return GN_ERR_WRONGDATAFORMAT;/* invalid text mode parameter */
568 
569 		case 310: return GN_ERR_SIMPROBLEM;	/* SIM not inserted */
570 		case 311: return GN_ERR_CODEREQUIRED;	/* SIM PIN required */
571 		case 312: return GN_ERR_CODEREQUIRED;	/* PH-SIM PIN required */
572 		case 313: return GN_ERR_SIMPROBLEM;	/* SIM failure */
573 		case 314: return GN_ERR_TRYAGAIN;	/* SIM busy */
574 		case 315: return GN_ERR_SIMPROBLEM;	/* SIM wrong */
575 		case 316: return GN_ERR_CODEREQUIRED;	/* SIM PUK required */
576 		case 317: return GN_ERR_CODEREQUIRED;	/* SIM PIN2 required */
577 		case 318: return GN_ERR_CODEREQUIRED;	/* SIM PUK2 required */
578 
579 		case 320: return GN_ERR_FAILED;		/* memory failure */
580 		case 321: return GN_ERR_INVALIDLOCATION;/* invalid memory index */
581 		case 322: return GN_ERR_MEMORYFULL;	/* memory full */
582 
583 		case 330: return GN_ERR_FAILED;		/* SMSC address unknown */
584 		case 331: return GN_ERR_NOCARRIER;	/* no network service */
585 		case 332: return GN_ERR_TIMEOUT;	/* network timeout */
586 
587 		case 340: return GN_ERR_FAILED;		/* no +CNMA acknowledgement expected */
588 
589 		case 500: return GN_ERR_UNKNOWN;	/* unknown error */
590 
591 		default:
592 			if (code >= 512 && drvinst->manufacturer_error)
593 				return drvinst->manufacturer_error(GN_AT_CMS, code, state);
594 			break;
595 		}
596 		break;
597 
598 	case GN_AT_CME:
599 		code = 256 * buffer[1] + buffer[2];
600 		switch (code) {
601 		case   0: return GN_ERR_FAILED;		/* phone failure */
602 		case   1: return GN_ERR_NOLINK;		/* no connection to phone */
603 		case   2: return GN_ERR_BUSY;		/* phone-adaptor link reserved */
604 		case   3: return GN_ERR_FAILED;		/* operation not allowed */
605 		case   4: return GN_ERR_NOTSUPPORTED;	/* operation not supported */
606 		case   5: return GN_ERR_CODEREQUIRED;	/* PH-SIM PIN required */
607 		case   6: return GN_ERR_CODEREQUIRED;	/* PH-FSIM PIN required */
608 		case   7: return GN_ERR_CODEREQUIRED;	/* PH-FSIM PUK required */
609 
610 		case  10: return GN_ERR_SIMPROBLEM;	/* SIM not inserted */
611 		case  11: return GN_ERR_CODEREQUIRED;	/* SIM PIN required */
612 		case  12: return GN_ERR_CODEREQUIRED;	/* SIM PUK required */
613 		case  13: return GN_ERR_SIMPROBLEM;	/* SIM failure */
614 		case  14: return GN_ERR_TRYAGAIN;	/* SIM busy */
615 		case  15: return GN_ERR_SIMPROBLEM;	/* SIM wrong */
616 		case  16: return GN_ERR_INVALIDSECURITYCODE;	/* incorrect password */
617 		case  17: return GN_ERR_CODEREQUIRED;	/* SIM PIN2 required */
618 		case  18: return GN_ERR_CODEREQUIRED;	/* SIM PUK2 required */
619 
620 		case  20: return GN_ERR_MEMORYFULL;	/* memory full */
621 		case  21: return GN_ERR_INVALIDLOCATION;/* invalid index */
622 		case  22: return GN_ERR_EMPTYLOCATION;	/* not found */
623 		case  23: return GN_ERR_FAILED;		/* memory failure */
624 		case  24: return GN_ERR_ENTRYTOOLONG;	/* text string too long */
625 		case  25: return GN_ERR_WRONGDATAFORMAT;/* invalid characters in text string */
626 		case  26: return GN_ERR_ENTRYTOOLONG;	/* dial string too long */
627 		case  27: return GN_ERR_WRONGDATAFORMAT;/* invalid characters in dial string */
628 
629 		case  30: return GN_ERR_NOCARRIER;	/* no network service */
630 		case  31: return GN_ERR_TIMEOUT;	/* network timeout */
631 		case  32: return GN_ERR_FAILED;		/* network not allowed - emergency calls only */
632 
633 		case  40: return GN_ERR_CODEREQUIRED;	/* network personalisation PIN required */
634 		case  41: return GN_ERR_CODEREQUIRED;	/* network personalisation PUK required */
635 		case  42: return GN_ERR_CODEREQUIRED;	/* network subset personalisation PIN required */
636 		case  43: return GN_ERR_CODEREQUIRED;	/* network subset personalisation PUK required */
637 		case  44: return GN_ERR_CODEREQUIRED;	/* service provider personalisation PIN required */
638 		case  45: return GN_ERR_CODEREQUIRED;	/* service provider personalisation PUK required */
639 		case  46: return GN_ERR_CODEREQUIRED;	/* corporate personalisation PIN required */
640 		case  47: return GN_ERR_CODEREQUIRED;	/* corporate personalisation PUK required */
641 
642 		case 100: return GN_ERR_UNKNOWN;	/* unknown */
643 
644 		default:
645 			if (code >= 512 && drvinst->manufacturer_error)
646 				return drvinst->manufacturer_error(GN_AT_CME, code, state);
647 			break;
648 		}
649 		break;
650 
651 	default:
652 		return GN_ERR_INTERNALERROR;	/* shouldn't happen */
653 	}
654 
655 	return GN_ERR_UNKNOWN;
656 }
657 
658 /* StoreDefaultCharset
659  *
660  * for a correct communication with the phone for phonebook entries or
661  * SMS text mode, we need to set a suited charset. a suited charset
662  * doesn't contain characters which are also used by the serial line for
663  * software handshake. so the GSM charset (or PC437, latin-1, etc) are
664  * a bad choice.
665  * so the GSM specification defines the HEX charset which is a hexidecimal
666  * representation of the "original" charset. this is a good choice for the
667  * above problem. but the GSM specification defines the default charset and
668  * no "original" charset.
669  * so what we do is to ask the phone (after a reset) for its original
670  * charset and store the result for future referece. we don't do a full
671  * initialization for speed reason. at further processing we can chose
672  * a working charset if needed.
673  *
674  * see also AT_SetCharset, AT_GetCharset
675  */
StoreDefaultCharset(struct gn_statemachine * state)676 static void StoreDefaultCharset(struct gn_statemachine *state)
677 {
678 	at_driver_instance *drvinst = AT_DRVINST(state);
679 	gn_data data;
680 	gn_error error;
681 
682 	gn_data_clear(&data);
683 	error = state->driver.functions(GN_OP_AT_GetCharset, &data, state);
684 	drvinst->defaultcharset = error ? AT_CHAR_UNKNOWN : drvinst->charset;
685 }
686 
at_memory_type_set(gn_memory_type mt,struct gn_statemachine * state)687 gn_error at_memory_type_set(gn_memory_type mt, struct gn_statemachine *state)
688 {
689 	at_driver_instance *drvinst = AT_DRVINST(state);
690 	gn_data data;
691 	char req[32];
692 	const char *memory_name;
693 	char memory_name_enc[16];
694 	int len;
695 	gn_error ret = GN_ERR_NONE;
696 
697 	if (mt != drvinst->memorytype) {
698 		memory_name = gn_memory_type2str(mt);
699 		if (!memory_name)
700 			return GN_ERR_INVALIDMEMORYTYPE;
701 		if (drvinst->encode_memory_type) {
702 			gn_data_clear(&data);
703 			at_encode(drvinst->charset, memory_name_enc, sizeof(memory_name_enc), memory_name, strlen(memory_name));
704 			memory_name = memory_name_enc;
705 		}
706 		len = snprintf(req, sizeof(req), "AT+CPBS=\"%s\"\r", memory_name);
707 		ret = sm_message_send(len, GN_OP_Init, req, state);
708 		if (ret != GN_ERR_NONE)
709 			return ret;
710 		gn_data_clear(&data);
711 		ret = sm_block_no_retry(GN_OP_Init, &data, state);
712 		if (ret != GN_ERR_NONE)
713 			return ret;
714 		drvinst->memorytype = mt;
715 
716 		gn_data_clear(&data);
717 		ret = state->driver.functions(GN_OP_AT_GetMemoryRange, &data, state);
718 	}
719 	return ret;
720 }
721 
722 /* GSM 07.05 section 3.2.3 specified the +CPMS (Preferred Message Store) AT
723  * command as taking 3 memory parameters <mem1>, <mem2> and <mem3>.  Each of
724  * these stores is used for different purposes:
725  *   <mem1> - memory from which messages are read and deleted
726  *   <mem2> - memory to which writing and sending operations are made
727  *   <mem3> - memory to which received SMs are preferred to be stored
728  *
729  * According to ETSI TS 127 005 V6.0.1 (2005-01) section 3.2.2, second and
730  * third parameter are optional, so we set only <mem1> to be more compatible.
731  */
AT_SetSMSMemoryType(gn_memory_type mt,struct gn_statemachine * state)732 gn_error AT_SetSMSMemoryType(gn_memory_type mt, struct gn_statemachine *state)
733 {
734 	at_driver_instance *drvinst = AT_DRVINST(state);
735 	gn_data data;
736 	char req[32];
737 	const char *memory_name;
738 	char memory_name_enc[16];
739 	int len;
740 	gn_error ret = GN_ERR_NONE;
741 
742 	if (mt != drvinst->smsmemorytype) {
743 		memory_name = gn_memory_type2str(mt);
744 		if (!memory_name)
745 			return GN_ERR_INVALIDMEMORYTYPE;
746 		if (drvinst->encode_memory_type) {
747 			gn_data_clear(&data);
748 			at_encode(drvinst->charset, memory_name_enc, sizeof(memory_name_enc), memory_name, strlen(memory_name));
749 			memory_name = memory_name_enc;
750 		}
751 		len = snprintf(req, sizeof(req), "AT+CPMS=\"%s\"\r", memory_name);
752 		ret = sm_message_send(len, GN_OP_Init, req, state);
753 		if (ret != GN_ERR_NONE)
754 			return ret;
755 		gn_data_clear(&data);
756 		ret = sm_block_no_retry(GN_OP_Init, &data, state);
757 		if (ret != GN_ERR_NONE)
758 			return ret;
759 		drvinst->smsmemorytype = mt;
760 	}
761 	return ret;
762 }
763 
764 /* AT_SetCharset
765  *
766  * before we start sending or receiving phonebook entries from the phone,
767  * we should set a charset. this is done once before the first read or write.
768  *
769  * we try to chose a charset with hexadecimal representation. first ucs2
770  * (which is a hexencoded unicode charset) is tested and set if available.
771  * if this fails for any reason, it is checked if the original charset is
772  * GSM. if this is true, we try to set HEX (a hexencoded GSM charset). if
773  * this again fails or is impossible, we try to use the GSM charset. if
774  * the original charset was GSM nothing is done (we rely on not changing
775  * anything by the failing tries before). if the original charset was
776  * something else, we set the GSM charset. if this too fails, the user is
777  * on his own, characters will be copied from or to the phone without
778  * conversion.
779  *
780  * the whole bunch is needed to get a reasonable support for different
781  * phones. eg a siemens s25 has GSM as original charset and aditional
782  * supports only UCS2, a nokia 7110 has PCCP437 as original charset which
783  * renders HEX unusable for us (in this case HEX will give a hexadecimal
784  * encoding of the PCCP437 charset) and no UCS2. a ericsson t39 uses
785  * GSM as original charset but has never heard of any hex encoded charset.
786  * but this doesn't matter with IRDA and i haven't found a serial cable
787  * in a shop yet, so this is no problem
788  *
789  * see AT_GetCharset, StoreDefaultCharset
790  */
AT_SetCharset(gn_data * data,struct gn_statemachine * state)791 static gn_error AT_SetCharset(gn_data *data, struct gn_statemachine *state)
792 {
793 	at_driver_instance *drvinst = AT_DRVINST(state);
794 	gn_data tmpdata;
795 	gn_error error = GN_ERR_NONE;
796 
797 	if (drvinst->charset != AT_CHAR_UNKNOWN)
798 		return GN_ERR_NONE;
799 
800 	/* check available charsets */
801 	if (drvinst->availcharsets == 0) {
802 		error = sm_message_send(10, GN_OP_AT_GetCharset, "AT+CSCS=?\r", state);
803 		if (error)
804 			return error;
805 		gn_data_clear(&tmpdata);
806 		error = sm_block_no_retry(GN_OP_AT_GetCharset, &tmpdata, state);
807 	}
808 
809 	if (!error && (drvinst->availcharsets & AT_CHAR_UCS2) && (drvinst->charset != AT_CHAR_UCS2)) {
810 		/* UCS2 charset found. try to set it */
811 		error = sm_message_send(15, GN_OP_Init, "AT+CSCS=\"UCS2\"\r", state);
812 		if (error)
813 			return error;
814 		error = sm_block_no_retry(GN_OP_Init, &tmpdata, state);
815 		if (!error)
816 			drvinst->charset = AT_CHAR_UCS2;
817 	}
818 	if (drvinst->charset != AT_CHAR_UNKNOWN)
819 		return GN_ERR_NONE;
820 
821 	/* no UCS2 charset found or error occured */
822 	if ((drvinst->availcharsets & AT_CHAR_HEXGSM) && (drvinst->charset != AT_CHAR_HEXGSM)) {
823 		/* try to set HEX charset */
824 		error = sm_message_send(14, GN_OP_Init, "AT+CSCS=\"HEX\"\r", state);
825 		if (error)
826 			return error;
827 		error = sm_block_no_retry(GN_OP_Init, &tmpdata, state);
828 		if (!error)
829 			drvinst->charset = AT_CHAR_HEXGSM;
830 	}
831 	if (drvinst->charset != AT_CHAR_UNKNOWN)
832 		return GN_ERR_NONE;
833 
834 	/* no support for HEXGSM, be happy with GSM */
835 	if ((drvinst->availcharsets & AT_CHAR_GSM) && (drvinst->charset != AT_CHAR_HEXGSM)) {
836 		error = sm_message_send(14, GN_OP_Init, "AT+CSCS=\"GSM\"\r", state);
837 		if (error)
838 			return error;
839 		error = sm_block_no_retry(GN_OP_Init, &tmpdata, state);
840 		if (!error)
841 			drvinst->charset = AT_CHAR_GSM;
842 	}
843 	if (drvinst->charset != AT_CHAR_UNKNOWN)
844 		return GN_ERR_NONE;
845 
846 	drvinst->charset = drvinst->defaultcharset;
847 	error = (drvinst->charset == AT_CHAR_UNKNOWN) ? error : GN_ERR_NONE;
848 	return error;
849 }
850 
851 /* AT_GetCharset
852  *
853  * this function detects the current charset used by the phone. if it is
854  * called immediatedly after a reset of the phone, this is also the
855  * original charset of the phone.
856  */
AT_GetCharset(gn_data * data,struct gn_statemachine * state)857 static gn_error AT_GetCharset(gn_data *data, struct gn_statemachine *state)
858 {
859 	gn_error ret;
860 
861 	ret = sm_message_send(9, GN_OP_AT_GetCharset, "AT+CSCS?\r", state);
862 	if (ret)
863 		return GN_ERR_NOTREADY;
864 	return sm_block_no_retry(GN_OP_AT_GetCharset, data, state);
865 }
866 
AT_Identify(gn_data * data,struct gn_statemachine * state)867 static gn_error AT_Identify(gn_data *data, struct gn_statemachine *state)
868 {
869 	gn_error ret;
870 
871 	if ((ret = state->driver.functions(GN_OP_GetModel, data, state)))
872 		return ret;
873 	if ((ret = state->driver.functions(GN_OP_GetManufacturer, data, state)))
874 		return ret;
875 	if ((ret = state->driver.functions(GN_OP_GetRevision, data, state)))
876 		return ret;
877 	return state->driver.functions(GN_OP_GetImei, data, state);
878 }
879 
AT_GetModel(gn_data * data,struct gn_statemachine * state)880 static gn_error AT_GetModel(gn_data *data, struct gn_statemachine *state)
881 {
882 	gn_error err;
883 	/*
884 	 * prefer AT+GMM over AT+CGMM because it returns a user friendly model name
885 	 * for some phones (e.g. Sony Ericsson Z310i)
886 	 */
887 
888 	if (sm_message_send(7, GN_OP_Identify, "AT+GMM\r", state))
889 		return GN_ERR_NOTREADY;
890 	if ((err = sm_block_no_retry(GN_OP_Identify, data, state)) == GN_ERR_NONE)
891 		return GN_ERR_NONE;
892 
893 	if (sm_message_send(8, GN_OP_Identify, "AT+CGMM\r", state))
894 		return GN_ERR_NOTREADY;
895 	if ((err = sm_block_no_retry(GN_OP_Identify, data, state)) == GN_ERR_NONE)
896 		return GN_ERR_NONE;
897 
898 	return err;
899 }
900 
AT_GetManufacturer(gn_data * data,struct gn_statemachine * state)901 static gn_error AT_GetManufacturer(gn_data *data, struct gn_statemachine *state)
902 {
903 	gn_error err;
904 
905 	if (sm_message_send(8, GN_OP_Identify, "AT+CGMI\r", state))
906 		return GN_ERR_NOTREADY;
907 	if ((err = sm_block_no_retry(GN_OP_Identify, data, state)) == GN_ERR_NONE)
908 		return GN_ERR_NONE;
909 
910 	if (sm_message_send(7, GN_OP_Identify, "AT+GMI\r", state))
911 		return GN_ERR_NOTREADY;
912 	if (sm_block_no_retry(GN_OP_Identify, data, state) == GN_ERR_NONE)
913 		return GN_ERR_NONE;
914 
915 	return err;
916 }
917 
AT_GetRevision(gn_data * data,struct gn_statemachine * state)918 static gn_error AT_GetRevision(gn_data *data, struct gn_statemachine *state)
919 {
920 	gn_error err;
921 
922 	if (sm_message_send(8, GN_OP_Identify, "AT+CGMR\r", state))
923 		return GN_ERR_NOTREADY;
924 	if ((err = sm_block_no_retry(GN_OP_Identify, data, state)) == GN_ERR_NONE)
925 		return GN_ERR_NONE;
926 
927 	if (sm_message_send(7, GN_OP_Identify, "AT+GMR\r", state))
928 		return GN_ERR_NOTREADY;
929 	if (sm_block_no_retry(GN_OP_Identify, data, state) == GN_ERR_NONE)
930 		return GN_ERR_NONE;
931 
932 	return err;
933 }
934 
AT_GetIMEI(gn_data * data,struct gn_statemachine * state)935 static gn_error AT_GetIMEI(gn_data *data, struct gn_statemachine *state)
936 {
937 	gn_error err;
938 
939 	if (sm_message_send(8, GN_OP_Identify, "AT+CGSN\r", state))
940 		return GN_ERR_NOTREADY;
941 	if ((err = sm_block_no_retry(GN_OP_Identify, data, state)) == GN_ERR_NONE)
942 		return GN_ERR_NONE;
943 
944 	if (sm_message_send(7, GN_OP_Identify, "AT+GSN\r", state))
945 		return GN_ERR_NOTREADY;
946 	if (sm_block_no_retry(GN_OP_Identify, data, state) == GN_ERR_NONE)
947 		return GN_ERR_NONE;
948 
949 	return err;
950 }
951 
952 /* gets battery level and power source */
AT_GetBattery(gn_data * data,struct gn_statemachine * state)953 static gn_error AT_GetBattery(gn_data *data, struct gn_statemachine *state)
954 {
955 	at_driver_instance *drvinst = AT_DRVINST(state);
956 	char key[4];
957 
958 	snprintf(key, 4, "CBC");
959 	if (map_get(&drvinst->cached_capabilities, key, 1))
960 		return Parse_ReplyGetBattery(data, state);
961 	else if (sm_message_send(7, GN_OP_GetBatteryLevel, "AT+CBC\r", state))
962 		return GN_ERR_NOTREADY;
963 	return sm_block_no_retry(GN_OP_GetBatteryLevel, data, state);
964 }
965 
AT_GetRFLevel(gn_data * data,struct gn_statemachine * state)966 static gn_error AT_GetRFLevel(gn_data *data, struct gn_statemachine *state)
967 {
968 	if (sm_message_send(7, GN_OP_GetRFLevel, "AT+CSQ\r", state))
969 		return GN_ERR_NOTREADY;
970 	return sm_block_no_retry(GN_OP_GetRFLevel, data, state);
971 }
972 
AT_GetMemoryStatus(gn_data * data,struct gn_statemachine * state)973 static gn_error AT_GetMemoryStatus(gn_data *data, struct gn_statemachine *state)
974 {
975 	gn_error ret;
976 
977 	ret = at_memory_type_set(data->memory_status->memory_type,  state);
978 	if (ret)
979 		return ret;
980 	if (sm_message_send(9, GN_OP_GetMemoryStatus, "AT+CPBS?\r", state))
981 		return GN_ERR_NOTREADY;
982 	return sm_block_no_retry(GN_OP_GetMemoryStatus, data, state);
983 }
984 
AT_GetMemoryRange(gn_data * data,struct gn_statemachine * state)985 static gn_error AT_GetMemoryRange(gn_data *data, struct gn_statemachine *state)
986 {
987 	at_driver_instance *drvinst = AT_DRVINST(state);
988 	gn_error ret;
989 	char key[7];
990 
991 	snprintf(key, 7, "%s%s", "CPBR", gn_memory_type2str(drvinst->memorytype));
992 	if (map_get(&drvinst->cached_capabilities, key, 0)) {
993 		ret = Parse_ReplyMemoryRange(data, state);
994 	} else {
995 		ret = sm_message_send(10, GN_OP_AT_GetMemoryRange, "AT+CPBR=?\r", state);
996 		if (ret)
997 			return GN_ERR_NOTREADY;
998 		ret = sm_block_no_retry(GN_OP_AT_GetMemoryRange, data, state);
999 	}
1000 	return ret;
1001 }
1002 
AT_ReadPhonebook(gn_data * data,struct gn_statemachine * state)1003 static gn_error AT_ReadPhonebook(gn_data *data, struct gn_statemachine *state)
1004 {
1005 	at_driver_instance *drvinst = AT_DRVINST(state);
1006 	char req[32];
1007 	gn_error ret;
1008 
1009 	ret = at_memory_type_set(data->phonebook_entry->memory_type, state);
1010 	if (ret)
1011 		return ret;
1012 	/* Try to read in UCS2. Ignore errors. */
1013 	ret = at_set_charset(data, state, AT_CHAR_UCS2);
1014 	snprintf(req, sizeof(req), "AT+CPBR=%d\r", data->phonebook_entry->location + drvinst->memoryoffset);
1015 	if (sm_message_send(strlen(req), GN_OP_ReadPhonebook, req, state))
1016 		return GN_ERR_NOTREADY;
1017 	return sm_block_no_retry(GN_OP_ReadPhonebook, data, state);
1018 }
1019 
AT_WritePhonebook(gn_data * data,struct gn_statemachine * state)1020 static gn_error AT_WritePhonebook(gn_data *data, struct gn_statemachine *state)
1021 {
1022 	at_driver_instance *drvinst = AT_DRVINST(state);
1023 	int len, ofs;
1024 	char req[256], *tmp;
1025 	char number[64];
1026 	gn_error ret;
1027 
1028 	ret = at_memory_type_set(data->phonebook_entry->memory_type, state);
1029 	if (ret)
1030 		return ret;
1031 	if (data->phonebook_entry->empty) {
1032 		return AT_DeletePhonebook(data, state);
1033 	} else {
1034 		ret = state->driver.functions(GN_OP_AT_SetCharset, data, state);
1035 		if (ret)
1036 			return ret;
1037 		memset(number, 0, sizeof(number));
1038 		if (drvinst->encode_number)
1039 			at_encode(drvinst->charset, number, sizeof(number),
1040 				data->phonebook_entry->number,
1041 				strlen(data->phonebook_entry->number));
1042 		else
1043 			strncpy(number, data->phonebook_entry->number, sizeof(number));
1044 		ofs = snprintf(req, sizeof(req), "AT+CPBW=%d,\"%s\",%s,\"",
1045 			       data->phonebook_entry->location+drvinst->memoryoffset,
1046 			       number,
1047 			       data->phonebook_entry->number[0] == '+' ? "145" : "129");
1048 		tmp = req + ofs;
1049 		len = at_encode(drvinst->charset, tmp, sizeof(req) - ofs,
1050 				data->phonebook_entry->name,
1051 				strlen(data->phonebook_entry->name));
1052 		tmp[len-1] = '"';
1053 		tmp[len++] = '\r';
1054 		len += ofs;
1055 	}
1056 	if (sm_message_send(len, GN_OP_WritePhonebook, req, state))
1057 		return GN_ERR_NOTREADY;
1058 	return sm_block_no_retry(GN_OP_WritePhonebook, data, state);
1059 }
1060 
AT_DeletePhonebook(gn_data * data,struct gn_statemachine * state)1061 static gn_error AT_DeletePhonebook(gn_data *data, struct gn_statemachine *state)
1062 {
1063 	at_driver_instance *drvinst = AT_DRVINST(state);
1064 	int len;
1065 	char req[64];
1066 	gn_error ret;
1067 
1068 	if (!data->phonebook_entry)
1069 		return GN_ERR_INTERNALERROR;
1070 
1071 	ret = at_memory_type_set(data->phonebook_entry->memory_type, state);
1072 	if (ret)
1073 		return ret;
1074 
1075 	len = snprintf(req, sizeof(req), "AT+CPBW=%d\r", data->phonebook_entry->location+drvinst->memoryoffset);
1076 
1077 	if (sm_message_send(len, GN_OP_DeletePhonebook, req, state))
1078 		return GN_ERR_NOTREADY;
1079 	return sm_block_no_retry(GN_OP_DeletePhonebook, data, state);
1080 }
1081 
AT_ReadPhonebookExt(gn_data * data,struct gn_statemachine * state)1082 static gn_error AT_ReadPhonebookExt(gn_data *data, struct gn_statemachine *state) {
1083 	at_driver_instance *drvinst = AT_DRVINST(state);
1084 	char req[32];
1085 	gn_error ret;
1086 
1087 	ret = state->driver.functions(GN_OP_AT_SetCharset, data, state);
1088 	if (ret)
1089 		return ret;
1090 	ret = at_memory_type_set(data->phonebook_entry->memory_type, state);
1091 	if (ret)
1092 		return ret;
1093 	snprintf(req, sizeof(req), "AT+SPBR=%d\r", data->phonebook_entry->location+drvinst->memoryoffset);
1094 	if (sm_message_send(strlen(req), GN_OP_ReadPhonebook, req, state))
1095 		return GN_ERR_NOTREADY;
1096 	return sm_block_no_retry(GN_OP_ReadPhonebook, data, state);
1097 }
1098 
AT_DeletePhonebookExt(gn_data * data,struct gn_statemachine * state)1099 static gn_error AT_DeletePhonebookExt(gn_data *data, struct gn_statemachine *state)
1100 {
1101 	at_driver_instance *drvinst = AT_DRVINST(state);
1102 	int len;
1103 	char req[64];
1104 	gn_error ret;
1105 
1106 	if (!data->phonebook_entry)
1107 		return GN_ERR_INTERNALERROR;
1108 
1109 	ret = at_memory_type_set(data->phonebook_entry->memory_type, state);
1110 	if (ret)
1111 		return ret;
1112 
1113 	len = snprintf(req, sizeof(req), "AT+SPBW=%d\r", data->phonebook_entry->location+drvinst->memoryoffset);
1114 
1115 	if (sm_message_send(len, GN_OP_DeletePhonebook, req, state))
1116 		return GN_ERR_NOTREADY;
1117 	return sm_block_no_retry(GN_OP_DeletePhonebook, data, state);
1118 }
1119 
1120 #define MAX_REQ 2048
AT_WritePhonebookExt(gn_data * data,struct gn_statemachine * state)1121 static gn_error AT_WritePhonebookExt(gn_data *data, struct gn_statemachine *state)
1122 {
1123 	at_driver_instance *drvinst = AT_DRVINST(state);
1124 	int len, ofs;
1125 	char req[MAX_REQ + 1], tmp[MAX_REQ + 1];
1126 	char *mobile, *home, *work, *fax, *general, *email, *first_name, *last_name, *note;
1127 	gn_phonebook_entry *entry = data->phonebook_entry;
1128 	gn_data data2;
1129 	gn_memory_status memstat;
1130 	gn_error ret;
1131 	int ix;
1132 
1133 	if (entry->empty)
1134 		return AT_DeletePhonebook(data, state);
1135 
1136 	ret = at_memory_type_set(entry->memory_type, state);
1137 	if (ret)
1138 		return ret;
1139 
1140 	ret = state->driver.functions(GN_OP_AT_SetCharset, data, state);
1141 	if (ret)
1142 		return ret;
1143 
1144 	gn_data_clear(&data2);
1145 	memstat.memory_type = entry->memory_type;
1146 	data2.memory_status = &memstat;
1147 	ret = state->driver.functions(GN_OP_GetMemoryStatus, &data2, state);
1148 	if (ret)
1149 		return ret;
1150 
1151 	if (entry->memory_type != GN_MT_SM && entry->location > memstat.used)
1152 		ix = 0;
1153 	else
1154 		ix = entry->location + drvinst->memoryoffset;
1155 
1156 	mobile = extpb_find_number_subentry(entry, GN_PHONEBOOK_NUMBER_Mobile);
1157 	home = extpb_find_number_subentry(entry, GN_PHONEBOOK_NUMBER_Home);
1158 	work = extpb_find_number_subentry(entry, GN_PHONEBOOK_NUMBER_Work);
1159 	fax = extpb_find_number_subentry(entry, GN_PHONEBOOK_NUMBER_Fax);
1160 	general = extpb_find_number_subentry(entry, GN_PHONEBOOK_NUMBER_General);
1161 	if (!(mobile || home || work || fax || general) && entry->number[0] != 0)
1162 		mobile = entry->number;
1163 	email = extpb_find_subentry(entry, GN_PHONEBOOK_ENTRY_Email);
1164 	first_name = extpb_find_subentry(entry, GN_PHONEBOOK_ENTRY_FirstName);
1165 	last_name = extpb_find_subentry(entry, GN_PHONEBOOK_ENTRY_LastName);
1166 	if (!(first_name || last_name) && entry->name[0] != 0)
1167 		first_name = entry->name;
1168 	note = extpb_find_subentry(entry, GN_PHONEBOOK_ENTRY_Note);
1169 
1170 	ofs = snprintf(req, MAX_REQ, "AT+SPBW=%d,\"", ix);
1171 
1172 	if (mobile)
1173 		ofs += at_encode(drvinst->charset, req + ofs, MAX_REQ - ofs, mobile, strlen(mobile)) - 1;
1174 	strncat(req, "\",\"", MAX_REQ - ofs);
1175 	ofs += 3;
1176 
1177 	if (home)
1178 		ofs += at_encode(drvinst->charset, req + ofs, MAX_REQ - ofs, home, strlen(home)) - 1;
1179 	strncat(req, "\",\"", MAX_REQ - ofs);
1180 	ofs += 3;
1181 
1182 	if (work)
1183 		ofs += at_encode(drvinst->charset, req + ofs, MAX_REQ - ofs, work, strlen(work)) - 1;
1184 	strncat(req, "\",\"", MAX_REQ - ofs);
1185 	ofs += 3;
1186 
1187 	if (fax)
1188 		ofs += at_encode(drvinst->charset, req + ofs, MAX_REQ - ofs, fax, strlen(fax)) - 1;
1189 	strncat(req, "\",\"", MAX_REQ - ofs);
1190 	ofs += 3;
1191 
1192 	if (general)
1193 		ofs += at_encode(drvinst->charset, req + ofs, MAX_REQ - ofs, general, strlen(general)) - 1;
1194 	strncat(req, "\",\"", MAX_REQ - ofs);
1195 	ofs += 3;
1196 
1197 	if (email)
1198 		ofs += at_encode(drvinst->charset, req + ofs, MAX_REQ - ofs, email, strlen(email)) - 1;
1199 	strncat(req, "\",\"", MAX_REQ - ofs);
1200 	ofs += 3;
1201 
1202 	if (first_name) {
1203 		len = at_encode(drvinst->charset, tmp, MAX_REQ, first_name, strlen(first_name)) - 1;
1204 		ofs += snprintf(req + ofs, MAX_REQ - ofs, "%d,", len);
1205 		memcpy(req + ofs, tmp, len + 1);
1206 		ofs += len;
1207 	} else
1208 		ofs += snprintf(req + ofs, MAX_REQ - ofs, "0,");
1209 	strncat(req, "\",\"", MAX_REQ - ofs);
1210 	ofs += 3;
1211 
1212 	if (last_name) {
1213 		len = at_encode(drvinst->charset, tmp, MAX_REQ, last_name, strlen(last_name)) - 1;
1214 		ofs += snprintf(req + ofs, MAX_REQ - ofs, "%d,", len);
1215 		memcpy(req + ofs, tmp, len + 1);
1216 		ofs += len;
1217 	} else
1218 		ofs += snprintf(req + ofs, MAX_REQ - ofs, "0,");
1219 	strncat(req, "\",\"", MAX_REQ - ofs);
1220 	ofs += 3;
1221 
1222 	if (note) {
1223 		len = at_encode(drvinst->charset, tmp, MAX_REQ, note, strlen(note)) - 1;
1224 		ofs += snprintf(req + ofs, MAX_REQ - ofs, "%d,", len);
1225 		memcpy(req + ofs, tmp, len + 1);
1226 		ofs += len;
1227 	} else
1228 		ofs += snprintf(req + ofs, MAX_REQ - ofs, "0,");
1229 	strncat(req, "\",\"0,\"\r", MAX_REQ - ofs);
1230 	ofs += 7;
1231 	req[ofs] = 0;
1232 
1233 	if (sm_message_send(ofs, GN_OP_WritePhonebook, req, state))
1234 		return GN_ERR_NOTREADY;
1235 	return sm_block_no_retry(GN_OP_WritePhonebook, data, state);
1236 }
1237 #undef MAX_REQ
1238 
AT_CallDivert(gn_data * data,struct gn_statemachine * state)1239 static gn_error AT_CallDivert(gn_data *data, struct gn_statemachine *state)
1240 {
1241 	char req[64];
1242 	int ctype;
1243 
1244 	if (!data->call_divert)
1245 		return GN_ERR_UNKNOWN;
1246 
1247 	switch (data->call_divert->ctype) {
1248 	case GN_CDV_VoiceCalls:
1249 		ctype = 1;
1250 		break;
1251 	case GN_CDV_FaxCalls:
1252 		ctype = 2;
1253 		break;
1254 	case GN_CDV_DataCalls:
1255 		ctype = 4;
1256 		break;
1257 	default:
1258 		ctype = 7;
1259 		break;
1260 	}
1261 
1262 	if (data->call_divert->operation == GN_CDV_Register) {
1263 		/*
1264 		 * Nokias do not like zero timeout:
1265 		 *
1266 		 * AT+CCFC=0,3,"123456789",129,7,,,0
1267 		 * ERROR
1268 		 *
1269 		 * AT+CCFC=0,3,"123456789",129,7,,,10
1270 		 * OK
1271 		 *
1272 		 * AT+CCFC=0,3,"123456789",129,7
1273 		 * OK
1274 		 */
1275 		if (data->call_divert->timeout)
1276 			snprintf(req, sizeof(req), "AT+CCFC=%d,%d,\"%s\",%d,%d,,,%d\r",
1277 				 data->call_divert->type,
1278 				 data->call_divert->operation,
1279 				 data->call_divert->number.number,
1280 				 data->call_divert->number.type,
1281 				 ctype, data->call_divert->timeout);
1282 		else
1283 			snprintf(req, sizeof(req), "AT+CCFC=%d,%d,\"%s\",%d,%d\r",
1284 				 data->call_divert->type,
1285 				 data->call_divert->operation,
1286 				 data->call_divert->number.number,
1287 				 data->call_divert->number.type,
1288 				 ctype);
1289 	} else {
1290 		snprintf(req, sizeof(req), "AT+CCFC=%d,%d\r",
1291 				data->call_divert->type,
1292 				data->call_divert->operation);
1293 	}
1294 
1295 	if (sm_message_send(strlen(req), GN_OP_CallDivert, req, state))
1296 		return GN_ERR_NOTREADY;
1297 	/* Divert commands are slow */
1298 	return sm_block_no_retry_timeout(GN_OP_CallDivert, 2000, data, state);
1299 }
1300 
AT_SetPDUMode(gn_data * data,struct gn_statemachine * state)1301 static gn_error AT_SetPDUMode(gn_data *data, struct gn_statemachine *state)
1302 {
1303 	gn_error error;
1304 	at_driver_instance *drvinst = AT_DRVINST(state);
1305 
1306 	/* If we're already in PDU mode don't send this AT command again */
1307 	if (drvinst->pdumode)
1308 		return GN_ERR_NONE;
1309 
1310 	if (sm_message_send(10, GN_OP_AT_SetPDUMode, "AT+CMGF=0\r", state))
1311 		return GN_ERR_NOTREADY;
1312 	error = sm_block_no_retry(GN_OP_AT_SetPDUMode, data, state);
1313 	/* If we successfully changed mode to PDU, let's store this information */
1314 	if (error == GN_ERR_NONE)
1315 		drvinst->pdumode = 1;
1316 	return error;
1317 }
1318 
AT_GetSMSFolders(gn_data * data,struct gn_statemachine * state)1319 static gn_error AT_GetSMSFolders(gn_data *data, struct gn_statemachine *state)
1320 {
1321 	gn_error ret;
1322 
1323 	if (!data || !data->sms_folder_list)
1324 		return GN_ERR_INTERNALERROR;
1325 
1326 	ret = sm_message_send(10, GN_OP_GetSMSFolders, "AT+CPMS=?\r", state);
1327 	if (ret != GN_ERR_NONE)
1328 		return ret;
1329 	return sm_block_no_retry(GN_OP_GetSMSFolders, data, state);
1330 }
1331 
AT_GetSMSStatusInternal(gn_data * data,struct gn_statemachine * state)1332 static gn_error AT_GetSMSStatusInternal(gn_data *data, struct gn_statemachine *state)
1333 {
1334 	gn_error ret;
1335 
1336 	if (!data->sms_status)
1337 		return GN_ERR_INTERNALERROR;
1338 
1339         if (data->memory_status) {
1340                 ret = AT_SetSMSMemoryType(data->memory_status->memory_type,  state);
1341                 if (ret != GN_ERR_NONE)
1342                         return ret;
1343         }
1344 
1345 	ret = sm_message_send(9, GN_OP_GetSMSStatus, "AT+CPMS?\r", state);
1346 	if (ret != GN_ERR_NONE)
1347 		return GN_ERR_NOTREADY;
1348 	return sm_block_no_retry(GN_OP_GetSMSStatus, data, state);
1349 }
1350 
AT_GetSMSFolderStatus(gn_data * data,struct gn_statemachine * state)1351 static gn_error AT_GetSMSFolderStatus(gn_data *data, struct gn_statemachine *state)
1352 {
1353 	gn_sms_status smsstatus = {0, 0, 0, 0, GN_MT_XX}, *save_smsstatus;
1354 	gn_memory_status memory_status = {GN_MT_ME, 0, 0}, *save_memory_status;
1355 	gn_error ret;
1356 
1357 	memory_status.memory_type = data->sms_folder->folder_id;
1358 
1359 	/*
1360 	 * This driver needs some structures that other drivers don't need
1361 	 * and the callers (eg. gnokii) may not be aware of that
1362 	 * so always use a local copy.
1363 	 */
1364 	save_smsstatus = data->sms_status;
1365 	data->sms_status = &smsstatus;
1366 	save_memory_status = data->memory_status;
1367 	data->memory_status = &memory_status;
1368 	ret = AT_GetSMSStatusInternal(data, state);
1369 	data->memory_status = save_memory_status;
1370 	data->sms_status = save_smsstatus;
1371 	if (ret != GN_ERR_NONE)
1372 		return ret;
1373 
1374 	data->sms_folder->number = smsstatus.number;
1375 
1376 	return GN_ERR_NONE;
1377 }
1378 
AT_GetSMSStatus(gn_data * data,struct gn_statemachine * state)1379 static gn_error AT_GetSMSStatus(gn_data *data, struct gn_statemachine *state)
1380 {
1381 	gn_sms_status smsstatus = {0, 0, 0, 0, GN_MT_XX}, *save_smsstatus;
1382 	gn_memory_status memory_status = {GN_MT_ME, 0, 0}, *save_memory_status;
1383 	gn_error ret_me, ret_sm;
1384 
1385 	save_smsstatus = data->sms_status;
1386 	data->sms_status = &smsstatus;
1387 	save_memory_status = data->memory_status;
1388 	data->memory_status = &memory_status;
1389 	ret_me = AT_GetSMSStatusInternal(data, state);
1390 	if (ret_me == GN_ERR_NONE)
1391 		save_smsstatus->number = smsstatus.number;
1392 	data->memory_status->memory_type = GN_MT_SM;
1393 	ret_sm = AT_GetSMSStatusInternal(data, state);
1394 	if (ret_sm == GN_ERR_NONE)
1395 		save_smsstatus->number += smsstatus.number;
1396 	data->memory_status = save_memory_status;
1397 	data->sms_status = save_smsstatus;
1398 	/* Don't fail if phone (or data card) supports at least one memory type */
1399 	if ((ret_me != GN_ERR_NONE) && (ret_sm != GN_ERR_NONE))
1400 		return ret_me;
1401 	return GN_ERR_NONE;
1402 }
1403 
AT_SendSMS(gn_data * data,struct gn_statemachine * state)1404 static gn_error AT_SendSMS(gn_data *data, struct gn_statemachine *state)
1405 {
1406 	return AT_WriteSMS(data, state, "CMGS");
1407 }
1408 
AT_SaveSMS(gn_data * data,struct gn_statemachine * state)1409 static gn_error AT_SaveSMS(gn_data *data, struct gn_statemachine *state)
1410 {
1411 	gn_error ret;
1412 
1413 	ret = AT_SetSMSMemoryType(data->raw_sms->memory_type,  state);
1414 	if (ret)
1415 		return ret;
1416 	return AT_WriteSMS(data, state, "CMGW");
1417 }
1418 
AT_WriteSMS(gn_data * data,struct gn_statemachine * state,unsigned char * cmd)1419 static gn_error AT_WriteSMS(gn_data *data, struct gn_statemachine *state,
1420 			    unsigned char *cmd)
1421 {
1422 	unsigned char req[10240], req2[5120];
1423 	gn_error error;
1424 	unsigned int length, tmp, offset = 0;
1425 	at_driver_instance *drvinst = AT_DRVINST(state);
1426 
1427 	if (!data->raw_sms)
1428 		return GN_ERR_INTERNALERROR;
1429 
1430 	/* Select PDU mode */
1431 	error = state->driver.functions(GN_OP_AT_SetPDUMode, data, state);
1432 	if (error) {
1433 		dprintf("PDU mode is not supported by the phone. This mobile supports only TEXT mode\nwhile gnokii supports only PDU mode.\n");
1434 		return error;
1435 	}
1436 	dprintf("PDU mode set\n");
1437 
1438 	/* Prepare the message and count the size */
1439 	if (drvinst->no_smsc) {
1440 		/* not even a length byte included */
1441 		offset--;
1442 	} else {
1443 		memcpy(req2, data->raw_sms->message_center,
1444 		       data->raw_sms->message_center[0] + 1);
1445 		offset += data->raw_sms->message_center[0];
1446 	}
1447 	/* Validity period in relative format */
1448 	req2[offset + 1] = 0x01 | 0x10;
1449 	if (data->raw_sms->reject_duplicates)
1450 		req2[offset + 1] |= 0x04;
1451 	if (data->raw_sms->report)
1452 		req2[offset + 1] |= 0x20;
1453 	if (data->raw_sms->udh_indicator)
1454 		req2[offset + 1] |= 0x40;
1455 	if (data->raw_sms->reply_via_same_smsc)
1456 		req2[offset + 1] |= 0x80;
1457 	req2[offset + 2] = 0x00; /* Message Reference */
1458 
1459 	tmp = data->raw_sms->remote_number[0];
1460 	if (tmp % 2)
1461 		tmp++;
1462 	tmp /= 2;
1463 	memcpy(req2 + offset + 3, data->raw_sms->remote_number, tmp + 2);
1464 	offset += tmp + 1;
1465 
1466 	req2[offset + 4] = data->raw_sms->pid;
1467 	req2[offset + 5] = data->raw_sms->dcs;
1468 	req2[offset + 6] = 0xaa; /* Validity period */
1469 	req2[offset + 7] = data->raw_sms->length;
1470 	memcpy(req2 + offset + 8, data->raw_sms->user_data,
1471 	       data->raw_sms->user_data_length);
1472 
1473 	length = data->raw_sms->user_data_length + offset + 8;
1474 
1475 	/* Length in AT mode is the length of the full message minus
1476 	 * SMSC field length */
1477 	if (drvinst->no_smsc) {
1478 		snprintf(req, sizeof(req), "AT+%s=%d\r", cmd, length);
1479 	} else {
1480 		snprintf(req, sizeof(req), "AT+%s=%d\r", cmd, length - data->raw_sms->message_center[0] - 1);
1481 	}
1482 	dprintf("Sending initial sequence\n");
1483 	if (sm_message_send(strlen(req), GN_OP_AT_Prompt, req, state))
1484 		return GN_ERR_NOTREADY;
1485 	error = sm_block_no_retry(GN_OP_AT_Prompt, data, state);
1486 	dprintf("Got response: %s\n", gn_error_print(error));
1487 	if (error)
1488 		return error;
1489 
1490 	bin2hex(req, req2, length);
1491 	req[length * 2] = 0x1a;
1492 	req[length * 2 + 1] = 0;
1493 	dprintf("Sending frame: %s\n", req);
1494 	if (sm_message_send(strlen(req), GN_OP_SendSMS, req, state))
1495 		return GN_ERR_NOTREADY;
1496 	do {
1497 		error = sm_block_no_retry_timeout(GN_OP_SendSMS, state->config.smsc_timeout, data, state);
1498 	} while (!state->config.smsc_timeout && error == GN_ERR_TIMEOUT);
1499 	return error;
1500 }
1501 
AT_GetSMS(gn_data * data,struct gn_statemachine * state)1502 static gn_error AT_GetSMS(gn_data *data, struct gn_statemachine *state)
1503 {
1504 	/* Sony Ericsson can return on notification a location that is 9-digits long */
1505 	unsigned char req[32];
1506 	gn_error err;
1507 
1508 	err = AT_SetSMSMemoryType(data->raw_sms->memory_type,  state);
1509 
1510 	if (err)
1511 		return err;
1512 
1513 	err = state->driver.functions(GN_OP_AT_SetPDUMode, data, state);
1514 	if (err) {
1515 		dprintf("PDU mode is not supported by the phone. This mobile supports only TEXT mode\nwhile gnokii supports only PDU mode.\n");
1516 		return err;
1517 	}
1518 	dprintf("PDU mode set\n");
1519 
1520 	snprintf(req, sizeof(req), "AT+CMGR=%d\r", data->raw_sms->number);
1521 	if (sm_message_send(strlen(req), GN_OP_GetSMS, req, state))
1522 		return GN_ERR_NOTREADY;
1523 	return sm_block_no_retry(GN_OP_GetSMS, data, state);
1524 }
1525 
AT_DeleteSMS(gn_data * data,struct gn_statemachine * state)1526 static gn_error AT_DeleteSMS(gn_data *data, struct gn_statemachine *state)
1527 {
1528 	unsigned char req[32];
1529 	gn_error err;
1530 
1531 	err = AT_SetSMSMemoryType(data->raw_sms->memory_type,  state);
1532 	if (err)
1533 		return err;
1534 	snprintf(req, sizeof(req), "AT+CMGD=%d\r", data->sms->number);
1535 
1536 	if (sm_message_send(strlen(req), GN_OP_DeleteSMS, req, state))
1537  		return GN_ERR_NOTREADY;
1538 	return sm_block_no_retry(GN_OP_DeleteSMS, data, state);
1539 }
1540 
1541 /*
1542  * Hey nokia users. don't expect this to return anything useful.
1543  * You can't read the number set by the phone menu with this command,
1544  * nor can you change this number by AT commands. Worse, an ATZ will
1545  * clear a SMS Center Number set by AT commands. This doesn't affect
1546  * the number set by the phone menu.
1547  */
AT_GetSMSCenter(gn_data * data,struct gn_statemachine * state)1548 static gn_error AT_GetSMSCenter(gn_data *data, struct gn_statemachine *state)
1549 {
1550 	/* AT protocol supports only one SMS Center */
1551 	if (data->message_center && data->message_center->id != 1)
1552 		return GN_ERR_INVALIDLOCATION;
1553 	at_set_charset(data, state, AT_CHAR_GSM);
1554  	if (sm_message_send(9, GN_OP_GetSMSCenter, "AT+CSCA?\r", state))
1555 		return GN_ERR_NOTREADY;
1556 	return sm_block_no_retry(GN_OP_GetSMSCenter, data, state);
1557 }
1558 
1559 #ifdef SECURITY
AT_GetSecurityCodeStatus(gn_data * data,struct gn_statemachine * state)1560 static gn_error AT_GetSecurityCodeStatus(gn_data *data, struct gn_statemachine *state)
1561 {
1562  	if (sm_message_send(9, GN_OP_GetSecurityCodeStatus, "AT+CPIN?\r", state))
1563 		return GN_ERR_NOTREADY;
1564 	return sm_block_no_retry(GN_OP_GetSecurityCodeStatus, data, state);
1565 }
1566 
AT_EnterSecurityCode(gn_data * data,struct gn_statemachine * state)1567 static gn_error AT_EnterSecurityCode(gn_data *data, struct gn_statemachine *state)
1568 {
1569 	unsigned char req[32];
1570 
1571 	if (data->security_code->type != GN_SCT_Pin)
1572 		return GN_ERR_NOTIMPLEMENTED;
1573 
1574 	snprintf(req, sizeof(req), "AT+CPIN=\"%s\"\r", data->security_code->code);
1575  	if (sm_message_send(strlen(req), GN_OP_EnterSecurityCode, req, state))
1576 		return GN_ERR_NOTREADY;
1577 	return sm_block_no_retry(GN_OP_EnterSecurityCode, data, state);
1578 }
1579 #endif
1580 
AT_DialVoice(gn_data * data,struct gn_statemachine * state)1581 static gn_error AT_DialVoice(gn_data *data, struct gn_statemachine *state)
1582 {
1583 	unsigned char req[32];
1584 
1585 	if (!data->call_info)
1586 		return GN_ERR_INTERNALERROR;
1587 	snprintf(req, sizeof(req), "ATD%s;\r", data->call_info->number);
1588 	if (sm_message_send(strlen(req), GN_OP_MakeCall, req, state))
1589 		return GN_ERR_NOTREADY;
1590 	return sm_block_no_retry(GN_OP_MakeCall, data, state);
1591 }
1592 
AT_AnswerCall(gn_data * data,struct gn_statemachine * state)1593 static gn_error AT_AnswerCall(gn_data *data, struct gn_statemachine *state)
1594 {
1595 	if (sm_message_send(4, GN_OP_AnswerCall, "ATA\r", state))
1596 		return GN_ERR_NOTREADY;
1597 	return sm_block_no_retry(GN_OP_AnswerCall, data, state);
1598 }
1599 
AT_CancelCall(gn_data * data,struct gn_statemachine * state)1600 static gn_error AT_CancelCall(gn_data *data, struct gn_statemachine *state)
1601 {
1602 	if (sm_message_send(8, GN_OP_CancelCall, "AT+CHUP\r", state))
1603 		return GN_ERR_NOTREADY;
1604 	return sm_block_no_retry(GN_OP_CancelCall, data, state);
1605 }
1606 
AT_SetCallNotification(gn_data * data,struct gn_statemachine * state)1607 static gn_error AT_SetCallNotification(gn_data *data, struct gn_statemachine *state)
1608 {
1609 	at_driver_instance *drvinst = AT_DRVINST(state);
1610 	gn_error err;
1611 
1612 	if (!drvinst->call_notification && !data->call_notification)
1613 		return GN_ERR_NONE;
1614 
1615 	if (!drvinst->call_notification) {
1616 		if (sm_message_send(9, GN_OP_SetCallNotification, "AT+CRC=1\r", state))
1617 			return GN_ERR_NOTREADY;
1618 		if ((err = sm_block_no_retry(GN_OP_SetCallNotification, data, state)) != GN_ERR_NONE)
1619 			return err;
1620 		if (sm_message_send(10, GN_OP_SetCallNotification, "AT+CLIP=1\r", state))
1621 			return GN_ERR_NOTREADY;
1622 		/* Ignore errors when we can't set Call Line Identity, just set that we
1623 		 * don't handle it */
1624 		if (sm_block_no_retry(GN_OP_SetCallNotification, data, state) == GN_ERR_NONE)
1625 			drvinst->clip_supported = 1;
1626 		if (sm_message_send(10, GN_OP_SetCallNotification, "AT+CLCC=1\r", state))
1627 			return GN_ERR_NOTREADY;
1628 		/* Ignore errors when we can't set List Current Calls notifications */
1629 		sm_block_no_retry(GN_OP_SetCallNotification, data, state);
1630 	}
1631 
1632 	drvinst->call_notification = data->call_notification;
1633 	drvinst->call_callback_data = data->callback_data;
1634 
1635 	return GN_ERR_NONE;
1636 }
1637 
AT_GetNetworkInfo(gn_data * data,struct gn_statemachine * state)1638 static gn_error AT_GetNetworkInfo(gn_data *data, struct gn_statemachine *state)
1639 {
1640 	at_driver_instance *drvinst = AT_DRVINST(state);
1641 
1642 	/*
1643 	 * AT+CREG enables +CREG notifications, so register notification
1644 	 * callback.
1645 	 */
1646 	drvinst->reg_notification = data->reg_notification;
1647 	drvinst->reg_callback_data = data->callback_data;
1648 
1649 	if (!data->network_info)
1650 		return GN_ERR_INTERNALERROR;
1651 
1652 	if (!drvinst->extended_reg_status) {
1653 		if (sm_message_send(10, GN_OP_GetNetworkInfo, "AT+CREG=?\r", state))
1654 			return GN_ERR_NOTREADY;
1655 
1656 		/* Let's ignore the error. We try to get as much as possible */
1657 		sm_block_no_retry(GN_OP_GetNetworkInfo, data, state);
1658 	}
1659 
1660 	/*
1661 	 * We only check the registration status when the phone supports it.
1662 	 * What we want in fact is the LAC ID and CELL ID.
1663 	 */
1664 	if (drvinst->extended_reg_status == 2) {
1665 		if (sm_message_send(10, GN_OP_GetNetworkInfo, "AT+CREG=2\r", state))
1666 			return GN_ERR_NOTREADY;
1667 
1668 		/* Let's ignore the error. We try to get as much as possible */
1669 		sm_block_no_retry(GN_OP_GetNetworkInfo, data, state);
1670 
1671 		if (sm_message_send(9, GN_OP_GetNetworkInfo, "AT+CREG?\r", state))
1672 			return GN_ERR_NOTREADY;
1673 
1674 		/* Let's ignore the error. We try to get as much as possible */
1675 		sm_block_no_retry(GN_OP_GetNetworkInfo, data, state);
1676 	}
1677 
1678 	/*
1679 	 * We want to get the network information in the numerical format (network code).
1680 	 * Format of the command is as follows:
1681 	 *   AT+COPS=<MODE>,<FORMAT>,<OPERATOR>
1682 	 * <MODE> can be one of the following:
1683 	 *   0 - automatic mode (<OPERATOR> is ignored)
1684 	 *   1 - manual mode (<OPERATOR> is required)
1685 	 *   2 - unregister from the network
1686 	 *   3 - set <FORMAT> field
1687 	 *   4 - mixed manual and automatic mode (if manual fails, go into the automatic mode)
1688 	 * <FORMAT> can be one of the following:
1689 	 *   0 - long alphanumeric format (max 16 chars)
1690 	 *   1 - short alphanumeric format
1691 	 *   2 - numeric format (LAI)
1692 	 * <OPERATOR> should be alphanumeric network name or network code according to <FORMAT> value
1693 	 */
1694 	if (sm_message_send(12, GN_OP_GetNetworkInfo, "AT+COPS=3,2\r", state))
1695 		return GN_ERR_NOTREADY;
1696 	/* Ignore the error. Nokias do not support this command and give always network code. */
1697 	sm_block_no_retry(GN_OP_GetNetworkInfo, data, state);
1698 
1699 	if (sm_message_send(9, GN_OP_GetNetworkInfo, "AT+COPS?\r", state))
1700 		return GN_ERR_NOTREADY;
1701 
1702 	sm_block_no_retry(GN_OP_GetNetworkInfo, data, state);
1703 	return GN_ERR_NONE;
1704 }
1705 
AT_SetDateTime(gn_data * data,struct gn_statemachine * state)1706 static gn_error AT_SetDateTime(gn_data *data, struct gn_statemachine *state)
1707 {
1708 	at_driver_instance *drvinst = AT_DRVINST(state);
1709 	char req[64];
1710 	gn_timestamp aux;
1711 	gn_timestamp *dt = data->datetime;
1712 
1713 	memset(&aux, 0, sizeof(gn_timestamp));
1714 	/* Make sure GetDateTime doesn't overwrite dt */
1715 	data->datetime = &aux;
1716 	/* ignore errors */
1717 	AT_GetDateTime(data, state);
1718 	AT_PrepareDateTime(data, state);
1719 
1720 	data->datetime = dt;
1721 	if (drvinst->timezone)
1722 		snprintf(req, sizeof(req), "AT+CCLK=\"%02d/%02d/%02d,%02d:%02d:%02d%s\"\r",
1723 			 dt->year % 100, dt->month, dt->day,
1724 			 dt->hour, dt->minute, dt->second, drvinst->timezone);
1725 	else
1726 		snprintf(req, sizeof(req), "AT+CCLK=\"%02d/%02d/%02d,%02d:%02d:%02d\"\r",
1727 			 dt->year % 100, dt->month, dt->day,
1728 			 dt->hour, dt->minute, dt->second);
1729 
1730 	if (sm_message_send(strlen(req), GN_OP_SetDateTime, req, state))
1731 		return GN_ERR_NOTREADY;
1732 	return sm_block_no_retry(GN_OP_SetDateTime, data, state);
1733 }
1734 
AT_GetDateTime(gn_data * data,struct gn_statemachine * state)1735 static gn_error AT_GetDateTime(gn_data *data, struct gn_statemachine *state)
1736 {
1737 	if (sm_message_send(9, GN_OP_GetDateTime, "AT+CCLK?\r", state))
1738 		return GN_ERR_NOTREADY;
1739 	return sm_block_no_retry(GN_OP_GetDateTime, data, state);
1740 }
1741 
AT_PrepareDateTime(gn_data * data,struct gn_statemachine * state)1742 static gn_error AT_PrepareDateTime(gn_data *data, struct gn_statemachine *state)
1743 {
1744 	if (sm_message_send(10, GN_OP_AT_PrepareDateTime, "AT+CCLK=?\r", state))
1745 		return GN_ERR_NOTREADY;
1746 	return sm_block_no_retry(GN_OP_AT_PrepareDateTime, data, state);
1747 }
1748 
1749 /*
1750  * This command allows to send DTMF tones and arbitrary tones.
1751  * DTMF is a single ASCII character in the set 0-9, *, #, A-D
1752  * FIXME: tone and duration parameters are not yet supported
1753  */
AT_SendDTMF(gn_data * data,struct gn_statemachine * state)1754 static gn_error AT_SendDTMF(gn_data *data, struct gn_statemachine *state)
1755 {
1756 	gn_error error = GN_ERR_NONE;
1757 	unsigned char req[32];
1758 	int len, i, dtmf_len;
1759 
1760 	if (!data || !data->dtmf_string)
1761 		return GN_ERR_INTERNALERROR;
1762 
1763 	dtmf_len = strlen(data->dtmf_string);
1764 	if (dtmf_len < 1)
1765 		return GN_ERR_WRONGDATAFORMAT;
1766 
1767 	/* First let's check out if the command is supported by the phone */
1768 	len = snprintf(req, sizeof(req), "AT+VTS=?\r");
1769 	if (sm_message_send(len, GN_OP_SendDTMF, req, state))
1770 		return GN_ERR_NOTREADY;
1771 	if (sm_block_no_retry(GN_OP_SendDTMF, data, state) != GN_ERR_NONE)
1772 		return GN_ERR_NOTSUPPORTED;
1773 
1774 	/* Send it char by char */
1775 	for (i = 0; i < dtmf_len; i++) {
1776 		len = snprintf(req, sizeof(req), "AT+VTS=%c\r", data->dtmf_string[i]);
1777 		if (sm_message_send(len, GN_OP_SendDTMF, req, state))
1778 			return GN_ERR_NOTREADY;
1779 		error = sm_block_no_retry(GN_OP_SendDTMF, data, state);
1780 		if (error)
1781 			break;
1782 	}
1783 
1784 	return error;
1785 }
1786 
AT_GetActiveCalls(gn_data * data,struct gn_statemachine * state)1787 static gn_error AT_GetActiveCalls(gn_data *data, struct gn_statemachine *state)
1788 {
1789 	if (sm_message_send(8, GN_OP_GetActiveCalls, "AT+CPAS\r", state))
1790 		return GN_ERR_NOTREADY;
1791 	return sm_block_no_retry(GN_OP_GetActiveCalls, data, state);
1792 }
1793 
AT_OnSMS(gn_data * data,struct gn_statemachine * state)1794 static gn_error AT_OnSMS(gn_data *data, struct gn_statemachine *state)
1795 {
1796 	at_driver_instance *drvinst = AT_DRVINST(state);
1797 	gn_error error;
1798 	int mode;
1799 	char req[13];
1800 
1801 	mode = drvinst->cnmi_mode;
1802 	do {
1803 		snprintf(req, sizeof(req), "AT+CNMI=%d,1\r", mode);
1804 		if (sm_message_send(strlen(req), GN_OP_OnSMS, req, state))
1805 			return GN_ERR_NOTREADY;
1806 
1807 		error = sm_block_no_retry(GN_OP_OnSMS, data, state);
1808 	} while (mode-- && error);
1809 	if (error == GN_ERR_NONE) {
1810 		AT_DRVINST(state)->on_sms = data->on_sms;
1811 		AT_DRVINST(state)->sms_callback_data = data->callback_data;
1812 	}
1813 	return error;
1814 }
1815 
AT_GetSMSMemorySize(gn_data * data,struct gn_statemachine * state)1816 static gn_error AT_GetSMSMemorySize(gn_data *data, struct gn_statemachine *state)
1817 {
1818 	if (sm_message_send(18, GN_OP_AT_GetSMSMemorySize, "AT+CPMS=\"ME\",\"SM\"\r", state))
1819 		return GN_ERR_NOTREADY;
1820 
1821 	return sm_block_no_retry(GN_OP_AT_GetSMSMemorySize, data, state);
1822 }
1823 
ReplyReadPhonebook(int messagetype,unsigned char * buffer,int length,gn_data * data,struct gn_statemachine * state)1824 static gn_error ReplyReadPhonebook(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state)
1825 {
1826 	at_driver_instance *drvinst = AT_DRVINST(state);
1827 	at_line_buffer buf;
1828 	char *pos;
1829 	gn_error error;
1830 
1831 	error = at_error_get(buffer, state);
1832 	switch (error) {
1833 	case GN_ERR_NONE:
1834 		break;
1835 	case GN_ERR_FAILED:
1836 		/* Some phones return "+CME ERROR: 3" for invalid locations */
1837 		/* Fall through */
1838 	case GN_ERR_UNKNOWN:
1839 		/* Some phones return "+CME ERROR: 100" instead of "OK" for empty locations */
1840 		if (data->phonebook_entry->location >= drvinst->memoryoffset && data->phonebook_entry->location < drvinst->memoryoffset + drvinst->memorysize) {
1841 			return GN_ERR_EMPTYLOCATION;
1842 		}
1843 		return GN_ERR_INVALIDLOCATION;
1844 	default:
1845 		return error;
1846 	}
1847 
1848 	buf.line1 = buffer + 1;
1849 	buf.length = length;
1850 	splitlines(&buf);
1851 
1852 	if (strncmp(buf.line1, "AT+CPBR", 7)) {
1853 		return GN_ERR_UNKNOWN;
1854 	}
1855 
1856 	if (!strncmp(buf.line2, "OK", 2)) {
1857 		/* Empty phonebook location found */
1858 		if (data->phonebook_entry) {
1859 			*(data->phonebook_entry->number) = '\0';
1860 			*(data->phonebook_entry->name) = '\0';
1861 			data->phonebook_entry->caller_group = GN_PHONEBOOK_GROUP_None;
1862 			data->phonebook_entry->subentries_count = 0;
1863 			data->phonebook_entry->empty = true;
1864 		}
1865 		return GN_ERR_NONE;
1866 	}
1867 	if (data->phonebook_entry) {
1868 		char *part[6];
1869 		int parts, quoted;
1870 
1871 		data->phonebook_entry->caller_group = GN_PHONEBOOK_GROUP_None;
1872 		data->phonebook_entry->subentries_count = 0;
1873 		data->phonebook_entry->empty = false;
1874 
1875 		/* split in several parts a line like +CPBR: 1,"123",129,"Name","2008/03/19,18:57"
1876 		   part[] must have one more item than the string, otherwise the last *part will point to string tail
1877 		   commas can appear unescaped inside quotes
1878 		   quotes can appear only as delimiters
1879 		 */
1880 		part[0] = pos = buf.line2 + 7;
1881 		for (parts = 1; parts < (sizeof(part) / sizeof(*part)); parts++)
1882 			part[parts] = NULL;
1883 		quoted = 0;
1884 		parts = 1;
1885 		while (*pos && (parts < (sizeof(part) / sizeof(*part)))) {
1886 			switch (*pos) {
1887 			case '"':
1888 				quoted = !quoted;
1889 				break;
1890 			case ',':
1891 				if (!quoted) {
1892 					*pos = '\0';
1893 					part[parts] = pos + 1;
1894 					/* Some phones add a space after a comma */
1895 					while (*part[parts] == ' ')
1896 						part[parts]++;
1897 					parts++;
1898 				}
1899 				break;
1900 			}
1901 			pos++;
1902 		}
1903 		/* DEBUG */
1904 		for (parts = 0; parts < (sizeof(part) / sizeof(*part)) && part[parts]; parts++) {
1905 			dprintf("part[%d] = \"%s\"\n", parts, part[parts]);
1906 		}
1907 
1908 		/* store number */
1909 		pos = part[1];
1910 		if (pos) {
1911 			dprintf("NUMBER: %s\n", pos);
1912 			pos = strip_quotes(pos);
1913 			if (drvinst->encode_number)
1914 				at_decode(drvinst->charset, data->phonebook_entry->number, pos, strlen(pos), drvinst->ucs2_as_utf8);
1915 			else
1916 				snprintf(data->phonebook_entry->number, sizeof(data->phonebook_entry->number), "%s", pos);
1917 		}
1918 		/* store name */
1919 		pos = part[3];
1920 		if (pos) {
1921 			dprintf("NAME: %s\n", pos);
1922 			pos = strip_quotes(pos);
1923 			at_decode(drvinst->charset, data->phonebook_entry->name, pos, strlen(pos), drvinst->ucs2_as_utf8);
1924 		}
1925 		/* store date/time (usually sent with DC, MC, RC entries) */
1926 		pos = part[4];
1927 		if (pos) {
1928 			char *date_buf = NULL;
1929 
1930 			dprintf("DATE: %s\n", pos);
1931 			if (*pos == '"')
1932 				pos++;
1933 			if (drvinst->encode_number) {
1934 				date_buf = calloc(strlen(pos) + 1, sizeof(char));
1935 				at_decode(drvinst->charset, date_buf, pos, strlen(pos), drvinst->ucs2_as_utf8);
1936 				pos = date_buf;
1937 				dprintf("DATE: %s\n", pos);
1938 			}
1939 			/* seconds may not be present */
1940 			data->phonebook_entry->date.second = 0;
1941 			if (sscanf(pos, "%d/%d/%d,%d:%d:%d",
1942 				&data->phonebook_entry->date.year,
1943 				&data->phonebook_entry->date.month,
1944 				&data->phonebook_entry->date.day,
1945 				&data->phonebook_entry->date.hour,
1946 				&data->phonebook_entry->date.minute,
1947 				&data->phonebook_entry->date.second) < 5) {
1948 				/* not a fatal error */
1949 				data->phonebook_entry->date.year = 0;
1950 			}
1951 			free(date_buf);
1952 		}
1953 	}
1954 	return GN_ERR_NONE;
1955 }
1956 
ReplyReadPhonebookExt(int messagetype,unsigned char * buffer,int length,gn_data * data,struct gn_statemachine * state)1957 static gn_error ReplyReadPhonebookExt(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state)
1958 {
1959 	at_driver_instance *drvinst = AT_DRVINST(state);
1960 	at_line_buffer buf;
1961 	char *pos, *first_name, *last_name, *tmp;
1962 	gn_error error;
1963 	size_t len = 0;
1964 
1965 	if ((error = at_error_get(buffer, state)) != GN_ERR_NONE)
1966 		return (error == GN_ERR_UNKNOWN) ? GN_ERR_INVALIDLOCATION : error;
1967 
1968 	buf.line1 = buffer + 1;
1969 	buf.length = length;
1970 	splitlines(&buf);
1971 
1972 	if (strncmp(buf.line1, "AT+SPBR=", 8)) {
1973 		return GN_ERR_UNKNOWN;
1974 	}
1975 
1976 	if (!strncmp(buf.line2, "OK", 2)) {
1977 		/* Empty phonebook location found */
1978 		if (data->phonebook_entry) {
1979 			data->phonebook_entry->number[0] = 0;
1980 			data->phonebook_entry->name[0] = 0;
1981 			data->phonebook_entry->caller_group = GN_PHONEBOOK_GROUP_None;
1982 			data->phonebook_entry->subentries_count = 0;
1983 			data->phonebook_entry->empty = true;
1984 		}
1985 		return GN_ERR_NONE;
1986 	}
1987 	if (strncmp(buf.line2, "+SPBR: ", 7))
1988 		return GN_ERR_UNKNOWN;
1989 
1990 	if (data->phonebook_entry) {
1991 		gn_phonebook_entry *entry = data->phonebook_entry;
1992 		data->phonebook_entry->number[0] = 0;
1993 		data->phonebook_entry->name[0] = 0;
1994 		entry->caller_group = GN_PHONEBOOK_GROUP_None;
1995 		entry->subentries_count = 0;
1996 		entry->empty = false;
1997 		pos = buf.line2;
1998 
1999 		/* store sub entries */
2000 		pos = extpb_scan_entry(drvinst, pos, entry, GN_PHONEBOOK_ENTRY_Number, GN_PHONEBOOK_NUMBER_Mobile, 0);
2001 		pos = extpb_scan_entry(drvinst, pos, entry, GN_PHONEBOOK_ENTRY_Number, GN_PHONEBOOK_NUMBER_Home, 0);
2002 		pos = extpb_scan_entry(drvinst, pos, entry, GN_PHONEBOOK_ENTRY_Number, GN_PHONEBOOK_NUMBER_Work, 0);
2003 		pos = extpb_scan_entry(drvinst, pos, entry, GN_PHONEBOOK_ENTRY_Number, GN_PHONEBOOK_NUMBER_Fax, 0);
2004 		pos = extpb_scan_entry(drvinst, pos, entry, GN_PHONEBOOK_ENTRY_Number, GN_PHONEBOOK_NUMBER_General, 0);
2005 		pos = extpb_scan_entry(drvinst, pos, entry, GN_PHONEBOOK_ENTRY_Email, GN_PHONEBOOK_NUMBER_None, 0);
2006 		pos = extpb_scan_entry(drvinst, pos, entry, GN_PHONEBOOK_ENTRY_FirstName, GN_PHONEBOOK_NUMBER_None, 1);
2007 		pos = extpb_scan_entry(drvinst, pos, entry, GN_PHONEBOOK_ENTRY_LastName, GN_PHONEBOOK_NUMBER_None, 1);
2008 		pos = extpb_scan_entry(drvinst, pos, entry, GN_PHONEBOOK_ENTRY_Note, GN_PHONEBOOK_NUMBER_None, 1);
2009 
2010 		/* compile a name out of first name + last name */
2011 		first_name = extpb_find_subentry(entry, GN_PHONEBOOK_ENTRY_FirstName);
2012 		last_name = extpb_find_subentry(entry, GN_PHONEBOOK_ENTRY_LastName);
2013 		if (first_name || last_name) {
2014 			if (first_name)
2015 				len += strlen(first_name);
2016 			if (last_name)
2017 				len += strlen(last_name);
2018 			if (!(tmp = (char *)malloc(len + 2))) /* +2 for \0 and space */
2019 				return GN_ERR_INTERNALERROR;
2020 			tmp[0] = 0;
2021 			if (first_name) {
2022 				if (strlen(first_name) + strlen(entry->name) + 1 > sizeof(entry->name)) {
2023 					free(tmp);
2024 					return GN_ERR_FAILED;
2025 				}
2026 				strncat(entry->name, first_name, strlen(first_name));
2027 				if (last_name)
2028 					strncat(entry->name, " ", strlen(" "));
2029 			}
2030 			if (last_name) {
2031 				if (strlen(last_name) + strlen(entry->name) + 1 > sizeof(entry->name)) {
2032 					free(tmp);
2033 					return GN_ERR_FAILED;
2034 				}
2035 				strncat(entry->name, last_name, strlen (last_name));
2036 			}
2037 			free(tmp);
2038 		}
2039 	}
2040 	return GN_ERR_NONE;
2041 }
2042 
ReplyGetSMSCenter(int messagetype,unsigned char * buffer,int length,gn_data * data,struct gn_statemachine * state)2043 static gn_error ReplyGetSMSCenter(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state)
2044 {
2045 	at_line_buffer buf;
2046 	unsigned char *pos, *aux;
2047 	gn_error error;
2048 
2049 	if ((error = at_error_get(buffer, state)) != GN_ERR_NONE) return error;
2050 
2051 	buf.line1 = buffer + 1;
2052 	buf.length= length;
2053 
2054 	splitlines(&buf);
2055 
2056 	if (data->message_center && strstr(buf.line2, "+CSCA")) {
2057 		pos = strchr(buf.line2 + 8, '\"');
2058 		if (pos) {
2059 			*pos++ = '\0';
2060 			data->message_center->id = 1;
2061 			snprintf(data->message_center->smsc.number, GN_BCD_STRING_MAX_LENGTH, "%s", buf.line2 + 8);
2062 			/* Now we look for the number type */
2063 			aux = strchr(pos, ',');
2064 			if (aux)
2065 				data->message_center->smsc.type = atoi(++aux);
2066 			else if (data->message_center->smsc.number[0] == '+')
2067 				data->message_center->smsc.type = GN_GSM_NUMBER_International;
2068 			else
2069 				data->message_center->smsc.type = GN_GSM_NUMBER_Unknown;
2070 		} else {
2071 			data->message_center->id = 0;
2072 			data->message_center->smsc.type = GN_GSM_NUMBER_Unknown;
2073 		}
2074 		/* Set a default SMSC name because +CSCA doesn't provide one */
2075 		snprintf(data->message_center->name, sizeof(data->message_center->name), _("Set %d"), data->message_center->id);
2076 		data->message_center->default_name = data->message_center->id;
2077 		/* FIXME? following information is given by AT+CSMP (if supported by phone) but is valid only for text mode */
2078 		data->message_center->format = GN_SMS_MF_Text; /* whatever */
2079 		data->message_center->validity = GN_SMS_VP_Max;
2080 		data->message_center->recipient.number[0] = 0;
2081 	}
2082 	return GN_ERR_NONE;
2083 }
2084 
ReplyMemoryStatus(int messagetype,unsigned char * buffer,int length,gn_data * data,struct gn_statemachine * state)2085 static gn_error ReplyMemoryStatus(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state)
2086 {
2087 	at_driver_instance *drvinst = AT_DRVINST(state);
2088 	at_line_buffer buf;
2089 	char *pos;
2090 	gn_error error;
2091 
2092 	if ((error = at_error_get(buffer, state)) != GN_ERR_NONE)
2093 		return (error == GN_ERR_UNKNOWN) ? GN_ERR_INVALIDMEMORYTYPE : error;
2094 
2095 	buf.line1 = buffer + 1;
2096 	buf.length= length;
2097 
2098 	splitlines(&buf);
2099 
2100 	if (data->memory_status && strstr(buf.line2, "+CPBS")) {
2101 		pos = strchr(buf.line2, ',');
2102 		if (pos) {
2103 			data->memory_status->used = atoi(++pos);
2104 		} else {
2105 			data->memory_status->used = drvinst->memorysize;
2106 			data->memory_status->free = 0;
2107 			return GN_ERR_NOTSUPPORTED;
2108 		}
2109 		pos = strchr(pos, ',');
2110 		if (pos) {
2111 			data->memory_status->free = atoi(++pos) - data->memory_status->used;
2112 		} else {
2113 			return GN_ERR_UNKNOWN;
2114 		}
2115 	}
2116 	return GN_ERR_NONE;
2117 }
2118 
Parse_ReplyMemoryRange(gn_data * data,struct gn_statemachine * state)2119 static gn_error Parse_ReplyMemoryRange(gn_data *data, struct gn_statemachine *state)
2120 {
2121 	at_driver_instance *drvinst = AT_DRVINST(state);
2122 	char *r, *s, *t, *pos;
2123 	char key[7];
2124 
2125 	snprintf(key, 7, "%s%s", "CPBR", gn_memory_type2str(drvinst->memorytype));
2126 	r = strdup(map_get(&drvinst->cached_capabilities, key, 0));
2127 	s = r + 7;
2128 	pos = strchr(s, ',');
2129 	if (pos) {
2130 		*pos = '\0';
2131 		s = strip_brackets(s);
2132 		t = strchr(s, '-');
2133 		if (t) {
2134 			int first, last;
2135 			first = atoi(s);
2136 			last = atoi(t+1);
2137 			drvinst->memoryoffset = first - 1;
2138 			dprintf("Memory offset: %d\n", drvinst->memoryoffset);
2139 			drvinst->memorysize = last - first + 1;
2140 			dprintf("Memory size: %d\n", drvinst->memorysize);
2141 		}
2142 	}
2143 	free(r);
2144 	return GN_ERR_NONE;
2145 }
2146 
2147 /*
2148  * Response of of a form:
2149  * +CPBR: (list of supported indexes), <nlength>, <tlength>
2150  * 	list of supported indexes is usually in 1, 2500 form
2151  * 	nlength is the maximal length of the number
2152  * 	tlength is the maximal length of the name
2153  */
ReplyMemoryRange(int messagetype,unsigned char * buffer,int length,gn_data * data,struct gn_statemachine * state)2154 static gn_error ReplyMemoryRange(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state)
2155 {
2156 	at_driver_instance *drvinst = AT_DRVINST(state);
2157 	at_line_buffer buf;
2158 	gn_error error;
2159 
2160 	drvinst->memoryoffset = 0;
2161 	drvinst->memorysize = 100;
2162 
2163 	if ((error = at_error_get(buffer, state)) != GN_ERR_NONE)
2164 		return error;
2165 
2166 	buf.line1 = buffer + 1;
2167 	buf.length= length;
2168 
2169 	splitlines(&buf);
2170 
2171 	if (strncmp(buf.line2, "+CPBR: ", 7) == 0) {
2172 		char key[7];
2173 		snprintf(key, 7, "%s%s", "CPBR", gn_memory_type2str(drvinst->memorytype));
2174 		map_add(&drvinst->cached_capabilities, strdup(key), strdup(buf.line2));
2175 		Parse_ReplyMemoryRange(data, state);
2176 	}
2177 
2178 	return GN_ERR_NONE;
2179 }
2180 
2181 /*
2182  * Parse a response similar to
2183  * +CBC: 0, 50
2184  * see subclause 8.4 of ETSI TS 127 007 V8.6.0 (2009-01)
2185 */
Parse_ReplyGetBattery(gn_data * data,struct gn_statemachine * state)2186 static gn_error Parse_ReplyGetBattery(gn_data *data, struct gn_statemachine *state)
2187 {
2188 	at_driver_instance *drvinst = AT_DRVINST(state);
2189 	const char *line, *pos;
2190 	char key[4];
2191 
2192 	snprintf(key, 4, "CBC");
2193 	line = map_get(&drvinst->cached_capabilities, key, 1);
2194 	if (data->battery_level) {
2195 		if (data->battery_unit)
2196 			*(data->battery_unit) = GN_BU_Percentage;
2197 		pos = strchr(line, ',');
2198 		if (pos) {
2199 			pos++;
2200 			*(data->battery_level) = atoi(pos);
2201 		} else {
2202 			*(data->battery_level) = 1;
2203 		}
2204 	}
2205 	if (data->power_source) {
2206 		pos = line + strlen("+CBC: ");
2207 		switch (*pos) {
2208 		case '0':
2209 			*(data->power_source) = GN_PS_BATTERY;
2210 			break;
2211 		case '1':
2212 			*(data->power_source) = GN_PS_ACDC;
2213 			break;
2214 		case '2':
2215 			*(data->power_source) = GN_PS_NOBATTERY;
2216 			break;
2217 		case '3':
2218 			*(data->power_source) = GN_PS_FAULT;
2219 			break;
2220 		default:
2221 			dprintf("Unknown power status '%c'\n", *pos);
2222 			*(data->power_source) = GN_PS_UNKNOWN;
2223 		}
2224 	}
2225 	return GN_ERR_NONE;
2226 }
2227 
2228 /*
2229  * Let's cache it. --monitor calls it twice to get battery level
2230  * and battery source.
2231  */
ReplyGetBattery(int messagetype,unsigned char * buffer,int length,gn_data * data,struct gn_statemachine * state)2232 static gn_error ReplyGetBattery(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state)
2233 {
2234 	at_driver_instance *drvinst = AT_DRVINST(state);
2235 	at_line_buffer buf;
2236 	gn_error error;
2237 
2238 	if ((error = at_error_get(buffer, state)) != GN_ERR_NONE) return error;
2239 
2240 	buf.line1 = buffer + 1;
2241 	buf.length= length;
2242 
2243 	splitlines(&buf);
2244 
2245 	if (!strncmp(buf.line1, "AT+CBC", 6) && !strncmp(buf.line2, "+CBC: ", 6)) {
2246 		char key[4];
2247 		snprintf(key, 4, "CBC");
2248 		map_add(&drvinst->cached_capabilities, strdup(key), strdup(buf.line2));
2249 		Parse_ReplyGetBattery(data, state);
2250 	}
2251 	return GN_ERR_NONE;
2252 }
2253 
ReplyGetRFLevel(int messagetype,unsigned char * buffer,int length,gn_data * data,struct gn_statemachine * state)2254 static gn_error ReplyGetRFLevel(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state)
2255 {
2256 	at_line_buffer buf;
2257 	char *pos1, *pos2;
2258 	gn_error error;
2259 
2260 	if ((error = at_error_get(buffer, state)) != GN_ERR_NONE) return error;
2261 
2262 	buf.line1 = buffer + 1;
2263 	buf.length= length;
2264 
2265 	splitlines(&buf);
2266 
2267 	if (data->rf_unit && !strncmp(buf.line1, "AT+CSQ", 6)) { /* FIXME realy needed? */
2268 		*(data->rf_unit) = GN_RF_CSQ;
2269 		pos1 = buf.line2 + 6;
2270 		pos2 = strchr(buf.line2, ',');
2271 		if (pos1 < pos2) {
2272 			*(data->rf_level) = atoi(pos1);
2273 		} else {
2274 			*(data->rf_level) = 1;
2275 		}
2276 	}
2277 	return GN_ERR_NONE;
2278 }
2279 
ReplyIdentify(int messagetype,unsigned char * buffer,int length,gn_data * data,struct gn_statemachine * state)2280 static gn_error ReplyIdentify(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state)
2281 {
2282 	at_line_buffer buf;
2283 	gn_error error;
2284 
2285 	if ((error = at_error_get(buffer, state)) != GN_ERR_NONE)
2286 		return error;
2287 
2288 	buf.line1 = buffer + 1;
2289 	buf.length = length;
2290 	splitlines(&buf);
2291 	if (!strncmp(buf.line1, "AT+CG", 5)) {
2292 		reply_simpletext(buf.line1+2, buf.line2, "+CGSN: ", data->imei, GN_IMEI_MAX_LENGTH);
2293 		if (!data->model[0])
2294 			reply_simpletext(buf.line1+2, buf.line2, "+CGMM: ", data->model, GN_MODEL_MAX_LENGTH);
2295 		reply_simpletext(buf.line1+2, buf.line2, "+CGMI: ", data->manufacturer, GN_MANUFACTURER_MAX_LENGTH);
2296 		reply_simpletext(buf.line1+2, buf.line2, "+CGMR: ", data->revision, GN_REVISION_MAX_LENGTH);
2297 		if (!data->model[0])
2298 			reply_simpletext(buf.line1+2, buf.line4, "+CGMR: ", data->model, GN_MODEL_MAX_LENGTH);
2299 	} else if (!strncmp(buf.line1, "AT+G", 4)) {
2300 		reply_simpletext(buf.line1+2, buf.line2, "+GSN: ", data->imei, GN_IMEI_MAX_LENGTH);
2301 		if (!data->model[0])
2302 			reply_simpletext(buf.line1+2, buf.line2, "+GMM: ", data->model, GN_MODEL_MAX_LENGTH);
2303 		reply_simpletext(buf.line1+2, buf.line2, "+GMI: ", data->manufacturer, GN_MANUFACTURER_MAX_LENGTH);
2304 		reply_simpletext(buf.line1+2, buf.line2, "+GMR: ", data->revision, GN_REVISION_MAX_LENGTH);
2305 	}
2306 	return GN_ERR_NONE;
2307 }
2308 
ReplyCallDivert(int messagetype,unsigned char * buffer,int length,gn_data * data,struct gn_statemachine * state)2309 static gn_error ReplyCallDivert(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state)
2310 {
2311 	/* FIXME: handle query responses */
2312 	return at_error_get(buffer, state);
2313 }
2314 
ReplyGetPrompt(int messagetype,unsigned char * buffer,int length,gn_data * data,struct gn_statemachine * state)2315 static gn_error ReplyGetPrompt(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state)
2316 {
2317 	switch (buffer[0]) {
2318 	case GN_AT_PROMPT: return GN_ERR_NONE;
2319 	case GN_AT_OK: return GN_ERR_INTERNALERROR;
2320 	default: return at_error_get(buffer, state);
2321 	}
2322 }
2323 
ReplyGetSMSFolders(int messagetype,unsigned char * buffer,int length,gn_data * data,struct gn_statemachine * state)2324 static gn_error ReplyGetSMSFolders(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state)
2325 {
2326 	at_line_buffer buf;
2327 	gn_error error;
2328 	char *pos, *memory_name, *line = NULL;
2329 	char **items;
2330 	int i, n;
2331 	gn_memory_type memory_type;
2332 
2333 	if ((error = at_error_get(buffer, state)) != GN_ERR_NONE) return error;
2334 
2335 	buf.line1 = buffer + 1;
2336 	buf.length = length;
2337 	splitlines(&buf);
2338 
2339 	/*
2340 	 * Samsung SHG-L760 answers with (no command echo):
2341 	 * >+CPMS: ("ME","MT","SM","SR"),("ME","MT","SM","SR"),("ME","MT","SM","SR")
2342 	 * >
2343 	 * >OK
2344 	 */
2345 	if (!strncmp("+CPMS:", buf.line1, 6))
2346 		line = buf.line1;
2347 	/*
2348 	 * Nokia 6230i (and most of the phones) answer with (command echo):
2349 	 * >AT+CPMS=?
2350 	 * >+CPMS: ("ME","SM"),("ME","SM"),("MT")
2351 	 * >
2352 	 * >OK
2353 	 */
2354 	if (!strncmp("+CPMS:", buf.line2, 6))
2355 		line = buf.line2;
2356 	if (!line)
2357 		return GN_ERR_INTERNALERROR;
2358 
2359 	/*
2360 	 * Split a string like +CPMS: ("ME","SM"),("ME","SM"),("ME","SM")
2361 	 * can't use strip_brackets() because it will strip the last ')',
2362 	 * not the first.
2363 	 */
2364 	pos = line + 6;
2365 	while (*pos && *pos != ')')
2366 		pos++;
2367 	*pos = '\0';
2368 	pos = buf.line2 + 6;
2369 	while (*pos == ' ' || *pos == '(')
2370 		pos++;
2371 	items = gnokii_strsplit(pos, ",", 4);
2372 	n = 0;
2373 	for (i = 0; items[i]; i++) {
2374 		memory_name = strip_quotes(items[i]);
2375 		if ((memory_type = gn_str2memory_type(memory_name)) != GN_MT_XX) {
2376 			data->sms_folder_list->folder_id[n] = memory_type;
2377 			data->sms_folder_list->folder[n].folder_id = memory_type;
2378 			snprintf(data->sms_folder_list->folder[n].name, sizeof(data->sms_folder_list->folder[0].name), "%s", gn_memory_type_print(memory_type));
2379 			n++;
2380 		} else {
2381 			dprintf("Ignoring unknown memory type \"%s\".\n", memory_name);
2382 		}
2383 	}
2384 	data->sms_folder_list->number = n;
2385 	gnokii_strfreev(items);
2386 
2387 	return GN_ERR_NONE;
2388 }
2389 
ReplyGetSMSStatus(int messagetype,unsigned char * buffer,int length,gn_data * data,struct gn_statemachine * state)2390 static gn_error ReplyGetSMSStatus(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state)
2391 {
2392 	at_line_buffer buf;
2393 	gn_error error;
2394 
2395 	if ((error = at_error_get(buffer, state)) != GN_ERR_NONE) return error;
2396 
2397 	buf.line1 = buffer + 1;
2398 	buf.length = length;
2399 	splitlines(&buf);
2400 
2401 	if (sscanf(buf.line2, "+CPMS: \"%*[^\"]\",%d,%*d", &data->sms_status->number) != 1)
2402 		return GN_ERR_FAILED;
2403 
2404 	data->sms_status->unread = 0;
2405 	data->sms_status->changed = 0;
2406 	data->sms_status->folders_count = 0;
2407 
2408 	return GN_ERR_NONE;
2409 }
2410 
ReplySendSMS(int messagetype,unsigned char * buffer,int length,gn_data * data,struct gn_statemachine * state)2411 static gn_error ReplySendSMS(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state)
2412 {
2413 	at_line_buffer buf;
2414 	gn_error error;
2415 
2416 	if ((error = at_error_get(buffer, state)) != GN_ERR_NONE) return error;
2417 
2418 	buf.line1 = buffer + 1;
2419 	buf.length = length;
2420 	splitlines(&buf);
2421 
2422 	if (!strncmp("+CMGW:", buf.line2, 6)) {
2423 		/* SaveSMS */
2424 		data->raw_sms->number = atoi(buf.line2 + 6);
2425 		dprintf("Message saved (location: %d)\n", data->raw_sms->number);
2426 	} else if (!strncmp("+CMGS:", buf.line2, 6)) {
2427 		/* SendSMS */
2428 		data->raw_sms->reference = atoi(buf.line2 + 6);
2429 		dprintf("Message sent (reference: %d)\n", data->raw_sms->reference);
2430 	} else {
2431 		data->raw_sms->reference = -1;
2432 	}
2433 	return GN_ERR_NONE;
2434 }
2435 
ReplyGetSMS(int messagetype,unsigned char * buffer,int length,gn_data * data,struct gn_statemachine * state)2436 static gn_error ReplyGetSMS(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state)
2437 {
2438 	at_line_buffer buf;
2439 	gn_error ret = GN_ERR_NONE;
2440 	unsigned int sms_len, pdu_flags;
2441 	unsigned char *tmp;
2442 	gn_error error;
2443  	at_driver_instance *drvinst = AT_DRVINST(state);
2444 
2445 	if ((error = at_error_get(buffer, state)) != GN_ERR_NONE)
2446 		return error;
2447 
2448 	buf.line1 = buffer + 1;
2449 	buf.length = length;
2450 
2451 	splitlines(&buf);
2452 
2453 	if (!data->raw_sms)
2454 		return GN_ERR_INTERNALERROR;
2455 
2456 	/* Try to figure out the status first */
2457 	tmp = strchr(buf.line2, ',');
2458 	if (tmp != NULL && ((char *) tmp - buf.line2 - strlen("+CMGR: ")) >= 1) {
2459 		char *status;
2460 		int len;
2461 
2462 		len = (char *) tmp - buf.line2 - strlen("+CMGR: ");
2463 		status = malloc(len + 1);
2464 		if (!status) {
2465 			dprintf("Not enough memory for buffer.\n");
2466 			return GN_ERR_INTERNALERROR;
2467 		}
2468 
2469 		memcpy(status, buf.line2 + strlen("+CMGR: "), len);
2470 		status[len] = '\0';
2471 
2472 		if (strstr(status, "UNREAD")) {
2473 			data->raw_sms->status = GN_SMS_Unread;
2474 		} else if (strstr(status, "READ")) {
2475 			data->raw_sms->status = GN_SMS_Read;
2476 		} else if (strstr(status, "UNSENT")) {
2477 			data->raw_sms->status = GN_SMS_Unsent;
2478 		} else if (strstr(status, "SENT")) {
2479 			data->raw_sms->status = GN_SMS_Sent;
2480 		} else {
2481 			int s;
2482 
2483 			s = atoi(status);
2484 			switch (s) {
2485 			case 0:
2486 				data->raw_sms->status = GN_SMS_Unread;
2487 				break;
2488 			case 1:
2489 				data->raw_sms->status = GN_SMS_Read;
2490 				break;
2491 			case 2:
2492 				data->raw_sms->status = GN_SMS_Unsent;
2493 				break;
2494 			case 3:
2495 				data->raw_sms->status = GN_SMS_Sent;
2496 				break;
2497 			}
2498 		}
2499 		free(status);
2500 	}
2501 
2502 	tmp = strrchr(buf.line2, ',');
2503 	/* The following sequence is correct for emtpy location:
2504 	 * w: AT+CMGR=9
2505 	 * r: AT+CMGR=9
2506 	 *  :
2507 	 *  : OK
2508 	 */
2509 	if (!tmp)
2510 		return GN_ERR_EMPTYLOCATION;
2511 	sms_len = atoi(tmp+1);
2512 	if (sms_len == 0)
2513 		return GN_ERR_EMPTYLOCATION;
2514 
2515 	sms_len = strlen(buf.line3) / 2;
2516 	tmp = calloc(sms_len, 1);
2517 	if (!tmp) {
2518 		dprintf("Not enough memory for buffer.\n");
2519 		return GN_ERR_INTERNALERROR;
2520 	}
2521 	dprintf("%s\n", buf.line3);
2522 	hex2bin(tmp, buf.line3, sms_len);
2523 
2524 	if (drvinst->no_smsc) {
2525 		pdu_flags = GN_SMS_PDU_NOSMSC;
2526 	} else {
2527 		pdu_flags = GN_SMS_PDU_DEFAULT;
2528 	}
2529 	ret = gn_sms_pdu2raw(data->raw_sms, tmp, sms_len, pdu_flags);
2530 
2531 	free(tmp);
2532 	return ret;
2533 }
2534 
2535 /* ReplyGetCharset
2536  *
2537  * parses the reponse from a check for the actual charset or the
2538  * available charsets. a bracket in the response is taken as a request
2539  * for available charsets.
2540  */
ReplyGetCharset(int messagetype,unsigned char * buffer,int length,gn_data * data,struct gn_statemachine * state)2541 static gn_error ReplyGetCharset(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state)
2542 {
2543 	at_driver_instance *drvinst = AT_DRVINST(state);
2544 	at_line_buffer buf;
2545 	int i;
2546 	gn_error error;
2547 
2548 	if ((error = at_error_get(buffer, state)) != GN_ERR_NONE) return error;
2549 
2550 	buf.line1 = buffer + 1;
2551 	buf.length= length;
2552 	splitlines(&buf);
2553 
2554 	if (!strncmp(buf.line1, "AT+CSCS?", 8)) {
2555 		/* return current charset */
2556 		drvinst->charset = AT_CHAR_UNKNOWN;
2557 		i = 0;
2558 		while (atcharsets[i].str && drvinst->charset == AT_CHAR_UNKNOWN) {
2559 			if (strstr(buf.line2, atcharsets[i].str))
2560 				drvinst->charset = atcharsets[i].charset;
2561 			i++;
2562 		}
2563 		return GN_ERR_NONE;
2564 	} else if (!strncmp(buf.line1, "AT+CSCS=", 8)) {
2565 		/* return available charsets */
2566 		drvinst->availcharsets = 0;
2567 		i = 0;
2568 		while (atcharsets[i].str) {
2569 			if (strstr(buf.line2, atcharsets[i].str))
2570 				drvinst->availcharsets |= atcharsets[i].charset;
2571 			i++;
2572 		}
2573 		return GN_ERR_NONE;
2574 	}
2575 	return GN_ERR_FAILED;
2576 }
2577 
2578 #ifdef SECURITY
ReplyGetSecurityCodeStatus(int messagetype,unsigned char * buffer,int length,gn_data * data,struct gn_statemachine * state)2579 static gn_error ReplyGetSecurityCodeStatus(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state)
2580 {
2581 	at_line_buffer buf;
2582 	char *pos;
2583 	gn_error error;
2584 
2585 	if ((error = at_error_get(buffer, state)) != GN_ERR_NONE) return error;
2586 
2587 	buf.line1 = buffer + 1;
2588 	buf.length= length;
2589 	splitlines(&buf);
2590 
2591 	if (data->security_code && !strncmp(buf.line1, "AT+CPIN", 7)) {
2592 		if (strncmp(buf.line2, "+CPIN: ", 7)) {
2593 			data->security_code->type = 0;
2594 			return GN_ERR_INTERNALERROR;
2595 		}
2596 
2597 		pos = 7 + buf.line2;
2598 
2599 		if (!strncmp(pos, "READY", 5)) {
2600 			data->security_code->type = GN_SCT_None;
2601 			return GN_ERR_NONE;
2602 		}
2603 
2604 		if (!strncmp(pos, "SIM ", 4)) {
2605 			pos += 4;
2606 			if (!strncmp(pos, "PIN2", 4)) {
2607 				data->security_code->type = GN_SCT_Pin2;
2608 			}
2609 			if (!strncmp(pos, "PUK2", 4)) {
2610 				data->security_code->type = GN_SCT_Puk2;
2611 			}
2612 			if (!strncmp(pos, "PIN", 3)) {
2613 				data->security_code->type = GN_SCT_Pin;
2614 			}
2615 			if (!strncmp(pos, "PUK", 3)) {
2616 				data->security_code->type = GN_SCT_Puk;
2617 			}
2618 		}
2619 	}
2620 	return GN_ERR_NONE;
2621 }
2622 #endif
2623 
ReplyRing(int messagetype,unsigned char * buffer,int length,gn_data * data,struct gn_statemachine * state)2624 static gn_error ReplyRing(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state)
2625 {
2626 	at_driver_instance *drvinst = AT_DRVINST(state);
2627 	at_line_buffer buf;
2628 	char *pos;
2629 	gn_call_info cinfo;
2630 	gn_call_status status;
2631 
2632 	if (!drvinst->call_notification) return GN_ERR_UNSOLICITED;
2633 
2634 	buf.line1 = buffer;
2635 	buf.length= length;
2636 	splitlines(&buf);
2637 
2638 	memset(&cinfo, 0, sizeof(cinfo));
2639 	cinfo.call_id = 1;
2640 
2641 	if (!strncmp(buf.line1, "RING", 4)) {
2642 		return GN_ERR_INTERNALERROR; /* AT+CRC=1 disables RING */
2643 	} else if (!strncmp(buf.line1, "+CRING: ", 8)) {
2644 		pos = buf.line1 + 8;
2645 		if (!strncmp(pos, "VOICE", 5))
2646 			cinfo.type = GN_CALL_Voice;
2647 		else if (*pos < ' ') /* some phones reply with "+CRING: <cr><lf>" only */
2648 			cinfo.type = GN_CALL_Voice;
2649 		else
2650 			return GN_ERR_UNHANDLEDFRAME;
2651 		status = GN_CALL_Incoming;
2652 	} else if (!strncmp(buf.line1, "CONNECT", 7)) {
2653 		status = GN_CALL_Established;
2654 	} else if (!strncmp(buf.line1, "BUSY", 4)) {
2655 		status = GN_CALL_RemoteHangup;
2656 	} else if (!strncmp(buf.line1, "NO ANSWER", 9)) {
2657 		status = GN_CALL_RemoteHangup;
2658 	} else if (!strncmp(buf.line1, "NO CARRIER", 10)) {
2659 		status = GN_CALL_RemoteHangup;
2660 	} else if (!strncmp(buf.line1, "NO DIALTONE", 11)) {
2661 		status = GN_CALL_LocalHangup;
2662 	} else if (!strncmp(buf.line1, "+CLIP: ", 7)) {
2663 		char **items;
2664 		int i;
2665 
2666 		items = gnokii_strsplit(buf.line1 + 7, ",", 6);
2667 		for (i = 0; i < 6; i++) {
2668 			if (items[i] == NULL)
2669 				break;
2670 			switch (i) {
2671 			/* Number, if known */
2672 			case 0:
2673 				snprintf(cinfo.number, GN_PHONEBOOK_NUMBER_MAX_LENGTH, "%s", strip_quotes(items[i]));
2674 				break;
2675 			/* 1 == Number "type"
2676 			 * 2 == String type subaddress
2677 			 * 3 == Type of subaddress
2678 			 * All ignored
2679 			 */
2680 			case 1:
2681 			case 2:
2682 			case 3:
2683 				break;
2684 			/* Name, if known */
2685 			case 4:
2686 				snprintf(cinfo.name, GN_PHONEBOOK_NAME_MAX_LENGTH, "%s", strip_quotes(items[i]));
2687 				break;
2688 			/* Validity of the name/number provided */
2689 			case 5:
2690 				switch (atoi(items[i])) {
2691 				case 1:
2692 					snprintf(cinfo.name, GN_PHONEBOOK_NAME_MAX_LENGTH, _("Withheld"));
2693 					break;
2694 				case 2:
2695 					snprintf(cinfo.name, GN_PHONEBOOK_NAME_MAX_LENGTH, _("Unknown"));
2696 					break;
2697 				}
2698 			}
2699 		}
2700 
2701 		if (cinfo.name == NULL)
2702 			snprintf(cinfo.name, GN_PHONEBOOK_NAME_MAX_LENGTH, _("Unknown"));
2703 		cinfo.type = drvinst->last_call_type;
2704 		drvinst->call_notification(drvinst->last_call_status, &cinfo, state, drvinst->call_callback_data);
2705 		gnokii_strfreev(items);
2706 		return GN_ERR_UNSOLICITED;
2707 	} else if (!strncmp(buf.line1, "+CLCC: ", 7)) {
2708 		char **items;
2709 		int i;
2710 
2711 		items = gnokii_strsplit(buf.line1 + 7, ",", 8);
2712 		status = -1;
2713 
2714 		for (i = 0; i < 8; i++) {
2715 			if (items[i] == NULL)
2716 				break;
2717 			switch (i) {
2718 			/* Call ID */
2719 			case 0:
2720 				cinfo.call_id = atoi(items[i]);
2721 				break;
2722 			/* Incoming, or finishing call */
2723 			case 1:
2724 				break;
2725 			case 2:
2726 				switch (atoi(items[i])) {
2727 				case 0:
2728 					status = GN_CALL_Established;
2729 					break;
2730 				case 1:
2731 					status = GN_CALL_Held;
2732 					break;
2733 				case 2:
2734 					status = GN_CALL_Dialing;
2735 					break;
2736 				case 3:
2737 					/* Alerting, remote end is ringing */
2738 					status = GN_CALL_Ringing;
2739 					break;
2740 				case 4:
2741 					status = GN_CALL_Incoming;
2742 					break;
2743 				case 5:
2744 					/* FIXME Call is "Waiting" */
2745 					status = GN_CALL_Held;
2746 					break;
2747 				case 6:
2748 					status = GN_CALL_LocalHangup;
2749 					break;
2750 				}
2751 				break;
2752 			case 3:
2753 				if (atoi(items[i]) == 0)
2754 					cinfo.type = GN_CALL_Voice;
2755 				else {
2756 					/* We don't handle non-voice calls */
2757 					gnokii_strfreev(items);
2758 					return GN_ERR_UNHANDLEDFRAME;
2759 				}
2760 				break;
2761 			/* Multiparty status */
2762 			case 4:
2763 				break;
2764 			case 5:
2765 				snprintf(cinfo.number, GN_PHONEBOOK_NUMBER_MAX_LENGTH, "%s", strip_quotes (items[i]));
2766 				break;
2767 			/* Phone display format */
2768 			case 6:
2769 				break;
2770 			case 7:
2771 				snprintf(cinfo.name, GN_PHONEBOOK_NAME_MAX_LENGTH, "%s", strip_quotes (items[i]));
2772 				break;
2773 			}
2774 		}
2775 
2776 		/* FIXME we don't handle calls > 1 anywhere else */
2777 		if (status < 0) {
2778 			gnokii_strfreev(items);
2779 			return GN_ERR_UNHANDLEDFRAME;
2780 		}
2781 
2782 		drvinst->call_notification(status, &cinfo, state, drvinst->call_callback_data);
2783 		gnokii_strfreev(items);
2784 		return GN_ERR_UNSOLICITED;
2785 	} else {
2786 		return GN_ERR_UNHANDLEDFRAME;
2787 	}
2788 
2789 	if (!drvinst->clip_supported || status != GN_CALL_Incoming) {
2790 		drvinst->call_notification(status, &cinfo, state, drvinst->call_callback_data);
2791 	} else {
2792 		drvinst->last_call_status = status;
2793 		drvinst->last_call_type = cinfo.type;
2794 	}
2795 
2796 	return GN_ERR_UNSOLICITED;
2797 }
2798 
ReplyIncomingSMS(int messagetype,unsigned char * buffer,int length,gn_data * data,struct gn_statemachine * state)2799 static gn_error ReplyIncomingSMS(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state)
2800 {
2801 	at_driver_instance *drvinst = AT_DRVINST(state);
2802 	at_line_buffer buf;
2803 	char *memory, *pos;
2804 	int index;
2805 	gn_memory_type mem;
2806 	int freesms = 0;
2807 	gn_error error = GN_ERR_NONE;
2808 
2809 	if (!drvinst->on_sms)
2810 		return GN_ERR_UNSOLICITED;
2811 
2812 	buf.line1 = buffer;
2813 	buf.length= length;
2814 	splitlines(&buf);
2815 
2816 	mem = GN_MT_XX;
2817 
2818 	if (strncmp(buf.line1, "+CMTI: ", 7))
2819 		return GN_ERR_UNSOLICITED;
2820 
2821 	pos = strrchr(buf.line1, ',');
2822 	if (pos == NULL)
2823 		return GN_ERR_UNSOLICITED;
2824 	pos[0] = '\0';
2825 	pos++;
2826 	index = atoi(pos);
2827 
2828 	memory = strip_quotes(buf.line1 + 7);
2829 	if (memory == NULL)
2830 		return GN_ERR_UNSOLICITED;
2831 	mem = gn_str2memory_type(memory);
2832 	if (mem == GN_MT_XX)
2833 		return GN_ERR_UNSOLICITED;
2834 
2835 	dprintf("Received message folder %s index %d\n", gn_memory_type2str(mem), index);
2836 
2837 	if (!data->sms) {
2838 		freesms = 1;
2839 		data->sms = calloc(1, sizeof(gn_sms));
2840 		if (!data->sms)
2841 			return GN_ERR_INTERNALERROR;
2842 	}
2843 
2844 	memset(data->sms, 0, sizeof(gn_sms));
2845 	data->sms->memory_type = mem;
2846 	data->sms->number = index;
2847 
2848 	dprintf("get sms %d\n", index);
2849 	error = gn_sms_get(data, state);
2850 	if (error == GN_ERR_NONE) {
2851 		error = GN_ERR_UNSOLICITED;
2852 		drvinst->on_sms(data->sms, state, drvinst->sms_callback_data);
2853 	}
2854 
2855 	if (freesms) {
2856 		free(data->sms);
2857 		data->sms = NULL;
2858 	}
2859 
2860 	return error;
2861 }
2862 
creg_parse(char ** strings,int i,gn_network_info * ninfo,int lac_swapped)2863 static gn_error creg_parse(char **strings, int i, gn_network_info *ninfo, int lac_swapped)
2864 {
2865 	char tmp[3] = {0, 0, 0};
2866 	char *pos;
2867 	int first = 0, second = 1;
2868 	size_t n, len;
2869 
2870 	if (!strings[i] || strlen(strings[i]) < 4 || !strings[i + 1] || strlen(strings[i + 1]) < 4)
2871 		return GN_ERR_FAILED;
2872 
2873 	pos = strip_quotes(strings[i]);
2874 
2875 	/*
2876 	 * Some phones have reverse order of the bytes in LAC.
2877 	 */
2878 	if (lac_swapped) {
2879 		first = 1;
2880 		second = 0;
2881 	}
2882 
2883 	tmp[0] = pos[0];
2884 	tmp[1] = pos[1];
2885 	ninfo->LAC[first] = strtol(tmp, NULL, 16);
2886 
2887 	tmp[0] = pos[2];
2888 	tmp[1] = pos[3];
2889 	ninfo->LAC[second] = strtol(tmp, NULL, 16);
2890 
2891 	/*
2892 	 * GSM phones usually return 4 hex digits, UMTS phones can return up to 8 with optional leading 0's
2893 	 */
2894 
2895 	pos = strip_quotes(strings[i + 1]);
2896 
2897 	n = 0;
2898 	len = strlen(pos);
2899 	if (len & 1) {
2900 		tmp[0] = *pos++;
2901 		tmp[1] = '\0';
2902 		ninfo->cell_id[n++] = strtol(tmp, NULL, 16);
2903 		len--;
2904 	}
2905 	while (len) {
2906 		tmp[0] = *pos++;
2907 		tmp[1] = *pos++;
2908 		ninfo->cell_id[n++] = strtol(tmp, NULL, 16);
2909 		len -= 2;
2910 	}
2911 
2912 	return GN_ERR_NONE;
2913 }
2914 
ReplyGetNetworkInfo(int messagetype,unsigned char * buffer,int length,gn_data * data,struct gn_statemachine * state)2915 static gn_error ReplyGetNetworkInfo(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state)
2916 {
2917 	at_driver_instance *drvinst = AT_DRVINST(state);
2918 	at_line_buffer buf;
2919 	char *pos;
2920 	char **strings;
2921 	gn_error error = GN_ERR_NONE;
2922 	int i;
2923 
2924 	buf.line1 = buffer + 1;
2925 	buf.length= length;
2926 
2927 	splitlines(&buf);
2928 
2929 	if (!strncmp(buf.line1, "AT+CREG=?", 9)) {
2930 		if ((error = at_error_get(buffer, state)) != GN_ERR_NONE)
2931 			return error;
2932 
2933 		/*
2934 		 * Answer to AT+CREG=? can be one of:
2935 		 * +CREG: (0-1)
2936 		 * +CREG: (0,1)
2937 		 * +CREG: (0-2)
2938 		 * +CREG: (0,1,2)
2939 		 * The interesting thing here is whether the phone supports extended mode (2)
2940 		 */
2941 		if (strstr(buf.line2, "2"))
2942 			drvinst->extended_reg_status = 2;
2943 		else
2944 			drvinst->extended_reg_status = 1;
2945 	} else if (!strncmp(buf.line1, "AT+CREG?", 8)) {
2946 
2947 		if (!data->network_info)
2948 			return GN_ERR_INTERNALERROR;
2949 
2950 		if ((error = at_error_get(buffer, state)) != GN_ERR_NONE)
2951 			return error;
2952 
2953 		strings = gnokii_strsplit(buf.line2, ",", 4);
2954 		i = strings[3] ? 2 : 1;
2955 
2956 		/*
2957 		 * Reply to AT+CREG? may have one of the forms:
2958 		 * when we are in basic status presentation mode (MODE=1)
2959 		 *   +CREG: <MODE>,<STATUS>
2960 		 * when we are in extended status presentation mode (MODE=2)
2961 		 *   +CREG: <MODE>,<STATUS>,<LAC>,<CELLID>
2962 		 * However if we are in MODE=2 and SIM card is inactive we'll
2963 		 * get (or we might get) the answer as with MODE=1.
2964 		 * FIXME: parse and return <STATUS> parameter
2965 		 *   0 - not registered, does not search for the network
2966 		 *   1 - registered in the home network
2967 		 *   2 - not registered, searching for the network
2968 		 *   3 - registration forbidden
2969 		 *   4 - status unknown
2970 		 *   5 - registered in roaming
2971 		 */
2972 		error = creg_parse(strings, i, data->network_info, drvinst->lac_swapped);
2973 
2974 		gnokii_strfreev(strings);
2975 
2976 		if (error != GN_ERR_NONE)
2977 			return error;
2978 	} else if (!strncmp(buf.line1, "CREG:", 5)) {
2979 		gn_network_info info;
2980 		strings = gnokii_strsplit(buf.line1, ",", 3);
2981 		i = strings[2] ? 1 : 0;
2982 
2983 		/*
2984 		 * Reply to AT+CREG? is of the form:
2985 		 *   +CREG: <STATUS>,<LAC>,<CELLID>
2986 		 * FIXME: parse and return <STATUS> parameter
2987 		 *   0 - not registered, does not search for the network
2988 		 *   1 - registered in the home network
2989 		 *   2 - not registered, searching for the network
2990 		 *   3 - registration forbidden
2991 		 *   4 - status unknown
2992 		 *   5 - registered in roaming
2993 		 */
2994 		error = creg_parse(strings, i, &info, drvinst->lac_swapped);
2995 		*(info.network_code) = '\0';
2996 
2997 		gnokii_strfreev(strings);
2998 
2999 		if (error != GN_ERR_NONE)
3000 			return error;
3001 
3002 		if (drvinst->reg_notification)
3003 			drvinst->reg_notification(&info, drvinst->reg_callback_data);
3004 	} else if (!strncmp(buf.line1, "AT+COPS?", 8)) {
3005 		char tmp[128];
3006 		int format;
3007 
3008 		if (!data->network_info)
3009 			return GN_ERR_INTERNALERROR;
3010 
3011 		if ((error = at_error_get(buffer, state)) != GN_ERR_NONE)
3012 			return error;
3013 
3014 		memset(tmp, 0, sizeof(tmp));
3015 		strings = gnokii_strsplit(buf.line2, ",", 3);
3016 		/* phone may respond with only the first value as in "+COPS: 0" */
3017 		if (strings[1]) {
3018 			format = atoi(strings[1]);
3019 		} else {
3020 			format = -1;
3021 		}
3022 		dprintf("Format given: %d\n", format);
3023 		switch (format) {
3024 		case -1: /* neither operator name nor code given (eg. no SIM or not registered) */
3025 			error = GN_ERR_NOTAVAILABLE;
3026 			data->network_info->network_code[0] = 0;
3027 			break;
3028 		case 0: /* network operator name given */
3029 			pos = strip_quotes(strings[2]);
3030 			at_decode(drvinst->charset, tmp, pos, strlen(pos), drvinst->ucs2_as_utf8);
3031 			snprintf(data->network_info->network_code, sizeof(data->network_info->network_code), "%s", gn_network_code_get(tmp));
3032 			break;
3033 		case 2: /* network operator code given */
3034 			/*
3035 			 * Siemens S55 follows own standards. With inactive SIM it returns:
3036 			 * AT+COPS?
3037 			 *  +COPS: 0,2
3038 			 *  OK
3039 			 * In contrary Nokia e50 gives:
3040 			 * AT+COPS?
3041 			 *  +COPS: 0
3042 			 *  OK
3043 			 */
3044 			if (!strings[2]) {
3045 				error = GN_ERR_NOTAVAILABLE;
3046 				data->network_info->network_code[0] = 0;
3047 			} else if (strlen(strings[2]) == 5) {
3048 				data->network_info->network_code[0] = strings[2][0];
3049 				data->network_info->network_code[1] = strings[2][1];
3050 				data->network_info->network_code[2] = strings[2][2];
3051 				data->network_info->network_code[3] = ' ';
3052 				data->network_info->network_code[4] = strings[2][3];
3053 				data->network_info->network_code[5] = strings[2][4];
3054 				data->network_info->network_code[6] = 0;
3055 			} else if (strlen(strings[2]) >= 6) {
3056 				data->network_info->network_code[0] = strings[2][1];
3057 				data->network_info->network_code[1] = strings[2][2];
3058 				data->network_info->network_code[2] = strings[2][3];
3059 				data->network_info->network_code[3] = ' ';
3060 				data->network_info->network_code[4] = strings[2][4];
3061 				data->network_info->network_code[5] = strings[2][5];
3062 				data->network_info->network_code[6] = 0;
3063 			} else { /* probably incorrect */
3064 				snprintf(data->network_info->network_code, sizeof(data->network_info->network_code), "%s", strings[2]);
3065 			}
3066 			break;
3067 		default: /* defined formats are in range (0-2) */
3068 			error = GN_ERR_UNHANDLEDFRAME;
3069 			data->network_info->network_code[0] = 0;
3070 			break;
3071 		}
3072 		gnokii_strfreev(strings);
3073 	}
3074 
3075 	return error;
3076 }
3077 
ReplyGetDateTime(int messagetype,unsigned char * buffer,int length,gn_data * data,struct gn_statemachine * state)3078 static gn_error ReplyGetDateTime(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state)
3079 {
3080 	at_driver_instance *drvinst = AT_DRVINST(state);
3081 	int cnt;
3082 	at_line_buffer buf;
3083 	gn_error error;
3084 	gn_timestamp *dt;
3085 	char timezone[6];
3086 
3087 	if ((error = at_error_get(buffer, state)) != GN_ERR_NONE)
3088 		return error;
3089 
3090 	buf.line1 = buffer + 1;
3091 	buf.length= length;
3092 
3093 	splitlines(&buf);
3094 
3095 	dt = data->datetime;
3096 	memset(timezone, 0, 6);
3097 	/* Use strip_quotes() since some phones do not use quotes. Add 7 to skip "+CCLK: " */
3098 	cnt = sscanf(strip_quotes(buf.line2 + 7), "%d/%d/%d,%d:%d:%d%[+-1234567890]",
3099 		     &dt->year, &dt->month, &dt->day,
3100 		     &dt->hour, &dt->minute, &dt->second, timezone);
3101 	switch (cnt) {
3102 	case 7:
3103 		drvinst->timezone = realloc(drvinst->timezone, strlen(timezone) + 1);
3104 		strcpy(drvinst->timezone, timezone);
3105 		break;
3106 	case 6:
3107 		break;
3108 	default:
3109 		return GN_ERR_FAILED;
3110 	}
3111 
3112 	if (dt->year < 100)
3113 		dt->year += 2000;
3114 
3115 	return GN_ERR_NONE;
3116 }
3117 
ReplyGetActiveCalls(int messagetype,unsigned char * buffer,int length,gn_data * data,struct gn_statemachine * state)3118 static gn_error ReplyGetActiveCalls(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state)
3119 {
3120 	at_driver_instance *drvinst;
3121 	gn_error error;
3122 	at_line_buffer buf;
3123 	int status;
3124 
3125 	if (!data->call_active)
3126 		return GN_ERR_INTERNALERROR;
3127 
3128 	if ((error = at_error_get(buffer, state)) != GN_ERR_NONE)
3129 		return error;
3130 
3131 	status = -1;
3132 
3133 	buf.line1 = buffer + 1;
3134 	buf.length = length;
3135 	splitlines(&buf);
3136 
3137 	memset(data->call_active, 0, GN_CALL_MAX_PARALLEL * sizeof(gn_call_active));
3138 
3139 	if (strncmp(buf.line1, "AT+CPAS", 7)) {
3140 		return GN_ERR_UNKNOWN;
3141 	}
3142 
3143 	data->call_active->call_id = 1;
3144 
3145 	switch (atoi(buf.line2 + strlen("+CPAS: "))) {
3146 	case 0:
3147 		status = GN_CALL_Idle;
3148 		break;
3149 	/* Terminal doesn't know */
3150 	case 1:
3151 	case 2:
3152 		break;
3153 	case 3:
3154 		status = GN_CALL_Ringing;
3155 		break;
3156 	case 4:
3157 		status = GN_CALL_Established;
3158 		break;
3159 	/* Low-power state, terminal can't answer */
3160 	case 5:
3161 		break;
3162 	}
3163 
3164 	if (status < 0)
3165 		return GN_ERR_UNKNOWN;
3166 
3167 	drvinst = AT_DRVINST(state);
3168 
3169 	data->call_active->state = status;
3170 	data->call_active->prev_state = drvinst->prev_state;
3171 
3172 	/* States go:
3173 	 * Idle -> Ringing -> (faked Local hangup) -> Idle
3174 	 * Idle -> Ringing -> Established -> (faked Remote hangup) -> Idle */
3175 	if (drvinst->prev_state == GN_CALL_Ringing && status == GN_CALL_Idle)
3176 		data->call_active->state = GN_CALL_LocalHangup;
3177 	else if (drvinst->prev_state == GN_CALL_Established && status == GN_CALL_Idle)
3178 		data->call_active->state = GN_CALL_RemoteHangup;
3179 	else
3180 		data->call_active->state = status;
3181 
3182 	drvinst->prev_state = data->call_active->state;
3183 	snprintf(data->call_active->name, GN_PHONEBOOK_NAME_MAX_LENGTH, _("Unknown"));
3184 	data->call_active->number[0] = '\0';
3185 
3186 	return GN_ERR_NONE;
3187 }
3188 
ReplyGetSMSMemorySize(int messagetype,unsigned char * buffer,int length,gn_data * data,struct gn_statemachine * state)3189 static gn_error ReplyGetSMSMemorySize(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state)
3190 {
3191 	at_driver_instance *drvinst = AT_DRVINST(state);
3192 	at_line_buffer buf;
3193 	gn_error error;
3194 
3195 	if ((error = at_error_get(buffer, state)) != GN_ERR_NONE)
3196 		return error;
3197 
3198 	buf.line1 = buffer + 1;
3199 	buf.length = length;
3200 	splitlines(&buf);
3201 
3202 	if (sscanf(buf.line2, "+CPMS: %*d,%d,%*d,%d", &drvinst->mememorysize, &drvinst->smmemorysize) != 2)
3203 		return GN_ERR_FAILED;
3204 	drvinst->smsmemorytype = GN_MT_ME;
3205 
3206 	return GN_ERR_NONE;
3207 }
3208 
3209 /* General reply function for phone responses. buffer[0] holds the compiled
3210  * success of the result (OK, ERROR, ... ). see links/atbus.h and links/atbus.c
3211  * for reference */
Reply(int messagetype,unsigned char * buffer,int length,gn_data * data,struct gn_statemachine * state)3212 static gn_error Reply(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state)
3213 {
3214 	return at_error_get(buffer, state);
3215 }
3216 
3217 #define at_manufacturer_compare(pattern)	strncasecmp(manufacturer, pattern, strlen(pattern))
3218 
Initialise(gn_data * setupdata,struct gn_statemachine * state)3219 static gn_error Initialise(gn_data *setupdata, struct gn_statemachine *state)
3220 {
3221 	at_driver_instance *drvinst;
3222 	gn_data data;
3223 	gn_error ret = GN_ERR_NONE;
3224 	char model[GN_MODEL_MAX_LENGTH];
3225 	char manufacturer[GN_MANUFACTURER_MAX_LENGTH];
3226 	int i;
3227 
3228 	dprintf("Initializing AT capable mobile phone ...\n");
3229 
3230 	/* initialize variables */
3231 	memset(model, 0, GN_MODEL_MAX_LENGTH);
3232 	memset(manufacturer, 0, GN_MANUFACTURER_MAX_LENGTH);
3233 
3234 	/* Copy in the phone info */
3235 	memcpy(&(state->driver), &driver_at, sizeof(gn_driver));
3236 
3237 	if (!(drvinst = malloc(sizeof(at_driver_instance))))
3238 		return GN_ERR_MEMORYFULL;
3239 
3240 	state->driver.incoming_functions = drvinst->incoming_functions;
3241 	AT_DRVINST(state) = drvinst;
3242 	drvinst->manufacturer_error = NULL;
3243 	drvinst->memorytype = GN_MT_XX;
3244 	drvinst->memoryoffset = 0;
3245 	drvinst->memorysize = 100;
3246 	drvinst->smsmemorytype = GN_MT_XX;
3247 	drvinst->defaultcharset = AT_CHAR_UNKNOWN;
3248 	drvinst->charset = AT_CHAR_UNKNOWN;
3249 	drvinst->no_smsc = 0;
3250 	drvinst->call_notification = NULL;
3251 	drvinst->call_callback_data = NULL;
3252 	drvinst->on_cell_broadcast = NULL;
3253 	drvinst->cb_callback_data = NULL;
3254 	drvinst->on_sms = NULL;
3255 	drvinst->sms_callback_data = NULL;
3256 	drvinst->reg_notification = NULL;
3257 	drvinst->reg_callback_data = NULL;
3258 	drvinst->clip_supported = 0;
3259 	drvinst->last_call_type = GN_CALL_Voice;
3260 	drvinst->last_call_status = GN_CALL_Idle;
3261 	drvinst->prev_state = GN_CALL_Idle;
3262 	drvinst->mememorysize = -1;
3263 	drvinst->smmemorysize = -1;
3264 	drvinst->timezone = NULL;
3265 	/* FIXME: detect if from AT+CNMI=? */
3266 	drvinst->cnmi_mode = 3;
3267 	drvinst->cached_capabilities = NULL;
3268 	drvinst->pdumode = 0;
3269 	drvinst->extended_reg_status = 0;
3270 	drvinst->availcharsets = 0;
3271 	drvinst->encode_memory_type = 0;
3272 	drvinst->encode_number = 0;
3273 	drvinst->lac_swapped = 0;
3274 	drvinst->extended_phonebook = 0;
3275 	drvinst->ucs2_as_utf8 = 0;
3276 
3277 	drvinst->if_pos = 0;
3278 	for (i = 0; i < GN_OP_AT_Max; i++) {
3279 		drvinst->functions[i] = NULL;
3280 		drvinst->incoming_functions[i].message_type = 0;
3281 		drvinst->incoming_functions[i].functions = NULL;
3282 	}
3283 	for (i = 0; i < ARRAY_LEN(at_function_init); i++) {
3284 		at_insert_send_function(at_function_init[i].gop, at_function_init[i].sfunc, state);
3285 		at_insert_recv_function(at_function_init[i].gop, at_function_init[i].rfunc, state);
3286 	}
3287 
3288 	switch (state->config.connection_type) {
3289 	case GN_CT_Serial:
3290 	case GN_CT_Bluetooth:
3291 	case GN_CT_Irda:
3292 	case GN_CT_TCP:
3293 		if (!strcmp(setupdata->model, "AT-HW"))
3294 			ret = atbus_initialise(true, state);
3295 		else
3296 			ret = atbus_initialise(false, state);
3297 		break;
3298 	default:
3299 		ret = GN_ERR_NOTSUPPORTED;
3300 		break;
3301 	}
3302 	if (ret)
3303 		goto out;
3304 
3305 	sm_initialise(state);
3306 
3307 	SoftReset(&data, state);
3308 	SetEcho(&data, state);
3309 	SetExtendedError(&data, state);
3310 
3311 	/*
3312 	 * detect manufacturer and model for further initialization
3313 	 */
3314 	gn_data_clear(&data);
3315 	data.model = model;
3316 	ret = state->driver.functions(GN_OP_GetModel, &data, state);
3317 	if (ret)
3318 		goto out;
3319 	data.manufacturer = manufacturer;
3320 	ret = state->driver.functions(GN_OP_GetManufacturer, &data, state);
3321 	if (ret)
3322 		goto out;
3323 
3324 	if (!at_manufacturer_compare("bosch"))
3325 		at_bosch_init(model, setupdata->model, state);
3326 	else if (!at_manufacturer_compare("ericsson"))
3327 		at_ericsson_init(model, setupdata->model, state);
3328 	else if (!at_manufacturer_compare("nokia"))
3329 		at_nokia_init(model, setupdata->model, state);
3330 	else if (!at_manufacturer_compare("siemens"))
3331 		at_siemens_init(model, setupdata->model, state);
3332 	else if (!at_manufacturer_compare("sony ericsson"))
3333 		at_sonyericsson_init(model, setupdata->model, state);
3334 	else if (!at_manufacturer_compare("samsung"))
3335 		at_samsung_init(model, setupdata->model, state);
3336 	else if (!at_manufacturer_compare("motorola"))
3337 		at_motorola_init(model, setupdata->model, state);
3338 	else if (!at_manufacturer_compare("sagem"))
3339 		at_sagem_init(model, setupdata->model, state);
3340 	else if (!at_manufacturer_compare("lg"))
3341 		at_lg_init(model, setupdata->model, state);
3342 	else if (!at_manufacturer_compare("huawei"))
3343 		at_huawei_init(model, setupdata->model, state);
3344 
3345 	StoreDefaultCharset(state);
3346 
3347 	/*
3348 	 * Postconfig
3349 	 */
3350 	if (drvinst->extended_phonebook)
3351 		register_extended_phonebook(state);
3352 
3353 	dprintf("Initialisation completed\n");
3354 out:
3355 	if (ret) {
3356 		dprintf("Initialization failed (%d)\n", ret);
3357 		/* ignore return value from GN_OP_Terminate, will use previous error code instead */
3358 		state->driver.functions(GN_OP_Terminate, &data, state);
3359 	}
3360 	return ret;
3361 }
3362 
Terminate(gn_data * data,struct gn_statemachine * state)3363 static gn_error Terminate(gn_data *data, struct gn_statemachine *state)
3364 {
3365 	if (AT_DRVINST(state)) {
3366 		if (AT_DRVINST(state)->cached_capabilities) {
3367 			map_free(&(AT_DRVINST(state)->cached_capabilities));
3368 			AT_DRVINST(state)->cached_capabilities = NULL;
3369 		}
3370 		if (AT_DRVINST(state)->timezone) {
3371 			free(AT_DRVINST(state)->timezone);
3372 			AT_DRVINST(state)->timezone = NULL;
3373 		}
3374 		free(AT_DRVINST(state));
3375 		AT_DRVINST(state) = NULL;
3376 	}
3377 	return pgen_terminate(data, state);
3378 }
3379 
splitlines(at_line_buffer * buf)3380 void splitlines(at_line_buffer *buf)
3381 {
3382 	char *pos;
3383 	int length = buf->length;
3384 
3385 	pos = findcrlf(buf->line1, 0, length);
3386 	if (pos) {
3387 		*pos = 0;
3388 		buf->line2 = skipcrlf(++pos);
3389 		length -= (buf->line2 - buf->line1);
3390 	} else {
3391 		buf->line2 = buf->line1;
3392 	}
3393 	pos = findcrlf(buf->line2, 1, length);
3394 	if (pos) {
3395 		*pos = 0;
3396 		buf->line3 = skipcrlf(++pos);
3397 		length -= (buf->line3 - buf->line2);
3398 	} else {
3399 		buf->line3 = buf->line2;
3400 	}
3401 	pos = findcrlf(buf->line3, 1, length);
3402 	if (pos) {
3403 		*pos = 0;
3404 		buf->line4 = skipcrlf(++pos);
3405 		length -= (buf->line4 - buf->line3);
3406 	} else {
3407 		buf->line4 = buf->line3;
3408 	}
3409 	pos = findcrlf(buf->line4, 1, length);
3410 	if (pos) {
3411 		*pos = 0;
3412 	}
3413 }
3414 
3415 /*
3416  * increments the argument until a char unequal to
3417  * <cr> or <lf> is found. returns the new position.
3418  */
skipcrlf(unsigned char * str)3419 char *skipcrlf(unsigned char *str)
3420 {
3421 	if (str == NULL)
3422 		return str;
3423 	while ((*str == '\n') || (*str == '\r') || (*str > 127))
3424 		str++;
3425 	return str;
3426 }
3427 
3428 /*
3429  * searches for <cr> or <lf> and returns the first
3430  * occurrence. if test is set, the gsm char @ which
3431  * is 0x00 is not considered as end of string.
3432  * return NULL if no <cr> or <lf> was found in the
3433  * range of max bytes.
3434  */
findcrlf(unsigned char * str,int test,int max)3435 char *findcrlf(unsigned char *str, int test, int max)
3436 {
3437 	if (str == NULL)
3438 		return str;
3439 	while ((max > 0) && (*str != '\n') && (*str != '\r') && ((*str != '\0') || test)) {
3440 		str++;
3441 		max--;
3442 	}
3443 	if ((*str == '\0') || ((max == 0) && (*str != '\n') && (*str != '\r')))
3444 		return NULL;
3445 	return str;
3446 }
3447 
3448