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 <ctype.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 
27 #include "lib_wrapper.h"
28 #include "ar_dbus.h"
29 #include "common.h"
30 #include "utils.h"
31 #include "cmds.h"
32 #include "conf.h"
33 #include "executor.h"
34 #include "dispatcher.h"
35 #include "pr_frontend.h"
36 #include "queue.h"
37 #include "timer.h"
38 #include "var.h"
39 #include "peer.h"
40 #include "state.h"
41 
42 extern int   getClip 	(char *string); // from atsend.h
43 
44 extern char	tmp[MAXMAXLEN];
45 
46 extern int  gotSignal;
47 extern boolean_t stillRun;
48 
49 static int  handle_command(int peer, char* cmd);
50 static int  handle_alarm  (char* cmd) ;
51 
52 static int  isBemusedCommand(char *cmd);
53 static int  isInpLircCommand(char *cmd);
54 static int  isLircCommand   (char *cmd);
55 static int  isIViewerCommand(char *cmd);
56 
57 static void handleInit();
58 static void handleConnect();
59 static void handleDisconnect();
60 static void handleExit();
61 
62 static void cleanAutoRepeatFlag();
63 
64 int  commandTimer = 0;
65 int  repeatTimer  = 0;
66 
67 char modifierString [MAXARGLEN];
68 
69 int  flushConf    = 0;
70 
71 SingleList * _peers = NULL;
72 
freeEMessage(void * ptr)73 void freeEMessage(void* ptr)
74 {
75     eMessage *em = (eMessage *) ptr;
76     if (em) {
77         free(em->value);
78         free(em);
79     }
80 }
81 
sendToExecutor(eMessage * buf)82 void sendToExecutor(eMessage *buf)
83 {
84     queuePush(Q_EXEC, (void*) buf);
85 }
86 
freePeerDataList(void * data)87 static void freePeerDataList(void* data)
88 {
89     PeerDef* peer = (PeerDef* ) data;
90     free(peer);
91 }
92 
freePeerData(int id)93 static void freePeerData(int id)
94 {
95     SingleList* list = _peers;
96 
97     while (list) {
98         PeerDef* peer = (PeerDef*) list->data;
99 
100         if (peer->id == id) {
101             DEBUG2("[EX]: Free peer %d data", id);
102             list = listSingleRemove(_peers, peer);
103             freePeerDataList(peer);
104             return;
105         }
106         list = listSingleNext(list);
107     }
108 }
109 
executorCleanup()110 static void executorCleanup()
111 {
112     listSingleFullFree(_peers, freePeerDataList);
113 }
114 
customizePeer(int id,int szX,int szY,int coverSz)115 void customizePeer(int id, int szX, int szY, int coverSz)
116 {
117 
118     // MUTEX ???
119     SingleList* list = _peers;
120 
121     while (list) {
122         PeerDef* peer = (PeerDef*) list->data;
123 
124         if (peer->id == id) {
125             if (szX != -1) {
126 	        peer->xSz = szX;
127 	    }
128             if (szY != -1) {
129                 peer->ySz     = szY;
130             }
131 	    if (coverSz != -1) {
132                 peer->coverSz = coverSz;
133             }
134 	    return;
135         }
136         list = listSingleNext(list);
137     }
138 
139     PeerDef* pd = (PeerDef*) malloc(sizeof(PeerDef));
140     pd->id  = id;
141     pd->xSz = szX;
142     pd->ySz = szY;
143     pd->coverSz = coverSz;
144     DEBUG2("[  ]: Peer data: Sizes %d -> %d %d %d", id, pd->xSz, pd->ySz, pd->coverSz);
145     _peers = listSingleAppend(_peers, pd);
146 }
147 
getEFinalizer()148 static eMessage* getEFinalizer()
149 {
150     eMessage* em = (eMessage*) malloc(sizeof(eMessage));
151     em->peer  = PEER_ANY;
152     em->type  = EM_AS_IS;
153     em->value = strdup("End();");
154 
155     return em;
156 }
157 
sendEventToExecutor(int peer,int event)158 void sendEventToExecutor(int peer, int event)
159 {
160     eMessage* em = (eMessage*) malloc(sizeof(eMessage));
161     em->peer  = peer;
162     em->type  = EM_EVENT;
163     em->value = malloc(sizeof(int));
164     *((int *)em->value) = event;
165 
166     sendToExecutor(em);
167 
168     if (needFinalizer() == EXIT_OK) {
169         sendToExecutor(getEFinalizer());
170     }
171 }
172 
initExecutor()173 static void initExecutor()
174 {
175     dbusInit();
176     //logger(L_INF,"[EX]: DBUS initialized");
177 
178     handleInit();
179     //logger(L_INF,"[EX]: init hooks done");
180 
181     setInitDone();
182     printConf();
183 
184     dMessage* dm = allocDMessage();
185     dm->type     = DM_EVENT;
186     dm->subtype  = ID_EVENT_INIT;
187 
188     sendToDispatcher(dm);
189 }
190 
191 // Should we auto-repeat command (timeout about 1/10 second) ?
doAutoRepeat()192 static void doAutoRepeat()
193 {
194     // Should we auto-repeat command (timeout about 1/10 second) ?
195     if (repeatNow() && getAutoRepeat()) {
196         int isOdd = ((int)repeatTimer/2)*2;
197 
198         if (repeatTimer > 100) {  // Check for infinite loop. Only 50 autorepeats per one press
199             cleanAutoRepeatFlag();
200             return;
201         } else if (repeatTimer > 0 && isOdd == repeatTimer) {
202             DEBUG2("[EX]: Auto repeat command ... (%d)", repeatTimer);
203             handleCmdByKey(PEER_ANY, repeatNow(),NULL);
204         }
205         repeatTimer++;
206     }
207 }
208 
doTimers()209 static void doTimers()
210 {
211     //DEBUG2("[EX]: check timers(%d)", commandTimer);
212     // Verify commands executed by timer (timeout about 1 sec)
213     if (commandTimer == 50) {
214         //logger(L_DBG,"[EX]: Verify timer commands ...");
215         verifyTimerCfg(1) ;
216         commandTimer = 0;
217     } else {
218         commandTimer++;
219     }
220 }
221 
handleKeyMsg(int peer,void * ptr)222 static int handleKeyMsg(int peer, void * ptr)
223 {
224     char * cmd = (char *) ptr;
225     sprintf(tmp, "[EX]: (%d) got key >%s<", peer, (cmd ? cmd : "NULL"));
226     logger(L_DBG, tmp);
227     handle_command(peer, cmd);
228     return 0;
229 }
230 
handleStringMsg(int peer,void * ptr)231 static int handleStringMsg(int peer, void * ptr)
232 {
233     char * msgIn = (char*) ptr;
234     sprintf(tmp, "[EX]: got string >%s<", msgIn);
235     logger(L_DBG, tmp);
236     execDynamically(msgIn);
237     return 0;
238 }
239 
handleEventMsg(int peer,void * ptr)240 static int handleEventMsg(int peer, void* ptr)
241 {
242     int exitFlag = 0;
243     if (ptr == NULL) {
244         return exitFlag;
245     }
246 
247     int* evt = (int*) ptr;
248 
249     if (*evt == ID_EVT_CONNECT) {
250         logger(L_DBG, "[EX]: got event EVT_CONNECT");
251         handleConnect();
252     } else if (*evt == ID_EVT_DISCONNECT) {
253         logger(L_DBG, "[EX]: got event EVT_DISCONNECT");
254         handleDisconnect(peer);
255     //} else if (*evt == ID_EVT_INIT) {
256         //logger(L_DBG, "[EX]: got event EVT_INIT");
257         //  handleInit();
258     } else if (*evt == ID_EVT_EXIT) {
259         logger(L_DBG, "[EX]: got event EVT_EXIT");
260         handleExit();
261         exitFlag = 1;
262     }
263     return exitFlag;
264 }
265 
handleAlarmMsg(int peer,void * ptr)266 static int handleAlarmMsg(int peer, void * ptr)
267 {
268     char * cmd = (char *) ptr;
269     sprintf(tmp, "[EX]: got alarm >%s<", cmd);
270     logger(L_DBG, tmp);
271     handle_alarm(cmd);
272     return 0;
273 }
274 
handleAsIsMsg(int peer,void * ptr)275 static int handleAsIsMsg(int peer, void * ptr)
276 {
277     logger(L_DBG, "[EX]: got as is");
278     char * cmd = (char *) ptr;
279 
280     dMessage* dm = allocDMessage();
281     dm->type     = DM_SET;
282     dm->subtype  = ID_SET_MAX;
283     dm->size     = strlen(cmd);
284     dm->value    = (void*) strdup(cmd);
285 
286     sendToDispatcher(dm);
287     return 0;
288 }
289 
290 static struct {
291     int id;
292     int (*hook)(int peer, void* p);
293 } _msgHooks[] = {
294     {EM_KEY,    handleKeyMsg   },
295     {EM_STRING, handleStringMsg},
296     {EM_EVENT,  handleEventMsg },
297     {EM_ALARM,  handleAlarmMsg },
298     {EM_AS_IS,  handleAsIsMsg  }
299 };
300 
executorRoutine(pointer_t thread)301 pointer_t executorRoutine(pointer_t thread)
302 {
303     if (queueExists(Q_EXEC) != RC_OK) {
304         logger(L_INF,"[EX]: Do not start executor thread");
305         return NULL;
306     }
307 
308     logger(L_INF,"[EX]: Start executor thread");
309     initExecutor();
310 
311     while (stillRun) {
312 
313         eMessage *em = (eMessage *) queuePop(Q_EXEC);
314         if (em != NULL) {
315 
316             DEBUG2("[EX]: got event from %d", em->peer);
317 
318             int exitFlag = (_msgHooks[em->type].hook)(em->peer, em->value);
319 
320             freeEMessage(em);
321 
322             if (exitFlag) {
323                 break;
324             }
325         }
326         //logger(L_DBG, "[EX]: command processed of empty input");
327 
328         // Should we auto-repeat command (timeout about 1/10 second) ?
329         doAutoRepeat();
330 
331         // Timers check (once per second)
332         doTimers();
333 
334         if (!stillRun) {
335             logger(L_DBG,"[EX]: Break from loop ...");
336             break;
337         }
338 
339         //logger(L_DBG, "[EX]: wait a bit");
340         usleep(20000); // loop timer (1/50 of second)
341     }
342 
343     executorCleanup();
344 
345     DEBUG2("[EX]: thread stopped");
346     return NULL;
347 }
348 
handleInit()349 static void handleInit()
350 {
351     int i = 0;
352     type_key *k = findItem(EVT_INIT, &i, NULL);
353     if (k && i == FLAG_EXACT) {
354         logger(L_INF, "[EX]: Exec cmd on init");
355         handleCmdByKey(PEER_ANY,k,NULL);
356     }
357     handleHook(ID_EVT_INIT);
358 }
359 
handleConnect()360 static void handleConnect()
361 {
362     int i = 0;
363     int ok1 = EXIT_NOK;
364     type_key *k = findItem(EVT_CONNECT, &i, NULL);
365     if (k && i == FLAG_EXACT) {
366         logger(L_INF, "[EX]: Exec cmd on connect");
367         ok1 = EXIT_OK;
368 
369         handleCmdByKey(PEER_ANY,k,NULL);
370     }
371     int ok2 = handleHook(ID_EVT_CONNECT);
372 
373     if (ok1 == EXIT_OK || ok2 == EXIT_OK) {
374         if (needFinalizer() == EXIT_OK) {
375             sendToDispatcher(getDFinalizer());
376         }
377     }
378 }
379 
handleDisconnect(int peer)380 static void handleDisconnect(int peer)
381 {
382     int i = 0;
383 
384     cleanAutoRepeatFlag();
385     freePeerData(peer);
386 
387     type_key *k = findItem(EVT_DISCONNECT, &i, NULL);
388     if (k && i == FLAG_EXACT) {
389         logger(L_INF, "[EX]: Exec cmd on disconnect");
390         handleCmdByKey(PEER_ANY,k,NULL);
391     }
392     handleHook(ID_EVT_DISCONNECT);
393 }
394 
handleExit()395 static void handleExit()
396 {
397     //printf("[EX]: handleExit\n");
398 
399     freeTimers(NULL);
400 
401     //printf("[EX]: handleExit EVT_EXIT\n");
402 
403     int i;
404     type_key *k = findItem(EVT_EXIT, &i, NULL);
405     if (k && i == FLAG_EXACT) {
406         logger(L_INF, "[EX]: Exec cmd on exit");
407         handleCmdByKey(PEER_ANY,k,NULL);   // Since we exiting now we did not interested in return code
408     }
409 
410     //printf("[EX]: handleExit handleHook\n");
411 
412     handleHook(ID_EVT_EXIT);
413 
414     //printf("[EX]: handleExit free data\n");
415 
416     freeTimers(NULL);  // can we create timer in (Exit) ???
417     freeVars();
418     freeCfg();
419     freeRegexps();
420     dbusFinish();
421 
422     freeState();
423 
424     //printf("[EX]: handleExit EXIT\n");
425 }
426 
cleanAutoRepeatFlag()427 static void cleanAutoRepeatFlag()
428 {
429     // Clear auto repeat flag
430     logger(L_DBG,"[EX]: Clean auto repeat flag");
431     setRepeatNow(NULL);
432     repeatTimer  = 0;
433 }
434 
handle_alarm(char * key)435 static int handle_alarm(char* key)
436 {
437     DEBUG2("[EX]: handle_alarm() >%s<", (key ? key : "NULL"));
438 
439     if (!key) {
440         return EXIT_OK;
441     }
442 
443     int i;
444     cmdParams params;
445     type_key *k = findItem(key , &i, &params);
446 
447     if (k && i == FLAG_EXACT) {
448         handleCmdByKeyEx(PEER_ANY,k, NULL, 0);
449 
450         if (flushConf == 1) {
451             logger(L_DBG, "[EX]: Flush old configuration");
452             flushConf = 0;
453 
454             flushOldConf();
455         }
456 
457     }
458     // else do nothing
459 
460     return EXIT_OK;
461 }
462 
handle_key_press(int peer,char * key,int isRepeatable)463 static int handle_key_press(int peer, char* key, int isRepeatable)
464 {
465     DEBUG2("[EX]: handle_key_press() >%s<", (key ? key :  "NULL"));
466     if (!key) {
467         return EXIT_OK;
468     }
469 
470     if (peer != 0 && strncmp("CoverSize(",key,10) == 0) {
471         int v = 0;
472         int i = 10;
473         while (isdigit(*(key+i))) {
474             v = v*10 + (*(key+i) - '0');
475             i++;
476         }
477         DEBUG2("[EX]: CoverSize: %d >%d<", peer, v);
478         customizePeer(peer, -1, -1, v);
479     }
480     if (peer != 0 && strncmp("SizeX(",key,6) == 0) {
481         int v = 0;
482         int i = 6;
483         while (isdigit(*(key+i))) {
484             v = v*10 + (*(key+i) - '0');
485             i++;
486         }
487         DEBUG2("[EX]: SizeX: %d >%d<", peer, v);
488         customizePeer(peer, v, -1, -1);
489     }
490     if (peer != 0 && strncmp("SizeY(",key,6) == 0) {
491         int v = 0;
492         int i = 6;
493         while (isdigit(*(key+i))) {
494             v = v*10 + (*(key+i) - '0');
495             i++;
496         }
497         DEBUG2("[EX]: SizeY: %d >%d<", peer, v);
498         customizePeer(peer, -1, v, -1);
499     }
500 
501     // If modifier was set already it needs to verify which sequence we go
502     if (modifierString[0] != '\0') {
503         strcat(modifierString," "); // Add one space first
504         strcat(modifierString, key);
505         DEBUG2("[EX]: Modifier+sequence is: >%s<", modifierString);
506     }
507 
508     // Execute appropriate command
509     int i;
510     cmdParams params;
511     type_key *k = findItem((modifierString[0] == '\0' ? key : modifierString), &i, &params);
512 
513     if (k && i == FLAG_EXACT) {
514         if (isRepeatable && (!repeatNow()) && getAutoRepeat()) {
515             logger(L_DBG, "[EX]: Set auto repeat flag");
516             setRepeatNow(k);
517         }
518         handleCmdByKey(peer, k, NULL);
519 
520         // Clean modifier string
521         modifierString[0] = '\0';
522 
523         if (flushConf == 1) {
524             logger(L_DBG, "[EX]: Flush old configuration");
525             flushConf = 0;
526 
527             flushOldConf();
528         }
529 
530     } else if (k && i == FLAG_MULTIKEY) {
531         logger(L_DBG, "[EX]: Got part of multi keys sequence. Nothing to do.");
532         if (modifierString[0] == '\0') {
533             logger(L_DBG, "[EX]: Start of multi key sequence");
534             strcpy(modifierString, key);
535         }
536 
537         if (needAtMainMenuReturn(peer)) {
538             sendToMainMenu(peer);
539         }
540     } else if (k && i == FLAG_PARAMETR) {
541         logger(L_DBG, "[EX]: Got parametrized command");
542 
543         handleCmdByKey(peer, k, &params);
544 
545         // Clean modifier string
546         modifierString[0] = '\0';
547 
548     } else {
549         // User had pressed some key ...
550         // Send ToMainMenu sequence of CKPD's to show main menu again
551         if (needAtMainMenuReturn(peer)) {
552             sendToMainMenu(peer);
553         }
554 
555         logger(L_DBG, "[EX]: No approprite key definition was found");
556         if (modifierString[0] != '\0') {
557             // Clean modifier string
558             modifierString[0] = '\0';
559             logger(L_DBG, "[EX]: Clean modifier string");
560         }
561     }
562 
563     return EXIT_OK;
564 }
565 
handle_at_command(int peer,char * cmd)566 static int handle_at_command(int peer, char* cmd)
567 {
568     // Handle different keypresses
569     // Motorola: +CKEV: "1",1
570     // SE	   : +CKEV: 1,1
571     // Sagem: in rare ) cases it could be (between > and <) >,1:< ?
572 
573     int isSE = MODEL_SE;
574 
575     char *key = cmd+7;
576 
577     // Sagem test
578     // key+=3;
579 
580     if (*key == '"') {	// Seems this is Motorola
581         key++;
582         //logger(L_DBG,"[EX]: +CKEV is in Motorola format");
583         isSE = MODEL_MOTOROLA;
584     }
585 
586     if (*key == ',') {	// Seems this is Sagem
587         logger(L_DBG,"[EX]: +CKEV is in rare Sagem format (Empty code)");
588         isSE = MODEL_SAGEM;
589     }
590 
591     int i = 1;
592 
593     if (isSE == MODEL_SE) { 	// SonyEricsson & default
594         while(key[i] != ',') {
595             i++;
596         }
597         key[i] ='\0';
598 
599         i = i+1;
600     } else if (isSE == MODEL_MOTOROLA) {	// Motorola
601         while(key[i] != '"') {
602             i++;
603         }
604         key[i] ='\0';
605 
606         i = i+2;
607     } else if (isSE == MODEL_SAGEM) {	// rare Sagem case
608         *key ='\0';
609     } else {
610         logger(L_ERR,"[EX]: Can't recognize +CKEV event !!!");
611         return EXIT_NOK;
612     }
613 
614     if (key[i] == '1') {
615         //logger(L_DBG,"[EX]: Button down event");
616 
617         dMessage* dm = allocDMessage();
618         dm->type     = DM_EVENT;
619         dm->subtype  = ID_EVENT_FRONTEND;
620         dm->value    = (void*) strdup(key);
621         dm->size     = strlen(key);
622 
623         sendToDispatcher(dm);
624 
625         return handle_key_press(peer,key,1);
626 
627     } else if (key[i] == '0') {
628 
629         //logger(L_DBG,"[EX]: Button up event");
630         // In general we skip this
631         cleanAutoRepeatFlag();
632         return EXIT_OK;
633 
634     }
635 
636     //else
637     DEBUG2("[EX]: something wrong: key should be pressed or released: cmd=>%s< char=>%c<", cmd, key[i]);
638     return EXIT_NOK;
639 }
640 
handle_command(int peer,char * cmd)641 static int handle_command(int peer, char* cmd)
642 {
643     //logger(L_DBG,"[EX]: handle_command");
644     if (!cmd) {
645         return EXIT_OK;
646     }
647 
648     if (memcmp(cmd, DEF_MSG, 4) == 0) {	    // Got event from Java client
649 
650         logger(L_DBG,"[EX]: Got event from client");
651         return handle_key_press(peer, cmd+4, 0);
652 
653     } else if (memcmp(cmd, DEF_CKEV, 6) == 0) {
654 
655         return handle_at_command(peer, cmd);
656 
657     } else if (memcmp(cmd, DEF_CLCC,6) == 0) {
658 
659         //logger(L_INF,"[EX]: Caller ID received. Skip it.");
660         return EXIT_OK;
661 
662     } else if (strstr(cmd, DEF_RING) != NULL) {	    // Incoming call, this event sent periodically until used answered a call
663 
664         logger(L_INF,"[EX]: Incoming call notification. Skip it."); // Handled inside peer read function
665         return EXIT_OK;
666 
667     } else if (isLircCommand(cmd)) {	    // LIRC tricks
668         return EXIT_OK;
669     } else if (isInpLircCommand(cmd)) {	    // inputLIRC tricks
670         return EXIT_OK;
671     } else if (isBemusedCommand(cmd)) {	    // Bemused server emulation tricks
672         return EXIT_OK;
673     } else if (isIViewerCommand(cmd)) {	    // CommandFusion iViewer protocol support
674         return EXIT_OK;
675     } else { // SERVER_STDIN ? Just direct input, try it
676 
677         //printf("DEBUG: Is it SERVER_STDIN ? %s\n", cmd);
678         char *p = cmd;
679         while (*p != '\0') {
680             if (*p == '\n') {
681                 *p = '\0';
682                 break;
683             }
684             p++;
685         }
686 
687         return handle_key_press(peer,cmd,1);
688     }
689 
690     DEBUG2("[EX]: Unhandled cmd %s", cmd);
691     return EXIT_OK;
692 }
693 
694 //
695 // Should be used in AT mode only
696 //
sendToMainMenu(int peer)697 void sendToMainMenu(int peer)
698 {
699     logger(L_INF,"[EX]: sendToMainMenu");
700     char *tmm = NULL;
701     if ((tmm = getToMainMenu()) != NULL) {
702 
703         dMessage* dm = allocDMessage();
704         dm->peer     = peer;
705         dm->type     = DM_CKPD;
706         dm->subtype  = ID_SET_MAX;
707         dm->value    = (void*) tmm;
708         dm->size     = strlen((char*) dm->value);
709 
710         sendToDispatcher(dm);
711     }
712 }
713 
714 //
715 // Bemused server limited emulation
716 // we could get more than one command at once
717 //
718 
isBemusedCommand(char * cmdIn)719 static int isBemusedCommand(char *cmdIn)
720 {
721     DEBUG2("[EX]: isBemusedCommand: >%s<",cmdIn);
722 
723     int isBemused = 0;
724 
725     char *cmd = cmdIn;
726     char *last = cmdIn + strlen(cmdIn);
727 
728     while (cmd < last) {
729         int handle = 0;
730         int shift  = 4;
731 
732         char oneCmd[16];
733         memset(oneCmd,0,16);
734 
735         char paramValue[8];
736         paramValue[0] = '\0';
737 
738         if (strncmp(cmd, "CHCK", 4) == 0 ||
739                 strncmp(cmd, "DINF", 4) == 0 ||
740                 strncmp(cmd, "EXIT", 4) == 0 ||
741                 strncmp(cmd, "FADE", 4) == 0 ||
742                 strncmp(cmd, "FFWD", 4) == 0 ||
743                 strncmp(cmd, "GVOL", 4) == 0 ||
744                 strncmp(cmd, "INF2", 4) == 0 ||
745                 strncmp(cmd, "INF",  3) == 0 ||
746                 strncmp(cmd, "LIST", 4) == 0 ||
747                 strncmp(cmd, "NEXT", 4) == 0 ||
748                 strncmp(cmd, "PAUS", 4) == 0 ||
749                 strncmp(cmd, "PLEN", 4) == 0 ||
750                 strncmp(cmd, "PLST", 4) == 0 ||
751                 strncmp(cmd, "PREV", 4) == 0 ||
752                 strncmp(cmd, "RMAL", 4) == 0 ||
753                 strncmp(cmd, "RWND", 4) == 0 ||
754                 strncmp(cmd, "SHUT", 4) == 0 ||
755                 strncmp(cmd, "STEN", 4) == 0 ||
756                 strncmp(cmd, "STOP", 4) == 0 ||
757                 strncmp(cmd, "STRT", 4) == 0 ||
758                 strncmp(cmd, "VERS", 4) == 0) {
759             handle = 1;
760         }
761 
762         if (strncmp(cmd, "VOLM", 4) == 0 ||
763                 strncmp(cmd, "REPT", 4) == 0 ||
764                 strncmp(cmd, "SHFL", 4) == 0) {
765 
766             unsigned char bc;
767 
768             // this must be handled in dispatcher thread
769             if (strlen(cmd) == 4) {
770                 if (strncmp(cmd, "VOLM", 4) == 0 && strlen(cmd) == 4) {  // read only VOLM without value to set
771                     ERROR2("[EX]: isBemusedCommand: %s without value", cmd);
772                     return 1;		// do nothing, but treat it as Bemused command
773                 }
774 
775                 // It is possible for REPT/SHFL: toggle command
776                 handle = 1;
777 
778             } else {
779                 bc = ((unsigned char) *(cmd + 4));
780 
781                 if (strncmp(cmd, "VOLM", 4) == 0) {
782                     // VOLM 0-255 -> 0%-100%
783                     sprintf(paramValue, "%d", ((int)bc * 100)/255);
784                     DEBUG2("[EX]: isBemusedCommand: VOLM parameter >%s<", paramValue);
785                 } else {
786                     // 0/1
787                     sprintf(paramValue, "%d", ((int)bc == 0 ? 0 : 1));
788                     DEBUG2("[EX]: isBemusedCommand: %s parameter >%s<", cmd, paramValue);
789                 }
790                 handle = 1;
791                 shift  = 5;
792             }
793         }
794         if (strncmp(cmd, "SLCT", 4) == 0) {
795 
796             unsigned char bc1 = *((unsigned char*) (cmd + 4));
797             unsigned char bc2 = *((unsigned char*) (cmd + 5));
798 
799             unsigned int ix = bc1*256+bc2;
800             sprintf(paramValue, "%d",ix);
801 
802             DEBUG2("[EX]: isBemusedCommand: SLCT parameter >%s<", paramValue);
803 
804             handle = 1;
805             shift  = 6;
806         }
807         if (strncmp(cmd, "SEEK", 4) == 0)  {
808 
809             sprintf(paramValue, "%d",
810                     (((unsigned char)*(cmd + 4)) << 24) +
811                     (((unsigned char)*(cmd + 5)) << 16) +
812                     (((unsigned char)*(cmd + 6)) << 8)  +
813                     (unsigned char)*(cmd + 7));
814 
815             handle = 1;
816             shift  = 8;
817         }
818         if (strncmp(cmd, "DLST", 4) == 0 ||
819                 strncmp(cmd, "DOWN", 4) == 0 ||
820                 strncmp(cmd, "FINF", 4) == 0 ||
821                 strncmp(cmd, "LADD", 4) == 0 ||
822                 strncmp(cmd, "PLAY", 4) == 0) {
823 
824             unsigned char bc = *((unsigned char*) (cmd + 4));
825             sprintf(paramValue, "%d",bc);
826 
827             shift  = 5 + bc;
828             handle = 1;
829         }
830         if (handle) {
831             isBemused = 1;
832             strncpy(oneCmd,cmd,4);
833             oneCmd[4] = '\0';
834             if (paramValue[0] != '\0') {
835                 strcat(oneCmd,"(-1,");
836                 strcat(oneCmd,paramValue);
837                 strcat(oneCmd,")");
838             }
839 
840             DEBUG2("[EX]: isBemusedCommand: one command >%s<", oneCmd);
841 
842             handle_key_press(PEER_ANY,oneCmd,1);
843         } else {
844             break;
845         }
846 
847         cmd = cmd + shift;
848     }
849     return isBemused;
850 }
851 
852 //
853 // LIRC dev/event handling
854 //
855 
isLircCommand(char * cmdIn)856 static int isLircCommand(char *cmdIn)
857 {
858     //  should got replay in form "0000000000010184 00 TEXT linux-input-layer"
859     //                            "0000000000010192 00 CHANNELUP linux-input-layer"
860     DEBUG2("[EX]: isLircCommand: >%s<",cmdIn);
861 
862     char *cmd = strdup(cmdIn);
863     char *bufPtr = NULL;
864 
865     if (strncmp(cmdIn, "000000",6) != 0) {
866         free(cmd);
867         return 0;
868     }
869 
870     char *token = strtok_r(cmd," ",&bufPtr);
871     if (token == NULL) {
872         free(cmd);
873         return 0;
874     }
875 
876     token = strtok_r(NULL," ",&bufPtr);
877     if (token == NULL) {
878         free(cmd);
879         return 0;
880     }
881 
882     token = strtok_r(NULL," ",&bufPtr);
883     if (token == NULL) {
884         free(cmd);
885         return 0;
886     }
887     handle_key_press(PEER_ANY,token,1);
888 
889     free(cmd);
890     return 1;
891 }
892 
893 //
894 // inputlirc dev/event handling
895 //
isInpLircCommand(char * cmdIn)896 static int isInpLircCommand(char *cmdIn)
897 {
898     // should got replay in form "2 0 KEY_1 event6"
899 
900     DEBUG2("[EX]: isInputLircCommand: >%s<",cmdIn);
901 
902     /*char *f = cmdIn;
903     sprintf(tmp, "isLircCommand: DUMP >%c< >%d<",*f,*f);
904         logger(L_DBG,tmp);
905     */
906 
907     int isLirc = 1;
908 
909     char *data = NULL;
910     char *cmd = strdup(cmdIn);
911     char *bufPtr = NULL;
912     char *token = strtok_r(cmd," ",&bufPtr);
913     if (token == NULL) {
914         free(cmd);
915         return 0;
916     }
917 
918     token = strtok_r(NULL," ",&bufPtr);
919     if (token == NULL) {
920         free(cmd);
921         return 0;
922     }
923 
924     token = strtok_r(NULL," ",&bufPtr);
925     if (token &&
926         (strncmp(token, "KEY_",4)==0 ||
927          strstr(token, "_KEY_")      || // can be CTRL_ALT_KEY_F3
928 	     strncmp(token, "BTN_",4)==0)) {
929         data = token;
930         token = strtok_r(NULL," ",&bufPtr);
931         if (token && strstr(token, "event") == NULL) {  // /dev/input/eventX or eventX
932  	    isLirc = 0;
933         }
934     } else {
935 	isLirc = 0;
936     }
937 
938     if (isLirc) {
939         DEBUG2("[EX]: isLircCommand: one command >%s<", data);
940         handle_key_press(PEER_ANY,data,1);
941     }
942 
943     free(cmd);
944     return isLirc;
945 }
946 
947 //
948 // Command Fusion iViewer protocol support
949 //
isIViewerCommand(char * cmdIn)950 static int isIViewerCommand(char *cmdIn)
951 {
952     // should got replay in form
953     // aXX=value\3
954     // dXX=value\3
955     // h=0\3
956     // i=1\3
957     // lXX=value\3	-- not yet supported
958     // m=[portrait|landscape]\3
959     // p=value\3
960     // sXX=value\3
961     // n=value
962 
963     DEBUG2("[EX]: isIViewerCommand: >%s<",cmdIn);
964 
965     char* cmdTmp = (char*) calloc(strlen(cmdIn) + 1, sizeof(char));
966     strcpy(cmdTmp,cmdIn);
967 
968     if (!((cmdTmp[0] == 'a' && isdigit(cmdTmp[1])) ||
969           (cmdTmp[0] == 'd' && isdigit(cmdTmp[1])) ||
970           (cmdTmp[0] == 'l' && isdigit(cmdTmp[1])) ||
971           (cmdTmp[0] == 's' && isdigit(cmdTmp[1])) ||
972           (cmdTmp[0] == 'm' && cmdTmp[1] == '=')   ||
973           (cmdTmp[0] == 'p' && cmdTmp[1] == '=')   ||
974           (cmdTmp[0] == 'n' && cmdTmp[1] == '=')   ||
975           strcmp(cmdTmp, "h=0") == 0 ||
976           strcmp(cmdTmp, "i=1") == 0
977          )) {
978         free(cmdTmp);
979         return 0;
980     }
981 
982     char *bufPtr = NULL;
983     char *token = strtok_r(cmdTmp,"=",&bufPtr);
984     if (token == NULL) {
985         free(cmdTmp);
986         return 0;
987     }
988     token = strtok_r(NULL,"=",&bufPtr);
989 
990     DEBUG2("[EX]: isIViewerCommand: OK >%d<", (int) strlen(cmdIn) + 6);
991 
992     char* cmd = (char*) calloc(strlen(cmdIn) + 6, sizeof(char));
993     strcpy(cmd,cmdTmp);
994 
995     strcat(cmd,"(");
996     if (cmdTmp[0] == 'm' ||
997         cmdTmp[0] == 'p' ||
998         cmdTmp[0] == 's' ||
999         cmdTmp[0] == 'n') {
1000 
1001         strcat(cmd,"-1,");
1002         if (token != NULL) {
1003             strcat(cmd,token);      // token is string
1004         }
1005 
1006         strcat(cmd,")");
1007     } else {
1008         if (token != NULL) {
1009             strcat(cmd,token);	// token is numeric
1010         }
1011         strcat(cmd,",)");
1012     }
1013     free(cmdTmp);
1014 
1015     DEBUG2("[EX]: isIViewerCommand: one command >%s<", cmd);
1016     handle_key_press(PEER_ANY,cmd,1);
1017 
1018     logger(L_INF, "[EX]: isIViewerCommand: EXIT");
1019     free(cmd);
1020     return 1;
1021 }
1022