autotimer: reduce xml config version to 5 again
[enigma2-plugins.git] / autotimer / src / AutoTimerConfiguration.py
1 # -*- coding: UTF-8 -*-
2 # for localized messages
3 from . import _
4
5 from AutoTimerComponent import preferredAutoTimerComponent
6 from RecordTimer import AFTEREVENT
7 from Tools.XMLTools import stringToXML
8 from ServiceReference import ServiceReference
9
10 from enigma import eServiceReference
11
12 CURRENT_CONFIG_VERSION = "5"
13
14 def getValue(definitions, default):
15         # Initialize Output
16         ret = ""
17
18         # How many definitions are present
19         if isinstance(definitions, list):
20                 Len = len(definitions)
21                 if Len > 0:
22                         childNodes = definitions[Len-1].text
23                 else:
24                         childNodes = ""
25         else:
26                 ret = definitions.text
27
28         # Return stripped output or (if empty) default
29         return ret.strip() or default
30
31 def parseConfig(configuration, list, version = None, uniqueTimerId = 0, defaultTimer = None):
32         if version != CURRENT_CONFIG_VERSION:
33                 parseConfigOld(configuration, list, uniqueTimerId)
34                 return
35
36         if defaultTimer is not None:
37                 # Read in defaults for a new timer
38                 for defaults in configuration.findall("defaults"):
39                         parseEntry(defaults, defaultTimer, True)
40
41         for timer in configuration.findall("timer"):
42                 uniqueTimerId += 1
43                 baseTimer = preferredAutoTimerComponent(
44                         uniqueTimerId,
45                         '',
46                         '',
47                         True
48                 )
49
50                 if parseEntry(timer, baseTimer):
51                         list.append(baseTimer)
52
53 def parseEntry(element, baseTimer, defaults = False):
54         if not defaults:
55                 # Read out match
56                 baseTimer.match = element.get("match", "").encode("UTF-8")
57                 if not baseTimer.match:
58                         print '[AutoTimer] Erroneous config is missing attribute "match", skipping entry'
59                         return False
60
61                 # Read out name
62                 baseTimer.name = element.get("name", "").encode("UTF-8")
63                 if not baseTimer.name:
64                         print '[AutoTimer] Timer is missing attribute "name", defaulting to match'
65                         baseTimer.name = baseTimer.match
66
67                 # Read out enabled
68                 enabled = element.get("enabled", "yes")
69                 if enabled == "no":
70                         baseTimer.enabled = False
71                 elif enabled == "yes":
72                         baseTimer.enabled = True
73                 else:
74                         print '[AutoTimer] Erroneous config contains invalid value for "enabled":', enabled,', disabling'
75                         baseTimer.enabled = False
76
77                 # Read timeframe
78                 before = element.get("before")
79                 after = element.get("after")
80                 if before and after:
81                         baseTimer.timeframe = (int(after), int(before))
82
83                 # VPS-Plugin settings
84                 vps_enabled = element.get("vps_enabled", "no")
85                 vps_overwrite = element.get("vps_overwrite", "no")
86                 baseTimer.vps_enabled = True if vps_enabled == "yes" else False
87                 baseTimer.vps_overwrite = True if vps_overwrite == "yes" else False
88                 del vps_enabled, vps_overwrite
89
90         # Read out encoding (won't change if no value is set)
91         baseTimer.encoding = element.get("encoding")
92
93         # Read out search type/case
94         baseTimer.searchType = element.get("searchType", baseTimer.searchType)
95         baseTimer.searchCase = element.get("searchCase", baseTimer.searchCase)
96
97         # Read out if we should change to alternative services
98         baseTimer.overrideAlternatives = int(element.get("overrideAlternatives", baseTimer.overrideAlternatives))
99
100         # Read out timespan
101         start = element.get("from")
102         end = element.get("to")
103         if start and end:
104                 start = [int(x) for x in start.split(':')]
105                 end = [int(x) for x in end.split(':')]
106                 baseTimer.timespan = (start, end)
107
108         # Read out max length
109         maxduration = element.get("maxduration")
110         if maxduration:
111                 baseTimer.maxduration = int(maxduration)*60
112
113         # Read out recording path
114         default = baseTimer.destination or ""
115         baseTimer.destination = element.get("location", default).encode("UTF-8") or None
116
117         # Read out offset
118         offset = element.get("offset")
119         if offset:
120                 offset = offset.split(",")
121                 if len(offset) == 1:
122                         before = after = int(offset[0] or 0) * 60
123                 else:
124                         before = int(offset[0] or 0) * 60
125                         after = int(offset[1] or 0) * 60
126                 baseTimer.offset = (before, after)
127
128         # Read out counter
129         baseTimer.matchCount = int(element.get("counter", 0))
130         baseTimer.matchFormatString = element.get("counterFormat", "")
131         if not defaults:
132                 baseTimer.matchLeft = int(element.get("left", baseTimer.matchCount))
133                 baseTimer.matchLimit = element.get("lastActivation", "")
134                 baseTimer.lastBegin = int(element.get("lastBegin", 0))
135
136         # Read out justplay
137         baseTimer.justplay = int(element.get("justplay", 0))
138
139         # Read out avoidDuplicateDescription
140         baseTimer.avoidDuplicateDescription = int(element.get("avoidDuplicateDescription", 0))
141
142         # Read out allowed services
143         l = element.findall("serviceref")
144         if l:
145                 servicelist = []
146
147                 for service in l:
148                         value = service.text
149                         if value:
150                                 myref = eServiceReference(str(value))
151                                 if not (myref.flags & eServiceReference.isGroup):
152                                         # strip all after last :
153                                         pos = value.rfind(':')
154                                         if pos != -1:
155                                                 if value[pos-1] == ':':
156                                                         pos -= 1
157                                                 value = value[:pos+1]
158
159                                 servicelist.append(value)
160                 baseTimer.services = servicelist
161
162         # Read out allowed bouquets
163         l = element.findall("bouquet")
164         if l:
165                 bouquets = []
166                 for bouquet in l:
167                         value = bouquet.text
168                         if value:
169                                 bouquets.append(value)
170                 baseTimer.bouquets = bouquets
171
172         # Read out afterevent
173         l = element.findall("afterevent")
174         if l:
175                 idx = {
176                         "none": AFTEREVENT.NONE,
177                         "deepstandby": AFTEREVENT.DEEPSTANDBY,
178                         "shutdown": AFTEREVENT.DEEPSTANDBY,
179                         "standby": AFTEREVENT.STANDBY,
180                         "auto": AFTEREVENT.AUTO
181                 }
182                 afterevents = []
183                 for afterevent in l:
184                         value = afterevent.text
185
186                         if idx.has_key(value):
187                                 value = idx[value]
188                         else:
189                                 print '[AutoTimer] Erroneous config contains invalid value for "afterevent":', afterevent,', ignoring definition'
190                                 continue
191
192                         start = afterevent.get("from")
193                         end = afterevent.get("to")
194                         if start and end:
195                                 start = [int(x) for x in start.split(':')]
196                                 end = [int(x) for x in end.split(':')]
197                                 afterevents.append((value, (start, end)))
198                         else:
199                                 afterevents.append((value, None))
200                 baseTimer.afterevent = afterevents
201
202         # Read out exclude
203         l = element.findall("exclude")
204         idx = {"title": 0, "shortdescription": 1, "description": 2, "dayofweek": 3}
205         if l:
206                 excludes = ([], [], [], [])
207                 for exclude in l:
208                         where = exclude.get("where")
209                         value = exclude.text
210                         if not (value and where):
211                                 continue
212
213                         if idx.has_key(where):
214                                 excludes[idx[where]].append(value.encode("UTF-8"))
215                 baseTimer.exclude = excludes
216
217         # Read out includes (use same idx)
218         l = element.findall("include")
219         if l:
220                 includes = ([], [], [], [])
221                 for include in l:
222                         where = include.get("where")
223                         value = include.text
224                         if not (value and where):
225                                 continue
226
227                         if idx.has_key(where):
228                                 includes[idx[where]].append(value.encode("UTF-8"))
229                 baseTimer.include = includes
230
231         # Read out recording tags
232         l =  element.findall("tag")
233         if l:
234                 tags = []
235                 for tag in l:
236                         value = tag.text
237                         if not value:
238                                 continue
239
240                         tags.append(value.encode("UTF-8"))
241                 baseTimer.tags = tags
242
243         return True
244
245 def parseConfigOld(configuration, list, uniqueTimerId = 0):
246         print "[AutoTimer] Trying to parse old config"
247
248         # Iterate Timers
249         for timer in configuration.findall("timer"):
250                 # Increment uniqueTimerId
251                 uniqueTimerId += 1
252
253                 # Get name (V2+)
254                 name = timer.get("name")
255                 if name:
256                         name = name.encode("UTF-8")
257                 # Get name (= match) (V1)
258                 else:
259                         # Read out name
260                         name = getValue(timer.findall("name"), "").encode("UTF-8")
261
262                 if not name:
263                         print '[AutoTimer] Erroneous config is missing attribute "name", skipping entry'
264                         continue
265
266                 # Read out match (V3+)
267                 match = timer.get("match")
268                 if match:
269                         # Read out match
270                         match = match.encode("UTF-8")
271                         if not match:
272                                 print '[AutoTimer] Erroneous config contains empty attribute "match", skipping entry'
273                                 continue
274                 # V2-
275                 else:
276                         # Setting match to name
277                         match = name
278
279
280                 # See if Timer is ensabled (V2+)
281                 enabled = timer.get("enabled")
282                 if enabled:
283                         if enabled == "no":
284                                 enabled = False
285                         elif enabled == "yes":
286                                 enabled = True
287                         else:
288                                 print '[AutoTimer] Erroneous config contains invalid value for "enabled":', enabled,', skipping entry'
289                                 enabled = False
290                 # V1
291                 else:
292                         elements = timer.findall("enabled")
293                         if elements:
294                                 if getValue(elements, "yes") == "no":
295                                         enabled = False
296                                 else:
297                                         enabled = True
298                         else:
299                                 enabled = True
300
301                 # Read out timespan (V4+; Falling back on missing definition should be OK)
302                 start = timer.get("from")
303                 end = timer.get("to")
304                 if start and end:
305                         start = [int(x) for x in start.split(':')]
306                         end = [int(x) for x in end.split(':')]
307                         timetuple = (start, end)
308                 # V3-
309                 else:
310                         elements = timer.findall("timespan")
311                         Len = len(elements)
312                         if Len:
313                                 # Read out last definition
314                                 start = elements[Len-1].get("from")
315                                 end = elements[Len-1].get("to")
316                                 if start and end:
317                                         start = [int(x) for x in start.split(':')]
318                                         end = [int(x) for x in end.split(':')]
319                                         timetuple = (start, end)
320                                 else:
321                                         print '[AutoTimer] Erroneous config contains invalid definition of "timespan", ignoring definition'
322                                         timetuple = None
323                         else:
324                                 timetuple = None
325
326                 # Read out allowed services (V*)
327                 elements = timer.findall("serviceref")
328                 if elements:
329                         servicelist = []
330                         for service in elements:
331                                 value = service.text
332                                 if value:
333                                         myref = eServiceReference(str(value))
334                                         if not (myref.flags & eServiceReference.isGroup):
335                                                 # strip all after last :
336                                                 pos = value.rfind(':')
337                                                 if pos != -1:
338                                                         if value[pos-1] == ':':
339                                                                 pos -= 1
340                                                         value = value[:pos+1]
341
342                                         servicelist.append(value)
343                 else:
344                         servicelist = None
345
346                 # Read out allowed bouquets (V* though officially supported since V4)
347                 bouquets = []
348                 for bouquet in timer.findall("bouquet"):
349                         value = bouquet.text
350                         if value:
351                                 bouquets.append(value)
352
353                 # Read out offset (V4+)
354                 offset = timer.get("offset")
355                 if offset:
356                         offset = offset.split(",")
357                         if len(offset) == 1:
358                                 before = after = int(offset[0] or 0) * 60
359                         else:
360                                 before = int(offset[0] or 0) * 60
361                                 after = int(offset[1] or 0) * 60
362                         offset = (before, after)
363                 # V3-
364                 else:
365                         elements = timer.findall("offset")
366                         Len = len(elements)
367                         if Len:
368                                 value = elements[Len-1].get("both")
369                                 if value == '':
370                                         before = int(elements[Len-1].get("before", 0)) * 60
371                                         after = int(elements[Len-1].get("after", 0)) * 60
372                                 else:
373                                         before = after = int(value) * 60
374                                 offset = (before, after)
375                         else:
376                                 offset = None
377
378                 # Read out counter
379                 counter = int(timer.get("counter", '0'))
380                 counterLeft = int(timer.get("left", counter))
381                 counterLimit = timer.get("lastActivation")
382                 counterFormat = timer.get("counterFormat", "")
383                 lastBegin = int(timer.get("lastBegin", 0))
384
385                 # Read out justplay
386                 justplay = int(timer.get("justplay", '0'))
387
388                 # Read out avoidDuplicateDescription
389                 avoidDuplicateDescription = int(timer.get("avoidDuplicateDescription", 0))
390
391                 # Read out afterevent (compatible to V* though behaviour for V3- is different as V4+ allows multiple afterevents while the last definication was chosen before)
392                 idx = {
393                         "none": AFTEREVENT.NONE,
394                         "deepstandby": AFTEREVENT.DEEPSTANDBY,
395                         "shutdown": AFTEREVENT.DEEPSTANDBY,
396                         "standby": AFTEREVENT.STANDBY,
397                         "auto": AFTEREVENT.AUTO
398                 }
399                 afterevent = []
400                 for element in timer.findall("afterevent"):
401                         value = element.text
402
403                         if idx.has_key(value):
404                                 value = idx[value]
405                         else:
406                                 print '[AutoTimer] Erroneous config contains invalid value for "afterevent":', afterevent,', ignoring definition'
407                                 continue
408
409                         start = element.get("from")
410                         end = element.get("to")
411                         if start and end:
412                                 start = [int(x) for x in start.split(':')]
413                                 end = [int(x) for x in end.split(':')]
414                                 afterevent.append((value, (start, end)))
415                         else:
416                                 afterevent.append((value, None))
417
418                 # Read out exclude (V*)
419                 idx = {"title": 0, "shortdescription": 1, "description": 2, "dayofweek": 3}
420                 excludes = ([], [], [], [])
421                 for exclude in timer.findall("exclude"):
422                         where = exclude.get("where")
423                         value = exclude.text
424                         if not (value and where):
425                                 continue
426
427                         if idx.has_key(where):
428                                 excludes[idx[where]].append(value.encode("UTF-8"))
429
430                 # Read out includes (use same idx) (V4+ feature, should not harm V3-)
431                 includes = ([], [], [], [])
432                 for include in timer.findall("include"):
433                         where = include.get("where")
434                         value = include.text
435                         if not (value and where):
436                                 continue
437
438                         if idx.has_key(where):
439                                 includes[idx[where]].append(value.encode("UTF-8"))
440
441                 # Read out max length (V4+)
442                 maxlen = timer.get("maxduration")
443                 if maxlen:
444                         maxlen = int(maxlen)*60
445                 # V3-
446                 else:
447                         elements = timer.findall("maxduration")
448                         if elements:
449                                 maxlen = getValue(elements, None)
450                                 if maxlen is not None:
451                                         maxlen = int(maxlen)*60
452                         else:
453                                 maxlen = None
454
455                 # Read out recording path
456                 destination = timer.get("destination", "").encode("UTF-8") or None
457
458                 # Read out recording tags
459                 tags = []
460                 for tag in timer.findall("tag"):
461                         value = tag.text
462                         if not value:
463                                 continue
464
465                         tags.append(value.encode("UTF-8"))
466
467                 # Finally append timer
468                 list.append(preferredAutoTimerComponent(
469                                 uniqueTimerId,
470                                 name,
471                                 match,
472                                 enabled,
473                                 timespan = timetuple,
474                                 services = servicelist,
475                                 offset = offset,
476                                 afterevent = afterevent,
477                                 exclude = excludes,
478                                 include = includes,
479                                 maxduration = maxlen,
480                                 destination = destination,
481                                 matchCount = counter,
482                                 matchLeft = counterLeft,
483                                 matchLimit = counterLimit,
484                                 matchFormatString = counterFormat,
485                                 lastBegin = lastBegin,
486                                 justplay = justplay,
487                                 avoidDuplicateDescription = avoidDuplicateDescription,
488                                 bouquets = bouquets,
489                                 tags = tags
490                 ))
491
492 def buildConfig(defaultTimer, timers, webif = False):
493         # Generate List in RAM
494         list = ['<?xml version="1.0" ?>\n<autotimer version="', CURRENT_CONFIG_VERSION, '">\n\n']
495         append = list.append
496         extend = list.extend
497
498         # This gets deleted afterwards if we do not have set any defaults
499         append(' <defaults')
500         if webif:
501                 extend((' id="', str(defaultTimer.getId()),'"'))
502
503         # Timespan
504         if defaultTimer.hasTimespan():
505                 extend((' from="', defaultTimer.getTimespanBegin(), '" to="', defaultTimer.getTimespanEnd(), '"'))
506
507         # Duration
508         if defaultTimer.hasDuration():
509                 extend((' maxduration="', str(defaultTimer.getDuration()), '"'))
510
511         # Destination
512         if defaultTimer.hasDestination():
513                 extend((' location="', stringToXML(defaultTimer.destination), '"'))
514
515         # Offset
516         if defaultTimer.hasOffset():
517                 if defaultTimer.isOffsetEqual():
518                         extend((' offset="', str(defaultTimer.getOffsetBegin()), '"'))
519                 else:
520                         extend((' offset="', str(defaultTimer.getOffsetBegin()), ',', str(defaultTimer.getOffsetEnd()), '"'))
521
522         # Counter
523         if defaultTimer.hasCounter():
524                 extend((' counter="', str(defaultTimer.getCounter()), '"'))
525                 if defaultTimer.hasCounterFormatString():
526                         extend((' counterFormat="', str(defaultTimer.getCounterFormatString()), '"'))
527
528         # Duplicate Description
529         if defaultTimer.getAvoidDuplicateDescription():
530                 extend((' avoidDuplicateDescription="', str(defaultTimer.getAvoidDuplicateDescription()), '"'))
531
532         # Only display justplay if true
533         if defaultTimer.justplay:
534                 extend((' justplay="', str(defaultTimer.getJustplay()), '"'))
535
536         # Only display encoding if != utf-8
537         if defaultTimer.encoding != 'UTF-8' or webif:
538                 extend((' encoding="', str(defaultTimer.encoding), '"'))
539
540         # Only display searchType if exact
541         if defaultTimer.searchType == "exact":
542                 extend((' searchType="', str(defaultTimer.searchType), '"'))
543
544         # Only display searchCase if sensitive
545         if defaultTimer.searchCase == "sensitive":
546                 extend((' searchCase="', str(defaultTimer.searchCase), '"'))
547
548         # Close still opened defaults tag
549         append('>\n')
550
551         if webif:
552                 # Services + Bouquets
553                 for serviceref in defaultTimer.services + defaultTimer.bouquets:
554                         ref = ServiceReference(str(serviceref))
555                         extend((
556                                 '  <e2service>\n',
557                                 '   <e2servicereference>', str(serviceref), '</e2servicereference>\n',
558                                 '   <e2servicename>', stringToXML(ref.getServiceName().replace('\xc2\x86', '').replace('\xc2\x87', '')), '</e2servicename>\n',
559                                 '  </e2service>\n',
560                         ))
561         else:
562                 # Services
563                 for serviceref in defaultTimer.services:
564                         ref = ServiceReference(str(serviceref))
565                         extend(('  <serviceref>', serviceref, '</serviceref>',
566                                                 ' <!-- ', stringToXML(ref.getServiceName().replace('\xc2\x86', '').replace('\xc2\x87', '')), ' -->\n',
567                         ))
568
569                 # Bouquets
570                 for bouquet in defaultTimer.bouquets:
571                         ref = ServiceReference(str(bouquet))
572                         extend(('  <bouquet>', str(bouquet), '</bouquet>',
573                                                 ' <!-- ', stringToXML(ref.getServiceName().replace('\xc2\x86', '').replace('\xc2\x87', '')), ' -->\n',
574                         ))
575
576         # AfterEvent
577         if defaultTimer.hasAfterEvent():
578                 idx = {
579                         AFTEREVENT.NONE: "none",
580                         AFTEREVENT.STANDBY: "standby",
581                         AFTEREVENT.DEEPSTANDBY: "shutdown",
582                         AFTEREVENT.AUTO: "auto"
583                 }
584                 for afterevent in defaultTimer.afterevent:
585                         action, timespan = afterevent
586                         append('  <afterevent')
587                         if timespan[0] is not None:
588                                 append(' from="%02d:%02d" to="%02d:%02d"' % (timespan[0][0], timespan[0][1], timespan[1][0], timespan[1][1]))
589                         extend(('>', idx[action], '</afterevent>\n'))
590
591         # Excludes
592         for title in defaultTimer.getExcludedTitle():
593                 extend(('  <exclude where="title">', stringToXML(title), '</exclude>\n'))
594         for short in defaultTimer.getExcludedShort():
595                 extend(('  <exclude where="shortdescription">', stringToXML(short), '</exclude>\n'))
596         for desc in defaultTimer.getExcludedDescription():
597                 extend(('  <exclude where="description">', stringToXML(desc), '</exclude>\n'))
598         for day in defaultTimer.getExcludedDays():
599                 extend(('  <exclude where="dayofweek">', stringToXML(day), '</exclude>\n'))
600
601         # Includes
602         for title in defaultTimer.getIncludedTitle():
603                 extend(('  <include where="title">', stringToXML(title), '</include>\n'))
604         for short in defaultTimer.getIncludedShort():
605                 extend(('  <include where="shortdescription">', stringToXML(short), '</include>\n'))
606         for desc in defaultTimer.getIncludedDescription():
607                 extend(('  <include where="description">', stringToXML(desc), '</include>\n'))
608         for day in defaultTimer.getIncludedDays():
609                 extend(('  <include where="dayofweek">', stringToXML(day), '</include>\n'))
610
611         # Tags
612         if webif and defaultTimer.tags:
613                 extend(('  <e2tags>', stringToXML(' '.join(defaultTimer.tags)), '</e2tags>\n'))
614         else:
615                 for tag in defaultTimer.tags:
616                         extend(('  <tag>', stringToXML(tag), '</tag>\n'))
617
618         # Keep the list clean
619         if len(list) == 5:
620                 list.pop() # >
621                 list.pop() # <defaults
622         else:
623                 append(' </defaults>\n\n')
624
625         # Iterate timers
626         for timer in timers:
627                 # Common attributes (match, enabled)
628                 extend((' <timer name="', stringToXML(timer.name), '" match="', stringToXML(timer.match), '" enabled="', timer.getEnabled(), '"'))
629                 if webif:
630                         extend((' id="', str(timer.getId()),'"'))
631
632                 # Timespan
633                 if timer.hasTimespan():
634                         extend((' from="', timer.getTimespanBegin(), '" to="', timer.getTimespanEnd(), '"'))
635
636                 # Timeframe
637                 if timer.hasTimeframe():
638                         extend((' after="', str(timer.getTimeframeBegin()), '" before="', str(timer.getTimeframeEnd()), '"'))
639
640                 # Duration
641                 if timer.hasDuration():
642                         extend((' maxduration="', str(timer.getDuration()), '"'))
643
644                 # Destination
645                 if timer.hasDestination():
646                         extend((' location="', stringToXML(timer.destination), '"'))
647
648                 # Offset
649                 if timer.hasOffset():
650                         if timer.isOffsetEqual():
651                                 extend((' offset="', str(timer.getOffsetBegin()), '"'))
652                         else:
653                                 extend((' offset="', str(timer.getOffsetBegin()), ',', str(timer.getOffsetEnd()), '"'))
654
655                 # Counter
656                 if timer.hasCounter():
657                         extend((' lastBegin="', str(timer.getLastBegin()), '" counter="', str(timer.getCounter()), '" left="', str(timer.getCounterLeft()) ,'"'))
658                         if timer.hasCounterFormatString():
659                                 extend((' lastActivation="', str(timer.getCounterLimit()), '"'))
660                                 extend((' counterFormat="', str(timer.getCounterFormatString()), '"'))
661
662                 # Duplicate Description
663                 if timer.getAvoidDuplicateDescription():
664                         extend((' avoidDuplicateDescription="', str(timer.getAvoidDuplicateDescription()), '"'))
665
666                 # Only display justplay if true
667                 if timer.justplay:
668                         extend((' justplay="', str(timer.getJustplay()), '"'))
669
670                 # Only display encoding if != utf-8
671                 if timer.encoding != 'UTF-8' or webif:
672                         extend((' encoding="', str(timer.encoding), '"'))
673
674                 # Only display searchType if exact
675                 if timer.searchType == "exact":
676                         extend((' searchType="', str(timer.searchType), '"'))
677
678                 # Only display searchCase if sensitive
679                 if timer.searchCase == "sensitive":
680                         extend((' searchCase="', str(timer.searchCase), '"'))
681
682                 # Only display overrideAlternatives if true
683                 if timer.overrideAlternatives:
684                         extend((' overrideAlternatives="', str(timer.getOverrideAlternatives()), '"'))
685
686                 # Only add vps related entries if true
687                 if timer.vps_enabled:
688                         append(' vps_enabled="yes"')
689                         if timer.vps_overwrite:
690                                 append(' vps_overwrite="yes"')
691
692                 # Close still opened timer tag
693                 append('>\n')
694
695                 if webif:
696                         # Services + Bouquets
697                         for serviceref in timer.services + timer.bouquets:
698                                 ref = ServiceReference(str(serviceref))
699                                 extend((
700                                         '  <e2service>\n',
701                                         '   <e2servicereference>', str(serviceref), '</e2servicereference>\n',
702                                         '   <e2servicename>', stringToXML(ref.getServiceName().replace('\xc2\x86', '').replace('\xc2\x87', '')), '</e2servicename>\n',
703                                         '  </e2service>\n',
704                                 ))
705                 else:
706                         # Services
707                         for serviceref in timer.services:
708                                 ref = ServiceReference(str(serviceref))
709                                 extend(('  <serviceref>', serviceref, '</serviceref>',
710                                                         ' <!-- ', stringToXML(ref.getServiceName().replace('\xc2\x86', '').replace('\xc2\x87', '')), ' -->\n',
711                                 ))
712
713                         # Bouquets
714                         for bouquet in timer.bouquets:
715                                 ref = ServiceReference(str(bouquet))
716                                 extend(('  <bouquet>', str(bouquet), '</bouquet>',
717                                                         ' <!-- ', stringToXML(ref.getServiceName().replace('\xc2\x86', '').replace('\xc2\x87', '')), ' -->\n',
718                                 ))
719
720                 # AfterEvent
721                 if timer.hasAfterEvent():
722                         idx = {
723                                 AFTEREVENT.NONE: "none",
724                                 AFTEREVENT.STANDBY: "standby",
725                                 AFTEREVENT.DEEPSTANDBY: "shutdown",
726                                 AFTEREVENT.AUTO: "auto"
727                         }
728                         for afterevent in timer.afterevent:
729                                 action, timespan = afterevent
730                                 append('  <afterevent')
731                                 if timespan[0] is not None:
732                                         append(' from="%02d:%02d" to="%02d:%02d"' % (timespan[0][0], timespan[0][1], timespan[1][0], timespan[1][1]))
733                                 extend(('>', idx[action], '</afterevent>\n'))
734
735                 # Excludes
736                 for title in timer.getExcludedTitle():
737                         extend(('  <exclude where="title">', stringToXML(title), '</exclude>\n'))
738                 for short in timer.getExcludedShort():
739                         extend(('  <exclude where="shortdescription">', stringToXML(short), '</exclude>\n'))
740                 for desc in timer.getExcludedDescription():
741                         extend(('  <exclude where="description">', stringToXML(desc), '</exclude>\n'))
742                 for day in timer.getExcludedDays():
743                         extend(('  <exclude where="dayofweek">', stringToXML(day), '</exclude>\n'))
744
745                 # Includes
746                 for title in timer.getIncludedTitle():
747                         extend(('  <include where="title">', stringToXML(title), '</include>\n'))
748                 for short in timer.getIncludedShort():
749                         extend(('  <include where="shortdescription">', stringToXML(short), '</include>\n'))
750                 for desc in timer.getIncludedDescription():
751                         extend(('  <include where="description">', stringToXML(desc), '</include>\n'))
752                 for day in timer.getIncludedDays():
753                         extend(('  <include where="dayofweek">', stringToXML(day), '</include>\n'))
754
755                 # Tags
756                 if webif and timer.tags:
757                         extend(('  <e2tags>', stringToXML(' '.join(timer.tags)), '</e2tags>\n'))
758                 else:
759                         for tag in timer.tags:
760                                 extend(('  <tag>', stringToXML(tag), '</tag>\n'))
761
762                 # End of Timer
763                 append(' </timer>\n\n')
764
765         # End of Configuration
766         append('</autotimer>\n')
767
768         return list
769