1 //
2 // anyRemote
3 // a wi-fi or bluetooth remote for your PC.
4 //
5 // Copyright (C) 2006-2016 Mikhail Fedotov <anyremote@mail.ru>
6 //
7 // This program is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License as published by
9 // the Free Software Foundation; either version 3 of the License, or
10 // (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 //
21
22 //
23 // AT+CKPD commands handling
24 //
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
30 #include <errno.h>
31 #include <termios.h>
32
33 #include "parse.h"
34 #include "utils.h"
35 #include "btio.h"
36 #include "conf.h"
37 #include "dispatcher.h"
38 #include "peer.h"
39 #include "pr_rfcomm.h"
40 #include "pr_serial.h"
41
42 #define PAUSE_TIME 1
43
44 extern char tmp[MAXMAXLEN];
45
46 static int useQuestionInCLCC = 0;
47 char callerId[MAXLEN];
48
49 //
50 // max should be >= 100
51 //
writeAtCommand(int fd,const char * command,char * answer,int max,int timeout,char * expect)52 int writeAtCommand(int fd,
53 const char* command,
54 char* answer,
55 int max,
56 int timeout,
57 char* expect)
58 {
59 int count=0;
60 int readcount;
61 char tmp2[100];
62 int timeoutcounter=0;
63 int found=0;
64
65 if (fd < 0) {
66 return 0;
67 }
68
69 logger(L_DBG,command);
70 DEBUG2("writeAtCommand command >%s<", command);
71 if (expect != NULL) {
72 DEBUG2("writeAtCommand skip till >%s<", expect);
73 }
74
75 // send command
76 if (command && command[0]) {
77 write(fd,command,strlen(command));
78 tcdrain(fd);
79 }
80
81 if (max == 0) {
82 return 0;
83 }
84
85 answer[0]=0;
86 do {
87 // try to read some bytes.
88 usleep(100000);
89
90 //write(1,".",1);
91 timeoutcounter++;
92
93 // read data
94 readcount=read(fd,tmp2,sizeof(tmp2)-1);
95 if (readcount<0) {
96 readcount=0;
97 }
98 tmp2[readcount]=0;
99
100 // add read bytes to the output buffer
101 if (readcount) {
102 //DEBUG2("writeAtCommand got reply >%s<", tmp2);
103
104 strcat(answer,tmp2);
105 count+=readcount;
106
107 // if we have more time to read, check if we got already the expected string
108 if ((timeoutcounter<timeout) && (found==0)) {
109
110 // check if it's the expected answer
111 if (strstr(answer,"OK\r") || strstr(answer,"ERR")) {
112 if (expect == NULL) {
113 found=1;
114 } else {
115 if (strstr(answer,"ERR")) { // got error, so nothing to expect
116 expect = NULL;
117 }
118 }
119 }
120
121 if (expect && expect[0]) {
122 if (strstr(answer,expect)) {
123 sprintf(tmp, "Got expected %s (iteration %d)", answer, timeoutcounter);
124 logger(L_DBG, tmp);
125 found=1;
126 }
127 }
128
129 // if found then set timoutcounter to read only 0.1s after that and not more
130 if (found) {
131 //timeoutcounter=timeout-1;
132 break;
133 }
134 }
135 }
136 }
137 // repeat until timout
138 while (timeoutcounter<timeout && count < max);
139
140 if (getLog()) {
141 char *a2 = answer;
142
143 while (a2[0] == '\r' || a2[0] == '\n') {
144 a2++;
145 }
146 logger(L_DBG,a2);
147 }
148
149 return count;
150 }
151
152 //
153 // Phones can send commad back as reply, so it needs to skip it
154 //
sendSyncCommand(int fd,const char * bytes,char * answer,int size,char * expect)155 static void sendSyncCommand(int fd, const char *bytes, char *answer, int size, char *expect)
156 {
157 DEBUG2("sendSyncCommand >%s<\n", bytes);
158
159 // initial timeout was 5
160 writeAtCommand(fd, bytes, answer, size, 40, expect);
161 }
162
sendCMER(int fd,int onOff)163 int sendCMER(int fd, int onOff)
164 {
165 char answer[100];
166 char cmd[64];
167
168 char * cmer = getAT_CMER(onOff);
169 if (cmer == NULL) {
170 return EXIT_NOK;
171 }
172
173 strcpy(cmd,cmer);
174 free(cmer);
175
176 strcat(cmd,"\r");
177 //sendSyncCommand(cmd, answer, sizeof(answer), NULL);
178 writeAtCommand (fd, cmd, answer, sizeof(answer), 10, NULL);
179
180 if(!IS_OK(answer)) {
181 DEBUG2("ERROR: AT_CMER SET >%s< -> %s\n", cmd, answer);
182 return EXIT_NOK;
183 }
184 return EXIT_OK;
185 }
186
187 // Send AT+CKPD command
sendCKPD(int fd,char * key)188 static int sendCKPD(int fd, char *key)
189 {
190 char answer[1024];
191 char ckpd[MAXCKPDLEN];
192
193 if (key == NULL || key[0] == '\0') {
194 logger(L_DBG,"Empty symbol in sendCKPD()");
195 return EXIT_NOK;
196 }
197 DEBUG2("sendCKPD >%s<", key);
198
199 sprintf(ckpd,"%s\"%s\"\r", DEF_AT_CKPD, key);
200
201 int model = getModel();
202
203 if (model == MODEL_SE || model == MODEL_SIEMENS) { // SE-K700, Siemens-S55
204 // If we send AT+CKPD=X
205 // SE phone will replay
206 // OK
207 // +CKEV: X,1
208 // +CKEV: X,0
209 // And we need to filter out that CKEVs
210 char expect[16];
211 strcpy(expect, DEF_CKEV);
212 strcat(expect, " ");
213 if (model == MODEL_SIEMENS) {
214 strcat(expect, "\"");
215 }
216 strcat(expect, key);
217 if (model == MODEL_SIEMENS) {
218 strcat(expect, "\"");
219 }
220 strcat(expect, ",0"); // Wait button up event
221
222 sendSyncCommand(fd, ckpd, answer, sizeof(answer), expect);
223 //DEBUG2("Expect >%s<", expect);
224 //DEBUG2("Got all >%s<", answer);
225
226 // Filter out button up
227 char *ptr = strstr(answer, expect);
228 if(ptr == NULL) {
229 logger(L_DBG,"cant find button up event");
230 } else {
231 int z;
232 int l = strlen(expect);
233 for (z=0; z<l; z++) {
234 *ptr = '\r';
235 ptr++;
236 }
237 }
238
239 // Filter out button down
240 strcpy(expect, DEF_CKEV);
241 strcat(expect, " ");
242 if (model == MODEL_SIEMENS) {
243 strcat(expect, "\"");
244 }
245 strcat(expect, key);
246 if (model == MODEL_SIEMENS) {
247 strcat(expect, "\"");
248 }
249 strcat(expect, ",1");
250 ptr = strstr(answer, expect);
251 if(ptr == NULL) {
252 logger(L_DBG,"can not find button down event");
253 } else {
254 int z;
255 int l = strlen(expect);
256 for (z=0; z<l; z++) {
257 *ptr = '\r';
258 ptr++;
259 }
260 }
261 DEBUG2("Filtered >%s<", answer);
262
263 } else {
264 sendSyncCommand(fd, ckpd, answer, sizeof(answer), NULL);
265 }
266
267 parseCommand(PEER_ANY, answer);
268
269 return EXIT_OK;
270 }
271
272 //
273 // Should be used in AT mode only
274 //
sendSeq(int fd,const char * seq)275 int sendSeq(int fd, const char *seq)
276 {
277 if (getUseScreen() == 0 || seq == NULL) {
278 return EXIT_OK;
279 }
280
281 DEBUG2("sendSeq() >%s<", seq);
282
283 char* copy = strdup(seq);
284
285 char *bufPtr = NULL;
286 char *ckpd = strtok_r(copy," ",&bufPtr);
287
288 while (ckpd != NULL) {
289 //DEBUG2("NEXT sendSeq()->sendCKPD()>%s<", ckpd);
290
291 if (strcmp(ckpd, PAUSE_STR)==0) {
292 sleep(PAUSE_TIME); // Just wait a bit
293 } else {
294 sendCKPD(fd, ckpd);
295 }
296 ckpd = strtok_r(NULL," ",&bufPtr);
297 }
298 free(copy);
299
300 return EXIT_OK;
301 }
302
parse_CLCC(char * clcc,char * dest)303 static void parse_CLCC(char *clcc, char* dest)
304 {
305 // There are could be more than one call at time ... but here we will get then one-by-one
306 // +CLCC: 1,,4,0,0,"<phone number here>",129,
307 char *start ,*ptr;
308 int commaCount = 0;
309
310 ptr = clcc;
311 while(ptr && commaCount < 5) {
312 if (*ptr == ',') {
313 commaCount++;
314 }
315 ptr++;
316 }
317
318 if (ptr == NULL) { // Call was finished
319 strcpy(dest, "FINISHED");
320 return;
321 }
322 if (ptr && *ptr == '"') {
323 ptr++;
324 }
325 start = ptr;
326 while(ptr && *ptr != '"' && *ptr != ',') {
327 ptr++;
328 }
329 if (ptr) {
330 *ptr = '\0';
331 }
332
333 if(start) {
334 DEBUG2("parse_CLCC >%s<", start);
335 } else {
336 DEBUG2("parse_CLCC >NULL callerID<");
337 strcpy(dest, "NO CALLER ID");
338 return;
339 }
340
341 strcpy(dest, start);
342 return;
343 }
344
getClip(int fd,char * CallerID)345 int getClip(int fd, char* CallerID)
346 {
347 char clcc[MTEXTLEN];
348 char answer[1024];
349 char *ptr;
350 int tryAnyway = 0;
351
352 answer[0] = '\0';
353
354 logger(L_DBG, "getClip()");
355
356 // Some phones uses AT+CLCC?, some just AT+CLCC (Sagem, Siemens-S55, SE-K750)
357
358 if (useQuestionInCLCC == 0) {
359 //logger(L_DBG, "getClip() send AT+CLCC");
360
361 strcpy(clcc,DEF_AT_CLCC);
362 strcat(clcc,"\r");
363
364 sendSyncCommand(fd, clcc, answer, sizeof(answer), NULL);
365
366 if ((ptr = strstr(answer,DEF_CLCC)) != NULL) {
367 parse_CLCC(ptr,CallerID);
368 return EXIT_EXACT;
369 } else if (strstr(answer,"OK") != NULL) {
370 return EXIT_OK;
371 } else if (strstr(answer,"ERR") != NULL) {
372 logger(L_WARN, "Got ERROR on AT+CLCC. Will try AT+CLCC?");
373 useQuestionInCLCC = 1; // Ask phone again; but will never ask AT+CLCC more
374 } else {
375 tryAnyway = 1; // Ask phone again; to be sure
376 }
377 }
378
379 if (useQuestionInCLCC == 1 || tryAnyway == 1) {
380
381 tryAnyway = 0;
382
383 //logger(L_DBG, "getClip() send AT+CLCC?");
384
385 strcpy(clcc,DEF_AT_CLCC);
386 strcat(clcc,"?");
387 strcat(clcc,"\r");
388
389 sendSyncCommand(fd, clcc, answer, sizeof(answer), NULL);
390
391 if ((ptr = strstr(answer,DEF_CLCC)) != NULL) {
392 parse_CLCC(ptr,CallerID);
393 return EXIT_EXACT;
394 } else if (strstr(answer,"OK") != NULL) {
395 return EXIT_OK;
396 } else if (strstr(answer,"ERR") != NULL) {
397 logger(L_ERR, "Got ERROR on AT+CLCC?");
398 return EXIT_NOK;
399 }
400 }
401
402 DEBUG2("sendClip() unappropriate answer: >%s<", answer);
403
404 return EXIT_NOK;
405 }
406
407 // CLIENT_RFCOMM / CLIENT_AT
setupAtConnection(ConnectInfo * peer,int fd)408 int setupAtConnection(ConnectInfo* peer, int fd)
409 {
410 char answer[1024];
411 char cmd[32];
412
413 answer[0] = '\0';
414 sendSyncCommand(fd, "ATZ\r", answer, sizeof(answer), NULL);
415 //sendSyncCommand("AT\r", answer, sizeof(answer), NULL);
416 // Do not care - it can fail after reconnect
417 //if(!IS_OK(answer)) {
418 // ERROR2("AT -> %s\n", answer)
419 // return -1;
420 //}
421
422 sendSyncCommand(fd, "ATE0\r", answer, sizeof(answer), NULL);
423 if(!IS_OK(answer)) {
424 ERROR2("ATE0 -> %s\n", answer);
425 }
426
427 char* ptr = getCharset();
428 if (ptr) {
429 sprintf(cmd,"%s\"%s\"\r", DEF_AT_CSCS, ptr);
430 sendSyncCommand(fd, cmd, answer, sizeof(answer), NULL);
431 if(!IS_OK(answer)) {
432 ERROR2("Can't set charset to %s\n", ptr);
433 }
434 free(ptr);
435 }
436
437 // Determine model
438 sprintf(cmd,"%s\r", DEF_AT_CGMI);
439 sendSyncCommand(fd, cmd, answer, sizeof(answer), NULL);
440
441 //Set model in conf. data
442 setModel(answer);
443
444 if (getModel() == MODEL_MOTOROLA) { // Motorola RIZR Z3 needs to set MODE=2 to allow AT+CLIP command
445 // do not care about responce
446 sendSyncCommand(fd, "AT+MODE=2\r", answer, sizeof(answer), NULL);
447 }
448
449 sprintf(cmd,"%s\r", DEF_AT_CLIP);
450 sendSyncCommand(fd, cmd, answer, sizeof(answer), NULL);
451 if(!IS_OK(answer)) {
452 ERROR2("Can't set CLIP ON\n");
453 }
454
455
456 int ret = sendCMER(fd, CMER_ON);
457 if(ret != EXIT_OK) {
458 ERROR2("fails in set event reporting on");
459 return -1;
460 }
461
462 // Siemens S55 needs additional AT+CMEC=2 to make AT+CKPD works
463 // not sure about other Siemens phones
464 if (getModel() == MODEL_SIEMENS) {
465 sprintf(cmd,"%s\r", DEF_AT_CMEC);
466 sendSyncCommand(fd, cmd, answer, sizeof(answer), NULL);
467 if(!IS_OK(answer)) {
468 ERROR2("ON AT+CMEC\n");
469 }
470 }
471
472 // Will set global callerId [MAXLEN];
473 ret = getClip(fd, callerId);
474 if(ret == EXIT_NOK) { // Got ERROR on AT+CLCC; probably phone does not supports this command
475 printf("ERROR: fails in getClip\n");
476
477 if (peer->mode == CLIENT_RFCOMM) {
478 _RfcommConnection* cn = (_RfcommConnection*) peer->connectionData;
479 if (cn) {
480 cn->useCallId = BOOL_NO;
481 }
482 } else if (peer->mode == CLIENT_AT) {
483 _SerialConnection* cn = (_SerialConnection*) peer->connectionData;
484 if (cn) {
485 cn->useCallId = BOOL_NO;
486 }
487 }
488 }
489
490 return 1;
491 }
492
493 //
494 // rfcomm peer reader
495 // in case of incoming call try to get caller ID
496 //
atRead(ConnectInfo * peer,char * buffer,int max)497 int atRead(ConnectInfo* peer, char* buffer, int max)
498 {
499 if (! (peer->mode == CLIENT_RFCOMM || peer->mode == CLIENT_AT)) {
500 ERROR2("[DS]: atRead() peer type mismatch");
501 return 0;
502 }
503
504 if (!peer->connectionData) return EXIT_NOK;
505
506 _RfcommConnection* cnr = NULL;
507 _SerialConnection* cns = NULL;
508 int fd = -1;
509 boolean_t useCallID = BOOL_NO;
510 boolean_t hasCall = BOOL_NO;
511
512 if (peer->mode == CLIENT_RFCOMM) {
513 cnr = (_RfcommConnection*) peer->connectionData;
514 fd = cnr->fileDescriptor;
515 useCallID = cnr->useCallId;
516 hasCall = cnr->hasActiveCall;
517 } else if (peer->mode == CLIENT_AT) {
518 cns = (_SerialConnection*) peer->connectionData;
519 fd = cns->fileDescriptor;
520 useCallID = cns->useCallId;
521 hasCall = cns->hasActiveCall;
522 }
523
524 if (fd < 0) {
525 ERROR2("[DS]: atRead() not connected");
526 return 0;
527 }
528
529 int nbytes = read(fd, buffer, max);
530 if (nbytes < 0) { // Read error
531 ERROR2("[DS]: atRead() error %d",errno);
532 errnoDebug("[DS]: atRead() read ",errno); // testing debug
533 } else if (nbytes == 0) {
534 DEBUG2("[DS]: atRead() EOF");
535 } else {
536
537 buffer[nbytes] = '\0';
538
539 if (strstr(buffer, DEF_RING) != NULL && !hasCall) { // Incoming call
540 logger(L_INF,"[DS]: Incoming call"); // This event sent periodically until used answered a call
541
542 if (cnr) {
543 cnr->hasActiveCall = BOOL_YES;
544 } else if (cns) {
545 cns->hasActiveCall = BOOL_YES;
546 }
547
548 if (useCallID) {
549
550 char callerId[MAXLEN];
551 int ret = getClip(fd, callerId);
552
553 if (ret == EXIT_EXACT) { // Active call exists, got ID
554 strcat(buffer, "Msg:InCall(,");
555 strcat(buffer, callerId);
556 strcat(buffer, ")\r");
557 nbytes = strlen(buffer);
558 }
559 } else {
560 strcat(buffer, "Msg:InCall(,)\r");
561 nbytes = strlen(buffer);
562 }
563 }
564 }
565
566 //DEBUG2("[DS]: atRead() got >%s< %d", buffer, nbytes);
567 return nbytes;
568 }
569
570
571