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