AutoTimer: add "Fast Scan" support
[vuplus_dvbapp-plugin] / autotimer / src / AutoTimerConfiguration.py
index 6f637f9..f31fd55 100644 (file)
@@ -2,11 +2,13 @@
 # for localized messages
 from . import _
 
-from AutoTimerComponent import AutoTimerComponent
+from AutoTimerComponent import preferredAutoTimerComponent
 from RecordTimer import AFTEREVENT
 from Tools.XMLTools import stringToXML
 from ServiceReference import ServiceReference
 
+from enigma import eServiceReference
+
 CURRENT_CONFIG_VERSION = "5"
 
 def getValue(definitions, default):
@@ -38,7 +40,7 @@ def parseConfig(configuration, list, version = None, uniqueTimerId = 0, defaultT
 
        for timer in configuration.findall("timer"):
                uniqueTimerId += 1
-               baseTimer = AutoTimerComponent(
+               baseTimer = preferredAutoTimerComponent(
                        uniqueTimerId,
                        '',
                        '',
@@ -72,6 +74,16 @@ def parseEntry(element, baseTimer, defaults = False):
                        print '[AutoTimer] Erroneous config contains invalid value for "enabled":', enabled,', disabling'
                        baseTimer.enabled = False
 
+       # Read out encoding (won't change if no value is set)
+       baseTimer.encoding = element.get("encoding")
+
+       # Read out search type/case
+       baseTimer.searchType = element.get("searchType", baseTimer.searchType)
+       baseTimer.searchCase = element.get("searchCase", baseTimer.searchCase)
+
+       # Read out if we should change to alternative services
+       baseTimer.overrideAlternatives = int(element.get("overrideAlternatives", baseTimer.overrideAlternatives))
+
        # Read out timespan
        start = element.get("from")
        end = element.get("to")
@@ -86,7 +98,8 @@ def parseEntry(element, baseTimer, defaults = False):
                baseTimer.maxduration = int(maxduration)*60
 
        # Read out recording path
-       baseTimer.destination = element.get("location", "").encode("UTF-8") or None
+       default = baseTimer.destination or ""
+       baseTimer.destination = element.get("location", default).encode("UTF-8") or None
 
        # Read out offset
        offset = element.get("offset")
@@ -103,100 +116,117 @@ def parseEntry(element, baseTimer, defaults = False):
        baseTimer.matchCount = int(element.get("counter", 0))
        baseTimer.matchFormatString = element.get("counterFormat", "")
        if not defaults:
-               baseTimer.counterLimit = element.get("lastActivation", "")
-               baseTimer.counterFormat = element.get("counterFormat", "")
+               baseTimer.matchLeft = int(element.get("left", baseTimer.matchCount))
+               baseTimer.matchLimit = element.get("lastActivation", "")
                baseTimer.lastBegin = int(element.get("lastBegin", 0))
 
        # Read out justplay
-       justplay = int(element.get("justplay", 0))
+       baseTimer.justplay = int(element.get("justplay", 0))
 
        # Read out avoidDuplicateDescription
        baseTimer.avoidDuplicateDescription = int(element.get("avoidDuplicateDescription", 0))
 
        # Read out allowed services
-       servicelist = baseTimer.services        
-       for service in element.findall("serviceref"):
-               value = service.text
-               if value:
-                       # strip all after last :
-                       pos = value.rfind(':')
-                       if pos != -1:
-                               value = value[:pos+1]
-
-                       servicelist.append(value)
-       baseTimer.services = servicelist
+       l = element.findall("serviceref")
+       if l:
+               servicelist = []
+
+               for service in l:
+                       value = service.text
+                       if value:
+                               myref = eServiceReference(str(value))
+                               if not (myref.flags & eServiceReference.isGroup):
+                                       # strip all after last :
+                                       pos = value.rfind(':')
+                                       if pos != -1:
+                                               if value[pos-1] == ':':
+                                                       pos -= 1
+                                               value = value[:pos+1]
+
+                               servicelist.append(value)
+               baseTimer.services = servicelist
 
        # Read out allowed bouquets
-       bouquets = baseTimer.bouquets
-       for bouquet in element.findall("bouquet"):
-               value = bouquet.text
-               if value:
-                       bouquets.append(value)
-       baseTimer.bouquets = bouquets
+       l = element.findall("bouquet")
+       if l:
+               bouquets = []
+               for bouquet in l:
+                       value = bouquet.text
+                       if value:
+                               bouquets.append(value)
+               baseTimer.bouquets = bouquets
 
        # Read out afterevent
-       idx = {
-               "none": AFTEREVENT.NONE,
-               "deepstandby": AFTEREVENT.DEEPSTANDBY,
-               "shutdown": AFTEREVENT.DEEPSTANDBY,
-               "standby": AFTEREVENT.STANDBY,
-               "auto": AFTEREVENT.AUTO
-       }
-       afterevent = baseTimer.afterevent
-       for element in element.findall("afterevent"):
-               value = element.text
-
-               if idx.has_key(value):
-                       value = idx[value]
-               else:
-                       print '[AutoTimer] Erroneous config contains invalid value for "afterevent":', afterevent,', ignoring definition'
-                       continue
+       l = element.findall("afterevent")
+       if l:
+               idx = {
+                       "none": AFTEREVENT.NONE,
+                       "deepstandby": AFTEREVENT.DEEPSTANDBY,
+                       "shutdown": AFTEREVENT.DEEPSTANDBY,
+                       "standby": AFTEREVENT.STANDBY,
+                       "auto": AFTEREVENT.AUTO
+               }
+               afterevents = []
+               for afterevent in l:
+                       value = afterevent.text
 
-               start = element.get("from")
-               end = element.get("to")
-               if start and end:
-                       start = [int(x) for x in start.split(':')]
-                       end = [int(x) for x in end.split(':')]
-                       afterevent.append((value, (start, end)))
-               else:
-                       afterevent.append((value, None))
-       baseTimer.afterevent = afterevent
+                       if idx.has_key(value):
+                               value = idx[value]
+                       else:
+                               print '[AutoTimer] Erroneous config contains invalid value for "afterevent":', afterevent,', ignoring definition'
+                               continue
+
+                       start = afterevent.get("from")
+                       end = afterevent.get("to")
+                       if start and end:
+                               start = [int(x) for x in start.split(':')]
+                               end = [int(x) for x in end.split(':')]
+                               afterevents.append((value, (start, end)))
+                       else:
+                               afterevents.append((value, None))
+               baseTimer.afterevent = afterevents
 
        # Read out exclude
+       l = element.findall("exclude")
        idx = {"title": 0, "shortdescription": 1, "description": 2, "dayofweek": 3}
-       excludes = (baseTimer.getExcludedTitle(), baseTimer.getExcludedShort(), baseTimer.getExcludedDescription(), baseTimer.getExcludedDays()) 
-       for exclude in element.findall("exclude"):
-               where = exclude.get("where")
-               value = exclude.text
-               if not (value and where):
-                       continue
+       if l:
+               excludes = ([], [], [], [])
+               for exclude in l:
+                       where = exclude.get("where")
+                       value = exclude.text
+                       if not (value and where):
+                               continue
 
-               if idx.has_key(where):
-                       excludes[idx[where]].append(value.encode("UTF-8"))
-       baseTimer.exclude = excludes
+                       if idx.has_key(where):
+                               excludes[idx[where]].append(value.encode("UTF-8"))
+               baseTimer.exclude = excludes
 
        # Read out includes (use same idx)
-       includes = (baseTimer.getIncludedTitle(), baseTimer.getIncludedShort(), baseTimer.getIncludedDescription(), baseTimer.getIncludedDays())
-       for include in element.findall("include"):
-               where = include.get("where")
-               value = include.text
-               if not (value and where):
-                       continue
+       l = element.findall("include")
+       if l:
+               includes = ([], [], [], [])
+               for include in l:
+                       where = include.get("where")
+                       value = include.text
+                       if not (value and where):
+                               continue
 
-               if idx.has_key(where):
-                       includes[idx[where]].append(value.encode("UTF-8"))
-       baseTimer.include = includes
+                       if idx.has_key(where):
+                               includes[idx[where]].append(value.encode("UTF-8"))
+               baseTimer.include = includes
 
-       # Read out recording tags (needs my enhanced tag support patch)
-       tags = baseTimer.tags
-       for tag in element.findall("tag"):
-               value = tag.text
-               if not value:
-                       continue
+       # Read out recording tags
+       l =  element.findall("tag")
+       if l:
+               tags = []
+               for tag in l:
+                       value = tag.text
+                       if not value:
+                               continue
+
+                       tags.append(value.encode("UTF-8"))
+               baseTimer.tags = tags
 
-               tags.append(value.encode("UTF-8"))
-       baseTimer.tags = tags
-       
        return True
 
 def parseConfigOld(configuration, list, uniqueTimerId = 0):
@@ -247,7 +277,7 @@ def parseConfigOld(configuration, list, uniqueTimerId = 0):
                # V1
                else:
                        elements = timer.findall("enabled")
-                       if len(elements):
+                       if elements:
                                if getValue(elements, "yes") == "no":
                                        enabled = False
                                else:
@@ -282,15 +312,19 @@ def parseConfigOld(configuration, list, uniqueTimerId = 0):
 
                # Read out allowed services (V*)
                elements = timer.findall("serviceref")
-               if len(elements):
+               if elements:
                        servicelist = []
                        for service in elements:
                                value = service.text
                                if value:
-                                       # strip all after last :
-                                       pos = value.rfind(':')
-                                       if pos != -1:
-                                               value = value[:pos+1]
+                                       myref = eServiceReference(str(value))
+                                       if not (myref.flags & eServiceReference.isGroup):
+                                               # strip all after last :
+                                               pos = value.rfind(':')
+                                               if pos != -1:
+                                                       if value[pos-1] == ':':
+                                                               pos -= 1
+                                                       value = value[:pos+1]
 
                                        servicelist.append(value)
                else:
@@ -370,7 +404,7 @@ def parseConfigOld(configuration, list, uniqueTimerId = 0):
 
                # Read out exclude (V*)
                idx = {"title": 0, "shortdescription": 1, "description": 2, "dayofweek": 3}
-               excludes = ([], [], [], []) 
+               excludes = ([], [], [], [])
                for exclude in timer.findall("exclude"):
                        where = exclude.get("where")
                        value = exclude.text
@@ -381,7 +415,7 @@ def parseConfigOld(configuration, list, uniqueTimerId = 0):
                                excludes[idx[where]].append(value.encode("UTF-8"))
 
                # Read out includes (use same idx) (V4+ feature, should not harm V3-)
-               includes = ([], [], [], []) 
+               includes = ([], [], [], [])
                for include in timer.findall("include"):
                        where = include.get("where")
                        value = include.text
@@ -398,7 +432,7 @@ def parseConfigOld(configuration, list, uniqueTimerId = 0):
                # V3-
                else:
                        elements = timer.findall("maxduration")
-                       if len(elements):
+                       if elements:
                                maxlen = getValue(elements, None)
                                if maxlen is not None:
                                        maxlen = int(maxlen)*60
@@ -408,7 +442,7 @@ def parseConfigOld(configuration, list, uniqueTimerId = 0):
                # Read out recording path
                destination = timer.get("destination", "").encode("UTF-8") or None
 
-               # Read out recording tags (needs my enhanced tag support patch)
+               # Read out recording tags
                tags = []
                for tag in timer.findall("tag"):
                        value = tag.text
@@ -418,7 +452,7 @@ def parseConfigOld(configuration, list, uniqueTimerId = 0):
                        tags.append(value.encode("UTF-8"))
 
                # Finally append timer
-               list.append(AutoTimerComponent(
+               list.append(preferredAutoTimerComponent(
                                uniqueTimerId,
                                name,
                                match,
@@ -442,37 +476,37 @@ def parseConfigOld(configuration, list, uniqueTimerId = 0):
                                tags = tags
                ))
 
-def writeConfig(filename, defaultTimer, timers):
+def buildConfig(defaultTimer, timers, webif = False):
        # Generate List in RAM
        list = ['<?xml version="1.0" ?>\n<autotimer version="', CURRENT_CONFIG_VERSION, '">\n\n']
 
-       # XXX: we might want to make sure that we don't save empty default here
-       list.extend([' <defaults'])
+       # This gets deleted afterwards if we do not have set any defaults
+       list.append(' <defaults')
 
        # Timespan
        if defaultTimer.hasTimespan():
-               list.extend([' from="', defaultTimer.getTimespanBegin(), '" to="', defaultTimer.getTimespanEnd(), '"'])
+               list.extend((' from="', defaultTimer.getTimespanBegin(), '" to="', defaultTimer.getTimespanEnd(), '"'))
 
        # Duration
        if defaultTimer.hasDuration():
-               list.extend([' maxduration="', str(defaultTimer.getDuration()), '"'])
+               list.extend((' maxduration="', str(defaultTimer.getDuration()), '"'))
 
        # Destination
        if defaultTimer.hasDestination():
-               list.extend([' location="', stringToXML(defaultTimer.destination), '"'])
+               list.extend((' location="', stringToXML(defaultTimer.destination), '"'))
 
        # Offset
        if defaultTimer.hasOffset():
                if defaultTimer.isOffsetEqual():
-                       list.extend([' offset="', str(defaultTimer.getOffsetBegin()), '"'])
+                       list.extend((' offset="', str(defaultTimer.getOffsetBegin()), '"'))
                else:
-                       list.extend([' offset="', str(defaultTimer.getOffsetBegin()), ',', str(defaultTimer.getOffsetEnd()), '"'])
+                       list.extend((' offset="', str(defaultTimer.getOffsetBegin()), ',', str(defaultTimer.getOffsetEnd()), '"'))
 
        # Counter
        if defaultTimer.hasCounter():
-               list.extend([' counter="', str(defaultTimer.getCounter()), '"'])
+               list.extend((' counter="', str(defaultTimer.getCounter()), '"'))
                if defaultTimer.hasCounterFormatString():
-                       list.extend([' counterFormat="', str(defaultTimer.getCounterFormatString()), '"'])
+                       list.extend((' counterFormat="', str(defaultTimer.getCounterFormatString()), '"'))
 
        # Duplicate Description
        if defaultTimer.getAvoidDuplicateDescription():
@@ -480,22 +514,47 @@ def writeConfig(filename, defaultTimer, timers):
 
        # Only display justplay if true
        if defaultTimer.justplay:
-               list.extend([' justplay="', str(defaultTimer.getJustplay()), '"'])
+               list.extend((' justplay="', str(defaultTimer.getJustplay()), '"'))
+
+       # Only display encoding if != utf-8
+       if defaultTimer.encoding != 'UTF-8':
+               list.extend((' encoding="', str(defaultTimer.encoding), '"'))
+
+       # Only display searchType if exact
+       if defaultTimer.searchType == "exact":
+               list.extend((' searchType="', str(defaultTimer.searchType), '"'))
+
+       # Only display searchCase if sensitive
+       if defaultTimer.searchCase == "sensitive":
+               list.extend((' searchCase="', str(defaultTimer.searchCase), '"'))
 
        # Close still opened defaults tag
        list.append('>\n')
 
-       # Services
-       for serviceref in defaultTimer.getServices():
-               list.extend(['  <serviceref>', serviceref, '</serviceref>'])
-               ref = ServiceReference(str(serviceref))
-               list.extend([' <!-- ', stringToXML(ref.getServiceName().replace('\xc2\x86', '').replace('\xc2\x87', '')), ' -->\n'])
+       if webif:
+               # Services + Bouquets
+               for serviceref in defaultTimer.services + defaultTimer.bouquets:
+                       ref = ServiceReference(str(serviceref))
+                       list.extend((
+                               '  <e2service>\n',
+                               '   <e2servicereference>', str(serviceref), '</e2servicereference>\n',
+                               '   <e2servicename>', stringToXML(ref.getServiceName().replace('\xc2\x86', '').replace('\xc2\x87', '')), '</e2servicename>\n',
+                               '  </e2service>\n',
+                       ))
+       else:
+               # Services
+               for serviceref in defaultTimer.services:
+                       ref = ServiceReference(str(serviceref))
+                       list.extend(('  <serviceref>', serviceref, '</serviceref>',
+                                               ' <!-- ', stringToXML(ref.getServiceName().replace('\xc2\x86', '').replace('\xc2\x87', '')), ' -->\n',
+                       ))
 
-       # Bouquets
-       for bouquet in defaultTimer.getBouquets():
-               list.extend(['  <bouquet>', str(bouquet), '</bouquet>'])
-               ref = ServiceReference(str(bouquet))
-               list.extend([' <!-- ', stringToXML(ref.getServiceName().replace('\xc2\x86', '').replace('\xc2\x87', '')), ' -->\n'])
+               # Bouquets
+               for bouquet in defaultTimer.bouquets:
+                       ref = ServiceReference(str(bouquet))
+                       list.extend(('  <bouquet>', str(bouquet), '</bouquet>',
+                                               ' <!-- ', stringToXML(ref.getServiceName().replace('\xc2\x86', '').replace('\xc2\x87', '')), ' -->\n',
+                       ))
 
        # AfterEvent
        if defaultTimer.hasAfterEvent():
@@ -505,93 +564,126 @@ def writeConfig(filename, defaultTimer, timers):
                        AFTEREVENT.DEEPSTANDBY: "shutdown",
                        AFTEREVENT.AUTO: "auto"
                }
-               for afterevent in defaultTimer.getCompleteAfterEvent():
+               for afterevent in defaultTimer.afterevent:
                        action, timespan = afterevent
                        list.append('  <afterevent')
                        if timespan[0] is not None:
                                list.append(' from="%02d:%02d" to="%02d:%02d"' % (timespan[0][0], timespan[0][1], timespan[1][0], timespan[1][1]))
-                       list.extend(['>', idx[action], '</afterevent>\n'])
+                       list.extend(('>', idx[action], '</afterevent>\n'))
 
        # Excludes
        for title in defaultTimer.getExcludedTitle():
-               list.extend(['  <exclude where="title">', stringToXML(title), '</exclude>\n'])
+               list.extend(('  <exclude where="title">', stringToXML(title), '</exclude>\n'))
        for short in defaultTimer.getExcludedShort():
-               list.extend(['  <exclude where="shortdescription">', stringToXML(short), '</exclude>\n'])
+               list.extend(('  <exclude where="shortdescription">', stringToXML(short), '</exclude>\n'))
        for desc in defaultTimer.getExcludedDescription():
-               list.extend(['  <exclude where="description">', stringToXML(desc), '</exclude>\n'])
+               list.extend(('  <exclude where="description">', stringToXML(desc), '</exclude>\n'))
        for day in defaultTimer.getExcludedDays():
-               list.extend(['  <exclude where="dayofweek">', stringToXML(day), '</exclude>\n'])
+               list.extend(('  <exclude where="dayofweek">', stringToXML(day), '</exclude>\n'))
 
        # Includes
        for title in defaultTimer.getIncludedTitle():
-               list.extend(['  <include where="title">', stringToXML(title), '</include>\n'])
+               list.extend(('  <include where="title">', stringToXML(title), '</include>\n'))
        for short in defaultTimer.getIncludedShort():
-               list.extend(['  <include where="shortdescription">', stringToXML(short), '</include>\n'])
+               list.extend(('  <include where="shortdescription">', stringToXML(short), '</include>\n'))
        for desc in defaultTimer.getIncludedDescription():
-               list.extend(['  <include where="description">', stringToXML(desc), '</include>\n'])
+               list.extend(('  <include where="description">', stringToXML(desc), '</include>\n'))
        for day in defaultTimer.getIncludedDays():
-               list.extend(['  <include where="dayofweek">', stringToXML(day), '</include>\n'])
+               list.extend(('  <include where="dayofweek">', stringToXML(day), '</include>\n'))
 
        # Tags
        for tag in defaultTimer.tags:
-               list.extend(['  <tag>', stringToXML(tag), '</tag>\n'])
+               list.extend(('  <tag>', stringToXML(tag), '</tag>\n'))
 
-       # End of Timer
-       list.append(' </defaults>\n\n')
+       # Keep the list clean
+       if len(list) == 5:
+               list.pop() # >
+               list.pop() # <defaults
+       else:
+               list.append(' </defaults>\n\n')
 
        # Iterate timers
        for timer in timers:
                # Common attributes (match, enabled)
-               list.extend([' <timer name="', stringToXML(timer.name), '" match="', stringToXML(timer.match), '" enabled="', timer.getEnabled(), '"'])
+               list.extend((' <timer name="', stringToXML(timer.name), '" match="', stringToXML(timer.match), '" enabled="', timer.getEnabled(), '"'))
 
                # Timespan
                if timer.hasTimespan():
-                       list.extend([' from="', timer.getTimespanBegin(), '" to="', timer.getTimespanEnd(), '"'])
+                       list.extend((' from="', timer.getTimespanBegin(), '" to="', timer.getTimespanEnd(), '"'))
 
                # Duration
                if timer.hasDuration():
-                       list.extend([' maxduration="', str(timer.getDuration()), '"'])
+                       list.extend((' maxduration="', str(timer.getDuration()), '"'))
 
                # Destination
                if timer.hasDestination():
-                       list.extend([' location="', stringToXML(timer.destination), '"'])
+                       list.extend((' location="', stringToXML(timer.destination), '"'))
 
                # Offset
                if timer.hasOffset():
                        if timer.isOffsetEqual():
-                               list.extend([' offset="', str(timer.getOffsetBegin()), '"'])
+                               list.extend((' offset="', str(timer.getOffsetBegin()), '"'))
                        else:
-                               list.extend([' offset="', str(timer.getOffsetBegin()), ',', str(timer.getOffsetEnd()), '"'])
+                               list.extend((' offset="', str(timer.getOffsetBegin()), ',', str(timer.getOffsetEnd()), '"'))
 
                # Counter
                if timer.hasCounter():
-                       list.extend([' lastBegin="', str(timer.getLastBegin()), '" counter="', str(timer.getCounter()), '" left="', str(timer.getCounterLeft()) ,'"'])
+                       list.extend((' lastBegin="', str(timer.getLastBegin()), '" counter="', str(timer.getCounter()), '" left="', str(timer.getCounterLeft()) ,'"'))
                        if timer.hasCounterFormatString():
-                               list.extend([' lastActivation="', str(timer.getCounterLimit()), '"'])
-                               list.extend([' counterFormat="', str(timer.getCounterFormatString()), '"'])
+                               list.extend((' lastActivation="', str(timer.getCounterLimit()), '"'))
+                               list.extend((' counterFormat="', str(timer.getCounterFormatString()), '"'))
 
                # Duplicate Description
                if timer.getAvoidDuplicateDescription():
-                       list.extend([' avoidDuplicateDescription="', str(timer.getAvoidDuplicateDescription()), '"'])
+                       list.extend((' avoidDuplicateDescription="', str(timer.getAvoidDuplicateDescription()), '"'))
 
                # Only display justplay if true
                if timer.justplay:
-                       list.extend([' justplay="', str(timer.getJustplay()), '"'])
+                       list.extend((' justplay="', str(timer.getJustplay()), '"'))
+
+               # Only display encoding if != utf-8
+               if timer.encoding != 'UTF-8':
+                       list.extend((' encoding="', str(timer.encoding), '"'))
+
+               # Only display searchType if exact
+               if timer.searchType == "exact":
+                       list.extend((' searchType="', str(timer.searchType), '"'))
+
+               # Only display searchCase if sensitive
+               if timer.searchCase == "sensitive":
+                       list.extend((' searchCase="', str(timer.searchCase), '"'))
+
+               # Only display overrideAlternatives if true
+               if timer.overrideAlternatives:
+                       list.extend((' overrideAlternatives="', str(timer.getOverrideAlternatives()), '"'))
 
                # Close still opened timer tag
                list.append('>\n')
 
-               # Services
-               for serviceref in timer.getServices():
-                       list.extend(['  <serviceref>', serviceref, '</serviceref>'])
-                       ref = ServiceReference(str(serviceref))
-                       list.extend([' <!-- ', stringToXML(ref.getServiceName().replace('\xc2\x86', '').replace('\xc2\x87', '')), ' -->\n'])
-
-               # Bouquets
-               for bouquet in timer.getBouquets():
-                       list.extend(['  <bouquet>', str(bouquet), '</bouquet>'])
-                       ref = ServiceReference(str(bouquet))
-                       list.extend([' <!-- ', stringToXML(ref.getServiceName().replace('\xc2\x86', '').replace('\xc2\x87', '')), ' -->\n'])
+               if webif:
+                       # Services + Bouquets
+                       for serviceref in timer.services + timer.bouquets:
+                               ref = ServiceReference(str(serviceref))
+                               list.extend((
+                                       '  <e2service>\n',
+                                       '   <e2servicereference>', str(serviceref), '</e2servicereference>\n',
+                                       '   <e2servicename>', stringToXML(ref.getServiceName().replace('\xc2\x86', '').replace('\xc2\x87', '')), '</e2servicename>\n',
+                                       '  </e2service>\n',
+                               ))
+               else:
+                       # Services
+                       for serviceref in timer.services:
+                               ref = ServiceReference(str(serviceref))
+                               list.extend(('  <serviceref>', serviceref, '</serviceref>',
+                                                       ' <!-- ', stringToXML(ref.getServiceName().replace('\xc2\x86', '').replace('\xc2\x87', '')), ' -->\n',
+                               ))
+
+                       # Bouquets
+                       for bouquet in timer.bouquets:
+                               ref = ServiceReference(str(bouquet))
+                               list.extend(('  <bouquet>', str(bouquet), '</bouquet>',
+                                                       ' <!-- ', stringToXML(ref.getServiceName().replace('\xc2\x86', '').replace('\xc2\x87', '')), ' -->\n',
+                               ))
 
                # AfterEvent
                if timer.hasAfterEvent():
@@ -601,36 +693,36 @@ def writeConfig(filename, defaultTimer, timers):
                                AFTEREVENT.DEEPSTANDBY: "shutdown",
                                AFTEREVENT.AUTO: "auto"
                        }
-                       for afterevent in timer.getCompleteAfterEvent():
+                       for afterevent in timer.afterevent:
                                action, timespan = afterevent
                                list.append('  <afterevent')
                                if timespan[0] is not None:
                                        list.append(' from="%02d:%02d" to="%02d:%02d"' % (timespan[0][0], timespan[0][1], timespan[1][0], timespan[1][1]))
-                               list.extend(['>', idx[action], '</afterevent>\n'])
+                               list.extend(('>', idx[action], '</afterevent>\n'))
 
                # Excludes
                for title in timer.getExcludedTitle():
-                       list.extend(['  <exclude where="title">', stringToXML(title), '</exclude>\n'])
+                       list.extend(('  <exclude where="title">', stringToXML(title), '</exclude>\n'))
                for short in timer.getExcludedShort():
-                       list.extend(['  <exclude where="shortdescription">', stringToXML(short), '</exclude>\n'])
+                       list.extend(('  <exclude where="shortdescription">', stringToXML(short), '</exclude>\n'))
                for desc in timer.getExcludedDescription():
-                       list.extend(['  <exclude where="description">', stringToXML(desc), '</exclude>\n'])
+                       list.extend(('  <exclude where="description">', stringToXML(desc), '</exclude>\n'))
                for day in timer.getExcludedDays():
-                       list.extend(['  <exclude where="dayofweek">', stringToXML(day), '</exclude>\n'])
+                       list.extend(('  <exclude where="dayofweek">', stringToXML(day), '</exclude>\n'))
 
                # Includes
                for title in timer.getIncludedTitle():
-                       list.extend(['  <include where="title">', stringToXML(title), '</include>\n'])
+                       list.extend(('  <include where="title">', stringToXML(title), '</include>\n'))
                for short in timer.getIncludedShort():
-                       list.extend(['  <include where="shortdescription">', stringToXML(short), '</include>\n'])
+                       list.extend(('  <include where="shortdescription">', stringToXML(short), '</include>\n'))
                for desc in timer.getIncludedDescription():
-                       list.extend(['  <include where="description">', stringToXML(desc), '</include>\n'])
+                       list.extend(('  <include where="description">', stringToXML(desc), '</include>\n'))
                for day in timer.getIncludedDays():
-                       list.extend(['  <include where="dayofweek">', stringToXML(day), '</include>\n'])
+                       list.extend(('  <include where="dayofweek">', stringToXML(day), '</include>\n'))
 
                # Tags
                for tag in timer.tags:
-                       list.extend(['  <tag>', stringToXML(tag), '</tag>\n'])
+                       list.extend(('  <tag>', stringToXML(tag), '</tag>\n'))
 
                # End of Timer
                list.append(' </timer>\n\n')
@@ -638,9 +730,5 @@ def writeConfig(filename, defaultTimer, timers):
        # End of Configuration
        list.append('</autotimer>\n')
 
-       # Save to Flash
-       file = open(filename, 'w')
-       file.writelines(list)
-
-       file.close()
+       return list