1 /***************************************************************************
2  *   copyright           : (C) 2002 by Hendrik Sattler                     *
3  *   mail                : post@hendrik-sattler.de                         *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) any later version.                                   *
9  *                                                                         *
10  ***************************************************************************/
11 
12 #include <atcommand.h>
13 #include <helper.h>
14 #include <gtincl.h>
15 #include <pinfile.h>
16 #include <w32compat.h>
17 
18 #include <stdio.h>
19 #include <stdarg.h>
20 #include <string.h>
21 #include <strings.h>
22 #include <errno.h>
23 
24 static char* at_last_command;
25 static char* at_last_parameter;
26 static int   at_last_was_syntax_request;
27 static char* PIN;
28 static struct at_hw_access at_tty;
29 
at_init(struct at_hw_access * tty,char * pin)30 void at_init (struct at_hw_access* tty, char* pin) {
31   at_last_command = NULL;
32   at_last_parameter = NULL;
33   at_last_was_syntax_request = 0;
34   PIN = str_dup(pin);
35   at_set_tty(tty);
36 }
37 
at_set_tty(struct at_hw_access * tty)38 void at_set_tty(struct at_hw_access* tty) {
39   at_tty.read = tty->read;
40   at_tty.write = tty->write;
41 }
42 
at_check_line_end(const char * input,const size_t len)43 int at_check_line_end (const char* input, const size_t len) {
44   return ((len >= 2 && input[len-2] == '\r' && input[len-1] == '\n') ||
45 	  (input[0] == '>' && len > 1));
46 }
47 
at_read_line_raw()48 char* at_read_line_raw () {
49   char* value;
50   char* temp;
51   int repeat;
52   int estatus;
53 
54   value = NULL;
55   do {
56     repeat = 0;
57     value = at_tty.read(at_check_line_end);
58     if (str_len(value) == 0) {
59       if (value == NULL) {
60         estatus = errno;
61       } else {
62         estatus = ETIMEDOUT;
63       }
64       errexit("%s: %s\n",_("Cannot read from device"),strerror(estatus));
65     } else {
66       if ((temp=strchr(value,'\r')) != NULL ||
67 	  (temp=strchr(value,'\n')) != NULL) {
68 	//we do not want values 13=<CR>='\r' and 10=<LF>='\n' in our strings
69 	memset(temp,0,1);
70 	//we do not want to return empty strings
71 	//we do not accept the at_command_p as answer
72 	if (strlen(value) == 0 ||
73 	    (strncmp(value,AT_PREFIX,sizeof(AT_PREFIX)-1) == 0 &&
74 	     strncmp(value+sizeof(AT_PREFIX)-1,
75 		     at_last_command,
76 		     str_len(at_last_command)) == 0)) {
77 	  value = mem_realloc(value,0);
78 	  repeat = 1;
79 	}
80       }
81     }
82   } while (repeat);
83   print_message(2,_("Received"),"%s\n",value);
84   return value;
85 }
86 
at_read_line()87 char* at_read_line () {
88   char* value;
89   char* temp;
90   char* ctemp;
91   char* ptemp;
92   char* pintype;
93   int srtemp;
94 
95   value = at_read_line_raw();
96 
97   //PIN handling for all function is done transparently here
98   if (at_line_type(value,NULL,&temp) == AT_RET_ERROR_CME) {
99     if (strstr(temp,"PIN") != NULL ||
100 	strstr(temp,"PUK") != NULL) {
101       //save previous command
102       ctemp = str_dup(at_last_command);
103       ptemp = str_dup(at_last_parameter);
104       srtemp = at_last_was_syntax_request;
105 
106       /* On first PIN usage, the command line option overrides
107        * pin file usage, subsequent request are always answered
108        * by pin file.
109        */
110       if (str_len(PIN) == 0) {
111         at_syntax_request(AT_GEN_PIN);
112 	pintype = at_read_line_raw();
113 	if (at_line_type(pintype,AT_GEN_PIN,&temp) == AT_RET_ANSWER)
114 	  mem_realloc(at_read_line_raw(),0);
115 	  PIN = pinfile_get(temp);
116 	mem_realloc(pintype,0);
117       }
118       if (str_len(PIN) == 0) {
119 	//fail if pin file lookup failed and nothing was specified at command line
120 	ctemp = mem_realloc(ctemp,0);
121 	ptemp = mem_realloc(ptemp,0);
122 	if (PIN != NULL) mem_realloc(PIN,0);
123 	at_line_type(value,NULL,&temp);
124 	errexit("%s\n%s\n",temp,_("Use the --pin parameter or edit the pin file."));
125       } else {
126         //resend command to be sure to be allowed to enter the pin
127 	if (srtemp) at_syntax_request(ctemp);
128 	else at_command_send(ctemp,ptemp);
129 	mem_realloc(at_read_line_raw(),0);
130 
131 	//enter the pin
132 	at_gen_pin(PIN);
133 	mem_realloc(value,0);
134 	value = at_read_line_raw();
135 	if (at_line_type(value,AT_GEN_PIN,&temp) != AT_RET_OK)
136 	  errexit("%s: %s\n",_("Using PIN failed"),temp);
137 	mem_realloc(value,0);
138 
139 	//prevent a loop, use pin file for multiple usages
140 	PIN = mem_realloc(PIN,0);
141 
142 	//resend previous command
143 	if (srtemp) at_syntax_request(ctemp);
144 	else at_command_send(ctemp,ptemp);
145 	ctemp = mem_realloc(ctemp,0);
146 	ptemp = mem_realloc(ptemp,0);
147 	value = at_read_line_raw();
148       }
149     }
150   } else if (strncmp(value,"RING",4) == 0 ||
151 	     strncmp(value,"NO CARRIER",10) == 0) {
152     mem_realloc(value,0);
153     value = at_read_line();
154   }
155   return mem_realloc(value,strlen(value)+1);
156 }
157 
at_command_send(const char * command,const char * parmlist)158 void at_command_send (const char* command, const char* parmlist) {
159   if (command == NULL) return;
160 
161   print_message(2,_("\nSending command"),"%s%s",AT_PREFIX,command);
162   if (str_len(parmlist) > 0) {
163     print_verbose(2,"%s%s\n",AT_WRITE_DELIM,parmlist);
164   } else {
165     print_verbose(2,"%s","\n");
166   }
167 
168   if (at_tty.write(AT_PREFIX,sizeof(AT_PREFIX)-1) == 0 ||
169       at_tty.write(command,strlen(command)) == 0 ||
170       (str_len(parmlist) != 0 &&
171        (at_tty.write(AT_WRITE_DELIM,sizeof(AT_WRITE_DELIM)-1) == 0 ||
172 	at_tty.write(parmlist,strlen(parmlist)) == 0)) ||
173       at_tty.write("\r",1) == 0) {
174     errexit("%s: %s\n",_("Cannot send at command"),strerror(errno));
175   } else {
176     at_last_command = mem_realloc(at_last_command,0);
177     at_last_command = str_dup(command);
178     at_last_parameter = mem_realloc(at_last_parameter,0);
179     at_last_parameter = str_dup(parmlist);
180     at_last_was_syntax_request = 0;
181   }
182 }
183 
at_syntax_request(const char * command)184 void at_syntax_request (const char* command) {
185   if (command == NULL) return;
186 
187   print_message(2,_("\nSending command"),"%s%s%s\n",
188 	   AT_PREFIX, command, AT_READ_SUFFIX);
189   if (at_tty.write(AT_PREFIX,sizeof(AT_PREFIX)-1) == 0 ||
190       at_tty.write(command,strlen(command)) == 0 ||
191       at_tty.write(AT_READ_SUFFIX,strlen(AT_READ_SUFFIX)) == 0 ||
192       at_tty.write("\r",1) == 0) {
193     errexit("%s: %s\n",_("Cannot send at command"),strerror(errno));
194   } else {
195     at_last_command = mem_realloc(at_last_command,0);
196     at_last_command = str_dup(command);
197     at_last_parameter = mem_realloc(at_last_parameter,0);
198     at_last_was_syntax_request = 1;
199   }
200 }
201 
at_data_send(const char * data,size_t size)202 void at_data_send (const char* data, size_t size) {
203   /* 0x1a is Ctrl-Z (represents end of data stream) */
204   if (at_tty.write(data,size))
205     at_tty.write("\x1a",1);
206 }
207 
208 
at_get_value(const char * command)209 char* at_get_value (const char* command) {
210   char* temp;
211   char* temp2;
212 
213   temp = at_read_line();
214   if (temp == NULL) return NULL;
215   switch (at_line_type(temp,command,&temp2)) {
216   case AT_RET_ANSWER:
217     memmove(temp,temp2,strlen(temp2)+1);
218     //no break
219   case AT_RET_OTHER:
220     temp2 = at_read_line();
221     if (at_line_type(temp2,NULL,NULL) == AT_RET_OK) {
222       mem_realloc(temp2,0);
223       return temp;
224     }
225     mem_realloc(temp2,0);
226     //no break
227   default:
228     mem_realloc(temp,0);
229     return NULL;
230   }
231 }
232 
233 
at_parse_stringlist(char * stringlist)234 char** at_parse_stringlist (char* stringlist) {
235   char* temp = stringlist;
236 
237   if (*temp == '(') ++temp;
238   if (*temp == '"') ++temp;
239   memmove(stringlist,temp,strlen(temp)+1);
240   temp = stringlist+strlen(stringlist)-1;
241   if (*temp == ')') --temp;
242   if (*temp != '"') ++temp;
243   memset(temp,0,1);
244   return str_split(stringlist,"\",\"",0);
245 }
246 
at_line_type(const char * response,const char * command,char ** content)247 enum return_code at_line_type (const char* response,
248 			       const char* command,
249 			       char** content)
250 {
251   char* temp = NULL;
252   enum return_code retval = AT_RET_OTHER;
253 
254   if (content != NULL) *content = (char*)response;
255   if (response == NULL) return retval;
256   if (strcasecmp(response,AT_OK) == 0) {
257     temp = "OK";
258     retval = AT_RET_OK;
259   } else if (strcasecmp(response,AT_ERROR) == 0) {
260     temp = "ERROR";
261     retval = AT_RET_ERROR;
262   } else if (strncasecmp(response,AT_ERROR_CME,
263 			 str_len(AT_ERROR_CME)) == 0) {
264     temp = "CME ERROR";
265     if (content != NULL) *content = (char*)response + str_len(AT_ERROR_CME);
266     retval =  AT_RET_ERROR_CME;
267   } else if (strncasecmp(response,AT_ERROR_CMS,
268 			 str_len(AT_ERROR_CMS)) == 0) {
269      temp = "CMS ERROR";
270     if (content != NULL) *content = (char*)response + str_len(AT_ERROR_CMS);
271     retval = AT_RET_ERROR_CMS;
272   } else if (command != NULL &&
273 	     strncasecmp(response,command,strlen(command)) == 0 &&
274 	     strncasecmp(response+str_len(command),
275 			 AT_REPLY_SEPERATOR,
276 			 str_len(AT_REPLY_SEPERATOR)) == 0) {
277     temp = _("command return value");
278     if (content != NULL) {
279       *content = (char*)response + str_len(command) + str_len(AT_REPLY_SEPERATOR);
280     }
281     retval = AT_RET_ANSWER;
282   } else {
283     temp = _("nothing");
284     retval =  AT_RET_OTHER;
285   }
286   print_verbose(3,_("Value matched %s.\n"),temp);
287   return retval;
288 }
289