From 47ba5b7178b56f821aae6d0c5490181444a73dac Mon Sep 17 00:00:00 2001
From: Stefan Hofmann <stefan.hofmann@t-online.de>
Date: Wed, 21 May 2025 13:30:08 +0200
Subject: [PATCH] Fixed issue with resetting string settings

---
 epgsearchext.c | 470 ++++++++++++++++++++++++++-----------------------
 1 file changed, 246 insertions(+), 224 deletions(-)

diff --git a/epgsearchext.c b/epgsearchext.c
index 8b2fa56..821e67f 100644
--- a/epgsearchext.c
+++ b/epgsearchext.c
@@ -402,7 +402,7 @@ bool cSearchExt::Parse(const char *s)
     char *line;
     char *pos;
     char *pos_next;
-    int parameter = 1;
+    int parameter = 0;
     size_t valuelen;
     char value[MaxFileName * 10];;       // assume 10-byte patterns for special characters
     bool disableSearchtimer = false;
@@ -414,240 +414,262 @@ bool cSearchExt::Parse(const char *s)
     pos_next = pos + strlen(pos);
     if (*pos_next == '\n') *pos_next = 0;
     while (*pos) {
+        char first = *pos;
         while (*pos == ' ') pos++;
-        if (*pos) {
-            if (*pos != ':') {
-                pos_next = strchr(pos, ':');
-                if (!pos_next)
-                    pos_next = pos + strlen(pos);
-                valuelen = pos_next - pos + 1;
-                if (valuelen > sizeof(value)) valuelen = sizeof(value);
-                strn0cpy(value, pos, valuelen);
-                pos = pos_next;
-                switch (parameter) {
-                case 1:
-                    if (!isnumber(value)) return false;
-                    ID = atoi(value);
-                    break;
-                case 2:
-                    strreplace(value, '|', ':');
-                    while (strstr(value, "!^pipe^!")) strreplace(value, "!^pipe^!", "|");
-                    strn0cpy(search, value, sizeof(search));
-                    break;
-                case 3:
-                    useTime = atoi(value);
-                    break;
-                case 4:
-                    startTime = atoi(value);
-                    break;
-                case 5:
-                    stopTime = atoi(value);
-                    break;
-                case 6:
-                    useChannel = atoi(value);
-                    break;
-                case 7:
-                    if (useChannel == 0) {
-                        channelMin = NULL;
-                        channelMax = NULL;
-                    } else if (useChannel == 1) {
-                        int minNum = 0, maxNum = 0;
-                        int fields = sscanf(value, "%d-%d", &minNum, &maxNum);
-                        if (fields == 0) { // stored with ID
+        // cater for both "...:" (keep last field) and "...: " (delete last field, if string),
+        // which may occur at the programmatic service interface
+        if (*pos && *pos != ':') {
+            // process non-blank field
+            pos_next = strchr(pos, ':');
+            if (!pos_next)
+                pos_next = pos + strlen(pos);
+            valuelen = pos_next - pos + 1;
+            if (valuelen > sizeof(value)) valuelen = sizeof(value);
+            strn0cpy(value, pos, valuelen);
+            pos = pos_next;
+            switch (parameter) {
+            case 0:
+                if (!isnumber(value)) return false;
+                ID = atoi(value);
+                break;
+            case 1:
+                strreplace(value, '|', ':');
+                while (strstr(value, "!^pipe^!")) strreplace(value, "!^pipe^!", "|");
+                strn0cpy(search, value, sizeof(search));
+                break;
+            case 2:
+                useTime = atoi(value);
+                break;
+            case 3:
+                startTime = atoi(value);
+                break;
+            case 4:
+                stopTime = atoi(value);
+                break;
+            case 5:
+                useChannel = atoi(value);
+                break;
+            case 6:
+                if (useChannel == 0) {
+                    channelMin = NULL;
+                    channelMax = NULL;
+                } else if (useChannel == 1) {
+                    int minNum = 0, maxNum = 0;
+                    int fields = sscanf(value, "%d-%d", &minNum, &maxNum);
+                    if (fields == 0) { // stored with ID
 #ifdef __FreeBSD__
-                            char *channelMinbuffer = MALLOC(char, 32);
-                            char *channelMaxbuffer = MALLOC(char, 32);
-                            int channels = sscanf(value, "%31[^|]|%31[^|]", channelMinbuffer, channelMaxbuffer);
+                        char *channelMinbuffer = MALLOC(char, 32);
+                        char *channelMaxbuffer = MALLOC(char, 32);
+                        int channels = sscanf(value, "%31[^|]|%31[^|]", channelMinbuffer, channelMaxbuffer);
 #else
-                            char *channelMinbuffer = NULL;
-                            char *channelMaxbuffer = NULL;
-                            int channels = sscanf(value, "%m[^|]|%m[^|]", &channelMinbuffer, &channelMaxbuffer);
+                        char *channelMinbuffer = NULL;
+                        char *channelMaxbuffer = NULL;
+                        int channels = sscanf(value, "%m[^|]|%m[^|]", &channelMinbuffer, &channelMaxbuffer);
 #endif
-                            LOCK_CHANNELS_READ;
-                            channelMin = Channels->GetByChannelID(tChannelID::FromString(channelMinbuffer), true, true);
-                            if (!channelMin) {
-                                LogFile.eSysLog("ERROR: channel '%s' not defined", channelMinbuffer);
+                        LOCK_CHANNELS_READ;
+                        channelMin = Channels->GetByChannelID(tChannelID::FromString(channelMinbuffer), true, true);
+                        if (!channelMin) {
+                            LogFile.eSysLog("ERROR: channel '%s' not defined", channelMinbuffer);
+                            channelMin = channelMax = NULL;
+                            disableSearchtimer = true;
+                            useChannel = 0;
+                        }
+                        if (channels == 1)
+                            channelMax = channelMin;
+                        else {
+                            channelMax = Channels->GetByChannelID(tChannelID::FromString(channelMaxbuffer), true, true);
+                            if (!channelMax) {
+                                LogFile.eSysLog("ERROR: channel '%s' not defined", channelMaxbuffer);
                                 channelMin = channelMax = NULL;
                                 disableSearchtimer = true;
                                 useChannel = 0;
                             }
-                            if (channels == 1)
-                                channelMax = channelMin;
-                            else {
-                                channelMax = Channels->GetByChannelID(tChannelID::FromString(channelMaxbuffer), true, true);
-                                if (!channelMax) {
-                                    LogFile.eSysLog("ERROR: channel '%s' not defined", channelMaxbuffer);
-                                    channelMin = channelMax = NULL;
-                                    disableSearchtimer = true;
-                                    useChannel = 0;
-                                }
-                            }
-                            free(channelMinbuffer);
-                            free(channelMaxbuffer);
                         }
-                    } else if (useChannel == 2)
-                        channelGroup = strdup(value);
-                    break;
-                case 8:
-                    useCase = atoi(value);
-                    break;
-                case 9:
-                    mode = atoi(value);
-                    break;
-                case 10:
-                    useTitle = atoi(value);
-                    break;
-                case 11:
-                    useSubtitle = atoi(value);
-                    break;
-                case 12:
-                    useDescription = atoi(value);
-                    break;
-                case 13:
-                    useDuration = atoi(value);
-                    break;
-                case 14:
-                    minDuration = atoi(value);
-                    break;
-                case 15:
-                    maxDuration = atoi(value);
-                    break;
-                case 16:
-                    useAsSearchTimer = atoi(value);
-                    break;
-                case 17:
-                    useDayOfWeek = atoi(value);
-                    break;
-                case 18:
-                    DayOfWeek = atoi(value);
-                    break;
-                case 19:
-                    useEpisode = atoi(value);
-                    break;
-                case 20:
-                    strreplace(value, '|', ':');
-                    while (strstr(value, "!^pipe^!")) strreplace(value, "!^pipe^!", "|");
-                    strn0cpy(directory, value, sizeof(directory));
-                    break;
-                case 21:
-                    Priority = atoi(value);
-                    break;
-                case 22:
-                    Lifetime = atoi(value);
-                    break;
-                case 23:
-                    MarginStart = atoi(value);
-                    break;
-                case 24:
-                    MarginStop = atoi(value);
-                    break;
-                case 25:
-                    useVPS = atoi(value);
-                    break;
-                case 26:
-                    action = atoi(value);
-                    break;
-                case 27:
-                    useExtEPGInfo = atoi(value);
-                    break;
-                case 28:
-                    if (!ParseExtEPGValues(value)) {
-                        LogFile.eSysLog("ERROR reading ext. EPG values - 1");
-                        free(line);
-                        return false;
-                    }
-                    break;
-                case 29:
-                    avoidRepeats = atoi(value);
-                    break;
-                case 30:
-                    allowedRepeats = atoi(value);
-                    break;
-                case 31:
-                    compareTitle = atoi(value);
-                    break;
-                case 32:
-                    compareSubtitle = atoi(value);
-                    break;
-                case 33:
-                    compareSummary = atoi(value);
-                    break;
-                case 34:
-                    catvaluesAvoidRepeat = atol(value);
-                    break;
-                case 35:
-                    repeatsWithinDays = atoi(value);
-                    break;
-                case 36:
-                    delAfterDays = atoi(value);
-                    break;
-                case 37:
-                    recordingsKeep = atoi(value);
-                    break;
-                case 38:
-                    switchMinsBefore = atoi(value);
-                    break;
-                case 39:
-                    pauseOnNrRecordings = atoi(value);
-                    break;
-                case 40:
-                    blacklistMode = atoi(value);
-                    break;
-                case 41:
-                    if (blacklistMode == blacklistsSelection && !ParseBlacklistIDs(value)) {
-                        LogFile.eSysLog("ERROR parsing blacklist IDs");
-                        free(line);
-                        return false;
+                        free(channelMinbuffer);
+                        free(channelMaxbuffer);
                     }
-                    break;
-                case 42:
-                    fuzzyTolerance = atoi(value);
-                    break;
-                case 43:
-                    useInFavorites = atoi(value);
-                    break;
-                case 44:
-                    menuTemplate = atoi(value);
-                    break;
-                case 45:
-                    delMode = atoi(value);
-                    break;
-                case 46:
-                    delAfterCountRecs = atoi(value);
-                    break;
-                case 47:
-                    delAfterDaysOfFirstRec = atoi(value);
-                    break;
-                case 48:
-                    useAsSearchTimerFrom = atol(value);
-                    break;
-                case 49:
-                    useAsSearchTimerTil = atol(value);
-                    break;
-                case 50:
-                    ignoreMissingEPGCats = atoi(value);
-                    break;
-                case 51:
-                    unmuteSoundOnSwitch = atoi(value);
-                    break;
-                case 52:
-                    compareSummaryMatchInPercent = atoi(value);
-                    break;
-                case 53:
-                    strreplace(value, '|', ':');
-                    while (strstr(value, "!^pipe^!")) strreplace(value, "!^pipe^!", "|");
-                    value[MaxFileName - 1] = '\0';  // simulate strn0cpy()
-                    contentsFilter = value;
-                    break;
-                case 54:
-                    compareDate = atoi(value);
-                    break;
-                default:
-                    break;
-                } //switch
-            }
-            parameter++;
+                } else if (useChannel == 2)
+                    channelGroup = strdup(value);
+                break;
+            case 7:
+                useCase = atoi(value);
+                break;
+            case 8:
+                mode = atoi(value);
+                break;
+            case 9:
+                useTitle = atoi(value);
+                break;
+            case 10:
+                useSubtitle = atoi(value);
+                break;
+            case 11:
+                useDescription = atoi(value);
+                break;
+            case 12:
+                useDuration = atoi(value);
+                break;
+            case 13:
+                minDuration = atoi(value);
+                break;
+            case 14:
+                maxDuration = atoi(value);
+                break;
+            case 15:
+                useAsSearchTimer = atoi(value);
+                break;
+            case 16:
+                useDayOfWeek = atoi(value);
+                break;
+            case 17:
+                DayOfWeek = atoi(value);
+                break;
+            case 18:
+                useEpisode = atoi(value);
+                break;
+            case 19:
+                strreplace(value, '|', ':');
+                while (strstr(value, "!^pipe^!")) strreplace(value, "!^pipe^!", "|");
+                strn0cpy(directory, value, sizeof(directory));
+                break;
+            case 20:
+                Priority = atoi(value);
+                break;
+            case 21:
+                Lifetime = atoi(value);
+                break;
+            case 22:
+                MarginStart = atoi(value);
+                break;
+            case 23:
+                MarginStop = atoi(value);
+                break;
+            case 24:
+                useVPS = atoi(value);
+                break;
+            case 25:
+                action = atoi(value);
+                break;
+            case 26:
+                useExtEPGInfo = atoi(value);
+                break;
+            case 27:
+                if (!ParseExtEPGValues(value)) {
+                    LogFile.eSysLog("ERROR reading ext. EPG values - 1");
+                    free(line);
+                    return false;
+                }
+                break;
+            case 28:
+                avoidRepeats = atoi(value);
+                break;
+            case 29:
+                allowedRepeats = atoi(value);
+                break;
+            case 30:
+                compareTitle = atoi(value);
+                break;
+            case 31:
+                compareSubtitle = atoi(value);
+                break;
+            case 32:
+                compareSummary = atoi(value);
+                break;
+            case 33:
+                catvaluesAvoidRepeat = atol(value);
+                break;
+            case 34:
+                repeatsWithinDays = atoi(value);
+                break;
+            case 35:
+                delAfterDays = atoi(value);
+                break;
+            case 36:
+                recordingsKeep = atoi(value);
+                break;
+            case 37:
+                switchMinsBefore = atoi(value);
+                break;
+            case 38:
+                pauseOnNrRecordings = atoi(value);
+                break;
+            case 39:
+                blacklistMode = atoi(value);
+                break;
+            case 40:
+                if (blacklistMode == blacklistsSelection && !ParseBlacklistIDs(value)) {
+                    LogFile.eSysLog("ERROR parsing blacklist IDs");
+                    free(line);
+                    return false;
+                }
+                break;
+            case 41:
+                fuzzyTolerance = atoi(value);
+                break;
+            case 42:
+                useInFavorites = atoi(value);
+                break;
+            case 43:
+                menuTemplate = atoi(value);
+                break;
+            case 44:
+                delMode = atoi(value);
+                break;
+            case 45:
+                delAfterCountRecs = atoi(value);
+                break;
+            case 46:
+                delAfterDaysOfFirstRec = atoi(value);
+                break;
+            case 47:
+                useAsSearchTimerFrom = atol(value);
+                break;
+            case 48:
+                useAsSearchTimerTil = atol(value);
+                break;
+            case 49:
+                ignoreMissingEPGCats = atoi(value);
+                break;
+            case 50:
+                unmuteSoundOnSwitch = atoi(value);
+                break;
+            case 51:
+                compareSummaryMatchInPercent = atoi(value);
+                break;
+            case 52:
+                strreplace(value, '|', ':');
+                while (strstr(value, "!^pipe^!")) strreplace(value, "!^pipe^!", "|");
+                value[MaxFileName - 1] = '\0';  // simulate strn0cpy()
+                contentsFilter = value;
+                break;
+            case 53:
+                compareDate = atoi(value);
+                break;
+            default:
+                break;
+            } //switch
+        } else if (first == ' ') {
+            // reset string parameter
+            switch (parameter) {
+            case 19:
+                directory[0] = '\0';
+                break;
+            case 27:
+                for (int index = 0; index < SearchExtCats.Count(); index++ ) {
+                    *catvalues[index] = 0;
+                }
+                break;
+            case 40:
+                if (blacklistMode == blacklistsSelection) blacklists.Clear();
+                break;
+            case 52:
+                contentsFilter = "";
+                break;
+            default:
+                break;
+            } //switch
         }
+        parameter++;
         if (*pos) pos++;
     } //while
 
-- 
2.49.0.windows.1

