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, ¶ms);
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, ¶ms);
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, ¶ms);
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