//
// anyRemote
// a wi-fi or bluetooth remote for your PC.
//
// Copyright (C) 2006-2016 Mikhail Fedotov <anyremote@mail.ru>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
//

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "lib_wrapper.h"
#include "ar_dbus.h"
#include "common.h"
#include "utils.h"
#include "cmds.h"
#include "conf.h"
#include "executor.h"
#include "dispatcher.h"
#include "pr_frontend.h"
#include "queue.h"
#include "timer.h"
#include "var.h"
#include "peer.h"
#include "state.h"

extern int   getClip 	(char *string); // from atsend.h

extern char	tmp[MAXMAXLEN];

extern int  gotSignal;
extern boolean_t stillRun;

static int  handle_command(int peer, char* cmd);
static int  handle_alarm  (char* cmd) ;

static int  isBemusedCommand(char *cmd);
static int  isInpLircCommand(char *cmd);
static int  isLircCommand   (char *cmd);
static int  isIViewerCommand(char *cmd);

static void handleInit();
static void handleConnect();
static void handleDisconnect();
static void handleExit();

static void cleanAutoRepeatFlag();

int  commandTimer = 0;
int  repeatTimer  = 0;

char modifierString [MAXARGLEN];

int  flushConf    = 0;

SingleList * _peers = NULL;

void freeEMessage(void* ptr)
{
    eMessage *em = (eMessage *) ptr;
    if (em) {
        free(em->value);
        free(em);
    }
}

void sendToExecutor(eMessage *buf)
{
    queuePush(Q_EXEC, (void*) buf);
}

static void freePeerDataList(void* data)
{
    PeerDef* peer = (PeerDef* ) data;
    free(peer);
}

static void freePeerData(int id)
{
    SingleList* list = _peers;
    
    while (list) {
        PeerDef* peer = (PeerDef*) list->data;
        
        if (peer->id == id) {
            DEBUG2("[EX]: Free peer %d data", id);
            list = listSingleRemove(_peers, peer);
            freePeerDataList(peer);
            return;
        }
        list = listSingleNext(list);
    }
}

static void executorCleanup()
{
    listSingleFullFree(_peers, freePeerDataList);
}

void customizePeer(int id, int szX, int szY, int coverSz)
{
    
    // MUTEX ???
    SingleList* list = _peers;
    
    while (list) {
        PeerDef* peer = (PeerDef*) list->data;
        
        if (peer->id == id) {
            if (szX != -1) {
	        peer->xSz = szX;
	    }
            if (szY != -1) {
                peer->ySz     = szY;
            }
	    if (coverSz != -1) {
                peer->coverSz = coverSz;
            }
	    return;
        }
        list = listSingleNext(list);
    }

    PeerDef* pd = (PeerDef*) malloc(sizeof(PeerDef));
    pd->id  = id;
    pd->xSz = szX; 
    pd->ySz = szY; 
    pd->coverSz = coverSz; 
    DEBUG2("[  ]: Peer data: Sizes %d -> %d %d %d", id, pd->xSz, pd->ySz, pd->coverSz);
    _peers = listSingleAppend(_peers, pd);
}

static eMessage* getEFinalizer()
{
    eMessage* em = (eMessage*) malloc(sizeof(eMessage));
    em->peer  = PEER_ANY;
    em->type  = EM_AS_IS;
    em->value = strdup("End();");

    return em;
}

void sendEventToExecutor(int peer, int event)
{
    eMessage* em = (eMessage*) malloc(sizeof(eMessage));
    em->peer  = peer;
    em->type  = EM_EVENT;
    em->value = malloc(sizeof(int));
    *((int *)em->value) = event;

    sendToExecutor(em);

    if (needFinalizer() == EXIT_OK) {
        sendToExecutor(getEFinalizer());
    }
}

static void initExecutor()
{
    dbusInit();
    //logger(L_INF,"[EX]: DBUS initialized");

    handleInit();
    //logger(L_INF,"[EX]: init hooks done");

    setInitDone();
    printConf();

    dMessage* dm = allocDMessage();
    dm->type     = DM_EVENT;
    dm->subtype  = ID_EVENT_INIT;

    sendToDispatcher(dm);
}

// Should we auto-repeat command (timeout about 1/10 second) ?
static void doAutoRepeat()
{
    // Should we auto-repeat command (timeout about 1/10 second) ?
    if (repeatNow() && getAutoRepeat()) {
        int isOdd = ((int)repeatTimer/2)*2;

        if (repeatTimer > 100) {  // Check for infinite loop. Only 50 autorepeats per one press
            cleanAutoRepeatFlag();
            return;
        } else if (repeatTimer > 0 && isOdd == repeatTimer) {
            DEBUG2("[EX]: Auto repeat command ... (%d)", repeatTimer);
            handleCmdByKey(PEER_ANY, repeatNow(),NULL);
        }
        repeatTimer++;
    }
}

static void doTimers()
{
    //DEBUG2("[EX]: check timers(%d)", commandTimer);
    // Verify commands executed by timer (timeout about 1 sec)
    if (commandTimer == 50) {
        //logger(L_DBG,"[EX]: Verify timer commands ...");
        verifyTimerCfg(1) ;
        commandTimer = 0;
    } else {
        commandTimer++;
    }
}

static int handleKeyMsg(int peer, void * ptr)
{
    char * cmd = (char *) ptr;
    sprintf(tmp, "[EX]: (%d) got key >%s<", peer, (cmd ? cmd : "NULL"));
    logger(L_DBG, tmp);
    handle_command(peer, cmd);
    return 0;
}

static int handleStringMsg(int peer, void * ptr)
{
    char * msgIn = (char*) ptr;
    sprintf(tmp, "[EX]: got string >%s<", msgIn);
    logger(L_DBG, tmp);
    execDynamically(msgIn);
    return 0;
}

static int handleEventMsg(int peer, void* ptr)
{
    int exitFlag = 0;
    if (ptr == NULL) {
        return exitFlag;
    }
    
    int* evt = (int*) ptr;

    if (*evt == ID_EVT_CONNECT) {
        logger(L_DBG, "[EX]: got event EVT_CONNECT");
        handleConnect();
    } else if (*evt == ID_EVT_DISCONNECT) {
        logger(L_DBG, "[EX]: got event EVT_DISCONNECT");
        handleDisconnect(peer);
    //} else if (*evt == ID_EVT_INIT) {
        //logger(L_DBG, "[EX]: got event EVT_INIT");
        //  handleInit();
    } else if (*evt == ID_EVT_EXIT) {
        logger(L_DBG, "[EX]: got event EVT_EXIT");
        handleExit();
        exitFlag = 1;
    }
    return exitFlag;
}

static int handleAlarmMsg(int peer, void * ptr)
{
    char * cmd = (char *) ptr;
    sprintf(tmp, "[EX]: got alarm >%s<", cmd);
    logger(L_DBG, tmp);
    handle_alarm(cmd);
    return 0;
}

static int handleAsIsMsg(int peer, void * ptr)
{
    logger(L_DBG, "[EX]: got as is");
    char * cmd = (char *) ptr;

    dMessage* dm = allocDMessage();
    dm->type     = DM_SET;
    dm->subtype  = ID_SET_MAX;
    dm->size     = strlen(cmd);
    dm->value    = (void*) strdup(cmd);

    sendToDispatcher(dm);
    return 0;
}

static struct {
    int id;
    int (*hook)(int peer, void* p);
} _msgHooks[] = {
    {EM_KEY,    handleKeyMsg   },
    {EM_STRING, handleStringMsg},
    {EM_EVENT,  handleEventMsg },
    {EM_ALARM,  handleAlarmMsg },
    {EM_AS_IS,  handleAsIsMsg  }
};

pointer_t executorRoutine(pointer_t thread)
{
    if (queueExists(Q_EXEC) != RC_OK) {
        logger(L_INF,"[EX]: Do not start executor thread");
        return NULL;
    }

    logger(L_INF,"[EX]: Start executor thread");
    initExecutor();

    while (stillRun) {

        eMessage *em = (eMessage *) queuePop(Q_EXEC);
        if (em != NULL) {
            
            DEBUG2("[EX]: got event from %d", em->peer);

            int exitFlag = (_msgHooks[em->type].hook)(em->peer, em->value);

            freeEMessage(em);

            if (exitFlag) {
                break;
            }
        }
        //logger(L_DBG, "[EX]: command processed of empty input");

        // Should we auto-repeat command (timeout about 1/10 second) ?
        doAutoRepeat();

        // Timers check (once per second)
        doTimers();

        if (!stillRun) {
            logger(L_DBG,"[EX]: Break from loop ...");
            break;
        }

        //logger(L_DBG, "[EX]: wait a bit");
        usleep(20000); // loop timer (1/50 of second)
    }
    
    executorCleanup();
    
    DEBUG2("[EX]: thread stopped");
    return NULL;
}

static void handleInit()
{
    int i = 0;
    type_key *k = findItem(EVT_INIT, &i, NULL);
    if (k && i == FLAG_EXACT) {
        logger(L_INF, "[EX]: Exec cmd on init");
        handleCmdByKey(PEER_ANY,k,NULL);
    }
    handleHook(ID_EVT_INIT);
}

static void handleConnect()
{
    int i = 0;
    int ok1 = EXIT_NOK;
    type_key *k = findItem(EVT_CONNECT, &i, NULL);
    if (k && i == FLAG_EXACT) {
        logger(L_INF, "[EX]: Exec cmd on connect");
        ok1 = EXIT_OK;

        handleCmdByKey(PEER_ANY,k,NULL);
    }
    int ok2 = handleHook(ID_EVT_CONNECT);

    if (ok1 == EXIT_OK || ok2 == EXIT_OK) {
        if (needFinalizer() == EXIT_OK) {
            sendToDispatcher(getDFinalizer());
        }
    }
}

static void handleDisconnect(int peer)
{
    int i = 0;

    cleanAutoRepeatFlag();
    freePeerData(peer);

    type_key *k = findItem(EVT_DISCONNECT, &i, NULL);
    if (k && i == FLAG_EXACT) {
        logger(L_INF, "[EX]: Exec cmd on disconnect");
        handleCmdByKey(PEER_ANY,k,NULL);
    }
    handleHook(ID_EVT_DISCONNECT);
}

static void handleExit()
{
    //printf("[EX]: handleExit\n");

    freeTimers(NULL);

    //printf("[EX]: handleExit EVT_EXIT\n");

    int i;
    type_key *k = findItem(EVT_EXIT, &i, NULL);
    if (k && i == FLAG_EXACT) {
        logger(L_INF, "[EX]: Exec cmd on exit");
        handleCmdByKey(PEER_ANY,k,NULL);   // Since we exiting now we did not interested in return code
    }

    //printf("[EX]: handleExit handleHook\n");

    handleHook(ID_EVT_EXIT);

    //printf("[EX]: handleExit free data\n");

    freeTimers(NULL);  // can we create timer in (Exit) ???
    freeVars();
    freeCfg();
    freeRegexps();
    dbusFinish();
    
    freeState();

    //printf("[EX]: handleExit EXIT\n");
}

static void cleanAutoRepeatFlag()
{
    // Clear auto repeat flag
    logger(L_DBG,"[EX]: Clean auto repeat flag");
    setRepeatNow(NULL);
    repeatTimer  = 0;
}

static int handle_alarm(char* key)
{
    DEBUG2("[EX]: handle_alarm() >%s<", (key ? key : "NULL"));

    if (!key) {
        return EXIT_OK;
    }

    int i;
    cmdParams params;
    type_key *k = findItem(key , &i, &params);

    if (k && i == FLAG_EXACT) {
        handleCmdByKeyEx(PEER_ANY,k, NULL, 0);

        if (flushConf == 1) {
            logger(L_DBG, "[EX]: Flush old configuration");
            flushConf = 0;

            flushOldConf();
        }

    }
    // else do nothing

    return EXIT_OK;
}

static int handle_key_press(int peer, char* key, int isRepeatable)
{
    DEBUG2("[EX]: handle_key_press() >%s<", (key ? key :  "NULL"));
    if (!key) {
        return EXIT_OK;
    }
    
    if (peer != 0 && strncmp("CoverSize(",key,10) == 0) {
        int v = 0;
        int i = 10;
        while (isdigit(*(key+i))) {
            v = v*10 + (*(key+i) - '0');
            i++;
        }
        DEBUG2("[EX]: CoverSize: %d >%d<", peer, v);
        customizePeer(peer, -1, -1, v);
    }
    if (peer != 0 && strncmp("SizeX(",key,6) == 0) {
        int v = 0;
        int i = 6;
        while (isdigit(*(key+i))) {
            v = v*10 + (*(key+i) - '0');
            i++;
        }
        DEBUG2("[EX]: SizeX: %d >%d<", peer, v);
        customizePeer(peer, v, -1, -1);
    }
    if (peer != 0 && strncmp("SizeY(",key,6) == 0) {
        int v = 0;
        int i = 6;
        while (isdigit(*(key+i))) {
            v = v*10 + (*(key+i) - '0');
            i++;
        }
        DEBUG2("[EX]: SizeY: %d >%d<", peer, v);
        customizePeer(peer, -1, v, -1);
    }

    // If modifier was set already it needs to verify which sequence we go
    if (modifierString[0] != '\0') {
        strcat(modifierString," "); // Add one space first
        strcat(modifierString, key);
        DEBUG2("[EX]: Modifier+sequence is: >%s<", modifierString);
    }

    // Execute appropriate command
    int i;
    cmdParams params;
    type_key *k = findItem((modifierString[0] == '\0' ? key : modifierString), &i, &params);

    if (k && i == FLAG_EXACT) {
        if (isRepeatable && (!repeatNow()) && getAutoRepeat()) {
            logger(L_DBG, "[EX]: Set auto repeat flag");
            setRepeatNow(k);
        }
        handleCmdByKey(peer, k, NULL);

        // Clean modifier string
        modifierString[0] = '\0';

        if (flushConf == 1) {
            logger(L_DBG, "[EX]: Flush old configuration");
            flushConf = 0;

            flushOldConf();
        }

    } else if (k && i == FLAG_MULTIKEY) {
        logger(L_DBG, "[EX]: Got part of multi keys sequence. Nothing to do.");
        if (modifierString[0] == '\0') {
            logger(L_DBG, "[EX]: Start of multi key sequence");
            strcpy(modifierString, key);
        }

        if (needAtMainMenuReturn(peer)) {
            sendToMainMenu(peer);
        }
    } else if (k && i == FLAG_PARAMETR) {
        logger(L_DBG, "[EX]: Got parametrized command");

        handleCmdByKey(peer, k, &params);

        // Clean modifier string
        modifierString[0] = '\0';

    } else {
        // User had pressed some key ...
        // Send ToMainMenu sequence of CKPD's to show main menu again
        if (needAtMainMenuReturn(peer)) {
            sendToMainMenu(peer);
        }

        logger(L_DBG, "[EX]: No approprite key definition was found");
        if (modifierString[0] != '\0') {
            // Clean modifier string
            modifierString[0] = '\0';
            logger(L_DBG, "[EX]: Clean modifier string");
        }
    }

    return EXIT_OK;
}

static int handle_at_command(int peer, char* cmd)
{
    // Handle different keypresses
    // Motorola: +CKEV: "1",1
    // SE	   : +CKEV: 1,1
    // Sagem: in rare ) cases it could be (between > and <) >,1:< ?

    int isSE = MODEL_SE;

    char *key = cmd+7;

    // Sagem test
    // key+=3;

    if (*key == '"') {	// Seems this is Motorola
        key++;
        //logger(L_DBG,"[EX]: +CKEV is in Motorola format");
        isSE = MODEL_MOTOROLA;
    }

    if (*key == ',') {	// Seems this is Sagem
        logger(L_DBG,"[EX]: +CKEV is in rare Sagem format (Empty code)");
        isSE = MODEL_SAGEM;
    }

    int i = 1;

    if (isSE == MODEL_SE) { 	// SonyEricsson & default
        while(key[i] != ',') {
            i++;
        }
        key[i] ='\0';

        i = i+1;
    } else if (isSE == MODEL_MOTOROLA) {	// Motorola
        while(key[i] != '"') {
            i++;
        }
        key[i] ='\0';

        i = i+2;
    } else if (isSE == MODEL_SAGEM) {	// rare Sagem case
        *key ='\0';
    } else {
        logger(L_ERR,"[EX]: Can't recognize +CKEV event !!!");
        return EXIT_NOK;
    }

    if (key[i] == '1') {
        //logger(L_DBG,"[EX]: Button down event");
        
        dMessage* dm = allocDMessage();
        dm->type     = DM_EVENT;
        dm->subtype  = ID_EVENT_FRONTEND;
        dm->value    = (void*) strdup(key);
        dm->size     = strlen(key);

        sendToDispatcher(dm);
	
        return handle_key_press(peer,key,1);
    
    } else if (key[i] == '0') {
        
        //logger(L_DBG,"[EX]: Button up event");
        // In general we skip this
        cleanAutoRepeatFlag();
        return EXIT_OK;
    
    } 
    
    //else 
    DEBUG2("[EX]: something wrong: key should be pressed or released: cmd=>%s< char=>%c<", cmd, key[i]);
    return EXIT_NOK;
}

static int handle_command(int peer, char* cmd)
{
    //logger(L_DBG,"[EX]: handle_command");
    if (!cmd) {
        return EXIT_OK;
    }
    
    if (memcmp(cmd, DEF_MSG, 4) == 0) {	    // Got event from Java client

        logger(L_DBG,"[EX]: Got event from client");
        return handle_key_press(peer, cmd+4, 0);

    } else if (memcmp(cmd, DEF_CKEV, 6) == 0) {

        return handle_at_command(peer, cmd);
    
    } else if (memcmp(cmd, DEF_CLCC,6) == 0) {

        //logger(L_INF,"[EX]: Caller ID received. Skip it.");
        return EXIT_OK;

    } else if (strstr(cmd, DEF_RING) != NULL) {	    // Incoming call, this event sent periodically until used answered a call
        
        logger(L_INF,"[EX]: Incoming call notification. Skip it."); // Handled inside peer read function
        return EXIT_OK;
	
    } else if (isLircCommand(cmd)) {	    // LIRC tricks
        return EXIT_OK;
    } else if (isInpLircCommand(cmd)) {	    // inputLIRC tricks
        return EXIT_OK;
    } else if (isBemusedCommand(cmd)) {	    // Bemused server emulation tricks
        return EXIT_OK;
    } else if (isIViewerCommand(cmd)) {	    // CommandFusion iViewer protocol support
        return EXIT_OK;
    } else { // SERVER_STDIN ? Just direct input, try it
        
        //printf("DEBUG: Is it SERVER_STDIN ? %s\n", cmd);
        char *p = cmd;
        while (*p != '\0') {
            if (*p == '\n') {
                *p = '\0';
                break;
            }
            p++;
        }

        return handle_key_press(peer,cmd,1);
    }

    DEBUG2("[EX]: Unhandled cmd %s", cmd);
    return EXIT_OK;
}

//
// Should be used in AT mode only
//
void sendToMainMenu(int peer)
{
    logger(L_INF,"[EX]: sendToMainMenu");
    char *tmm = NULL;
    if ((tmm = getToMainMenu()) != NULL) {

        dMessage* dm = allocDMessage();
        dm->peer     = peer;
        dm->type     = DM_CKPD;
        dm->subtype  = ID_SET_MAX;
        dm->value    = (void*) tmm;
        dm->size     = strlen((char*) dm->value);

        sendToDispatcher(dm);
    }
}

//
// Bemused server limited emulation
// we could get more than one command at once
//

static int isBemusedCommand(char *cmdIn)
{
    DEBUG2("[EX]: isBemusedCommand: >%s<",cmdIn);

    int isBemused = 0;

    char *cmd = cmdIn;
    char *last = cmdIn + strlen(cmdIn);

    while (cmd < last) {
        int handle = 0;
        int shift  = 4;

        char oneCmd[16];
        memset(oneCmd,0,16);

        char paramValue[8];
        paramValue[0] = '\0';

        if (strncmp(cmd, "CHCK", 4) == 0 ||
                strncmp(cmd, "DINF", 4) == 0 ||
                strncmp(cmd, "EXIT", 4) == 0 ||
                strncmp(cmd, "FADE", 4) == 0 ||
                strncmp(cmd, "FFWD", 4) == 0 ||
                strncmp(cmd, "GVOL", 4) == 0 ||
                strncmp(cmd, "INF2", 4) == 0 ||
                strncmp(cmd, "INF",  3) == 0 ||
                strncmp(cmd, "LIST", 4) == 0 ||
                strncmp(cmd, "NEXT", 4) == 0 ||
                strncmp(cmd, "PAUS", 4) == 0 ||
                strncmp(cmd, "PLEN", 4) == 0 ||
                strncmp(cmd, "PLST", 4) == 0 ||
                strncmp(cmd, "PREV", 4) == 0 ||
                strncmp(cmd, "RMAL", 4) == 0 ||
                strncmp(cmd, "RWND", 4) == 0 ||
                strncmp(cmd, "SHUT", 4) == 0 ||
                strncmp(cmd, "STEN", 4) == 0 ||
                strncmp(cmd, "STOP", 4) == 0 ||
                strncmp(cmd, "STRT", 4) == 0 ||
                strncmp(cmd, "VERS", 4) == 0) {
            handle = 1;
        }

        if (strncmp(cmd, "VOLM", 4) == 0 ||
                strncmp(cmd, "REPT", 4) == 0 ||
                strncmp(cmd, "SHFL", 4) == 0) {

            unsigned char bc;

            // this must be handled in dispatcher thread
            if (strlen(cmd) == 4) {
                if (strncmp(cmd, "VOLM", 4) == 0 && strlen(cmd) == 4) {  // read only VOLM without value to set
                    ERROR2("[EX]: isBemusedCommand: %s without value", cmd);
                    return 1;		// do nothing, but treat it as Bemused command
                }

                // It is possible for REPT/SHFL: toggle command
                handle = 1;

            } else {
                bc = ((unsigned char) *(cmd + 4));

                if (strncmp(cmd, "VOLM", 4) == 0) {
                    // VOLM 0-255 -> 0%-100%
                    sprintf(paramValue, "%d", ((int)bc * 100)/255);
                    DEBUG2("[EX]: isBemusedCommand: VOLM parameter >%s<", paramValue);
                } else {
                    // 0/1
                    sprintf(paramValue, "%d", ((int)bc == 0 ? 0 : 1));
                    DEBUG2("[EX]: isBemusedCommand: %s parameter >%s<", cmd, paramValue);
                }
                handle = 1;
                shift  = 5;
            }
        }
        if (strncmp(cmd, "SLCT", 4) == 0) {

            unsigned char bc1 = *((unsigned char*) (cmd + 4));
            unsigned char bc2 = *((unsigned char*) (cmd + 5));

            unsigned int ix = bc1*256+bc2;
            sprintf(paramValue, "%d",ix);

            DEBUG2("[EX]: isBemusedCommand: SLCT parameter >%s<", paramValue);

            handle = 1;
            shift  = 6;
        }
        if (strncmp(cmd, "SEEK", 4) == 0)  {

            sprintf(paramValue, "%d",
                    (((unsigned char)*(cmd + 4)) << 24) +
                    (((unsigned char)*(cmd + 5)) << 16) +
                    (((unsigned char)*(cmd + 6)) << 8)  +
                    (unsigned char)*(cmd + 7));

            handle = 1;
            shift  = 8;
        }
        if (strncmp(cmd, "DLST", 4) == 0 ||
                strncmp(cmd, "DOWN", 4) == 0 ||
                strncmp(cmd, "FINF", 4) == 0 ||
                strncmp(cmd, "LADD", 4) == 0 ||
                strncmp(cmd, "PLAY", 4) == 0) {

            unsigned char bc = *((unsigned char*) (cmd + 4));
            sprintf(paramValue, "%d",bc);

            shift  = 5 + bc;
            handle = 1;
        }
        if (handle) {
            isBemused = 1;
            strncpy(oneCmd,cmd,4);
            oneCmd[4] = '\0';
            if (paramValue[0] != '\0') {
                strcat(oneCmd,"(-1,");
                strcat(oneCmd,paramValue);
                strcat(oneCmd,")");
            }

            DEBUG2("[EX]: isBemusedCommand: one command >%s<", oneCmd);

            handle_key_press(PEER_ANY,oneCmd,1);
        } else {
            break;
        }

        cmd = cmd + shift;
    }
    return isBemused;
}

//
// LIRC dev/event handling
//

static int isLircCommand(char *cmdIn)
{
    //  should got replay in form "0000000000010184 00 TEXT linux-input-layer"
    //                            "0000000000010192 00 CHANNELUP linux-input-layer"
    DEBUG2("[EX]: isLircCommand: >%s<",cmdIn);

    char *cmd = strdup(cmdIn);
    char *bufPtr = NULL;

    if (strncmp(cmdIn, "000000",6) != 0) {
        free(cmd);
        return 0;
    }

    char *token = strtok_r(cmd," ",&bufPtr);
    if (token == NULL) {
        free(cmd);
        return 0;
    }

    token = strtok_r(NULL," ",&bufPtr);
    if (token == NULL) {
        free(cmd);
        return 0;
    }

    token = strtok_r(NULL," ",&bufPtr);
    if (token == NULL) {
        free(cmd);
        return 0;
    }
    handle_key_press(PEER_ANY,token,1);

    free(cmd);
    return 1;
}

//
// inputlirc dev/event handling
//
static int isInpLircCommand(char *cmdIn)
{
    // should got replay in form "2 0 KEY_1 event6"

    DEBUG2("[EX]: isInputLircCommand: >%s<",cmdIn);

    /*char *f = cmdIn;
    sprintf(tmp, "isLircCommand: DUMP >%c< >%d<",*f,*f);
        logger(L_DBG,tmp);
    */

    int isLirc = 1;

    char *data = NULL;
    char *cmd = strdup(cmdIn);
    char *bufPtr = NULL;
    char *token = strtok_r(cmd," ",&bufPtr);
    if (token == NULL) {
        free(cmd);
        return 0;
    }

    token = strtok_r(NULL," ",&bufPtr);
    if (token == NULL) {
        free(cmd);
        return 0;
    }

    token = strtok_r(NULL," ",&bufPtr);
    if (token && 
        (strncmp(token, "KEY_",4)==0 ||
         strstr(token, "_KEY_")      || // can be CTRL_ALT_KEY_F3
	     strncmp(token, "BTN_",4)==0)) {
        data = token;
        token = strtok_r(NULL," ",&bufPtr);
        if (token && strstr(token, "event") == NULL) {  // /dev/input/eventX or eventX
 	    isLirc = 0;
        }
    } else {
	isLirc = 0;
    }

    if (isLirc) {
        DEBUG2("[EX]: isLircCommand: one command >%s<", data);
        handle_key_press(PEER_ANY,data,1);
    }

    free(cmd);
    return isLirc;
}

//
// Command Fusion iViewer protocol support
//
static int isIViewerCommand(char *cmdIn)
{
    // should got replay in form
    // aXX=value\3
    // dXX=value\3
    // h=0\3
    // i=1\3
    // lXX=value\3	-- not yet supported
    // m=[portrait|landscape]\3
    // p=value\3
    // sXX=value\3
    // n=value

    DEBUG2("[EX]: isIViewerCommand: >%s<",cmdIn);

    char* cmdTmp = (char*) calloc(strlen(cmdIn) + 1, sizeof(char));
    strcpy(cmdTmp,cmdIn);

    if (!((cmdTmp[0] == 'a' && isdigit(cmdTmp[1])) ||
          (cmdTmp[0] == 'd' && isdigit(cmdTmp[1])) ||
          (cmdTmp[0] == 'l' && isdigit(cmdTmp[1])) ||
          (cmdTmp[0] == 's' && isdigit(cmdTmp[1])) ||
          (cmdTmp[0] == 'm' && cmdTmp[1] == '=')   ||
          (cmdTmp[0] == 'p' && cmdTmp[1] == '=')   ||
          (cmdTmp[0] == 'n' && cmdTmp[1] == '=')   ||
          strcmp(cmdTmp, "h=0") == 0 ||
          strcmp(cmdTmp, "i=1") == 0
         )) {
        free(cmdTmp);
        return 0;
    }

    char *bufPtr = NULL;
    char *token = strtok_r(cmdTmp,"=",&bufPtr);
    if (token == NULL) {
        free(cmdTmp);
        return 0;
    }
    token = strtok_r(NULL,"=",&bufPtr);

    DEBUG2("[EX]: isIViewerCommand: OK >%d<", (int) strlen(cmdIn) + 6);

    char* cmd = (char*) calloc(strlen(cmdIn) + 6, sizeof(char));
    strcpy(cmd,cmdTmp);

    strcat(cmd,"(");
    if (cmdTmp[0] == 'm' ||
        cmdTmp[0] == 'p' ||
        cmdTmp[0] == 's' ||
        cmdTmp[0] == 'n') {

        strcat(cmd,"-1,");
        if (token != NULL) {
            strcat(cmd,token);      // token is string
        }

        strcat(cmd,")");
    } else {
        if (token != NULL) {
            strcat(cmd,token);	// token is numeric
        }
        strcat(cmd,",)");
    }
    free(cmdTmp);

    DEBUG2("[EX]: isIViewerCommand: one command >%s<", cmd);
    handle_key_press(PEER_ANY,cmd,1);

    logger(L_INF, "[EX]: isIViewerCommand: EXIT");
    free(cmd);
    return 1;
}
