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 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <ctype.h>
26 #include <termios.h>
27
28 #include "parse.h"
29 #include "var.h"
30 #include "alarm.h"
31 #include "utils.h"
32 #include "mode.h"
33
34 #define EMPTY_STR "EMPTY"
35
36 extern char tmp[MAXMAXLEN];
37
38 extern CONF conf;
39
40 int initDone = 0;
41
42 boolean_t doLog = BOOL_NO;
43 boolean_t doDebug = BOOL_NO;
44 boolean_t isIViewer = BOOL_NO;
45 boolean_t isBemused = BOOL_NO;
46 int waitTimeout = -1;
47
48 static char * _btAddress = NULL;
49
50 /* ----------------- Interface functions ------------------------- */
51
boolValue(const char * value)52 boolean_t boolValue(const char* value)
53 {
54 if (!value) return BOOL_NO;
55 return (!value || strncmp(value,"false",5) == 0 || strncmp(value,"no",5) == 0 ? BOOL_NO : BOOL_YES);
56 }
57
setLog(const char * value)58 void setLog(const char* value)
59 {
60 doLog = boolValue(value);
61
62 doDebug = 0;
63 if (value && strncmp(value,"debug",5) == 0) {
64 doDebug = 1;
65 }
66 }
67
getLog()68 int getLog()
69 {
70 return doLog;
71 }
72
setBemused(const char * value)73 void setBemused(const char* value)
74 {
75 isBemused = boolValue(value);
76 }
77
getBemused()78 int getBemused()
79 {
80 return isBemused;
81 }
82
setIViewer(const char * value)83 void setIViewer(const char* value)
84 {
85 isIViewer = boolValue(value);
86 }
87
getIViewer()88 int getIViewer()
89 {
90 return isIViewer;
91 }
92
getDebug()93 int getDebug()
94 {
95 return doDebug;
96 }
97
getDevice()98 char* getDevice()
99 {
100 return dupVarValue("Device");
101 }
102
getBaudrate()103 int getBaudrate()
104 {
105 char* value = dupVarValue("Baudrate");
106 if (value != NULL) {
107
108 int rate = atoi(value);
109 free(value);
110
111 switch (rate) {
112 case 300:
113 return B300;
114 case 1200:
115 return B1200;
116 case 2400:
117 return B2400;
118 case 9600:
119 return B9600;
120 case 19200:
121 return B19200;
122 case 38400:
123 return 38400;
124 #ifdef B57600
125 case 57600:
126 return B57600;
127 #endif
128 #ifdef B115200
129 case 115200:
130 return B115200;
131 #endif
132 #ifdef B230400
133 case 230400:
134 return B230400;
135 #endif
136 default:
137 WARNING2("bad baudrate %d, defaulting to 9600", rate);
138 return B9600;
139 }
140 }
141 return B19200;
142 }
143
getRetrySecs()144 int getRetrySecs()
145 {
146 char* value = dupVarValue("RetrySeconds");
147 if (value != NULL) {
148 int v = atoi(value);
149 free(value);
150 return v;
151 }
152 return 10;
153 }
154
getWaitTime()155 int getWaitTime()
156 {
157 return waitTimeout;
158 }
159
setWaitTime(const char * value)160 void setWaitTime(const char* value)
161 {
162 waitTimeout = -1;
163
164 if (value != NULL) {
165 waitTimeout = atoi(value);
166 if (waitTimeout < 0) {
167 waitTimeout = -1;
168 }
169 }
170 }
171
autoConnect()172 int autoConnect()
173 {
174 int sz = 0;
175 const char* v = getVarValue(VAR_AUTOCONN, &sz);
176 if (v != NULL && sz > 3 && strncmp(v,"true",4) == 0) {
177 return 1;
178 }
179 return 0;
180 }
181
getAutoRepeat()182 int getAutoRepeat()
183 {
184 int sz = 0;
185 const char* v = getVarValue(VAR_AUTOREPEAT, &sz);
186 if (v != NULL && sz > 3 && strncmp(v,"true",4) == 0) {
187 return 1;
188 }
189 return 0;
190 }
191
192 static type_key* repeatCMD = NULL;
193
setRepeatNow(type_key * repeat)194 void setRepeatNow(type_key* repeat)
195 {
196 repeatCMD = repeat;
197 }
198
repeatNow()199 type_key* repeatNow()
200 {
201 return repeatCMD;
202 }
203
getUseScreen()204 int getUseScreen()
205 {
206 int sz = 0;
207 const char* v = getVarValue("TwoWayComm", &sz);
208 if (v != NULL && sz > 3 && strncmp(v,"true",4) == 0) {
209 return 1;
210 }
211 return 0;
212 }
213
getCharset()214 char* getCharset()
215 {
216 return dupVarValue(VAR_CHARSET);
217 }
218
getToMainMenu()219 char* getToMainMenu()
220 {
221 return dupVarValue("ToMainMenu");
222 }
223
getServiceName()224 char* getServiceName()
225 {
226 return dupVarValue("ServiceName");
227 }
228
getAT_CMER(int what)229 char* getAT_CMER(int what)
230 {
231 if (what == CMER_ON) {
232 char *cmer = dupVarValue("CmerOn");
233
234 if (cmer == NULL) {
235 if (conf.model == MODEL_MOTOROLA) {
236 return strdup(DEF_AT_CMER_ON_MOTOROLA);
237 } else if (conf.model == MODEL_SE) {
238 return strdup(DEF_AT_CMER_ON_SE);
239 } else if (conf.model == MODEL_SAGEM) {
240 return strdup(DEF_AT_CMER_ON_SAGEM);
241 } else if (conf.model == MODEL_SIEMENS) {
242 return strdup(DEF_AT_CMER_ON_SIEMENS);
243 } else {
244 return strdup(DEF_AT_CMER_ON_DEFAULT);
245 }
246 } else {
247 return cmer;
248 }
249 }
250
251 if (what == CMER_OFF) {
252 char *cmer = dupVarValue("CmerOff");
253
254 if (cmer == NULL) {
255 if (conf.model == MODEL_MOTOROLA) {
256 return strdup(DEF_AT_CMER_OFF_MOTOROLA);
257 } else if (conf.model == MODEL_SE) {
258 return strdup(DEF_AT_CMER_OFF_SE);
259 } else if (conf.model == MODEL_SAGEM) {
260 return strdup(DEF_AT_CMER_OFF_SAGEM);
261 } else if (conf.model == MODEL_SIEMENS) {
262 return strdup(DEF_AT_CMER_OFF_SIEMENS);
263 } else {
264 return strdup(DEF_AT_CMER_OFF_DEFAULT);
265 }
266 } else {
267 return cmer;
268 }
269 }
270 return NULL;
271 }
272
getFrontEnd()273 int getFrontEnd()
274 {
275 return conf.frontEnd;
276 }
277
setModel(char * answer)278 void setModel (char *answer)
279 {
280 if (answer == NULL) {
281 conf.model = MODEL_DEFAULT;
282 } else if (strstr(answer,STR_MOTOROLA)) {
283 conf.model = MODEL_MOTOROLA;
284 } else if (strstr(answer,STR_SE)) {
285 conf.model = MODEL_SE;
286 } else if (strstr(answer,STR_SAGEM)) {
287 conf.model = MODEL_SAGEM;
288 } else if (strstr(answer,STR_SIEMENS)) {
289 conf.model = MODEL_SIEMENS;
290 } else {
291 conf.model = MODEL_DEFAULT;
292 }
293 }
294
getModel(void)295 int getModel (void)
296 {
297 return conf.model;
298 }
299
setBtAddress(char * a)300 void setBtAddress (char* a)
301 {
302 _btAddress = a;
303 }
304
getBtAddress()305 char * getBtAddress()
306 {
307 return _btAddress;
308 }
309
freeBtAddress()310 void freeBtAddress()
311 {
312 if (_btAddress) {
313 free(_btAddress);
314 }
315 _btAddress = NULL;
316 }
317
318
319 /////////////////////////////////////////////////////////////////////////////////////////////////
320
findExact(mode * mode,const char * key)321 type_key* findExact(mode *mode, const char *key)
322 {
323 //DEBUG2("findExact() %s",key);
324 if (mode == NULL || key == NULL) {
325 logger(L_DBG, "findExact() input is empty ?");
326 return NULL;
327 }
328 type_key* It = mode->keys;
329
330 // Search exact command
331 while (It != NULL && It->key != NULL && strcmp(It->key,key) != 0) {
332 //sprintf(tmp,"findExact search >%s< compare to >%s<", It->key, key);
333 //logger(L_DBG,tmp);
334
335 It = (type_key*) It->next;
336 //logger(L_DBG, "findExact() next loop");
337 }
338 //logger(L_DBG, "findExact() exiting");
339 return It;
340 }
341
findStartingWith(mode * mode,const char * key)342 static type_key* findStartingWith(mode *mode, const char *key)
343 {
344 if (mode == NULL) {
345 return NULL;
346 }
347 type_key* It = mode->keys;
348
349 while (It && It->key != NULL) {
350 char *start = strstr(It->key,key);
351
352 //DEBUG2("[EX]: findStartingWith() %s %s %s",It->key,key,(start?"FOUND":"NOTFOUND"));
353
354 if (start && start == It->key) { // We got a part of multi-key or parametrized command
355
356 int lk = strlen(key);
357 int l2 = strlen(It->key);
358 int ok = 1;
359
360 if (*(key+lk-1) != '$' && // not parametrized
361 l2 > lk) { // part of multi-key should be followed by space
362
363 char next = *(It->key+lk);
364 if (next != ' ') {
365 ok = 0;
366 }
367 }
368
369 if (ok == 1) {
370 logger(L_DBG,"[EX]: Found part of multi-key or parametrized command");
371 return It;
372 }
373 }
374 It = (type_key*) It->next;
375 }
376
377 return It;
378 }
379
findItemInMode(mode * mode,const char * key,int * flag,cmdParams * params)380 static type_key* findItemInMode(mode *mode, const char *key, int *flag, cmdParams *params)
381 {
382 if (mode == NULL) {
383 logger(L_DBG,"[EX]: findItemInMode: mode is null");
384 return NULL;
385 }
386 int canLog = (strcmp(mode->name->str,"_INTERNAL_") != 0);
387
388 if(canLog) {
389 sprintf(tmp,"[EX]: findItemInMode >%s,%s<", mode->name->str, key);
390 logger(L_DBG,tmp);
391 }
392
393 // Prepare to search as parametrized command, control presence of both ( and )
394 const char *start = index(key,'(');
395 const char *finish = rindex(key,')');
396
397 if ((start != NULL && finish == NULL) || // Command was read partially?
398 (start == NULL && finish != NULL)) { // Command was incorectrly formed ?
399 if(canLog) {
400 logger(L_DBG,"[EX]: findItemInMode: Incorrectly formed parametrized command. One brace is absent");
401 }
402 return NULL;
403 }
404
405 // Clean-up
406 if (params != NULL) {
407 params->index[0] = '\0';
408 params->value[0] = '\0';
409 }
410
411 type_key* It = findExact(mode,key); // Search exact command
412 if (It) {
413 if(canLog) {
414 logger(L_DBG,"[EX]: findItemInMode: found exact command");
415 }
416 *flag = FLAG_EXACT;
417 return It;
418 }
419
420 It = findStartingWith(mode,key); // Search as part of multikey sequence
421 if (It) {
422 if(canLog) {
423 logger(L_DBG,"[EX]: findItemInMode: found part of multi-key command");
424 }
425 *flag = FLAG_MULTIKEY;
426 return It;
427 }
428
429 if (params == NULL) {
430 //if(canLog) {
431 // logger(L_DBG,"[EX]: findItemInMode: No parameters suspected. Item does not found.");
432 //}
433 return NULL;
434 }
435
436 // Search as parametrized command
437
438 if (start != NULL && finish != NULL && start != key) { // Do not match "(...)=..."
439 It = mode->keys;
440
441 char tag [MAXARGLEN];
442 memset(tag, 0,MAXARGLEN);
443 char index[6];
444 memset(index,0,6);
445 char value[MAXARGLEN];
446 memset(value,0,MAXARGLEN);
447
448 strncpy(tag, key, start-key);
449 *(tag+(start-key)) = '\0';
450
451 const char *comma = strstr(start+1,",");
452 if (comma == NULL || comma > finish) { // Parametrized command from Java Client should be in a form like List(1,String1)
453 if(canLog) {
454 logger(L_DBG,"[EX]: findItemInMode: Incorrectly formed parametrized command");
455 }
456 return NULL;
457 }
458
459 if (comma-start > 6) { // 65535 = max value in Comman Fusion iViewer
460 if(canLog) {
461 logger(L_ERR,"[EX]: findItemInMode: Received incorrect index!");
462 }
463 return NULL;
464 }
465 strncpy(index,start+1,comma-start-1);
466 *(index+(comma-start-1)) = '\0';
467
468 strncpy(value,comma+1,finish-comma-1);
469 *(value+(finish-comma-1)) = '\0';
470
471 if(canLog) {
472 sprintf(tmp,"[EX]: Parametrized command parsed as >%s< >%s< >%s< ", tag,index,value);
473 logger(L_DBG,tmp);
474 }
475
476 char * decodedVal = value;
477 int needFree = 0;
478
479 #ifdef USE_ICONV
480 if (needConvert() == 1) {
481 decodedVal = convCharsetSimple(value, CNV_TO);
482 needFree = 1;
483 DEBUG2("[EX]: Decoded string >%s< ", (decodedVal ? decodedVal : "NULL"));
484 }
485 #endif
486
487 // Try to search explicitly specified parametrized command (for ex List(1) or List(commandX))
488 // By index
489 strcat(tag,"(");
490 strcat(tag,index);
491 strcat(tag,")");
492 It = findExact(mode,tag);
493
494 if (It) {
495 if(canLog) {
496 logger(L_DBG,"[EX]: Found exact (explicitly specified by index) parametrized command");
497 }
498 *flag = FLAG_EXACT;
499
500 #ifdef USE_ICONV
501 if (needFree) {
502 free(decodedVal);
503 }
504 #endif
505
506 return It;
507 }
508
509 // Then by value
510 *(tag+(start-key+1)) = '\0';
511 strcat(tag,(decodedVal ? decodedVal : ""));
512 strcat(tag,")");
513 It = findExact(mode,tag);
514
515 if (It) {
516 if(canLog) {
517 logger(L_DBG,"[EX]: Found exact (specified by value) parametrized command");
518 }
519 *flag = FLAG_EXACT;
520
521 #ifdef USE_ICONV
522 if (needFree) {
523 free(decodedVal);
524 }
525 #endif
526
527 return It;
528 }
529
530 // Finally... Search command like ListItem($$)
531 *(tag+(start-key)) = '\0';
532
533 char* keyAndBrace = (char*) calloc(1,strlen(tag)+3);
534 strcpy(keyAndBrace,tag);
535 strcat(keyAndBrace,"($");
536
537 if(canLog) {
538 DEBUG2("[EX]: Search findStartingWith() >%s< ", keyAndBrace);
539 }
540 It = findStartingWith(mode,keyAndBrace);
541 free(keyAndBrace);
542 if (It) {
543 if(canLog) {
544 DEBUG2("EX]: Found parametrized command >%s,%s< ", index,decodedVal);
545 }
546 strcpy(params->index, index);
547 strcpy(params->value, decodedVal);
548
549 *flag = FLAG_PARAMETR;
550
551 #ifdef USE_ICONV
552 if (needFree) {
553 free(decodedVal);
554 }
555 #endif
556
557 return It;
558 }
559
560 #ifdef USE_ICONV
561 if (needFree) {
562 free(decodedVal);
563 }
564 #endif
565 }
566 //if(canLog) {
567 // logger(L_DBG,"[EX]: findItemInMode: not found");
568 //}
569 return NULL;
570 }
571
findItemInModeAndParents(mode * curMode,const char * key,int * flag,cmdParams * params)572 type_key* findItemInModeAndParents(mode* curMode, const char *key, int *flag, cmdParams *params)
573 {
574 DEBUG2("[EX]: findItemInModeAndParents() search in mode %s (parents %s)", curMode->name->str, (curMode->parent ? curMode->parent->str : "no parents"));
575 type_key* tk = findItemInMode(curMode, key, flag, params);
576
577 if (tk == NULL) {
578
579 if (curMode != getDefaultMode() && curMode->parent) {
580
581
582 string_t* parent = stringNew(curMode->parent->str);
583 char* ptrptr = NULL;
584 char* pmode = strtok_r(parent->str,",", &ptrptr);
585
586 while (pmode) {
587
588 // firstly strip spaces from start and tail
589
590 while (*pmode == ' ' || *pmode == '\t') {
591 pmode++;
592 if (*pmode == '\0') {
593 break;
594 }
595 }
596
597 if (*pmode != '\0') {
598
599 char *p2 = pmode + strlen(pmode) - 1;
600
601 while (*p2 == ' ' || *p2 == '\t') {
602 *p2 = '\0';
603 p2--;
604 if (pmode == p2) {
605 break;
606 }
607 }
608
609 if (*pmode != '\0') {
610 mode* tryMode = findMode(pmode);
611 if (tryMode) {
612 tk = findItemInModeAndParents(tryMode, key, flag, params);
613 if (tk) {
614 break;
615 }
616 } else {
617 ERROR2("[EX]: findItemInModeAndParents() parent mode %s not found",pmode);
618 }
619 }
620 }
621 pmode = strtok_r(NULL,",",&ptrptr);
622 }
623 stringFree(parent,BOOL_YES);
624 }
625 }
626
627 return tk;
628 }
629
findItem(const char * keyIn,int * flag,cmdParams * params)630 type_key* findItem(const char *keyIn, int *flag, cmdParams *params)
631 {
632 //logger(L_DBG,"[EX]: findItem()");
633 type_key *tk = NULL;
634
635 if (keyIn == NULL) {
636 return NULL;
637 }
638
639 char key[MAXARGLEN];
640 memset(key,0,MAXARGLEN);
641
642 if (*keyIn == '\0') {
643 logger(L_INF,"[EX]: Got empty key");
644 strcpy(key, EMPTY_STR);
645 } else {
646 strncpy(key, keyIn, MAXARGLEN - 1);
647 }
648
649 mode* curMode = getCurrentMode();
650
651 if (curMode) {
652
653 tk = findItemInModeAndParents(curMode, key, flag, params);
654
655 mode* defMode = getDefaultMode();
656 if (tk == NULL && curMode != defMode) {
657 logger(L_DBG,"[EX]: findItem() search in default");
658 tk = findItemInMode(defMode, key, flag, params);
659 }
660 }
661
662 // Search in "internal" commands
663 if (tk == NULL) {
664 logger(L_DBG,"[EX]: findItem() internal mode");
665 tk = findItemInMode(getInternalMode(), key, flag, params);
666 if (tk != NULL && *flag == FLAG_MULTIKEY) {
667 logger(L_DBG,"[EX]: findItem() multikey in internal command ?");
668 }
669 }
670
671 /*if (tk && tk->cmd) {
672 printf("TRACE %s->%s:%s \n",keyIn,tk->cmd->descr,(tk->cmd->exec ? tk->cmd->exec : "NULL"));
673 } else {
674 printf("TRACE %s->NOT FOUND?\n",keyIn);
675 }*/
676 return tk;
677 }
678
getCommand(type_key * item)679 SingleList *getCommand(type_key* item)
680 {
681 if (!item) {
682 //logger(L_DBG,"[EX]: getCommand(): Empty type_key was got");
683 return NULL;
684 }
685 if (item->key == NULL) {
686 //logger(L_DBG,"[EX]: Empty key was got");
687 return NULL;
688 }
689
690 //sprintf(tmp,"[EX]: getCommand for >%s<", item->key);
691 //logger(L_DBG,tmp);
692
693 return item->commands;
694 }
695
696 //
697 // Print cfg stuff
698 //
printKey(const char * key,SingleList * commands)699 static void printKey(const char* key, SingleList* commands)
700 {
701 sprintf(tmp, "%s=\\\n\t", key);
702
703 SingleList* list = commands;
704 while (list) {
705
706 cmdItem * item = (cmdItem *) list->data;
707 if (!item) continue;
708
709 strcat(tmp, id2Cmd(item->type));
710
711 if (item->descr || item->exec) {
712 strcat(tmp, "(");
713 }
714
715 int pComma = 0;
716 if (item->descr) {
717 //printf("descr %s\n",item->descr);
718 strcat(tmp, item->descr);
719 pComma = 1;
720 }
721 strcat(tmp, "<|>");
722 if (item->exec) {
723 if (pComma) {
724 strcat(tmp, ",");
725 }
726 strcat(tmp, item->exec);
727 }
728
729 if (item->descr || item->exec) {
730 strcat(tmp, ")");
731 }
732 strcat(tmp, ";");
733
734 list = listSingleNext(list);
735
736 if (item && list) {
737 strcat(tmp, "\\");
738 }
739 logger(L_CFG, tmp);
740 sprintf(tmp, "\t");
741
742 }
743 }
744
printKeys(type_key * key)745 void printKeys(type_key* key)
746 {
747 while (key && key->key != NULL) {
748
749 SingleList* commands = getCommand(key);
750
751 if (commands) {
752 printKey(key->key, commands);
753 } else {
754 sprintf(tmp, "\t%s = no command", key->key);
755 logger(L_CFG, tmp);
756 }
757
758 key = (type_key*) key->next;
759 }
760 }
761
setInitDone(void)762 void setInitDone(void)
763 {
764 initDone = 1;
765 }
766
printConf()767 void printConf()
768 {
769 //printf("printConf ENTER\n");fflush(stdout);
770 if (initDone == 0) return; // to avoid dumping several times on initialization
771
772 printModes();
773 printVars ();
774
775 return ;
776 }
777
778 //
779 // Clean-up stuff
780 //
781
destroyCommandItem(void * ptr)782 static void destroyCommandItem(void* ptr)
783 {
784 cmdItem* item = (cmdItem *) ptr;
785
786 if (item->descr != NULL) {
787 free(item->descr);
788 item->descr = NULL;
789 }
790 if (item->exec != NULL) {
791 free(item->exec);
792 item->exec = NULL;
793 }
794 free(item);
795 }
796
freeCmds(SingleList * commands)797 void freeCmds(SingleList* commands)
798 {
799 if (commands) {
800 listSingleFullFree(commands, destroyCommandItem);
801 }
802 }
803
freeCfg(void)804 void freeCfg(void)
805 {
806 logger(L_DBG, "freeCfg()");
807 freeModes(NULL); // delete all modes stuff
808 }
809