[FritzCall] FIX: DSL message for older FWs
[enigma2-plugins.git] / fritzcall / src / plugin.py
1 # -*- coding: utf-8 -*-
2 '''
3 Update rev
4 $Author: michael $
5 $Revision: 1039 $
6 $Date: 2014-11-15 16:13:49 +0100 (Sat, 15 Nov 2014) $
7 $Id: plugin.py 1039 2014-11-15 15:13:49Z michael $
8 '''
9
10 # C0111 (Missing docstring)
11 # C0103 (Invalid name)
12 # C0301 (line too long)
13 # W0603 (global statement)
14 # W0141 (map, filter, etc.)
15 # W0110 lambda with map,filter
16 # W0403 Relative import
17 # W1401 Anomalous backslash in string
18 # W0110 
19 # pylint: disable=C0111,C0103,C0301,W0603,W0141,W0403
20
21 from Screens.Screen import Screen
22 from Screens.MessageBox import MessageBox
23 from Screens.NumericalTextInputHelpDialog import NumericalTextInputHelpDialog
24 from Screens.InputBox import InputBox
25 from Screens import Standby
26 from Screens.HelpMenu import HelpableScreen
27 from Screens.LocationBox import LocationBox
28
29 from enigma import eTimer, eSize, ePoint #@UnresolvedImport # pylint: disable=E0611
30 from enigma import eDVBVolumecontrol, eConsoleAppContainer, eBackgroundFileEraser #@UnresolvedImport # pylint: disable=E0611
31 #BgFileEraser = eBackgroundFileEraser.getInstance()
32 #BgFileEraser.erase("blabla.txt")
33
34 from Components.ActionMap import ActionMap
35 from Components.Label import Label
36 from Components.Button import Button
37 from Components.Pixmap import Pixmap
38 from Components.Sources.List import List
39 from Components.config import config, ConfigSubsection, ConfigSelection, ConfigDirectory, ConfigEnableDisable, getConfigListEntry, ConfigText, ConfigInteger
40 from Components.ConfigList import ConfigListScreen
41 try:
42         from Components.config import ConfigPassword
43 except ImportError:
44         ConfigPassword = ConfigText
45
46 from Plugins.Plugin import PluginDescriptor
47 from Tools import Notifications
48 from Tools.NumericalTextInput import NumericalTextInput
49 from Tools.Directories import resolveFilename, SCOPE_PLUGINS, SCOPE_SKIN_IMAGE, SCOPE_CONFIG
50 from Tools.LoadPixmap import LoadPixmap
51 from GlobalActions import globalActionMap # for muting
52
53 from twisted.internet import reactor #@UnresolvedImport
54 from twisted.internet.protocol import ReconnectingClientFactory #@UnresolvedImport
55 from twisted.protocols.basic import LineReceiver #@UnresolvedImport
56
57 import re, time, os, traceback
58
59 from nrzuname import ReverseLookupAndNotifier
60 import FritzOutlookCSV, FritzLDIF
61 from . import _, __, initDebug, debug #@UnresolvedImport # pylint: disable=W0611,F0401
62
63 from enigma import getDesktop
64 DESKTOP_WIDTH = getDesktop(0).size().width()
65 DESKTOP_HEIGHT = getDesktop(0).size().height()
66
67 #
68 # this is pure magic.
69 # It returns the first value, if HD (1280x720),
70 # the second if SD (720x576),
71 # else something scaled accordingly
72 # if one of the parameters is -1, scale proportionally
73 #
74 def scaleH(y2, y1):
75         if y2 == -1:
76                 y2 = y1*1280/720
77         elif y1 == -1:
78                 y1 = y2*720/1280
79         return scale(y2, y1, 1280, 720, DESKTOP_WIDTH)
80 def scaleV(y2, y1):
81         if y2 == -1:
82                 y2 = y1*720/576
83         elif y1 == -1:
84                 y1 = y2*576/720
85         return scale(y2, y1, 720, 576, DESKTOP_HEIGHT)
86 def scale(y2, y1, x2, x1, x):
87         return (y2 - y1) * (x - x1) / (x2 - x1) + y1
88
89 my_global_session = None
90
91 config.plugins.FritzCall = ConfigSubsection()
92 config.plugins.FritzCall.fwVersion = ConfigSelection(choices=[(None, _("not configured")), ("old", _("before 05.27")), ("05.27", "05.27, 05.28"), ("05.50", "05.29 and newer")], default=None)
93 config.plugins.FritzCall.debug = ConfigEnableDisable(default=False)
94 #config.plugins.FritzCall.muteOnCall = ConfigSelection(choices=[(None, _("no")), ("ring", _("on ring")), ("connect", _("on connect"))])
95 #config.plugins.FritzCall.muteOnCall = ConfigSelection(choices=[(None, _("no")), ("ring", _("on ring"))])
96 config.plugins.FritzCall.muteOnCall = ConfigEnableDisable(default=False)
97 config.plugins.FritzCall.hostname = ConfigText(default="fritz.box", fixed_size=False)
98 config.plugins.FritzCall.afterStandby = ConfigSelection(choices=[("none", _("show nothing")), ("inList", _("show as list")), ("each", _("show each call"))])
99 config.plugins.FritzCall.filter = ConfigEnableDisable(default=False)
100 config.plugins.FritzCall.filtermsn = ConfigText(default="", fixed_size=False)
101 config.plugins.FritzCall.filtermsn.setUseableChars('0123456789,')
102 config.plugins.FritzCall.filterCallList = ConfigEnableDisable(default=True)
103 config.plugins.FritzCall.showOutgoing = ConfigEnableDisable(default=False)
104 config.plugins.FritzCall.timeout = ConfigInteger(default=15, limits=(0, 60))
105 config.plugins.FritzCall.lookup = ConfigEnableDisable(default=False)
106 config.plugins.FritzCall.internal = ConfigEnableDisable(default=False)
107 config.plugins.FritzCall.fritzphonebook = ConfigEnableDisable(default=False)
108 config.plugins.FritzCall.fritzphonebookName = ConfigText(default='Dreambox', fixed_size=False)
109 config.plugins.FritzCall.phonebook = ConfigEnableDisable(default=False)
110 config.plugins.FritzCall.addcallers = ConfigEnableDisable(default=False)
111 config.plugins.FritzCall.enable = ConfigEnableDisable(default=False)
112 config.plugins.FritzCall.username = ConfigText(default='BoxAdmin', fixed_size=False)
113 config.plugins.FritzCall.password = ConfigPassword(default="", fixed_size=False)
114 config.plugins.FritzCall.extension = ConfigText(default='1', fixed_size=False)
115 config.plugins.FritzCall.extension.setUseableChars('0123456789')
116 config.plugins.FritzCall.showType = ConfigEnableDisable(default=True)
117 config.plugins.FritzCall.showShortcut = ConfigEnableDisable(default=False)
118 config.plugins.FritzCall.showVanity = ConfigEnableDisable(default=False)
119 config.plugins.FritzCall.prefix = ConfigText(default="", fixed_size=False)
120 config.plugins.FritzCall.prefix.setUseableChars('0123456789')
121 config.plugins.FritzCall.connectionVerbose = ConfigEnableDisable(default=True)
122 config.plugins.FritzCall.ignoreUnknown = ConfigEnableDisable(default=False)
123 config.plugins.FritzCall.reloadPhonebookTime = ConfigInteger(default=8, limits=(0, 99))
124 config.plugins.FritzCall.FritzExtendedSearchFaces = ConfigEnableDisable(default=False)
125 config.plugins.FritzCall.FritzExtendedSearchNames = ConfigEnableDisable(default=False)
126 config.plugins.FritzCall.phonebookLocation = ConfigDirectory(default = resolveFilename(SCOPE_CONFIG))
127 config.plugins.FritzCall.guestSSID = ConfigText(default="FRITZ!Box Gastzugang", fixed_size=False)
128 config.plugins.FritzCall.guestSecure = ConfigEnableDisable(default=True)
129 config.plugins.FritzCall.guestPassword = ConfigText(default="guestguest!!!", fixed_size=False)
130
131 countryCodes = [
132         ("0049", _("Germany")),
133         ("0031", _("The Netherlands")),
134         ("0033", _("France")),
135         ("0039", _("Italy")),
136         ("0041", _("Switzerland")),
137         ("0043", _("Austria")),
138         ("", _("Others"))
139         ]
140 config.plugins.FritzCall.country = ConfigSelection(choices=countryCodes)
141
142 FBF_ALL_CALLS = "."
143 FBF_IN_CALLS = "1"
144 FBF_MISSED_CALLS = "2"
145 FBF_OUT_CALLS = "3"
146 fbfCallsChoices = {FBF_ALL_CALLS: _("All calls"),
147                                    FBF_IN_CALLS: _("Incoming calls"),
148                                    FBF_MISSED_CALLS: _("Missed calls"),
149                                    FBF_OUT_CALLS: _("Outgoing calls")
150                                    }
151 config.plugins.FritzCall.fbfCalls = ConfigSelection(choices=fbfCallsChoices)
152
153 config.plugins.FritzCall.name = ConfigText(default="", fixed_size=False)
154 config.plugins.FritzCall.number = ConfigText(default="", fixed_size=False)
155 config.plugins.FritzCall.number.setUseableChars('0123456789')
156
157 phonebook = None
158 fritzbox = None
159
160 avon = {}
161
162 def initAvon():
163         avonFileName = resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/avon.dat")
164         if os.path.exists(avonFileName):
165                 for line in open(avonFileName):
166                         line = line.decode("iso-8859-1").encode('utf-8')
167                         if line[0] == '#':
168                                 continue
169                         parts = line.split(':')
170                         if len(parts) == 2:
171                                 avon[parts[0].replace('-','').replace('*','').replace('/','')] = parts[1]
172
173 def resolveNumberWithAvon(number, countrycode):
174         if not number or number[0] != '0':
175                 return ""
176                 
177         countrycode = countrycode.replace('00','+')
178         if number[:2] == '00':
179                 normNumber = '+' + number[2:]
180         elif number[:1] == '0':
181                 normNumber = countrycode + number[1:]
182         else: # this should can not happen, but safety first
183                 return ""
184         
185         # debug('normNumer: ' + normNumber)
186         for i in reversed(range(min(10, len(number)))):
187                 if avon.has_key(normNumber[:i]):
188                         return '[' + avon[normNumber[:i]].strip() + ']'
189         return ""
190
191 def handleReverseLookupResult(name):
192         found = re.match("NA: ([^;]*);VN: ([^;]*);STR: ([^;]*);HNR: ([^;]*);PLZ: ([^;]*);ORT: ([^;]*)", name)
193         if found:
194                 ( name, firstname, street, streetno, zipcode, city ) = (found.group(1),
195                                                                                                 found.group(2),
196                                                                                                 found.group(3),
197                                                                                                 found.group(4),
198                                                                                                 found.group(5),
199                                                                                                 found.group(6)
200                                                                                                 )
201                 if firstname:
202                         name += ' ' + firstname
203                 if street or streetno or zipcode or city:
204                         name += ', '
205                 if street:
206                         name += street
207                 if streetno:
208                         name += ' ' + streetno
209                 if (street or streetno) and (zipcode or city):
210                         name += ', '
211                 if zipcode and city:
212                         name += zipcode + ' ' + city
213                 elif zipcode:
214                         name += zipcode
215                 elif city:
216                         name += city
217         return name
218
219 from xml.dom.minidom import parse
220 cbcInfos = {}
221 def initCbC():
222         callbycallFileName = resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/callbycall_world.xml")
223         if os.path.exists(callbycallFileName):
224                 dom = parse(callbycallFileName)
225                 for top in dom.getElementsByTagName("callbycalls"):
226                         for cbc in top.getElementsByTagName("country"):
227                                 code = cbc.getAttribute("code").replace("+","00")
228                                 cbcInfos[code] = cbc.getElementsByTagName("callbycall")
229         else:
230                 debug("[FritzCall] initCbC: callbycallFileName does not exist?!?!")
231
232 def stripCbCPrefix(number, countrycode):
233         if number and number[:2] != "00" and cbcInfos.has_key(countrycode):
234                 for cbc in cbcInfos[countrycode]:
235                         if len(cbc.getElementsByTagName("length"))<1 or len(cbc.getElementsByTagName("prefix"))<1:
236                                 debug("[FritzCall] stripCbCPrefix: entries for " + countrycode + " %s invalid")
237                                 return number
238                         length = int(cbc.getElementsByTagName("length")[0].childNodes[0].data)
239                         prefix = cbc.getElementsByTagName("prefix")[0].childNodes[0].data
240                         # if re.match('^'+prefix, number):
241                         if number[:len(prefix)] == prefix:
242                                 return number[length:]
243         return number
244
245 import FritzCallFBF
246
247 class FritzAbout(Screen):
248
249         def __init__(self, session):
250                 textFieldWidth = scaleV(350, 250)
251                 width = 5 + 150 + 20 + textFieldWidth + 5 + 175 + 5
252                 height = 5 + 175 + 5 + 25 + 5
253                 self.skin = """
254                         <screen name="FritzAbout" position="center,center" size="%d,%d" title="About FritzCall" >
255                                 <widget name="text" position="175,%d" size="%d,%d" font="Regular;%d" />
256                                 <ePixmap position="5,37" size="150,110" pixmap="%s" transparent="1" alphatest="blend" />
257                                 <ePixmap position="%d,5" size="175,175" pixmap="%s" transparent="1" alphatest="blend" />
258                                 <widget name="url" position="20,185" size="%d,25" font="Regular;%d" />
259                         </screen>""" % (
260                                                         width, height, # size
261                                                         (height-scaleV(150,130)) / 2, # text vertical position
262                                                         textFieldWidth,
263                                                         scaleV(150,130), # text height
264                                                         scaleV(24,21), # text font size
265                                                         resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/images/fritz.png"), # 150x110
266                                                         5 + 150 + 5 + textFieldWidth + 5, # qr code horizontal offset
267                                                         resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/images/website.png"), # 175x175
268                                                         width-40, # url width
269                                                         scaleV(24,21) # url font size
270                                                         )
271                 Screen.__init__(self, session)
272                 self["aboutActions"] = ActionMap(["OkCancelActions"],
273                 {
274                 "cancel": self.exit,
275                 "ok": self.exit,
276                 }, -2)
277                 self["text"] = Label(
278                                                         "FritzCall Plugin" + "\n\n" +
279                                                         "$Author: michael $"[1:-2] + "\n" +
280                                                         "$Revision: 1039 $"[1:-2] + "\n" + 
281                                                         "$Date: 2014-11-15 16:13:49 +0100 (Sat, 15 Nov 2014) $"[1:23] + "\n"
282                                                         )
283                 self["url"] = Label("http://wiki.blue-panel.com/index.php/FritzCall")
284                 self.onLayoutFinish.append(self.setWindowTitle)
285
286         def setWindowTitle(self):
287                 # TRANSLATORS: this is a window title.
288                 self.setTitle(_("About FritzCall"))
289
290         def exit(self):
291                 self.close()
292
293 from FritzCallFBF import FBF_dectActive, FBF_faxActive, FBF_rufumlActive, FBF_tamActive
294
295 class FritzMenu(Screen, HelpableScreen):
296         def __init__(self, session):
297                 if not fritzbox or not fritzbox.info:
298                         return
299
300                 if config.plugins.FritzCall.fwVersion.value == "old" or config.plugins.FritzCall.fwVersion.value == "05.27":
301                         fontSize = scaleV(24, 21) # indeed this is font size +2
302                         noButtons = 2 # reset, wlan
303         
304                         if fritzbox.info[FBF_tamActive]:
305                                 noButtons += 1 # toggle mailboxes
306                         width = max(DESKTOP_WIDTH - scaleH(500, 250), noButtons*140+(noButtons+1)*10)
307                         # boxInfo 2 lines, gap, internet 2 lines, gap, dsl/wlan each 1 line, gap, buttons
308                         height = 5 + 2*fontSize + 10 + 2*fontSize + 10 + 2*fontSize + 10 + 40 + 5
309                         if fritzbox.info[FBF_tamActive] is not None:
310                                 height += fontSize
311                         if fritzbox.info[FBF_dectActive] is not None:
312                                 height += fontSize
313                         if fritzbox.info[FBF_faxActive] is not None:
314                                 height += fontSize
315                         if fritzbox.info[FBF_rufumlActive] is not None:
316                                 height += fontSize
317                         buttonsGap = (width-noButtons*140)/(noButtons+1)
318                         buttonsVPos = height-40-5
319         
320                         varLinePos = 4
321                         if fritzbox.info[FBF_tamActive] is not None:
322                                 mailboxLine = """
323                                         <widget name="FBFMailbox" position="%d,%d" size="%d,%d" font="Regular;%d" />
324                                         <widget name="mailbox_inactive" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
325                                         <widget name="mailbox_active" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
326                                         <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
327                                         <widget name="key_yellow" position="%d,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
328                                         """ % (
329                                                         40, 5+2*fontSize+10+varLinePos*fontSize+10, # position mailbox
330                                                         width-40-20, fontSize, # size mailbox
331                                                         fontSize-2,
332                                                         "skin_default/buttons/button_green_off.png",
333                                                         20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button mailbox
334                                                         "skin_default/buttons/button_green.png",
335                                                         20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button mailbox
336                                                         noButtons*buttonsGap+(noButtons-1)*140, buttonsVPos,
337                                                         noButtons*buttonsGap+(noButtons-1)*140, buttonsVPos,
338                                         )
339                                 varLinePos += 1
340                         else:
341                                 mailboxLine = ""
342         
343                         if fritzbox.info[FBF_dectActive] is not None:
344                                 dectLine = """
345                                         <widget name="FBFDect" position="%d,%d" size="%d,%d" font="Regular;%d" />
346                                         <widget name="dect_inactive" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
347                                         <widget name="dect_active" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
348                                         """ % (
349                                                         40, 5+2*fontSize+10+varLinePos*fontSize+10, # position dect
350                                                         width-40-20, fontSize, # size dect
351                                                         fontSize-2,
352                                                         "skin_default/buttons/button_green_off.png",
353                                                         20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button dect
354                                                         "skin_default/buttons/button_green.png",
355                                                         20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button dect
356                                         )
357                                 varLinePos += 1
358                         else:
359                                 dectLine = ""
360         
361                         if fritzbox.info[FBF_faxActive] is not None:
362                                 faxLine = """
363                                         <widget name="FBFFax" position="%d,%d" size="%d,%d" font="Regular;%d" />
364                                         <widget name="fax_inactive" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
365                                         <widget name="fax_active" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
366                                         """ % (
367                                                         40, 5+2*fontSize+10+varLinePos*fontSize+10, # position dect
368                                                         width-40-20, fontSize, # size dect
369                                                         fontSize-2,
370                                                         "skin_default/buttons/button_green_off.png",
371                                                         20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button dect
372                                                         "skin_default/buttons/button_green.png",
373                                                         20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button dect
374                                         )
375                                 varLinePos += 1
376                         else:
377                                 faxLine = ""
378         
379                         if fritzbox.info[FBF_rufumlActive] is not None:
380                                 rufumlLine = """
381                                         <widget name="FBFRufuml" position="%d,%d" size="%d,%d" font="Regular;%d" />
382                                         <widget name="rufuml_inactive" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
383                                         <widget name="rufuml_active" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
384                                         """ % (
385                                                         40, 5+2*fontSize+10+varLinePos*fontSize+10, # position dect
386                                                         width-40-20, fontSize, # size dect
387                                                         fontSize-2,
388                                                         "skin_default/buttons/button_green_off.png",
389                                                         20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button dect
390                                                         "skin_default/buttons/button_green.png",
391                                                         20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button dect
392                                         )
393                                 varLinePos += 1
394                         else:
395                                 rufumlLine = ""
396                 
397                         self.skin = """
398                                 <screen name="FritzMenu" position="center,center" size="%d,%d" title="FRITZ!Box Fon Status" >
399                                         <widget name="FBFInfo" position="%d,%d" size="%d,%d" font="Regular;%d" />
400                                         <widget name="FBFInternet" position="%d,%d" size="%d,%d" font="Regular;%d" />
401                                         <widget name="internet_inactive" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
402                                         <widget name="internet_active" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
403                                         <widget name="FBFDsl" position="%d,%d" size="%d,%d" font="Regular;%d" />
404                                         <widget name="dsl_inactive" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
405                                         <widget name="dsl_active" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
406                                         <widget name="FBFWlan" position="%d,%d" size="%d,%d" font="Regular;%d" />
407                                         <widget name="wlan_inactive" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
408                                         <widget name="wlan_active" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
409                                         %s
410                                         %s
411                                         %s
412                                         %s
413                                         <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
414                                         <widget name="key_red" position="%d,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
415                                         <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
416                                         <widget name="key_green" position="%d,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
417                                 </screen>""" % (
418                                                         width, height, # size
419                                                         40, 5, # position info
420                                                         width-2*40, 2*fontSize, # size info
421                                                         fontSize-2,
422                                                         40, 5+2*fontSize+10, # position internet
423                                                         width-40, 2*fontSize, # size internet
424                                                         fontSize-2,
425                                                         "skin_default/buttons/button_green_off.png",
426                                                         20, 5+2*fontSize+10+(fontSize-16)/2, # position button internet
427                                                         "skin_default/buttons/button_green.png",
428                                                         20, 5+2*fontSize+10+(fontSize-16)/2, # position button internet
429                                                         40, 5+2*fontSize+10+2*fontSize+10, # position dsl
430                                                         width-40-20, fontSize, # size dsl
431                                                         fontSize-2,
432                                                         "skin_default/buttons/button_green_off.png",
433                                                         20, 5+2*fontSize+10+2*fontSize+10+(fontSize-16)/2, # position button dsl
434                                                         "skin_default/buttons/button_green.png",
435                                                         20, 5+2*fontSize+10+2*fontSize+10+(fontSize-16)/2, # position button dsl
436                                                         40, 5+2*fontSize+10+3*fontSize+10, # position wlan
437                                                         width-40-20, fontSize, # size wlan
438                                                         fontSize-2,
439                                                         "skin_default/buttons/button_green_off.png",
440                                                         20, 5+2*fontSize+10+3*fontSize+10+(fontSize-16)/2, # position button wlan
441                                                         "skin_default/buttons/button_green.png",
442                                                         20, 5+2*fontSize+10+3*fontSize+10+(fontSize-16)/2, # position button wlan
443                                                         mailboxLine,
444                                                         dectLine,
445                                                         faxLine,
446                                                         rufumlLine,
447                                                         buttonsGap, buttonsVPos, "skin_default/buttons/red.png", buttonsGap, buttonsVPos,
448                                                         buttonsGap+140+buttonsGap, buttonsVPos, "skin_default/buttons/green.png", buttonsGap+140+buttonsGap, buttonsVPos,
449                                                         )
450         
451                         Screen.__init__(self, session)
452                         HelpableScreen.__init__(self)
453                         # TRANSLATORS: keep it short, this is a button
454                         self["key_red"] = Button(_("Reset"))
455                         # TRANSLATORS: keep it short, this is a button
456                         self["key_green"] = Button(_("Toggle WLAN"))
457                         self._mailboxActive = False
458                         if fritzbox.info[FBF_tamActive] is not None:
459                                 # TRANSLATORS: keep it short, this is a button
460                                 self["key_yellow"] = Button(_("Toggle Mailbox"))
461                                 self["menuActions"] = ActionMap(["OkCancelActions", "ColorActions", "NumberActions", "EPGSelectActions"],
462                                                                                                 {
463                                                                                                 "cancel": self._exit,
464                                                                                                 "ok": self._exit,
465                                                                                                 "red": self._reset,
466                                                                                                 "green": self._toggleWlan,
467                                                                                                 "yellow": (lambda: self._toggleMailbox(-1)),
468                                                                                                 "0": (lambda: self._toggleMailbox(0)),
469                                                                                                 "1": (lambda: self._toggleMailbox(1)),
470                                                                                                 "2": (lambda: self._toggleMailbox(2)),
471                                                                                                 "3": (lambda: self._toggleMailbox(3)),
472                                                                                                 "4": (lambda: self._toggleMailbox(4)),
473                                                                                                 "info": self._getInfo,
474                                                                                                 }, -2)
475                                 # TRANSLATORS: keep it short, this is a help text
476                                 self.helpList.append((self["menuActions"], "ColorActions", [("yellow", _("Toggle all mailboxes"))]))
477                                 # TRANSLATORS: keep it short, this is a help text
478                                 self.helpList.append((self["menuActions"], "NumberActions", [("0", _("Toggle 1. mailbox"))]))
479                                 # TRANSLATORS: keep it short, this is a help text
480                                 self.helpList.append((self["menuActions"], "NumberActions", [("1", _("Toggle 2. mailbox"))]))
481                                 # TRANSLATORS: keep it short, this is a help text
482                                 self.helpList.append((self["menuActions"], "NumberActions", [("2", _("Toggle 3. mailbox"))]))
483                                 # TRANSLATORS: keep it short, this is a help text
484                                 self.helpList.append((self["menuActions"], "NumberActions", [("3", _("Toggle 4. mailbox"))]))
485                                 # TRANSLATORS: keep it short, this is a help text
486                                 self.helpList.append((self["menuActions"], "NumberActions", [("4", _("Toggle 5. mailbox"))]))
487                                 self["FBFMailbox"] = Label(_('Mailbox'))
488                                 self["mailbox_inactive"] = Pixmap()
489                                 self["mailbox_active"] = Pixmap()
490                                 self["mailbox_active"].hide()
491                         else:
492                                 self["menuActions"] = ActionMap(["OkCancelActions", "ColorActions", "EPGSelectActions"],
493                                                                                                 {
494                                                                                                 "cancel": self._exit,
495                                                                                                 "ok": self._exit,
496                                                                                                 "green": self._toggleWlan,
497                                                                                                 "red": self._reset,
498                                                                                                 "info": self._getInfo,
499                                                                                                 }, -2)
500         
501                         # TRANSLATORS: keep it short, this is a help text
502                         self.helpList.append((self["menuActions"], "OkCancelActions", [("cancel", _("Quit"))]))
503                         # TRANSLATORS: keep it short, this is a help text
504                         self.helpList.append((self["menuActions"], "OkCancelActions", [("ok", _("Quit"))]))
505                         # TRANSLATORS: keep it short, this is a help text
506                         self.helpList.append((self["menuActions"], "ColorActions", [("green", _("Toggle WLAN"))]))
507                         # TRANSLATORS: keep it short, this is a help text
508                         self.helpList.append((self["menuActions"], "ColorActions", [("red", _("Reset"))]))
509                         # TRANSLATORS: keep it short, this is a help text
510                         self.helpList.append((self["menuActions"], "EPGSelectActions", [("info", _("Refresh status"))]))
511         
512                         self["FBFInfo"] = Label(_('Getting status from FRITZ!Box Fon...'))
513         
514                         self["FBFInternet"] = Label('Internet')
515                         self["internet_inactive"] = Pixmap()
516                         self["internet_active"] = Pixmap()
517                         self["internet_active"].hide()
518         
519                         self["FBFDsl"] = Label('DSL')
520                         self["dsl_inactive"] = Pixmap()
521                         self["dsl_inactive"].hide()
522                         self["dsl_active"] = Pixmap()
523                         self["dsl_active"].hide()
524         
525                         self["FBFWlan"] = Label('WLAN ')
526                         self["wlan_inactive"] = Pixmap()
527                         self["wlan_inactive"].hide()
528                         self["wlan_active"] = Pixmap()
529                         self["wlan_active"].hide()
530                         self._wlanActive = False
531         
532                         if fritzbox.info[FBF_dectActive] is not None: 
533                                 self["FBFDect"] = Label('DECT')
534                                 self["dect_inactive"] = Pixmap()
535                                 self["dect_active"] = Pixmap()
536                                 self["dect_active"].hide()
537         
538                         if fritzbox.info[FBF_faxActive] is not None: 
539                                 self["FBFFax"] = Label('Fax')
540                                 self["fax_inactive"] = Pixmap()
541                                 self["fax_active"] = Pixmap()
542                                 self["fax_active"].hide()
543         
544                         if fritzbox.info[FBF_rufumlActive] is not None: 
545                                 self["FBFRufuml"] = Label(_('Call redirection'))
546                                 self["rufuml_inactive"] = Pixmap()
547                                 self["rufuml_active"] = Pixmap()
548                                 self["rufuml_active"].hide()
549                 else: # not (config.plugins.FritzCall.fwVersion.value == "old" or config.plugins.FritzCall.fwVersion.value == "05.27")
550                         fontSize = scaleV(24, 21) # indeed this is font size +2
551         
552                         noButtons = 2
553                         width = max(DESKTOP_WIDTH - scaleH(500, 250), noButtons*140+(noButtons+1)*10)
554                         # boxInfo 2 lines, gap, internet 2 lines, gap, dsl/wlan/dect/fax/rufuml/gast each 1 line, gap
555                         height = 5 + 2*fontSize + 10 + 2*fontSize + 10 + 6*fontSize + 10 + 40 + 5
556                         buttonsGap = (width-noButtons*140)/(noButtons+1)
557                         buttonsVPos = height-40-5
558         
559                         self.skin = """
560                                 <screen name="FritzMenuNew" position="center,center" size="%d,%d" title="FRITZ!Box Fon Status" >
561                                         <widget name="FBFInfo" position="%d,%d" size="%d,%d" font="Regular;%d" />
562                                         <widget name="FBFInternet" position="%d,%d" size="%d,%d" font="Regular;%d" />
563                                         <widget name="internet_inactive" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
564                                         <widget name="internet_active" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
565                                         <widget name="FBFDsl" position="%d,%d" size="%d,%d" font="Regular;%d" />
566                                         <widget name="dsl_inactive" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
567                                         <widget name="dsl_active" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
568                                         <widget name="FBFWlan" position="%d,%d" size="%d,%d" font="Regular;%d" />
569                                         <widget name="wlan_inactive" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
570                                         <widget name="wlan_active" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
571                                         <widget name="FBFDect" position="%d,%d" size="%d,%d" font="Regular;%d" />
572                                         <widget name="dect_inactive" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
573                                         <widget name="dect_active" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
574                                         <widget name="FBFFax" position="%d,%d" size="%d,%d" font="Regular;%d" />
575                                         <widget name="fax_inactive" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
576                                         <widget name="fax_active" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
577                                         <widget name="FBFRufuml" position="%d,%d" size="%d,%d" font="Regular;%d" />
578                                         <widget name="rufuml_inactive" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
579                                         <widget name="rufuml_active" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
580                                         <widget name="FBFGast" position="%d,%d" size="%d,%d" font="Regular;%d" />
581                                         <widget name="gast_inactive" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
582                                         <widget name="gast_active" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
583                                         <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
584                                         <widget name="key_green" position="%d,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
585                                         <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
586                                         <widget name="key_yellow" position="%d,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;16" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
587                                 </screen>""" % (
588                                                         width, height, # size
589                                                         40, 5, # position info
590                                                         width-2*40, 2*fontSize, # size info
591                                                         fontSize-2,
592                                                         40, 5+2*fontSize+10, # position internet
593                                                         width-40, 2*fontSize, # size internet
594                                                         fontSize-2,
595                                                         "skin_default/buttons/button_green_off.png",
596                                                         20, 5+2*fontSize+10+(fontSize-16)/2, # position button internet
597                                                         "skin_default/buttons/button_green.png",
598                                                         20, 5+2*fontSize+10+(fontSize-16)/2, # position button internet
599                                                         40, 5+2*fontSize+10+2*fontSize+10, # position dsl
600                                                         width-40-20, fontSize, # size dsl
601                                                         fontSize-2,
602                                                         "skin_default/buttons/button_green_off.png",
603                                                         20, 5+2*fontSize+10+2*fontSize+10+(fontSize-16)/2, # position button dsl
604                                                         "skin_default/buttons/button_green.png",
605                                                         20, 5+2*fontSize+10+2*fontSize+10+(fontSize-16)/2, # position button dsl
606                                                         40, 5+2*fontSize+10+3*fontSize+10, # position wlan
607                                                         width-40-20, fontSize, # size wlan
608                                                         fontSize-2,
609                                                         "skin_default/buttons/button_green_off.png",
610                                                         20, 5+2*fontSize+10+3*fontSize+10+(fontSize-16)/2, # position button wlan
611                                                         "skin_default/buttons/button_green.png",
612                                                         20, 5+2*fontSize+10+3*fontSize+10+(fontSize-16)/2, # position button wlan
613                                                         40, 5+2*fontSize+10+4*fontSize+10, # position dect
614                                                         width-40-20, fontSize, # size dect
615                                                         fontSize-2,
616                                                         "skin_default/buttons/button_green_off.png",
617                                                         20, 5+2*fontSize+10+4*fontSize+10+(fontSize-16)/2, # position button dect
618                                                         "skin_default/buttons/button_green.png",
619                                                         20, 5+2*fontSize+10+4*fontSize+10+(fontSize-16)/2, # position button dect
620                                                         40, 5+2*fontSize+10+5*fontSize+10, # position fax
621                                                         width-40-20, fontSize, # size fax
622                                                         fontSize-2,
623                                                         "skin_default/buttons/button_green_off.png",
624                                                         20, 5+2*fontSize+10+5*fontSize+10+(fontSize-16)/2, # position button fax
625                                                         "skin_default/buttons/button_green.png",
626                                                         20, 5+2*fontSize+10+5*fontSize+10+(fontSize-16)/2, # position button fax
627                                                         40, 5+2*fontSize+10+6*fontSize+10, # position rufuml
628                                                         width-40-20, fontSize, # size rufuml
629                                                         fontSize-2,
630                                                         "skin_default/buttons/button_green_off.png",
631                                                         20, 5+2*fontSize+10+6*fontSize+10+(fontSize-16)/2, # position button rufuml
632                                                         "skin_default/buttons/button_green.png",
633                                                         20, 5+2*fontSize+10+6*fontSize+10+(fontSize-16)/2, # position button rufuml
634                                                         40, 5+2*fontSize+10+7*fontSize+10, # position gast
635                                                         width-40-20, fontSize, # size gast
636                                                         fontSize-2,
637                                                         "skin_default/buttons/button_green_off.png",
638                                                         20, 5+2*fontSize+10+7*fontSize+10+(fontSize-16)/2, # position button gast
639                                                         "skin_default/buttons/button_green.png",
640                                                         20, 5+2*fontSize+10+7*fontSize+10+(fontSize-16)/2, # position button gast
641                                                         buttonsGap, buttonsVPos, "skin_default/buttons/green.png", buttonsGap, buttonsVPos,
642                                                         2*buttonsGap+140, buttonsVPos, "skin_default/buttons/yellow.png", 2*buttonsGap+140, buttonsVPos,
643                                                         )
644         
645                         Screen.__init__(self, session)
646                         HelpableScreen.__init__(self)
647                         # TRANSLATORS: keep it short, this is a button
648                         self["menuActions"] = ActionMap(["OkCancelActions", "ColorActions", "EPGSelectActions"],
649                                                                                         {
650                                                                                         "cancel": self._exit,
651                                                                                         "ok": self._exit,
652                                                                                         "green": self._toggleWlan,
653                                                                                         "yellow": self._toggleGast,
654                                                                                         "red": self._reset,
655                                                                                         "info": self._getInfo,
656                                                                                         }, -2)
657         
658                         # TRANSLATORS: keep it short, this is a help text
659                         self.helpList.append((self["menuActions"], "OkCancelActions", [("cancel", _("Quit"))]))
660                         # TRANSLATORS: keep it short, this is a help text
661                         self.helpList.append((self["menuActions"], "OkCancelActions", [("ok", _("Quit"))]))
662                         # TRANSLATORS: keep it short, this is a help text
663                         self.helpList.append((self["menuActions"], "ColorActions", [("green", _("Toggle WLAN"))]))
664                         # TRANSLATORS: keep it short, this is a help text
665                         self.helpList.append((self["menuActions"], "ColorActions", [("yellow", _("Toggle WLAN guest access"))]))
666                         # TRANSLATORS: keep it short, this is a help text
667                         self.helpList.append((self["menuActions"], "ColorActions", [("red", _("Reset"))]))
668                         # TRANSLATORS: keep it short, this is a help text
669                         self.helpList.append((self["menuActions"], "EPGSelectActions", [("info", _("Refresh status"))]))
670         
671                         # TRANSLATORS: keep it short, this is a button
672                         self["key_red"] = Button(_("Reset"))
673                         # TRANSLATORS: keep it short, this is a button
674                         self["key_green"] = Button(_("Toggle WLAN"))
675                         # TRANSLATORS: keep it short, this is a button
676                         self["key_yellow"] = Button(_("Activate WLAN guest access"))
677
678                         self["FBFInfo"] = Label(_('Getting status from FRITZ!Box Fon...'))
679         
680                         self["FBFInternet"] = Label('Internet')
681                         self["internet_inactive"] = Pixmap()
682                         self["internet_inactive"].hide()
683                         self["internet_active"] = Pixmap()
684                         self["internet_active"].hide()
685         
686                         self["FBFDsl"] = Label('DSL')
687                         self["dsl_inactive"] = Pixmap()
688                         self["dsl_inactive"].hide()
689                         self["dsl_active"] = Pixmap()
690                         self["dsl_active"].hide()
691         
692                         self["FBFWlan"] = Label('WLAN ')
693                         self["wlan_inactive"] = Pixmap()
694                         self["wlan_inactive"].hide()
695                         self["wlan_active"] = Pixmap()
696                         self["wlan_active"].hide()
697                         self._wlanActive = False
698         
699                         self["FBFDect"] = Label('DECT')
700                         self["dect_inactive"] = Pixmap()
701                         self["dect_inactive"].hide()
702                         self["dect_active"] = Pixmap()
703                         self["dect_active"].hide()
704         
705                         self["FBFFax"] = Label('Fax')
706                         self["fax_inactive"] = Pixmap()
707                         self["fax_inactive"].hide()
708                         self["fax_active"] = Pixmap()
709                         self["fax_active"].hide()
710         
711                         self["FBFRufuml"] = Label(_('Call redirection'))
712                         self["rufuml_inactive"] = Pixmap()
713                         self["rufuml_inactive"].hide()
714                         self["rufuml_active"] = Pixmap()
715                         self["rufuml_active"].hide()
716                         
717                         self["FBFGast"] = Label(_('Guest access'))
718                         self["gast_inactive"] = Pixmap()
719                         self["gast_inactive"].hide()
720                         self["gast_active"] = Pixmap()
721                         self["gast_active"].hide()
722                         self._guestActive = ""
723                         
724                 self._getInfo()
725                 self.onLayoutFinish.append(self.setWindowTitle)
726
727         def setWindowTitle(self):
728                 # TRANSLATORS: this is a window title.
729                 self.setTitle(_("FRITZ!Box Fon Status"))
730
731         def _getInfo(self):
732                 if fritzbox:
733                         fritzbox.getInfo(self._fillMenu)
734                         self._fillMenu(fritzbox.info, True)
735
736         def _fillMenu(self, status, refreshing=False):
737                 (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive, guestAccess) = status
738                 if wlanState:
739                         self._wlanActive = (wlanState[0] == '1')
740                 self._guestActive = guestAccess
741                 self._mailboxActive = False
742                 try:
743                         if not self.has_key("FBFInfo"): # screen is closed already
744                                 return
745
746                         if refreshing:
747                                 self["FBFInfo"].setText(_("Refreshing..."))
748                         else:
749                                 if boxInfo:
750                                         self["FBFInfo"].setText(boxInfo.replace(', ', '\n'))
751                                 else:
752                                         self["FBFInfo"].setText('BoxInfo ' + _('Status not available'))
753
754                         if ipAddress:
755                                 if upTime:
756                                         self["FBFInternet"].setText('Internet ' + _('IP Address:') + ' ' + ipAddress + '\n' + _('Connected since') + ' ' + upTime)
757                                 else:
758                                         self["FBFInternet"].setText('Internet ' + _('IP Address:') + ' ' + ipAddress)
759                                 self["internet_inactive"].hide()
760                                 self["internet_active"].show()
761                         else:
762                                 self["internet_active"].hide()
763                                 self["internet_inactive"].show()
764
765                         if dslState:
766                                 if dslState[0] == '5':
767                                         self["dsl_inactive"].hide()
768                                         self["dsl_active"].show()
769                                         if dslState[2]:
770                                                 message = dslState[2]
771                                         else:
772                                                 message = "DSL"
773                                         if dslState[1]:
774                                                 message = message + ' ' + dslState[1]
775                                         self["FBFDsl"].setText(message)
776                                 else:
777                                         self["dsl_active"].hide()
778                                         self["dsl_inactive"].show()
779                         else:
780                                 self["FBFDsl"].setText('DSL ' + _('Status not available'))
781                                 self["dsl_active"].hide()
782                                 self["dsl_inactive"].hide()
783
784                         if wlanState:
785                                 if wlanState[0 ] == '1':
786                                         self["wlan_inactive"].hide()
787                                         self["wlan_active"].show()
788                                         message = 'WLAN'
789                                         if wlanState[1] == '0':
790                                                 message += ' ' + _('not encrypted')
791                                         elif wlanState[1] == '1':
792                                                 message += ' ' + _('encrypted')
793                                         if wlanState[2]:
794                                                 if wlanState[2] == '0':
795                                                         message = message + ', ' + _('no device active')
796                                                 elif wlanState[2] == '1' or wlanState[2] == 'ein':
797                                                         message = message + ', ' + _('one device active')
798                                                 else:
799                                                         message = message + ', ' + wlanState[2] + ' ' + _('devices active')
800                                         self["FBFWlan"].setText(message)
801                                 else:
802                                         self["wlan_active"].hide()
803                                         self["wlan_inactive"].show()
804                                         self["FBFWlan"].setText('WLAN')
805                         else:
806                                 self["FBFWlan"].setText('WLAN ' + _('Status not available'))
807                                 self["wlan_active"].hide()
808                                 self["wlan_inactive"].hide()
809
810                         if fritzbox.info[FBF_tamActive]:
811                                 if  not tamActive or tamActive[0] == 0:
812                                         self._mailboxActive = False
813                                         self["mailbox_active"].hide()
814                                         self["mailbox_inactive"].show()
815                                         self["FBFMailbox"].setText(_('No mailbox active'))
816                                 else:
817                                         self._mailboxActive = True
818                                         message = ''
819                                         for i in range(min(len(tamActive)-1, 5)):
820                                                 if tamActive[i+1]:
821                                                         message = message + str(i) + ','
822                                         if message:
823                                                 message = '(' + message[:-1] + ')'
824                                         self["mailbox_inactive"].hide()
825                                         self["mailbox_active"].show()
826                                         if tamActive[0] == 1:
827                                                 self["FBFMailbox"].setText(_('One mailbox active') + ' ' + message)
828                                         else:
829                                                 self["FBFMailbox"].setText(str(tamActive[0]) + ' ' + _('mailboxes active') + ' ' + message)
830         
831                         if dectActive and self.has_key("dect_inactive"):
832                                 self["dect_inactive"].hide()
833                                 self["dect_active"].show()
834                                 if dectActive == 0:
835                                         self["FBFDect"].setText(_('No DECT phone registered'))
836                                 else:
837                                         if dectActive == 1:
838                                                 self["FBFDect"].setText(_('One DECT phone registered'))
839                                         else:
840                                                 self["FBFDect"].setText(str(dectActive) + ' ' + _('DECT phones registered'))
841                         else:
842                                 self["dect_active"].hide()
843                                 self["dect_inactive"].show()
844                                 self["FBFDect"].setText(_('DECT inactive'))
845
846                         if faxActive:
847                                 self["fax_inactive"].hide()
848                                 self["fax_active"].show()
849                                 self["FBFFax"].setText(_('Software fax active'))
850                         else:
851                                 self["fax_active"].hide()
852                                 self["fax_inactive"].show()
853                                 self["FBFFax"].setText(_('Software fax inactive'))
854
855                         if rufumlActive:
856                                 self["rufuml_inactive"].hide()
857                                 self["rufuml_active"].show()
858                                 if rufumlActive == -1: # means no number available
859                                         self["FBFRufuml"].setText(_('Call redirection active'))
860                                 elif rufumlActive == 1:
861                                         self["FBFRufuml"].setText(_('One call redirection active'))
862                                 else:
863                                         self["FBFRufuml"].setText(str(rufumlActive) + ' ' + _('call redirections active'))
864                         else:
865                                 self["rufuml_active"].hide()
866                                 self["rufuml_inactive"].show()
867                                 self["FBFRufuml"].setText(_('No call redirection active'))
868
869                         if guestAccess:
870                                 self["gast_inactive"].hide()
871                                 self["gast_active"].show()
872                                 self["FBFGast"].setText(_('Guest access on ') + guestAccess)
873                         else:
874                                 self["gast_active"].hide()
875                                 self["gast_inactive"].show()
876                                 self["FBFGast"].setText(_('Guest access not active'))
877
878                         if guestAccess.find('WLAN') != -1:
879                                 # TRANSLATORS: keep it short, this is a button
880                                 self["key_yellow"].setText(_("Deactivate WLAN guest access"))
881                         else:
882                                 # TRANSLATORS: keep it short, this is a button
883                                 self["key_yellow"].setText(_("Activate WLAN guest access"))
884
885
886                 except KeyError:
887                         debug("[FritzCallFBF] _fillMenu: " + traceback.format_exc())
888
889         def _toggleWlan(self):
890                 self["FBFInfo"].setText(_("Setting..."))
891                 if self._wlanActive:
892                         debug("[FritzMenu] toggleWlan off")
893                         fritzbox.changeWLAN('0', self._getInfo)
894                 else:
895                         debug("[FritzMenu] toggleWlan on")
896                         fritzbox.changeWLAN('1', self._getInfo)
897
898         def _toggleMailbox(self, which):
899                 debug("[FritzMenu] toggleMailbox")
900                 if fritzbox.info[FBF_tamActive]:
901                         debug("[FritzMenu] toggleMailbox off")
902                         fritzbox.changeMailbox(which, self._getInfo)
903
904         def _toggleGast(self):
905                 self["FBFInfo"].setText(_("Setting..."))
906                 fritzbox.changeGuestAccess(self._guestActive, self._getInfo)
907
908         def _reset(self):
909                 fritzbox.reset()
910                 self._exit()
911
912         def _exit(self):
913                 self.close()
914
915
916 class FritzDisplayCalls(Screen, HelpableScreen):
917
918         def __init__(self, session, text=""): #@UnusedVariable # pylint: disable=W0613
919                 self.width = DESKTOP_WIDTH * scaleH(75, 85)/100
920                 self.height = DESKTOP_HEIGHT * 0.75
921                 dateFieldWidth = scaleH(180, 105)
922                 dirFieldWidth = 16
923                 lengthFieldWidth = scaleH(55, 45)
924                 scrollbarWidth = scaleH(35, 35)
925                 entriesWidth = self.width -scaleH(40, 5) -5
926                 hereFieldWidth = entriesWidth -dirFieldWidth -5 -dateFieldWidth -5 -lengthFieldWidth -scrollbarWidth
927                 fieldWidth = entriesWidth -dirFieldWidth -5 -5 -scrollbarWidth
928                 fontSize = scaleV(22, 20)
929                 itemHeight = 2*fontSize+5
930                 entriesHeight = self.height -scaleV(15, 10) -5 -fontSize -5 -5 -5 -40 -5
931                 buttonGap = (self.width -4*140)/5
932                 buttonV = self.height -40
933                 debug("[FritzDisplayCalls] width: " + str(self.width))
934                 self.skin = """
935                         <screen name="FritzDisplayCalls" position="center,center" size="%d,%d" title="Phone calls" >
936                                 <eLabel position="0,0" size="%d,2" backgroundColor="#aaaaaa" />
937                                 <widget name="statusbar" position="%d,%d" size="%d,%d" font="Regular;%d" backgroundColor="#aaaaaa" transparent="1" />
938                                 <eLabel position="0,%d" size="%d,2" backgroundColor="#aaaaaa" />
939                                 <widget source="entries" render="Listbox" position="%d,%d" size="%d,%d" scrollbarMode="showOnDemand" transparent="1">
940                                         <convert type="TemplatedMultiContent">
941                                                 {"template": [
942                                                                 MultiContentEntryText(pos = (%d,%d), size = (%d,%d), font=0, flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER, text = 1), # index 0 is the number, index 1 is date
943                                                                 MultiContentEntryPixmapAlphaTest(pos = (%d,%d), size = (%d,%d), png = 2), # index 1 i direction pixmap
944                                                                 MultiContentEntryText(pos = (%d,%d), size = (%d,%d), font=1, flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER, text = 3), # index 2 is remote name/number
945                                                                 MultiContentEntryText(pos = (%d,%d), size = (%d,%d), font=0, flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER, text = 4), # index 3 is length of call
946                                                                 MultiContentEntryText(pos = (%d,%d), size = (%d,%d), font=0, flags = RT_HALIGN_RIGHT|RT_VALIGN_CENTER, text = 5), # index 4 is my number/name for number
947                                                         ],
948                                                 "fonts": [gFont("Regular", %d), gFont("Regular", %d)],
949                                                 "itemHeight": %d
950                                                 }
951                                         </convert>
952                                 </widget>
953                                 <eLabel position="0,%d" size="%d,2" backgroundColor="#aaaaaa" />
954                                 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
955                                 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
956                                 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
957                                 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
958                                 <widget name="key_red" position="%d,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;%d" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
959                                 <widget name="key_green" position="%d,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;%d" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
960                                 <widget name="key_yellow" position="%d,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;%d" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
961                                 <widget name="key_blue" position="%d,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;%d" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
962                         </screen>""" % (
963                                                 # scaleH(90, 75), scaleV(100, 78), # position 
964                                                 self.width, self.height, # size
965                                                 self.width, # eLabel width
966                                                 scaleH(40, 5), scaleV(10, 5), # statusbar position
967                                                 self.width, fontSize+5, # statusbar size
968                                                 scaleV(21, 21), # statusbar font size
969                                                 scaleV(10, 5)+5+fontSize+5, # eLabel position vertical
970                                                 self.width, # eLabel width
971                                                 scaleH(40, 5), scaleV(10, 5)+5+fontSize+5+5, # entries position
972                                                 entriesWidth, entriesHeight, # entries size
973                                                 5+dirFieldWidth+5, fontSize+5, dateFieldWidth, fontSize, # date pos/size
974                                                 5, (itemHeight-dirFieldWidth)/2, dirFieldWidth, dirFieldWidth, # dir pos/size
975                                                 5+dirFieldWidth+5, 5, fieldWidth, fontSize, # caller pos/size
976                                                 2+dirFieldWidth+2+dateFieldWidth+5, fontSize+5, lengthFieldWidth, fontSize, # length pos/size
977                                                 2+dirFieldWidth+2+dateFieldWidth+5+lengthFieldWidth+5, fontSize+5, hereFieldWidth, fontSize, # my number pos/size
978                                                 fontSize-4, fontSize, # fontsize
979                                                 itemHeight, # itemHeight
980                                                 buttonV-5, # eLabel position vertical
981                                                 self.width, # eLabel width
982                                                 buttonGap, buttonV, "skin_default/buttons/red.png", # widget red
983                                                 2*buttonGap+140, buttonV, "skin_default/buttons/green.png", # widget green
984                                                 3*buttonGap+2*140, buttonV, "skin_default/buttons/yellow.png", # widget yellow
985                                                 4*buttonGap+3*140, buttonV, "skin_default/buttons/blue.png", # widget blue
986                                                 buttonGap, buttonV, scaleV(22, 21), # widget red
987                                                 2*buttonGap+140, buttonV, scaleV(22, 21), # widget green
988                                                 3*buttonGap+2*140, buttonV, scaleV(22, 21), # widget yellow
989                                                 4*buttonGap+3*140, buttonV, scaleV(22, 21), # widget blue
990                                                                                                                 )
991                 # debug("[FritzDisplayCalls] skin: " + self.skin)
992                 Screen.__init__(self, session)
993                 HelpableScreen.__init__(self)
994
995                 # TRANSLATORS: keep it short, this is a button
996                 self["key_yellow"] = Button(_("All"))
997                 # TRANSLATORS: keep it short, this is a button
998                 self["key_red"] = Button(_("Missed"))
999                 # TRANSLATORS: keep it short, this is a button
1000                 self["key_blue"] = Button(_("Incoming"))
1001                 # TRANSLATORS: keep it short, this is a button
1002                 self["key_green"] = Button(_("Outgoing"))
1003
1004                 self["setupActions"] = ActionMap(["OkCancelActions", "ColorActions"],
1005                 {
1006                         "yellow": (lambda: self.display(FBF_ALL_CALLS)),
1007                         "red": (lambda: self.display(FBF_MISSED_CALLS)),
1008                         "blue": (lambda: self.display(FBF_IN_CALLS)),
1009                         "green": (lambda: self.display(FBF_OUT_CALLS)),
1010                         "cancel": self.ok,
1011                         "ok": self.showEntry, }, - 2)
1012
1013                 # TRANSLATORS: keep it short, this is a help text
1014                 self.helpList.append((self["setupActions"], "OkCancelActions", [("ok", _("Show details of entry"))]))
1015                 # TRANSLATORS: keep it short, this is a help text
1016                 self.helpList.append((self["setupActions"], "OkCancelActions", [("cancel", _("Quit"))]))
1017                 # TRANSLATORS: keep it short, this is a help text
1018                 self.helpList.append((self["setupActions"], "ColorActions", [("yellow", _("Display all calls"))]))
1019                 # TRANSLATORS: keep it short, this is a help text
1020                 self.helpList.append((self["setupActions"], "ColorActions", [("red", _("Display missed calls"))]))
1021                 # TRANSLATORS: keep it short, this is a help text
1022                 self.helpList.append((self["setupActions"], "ColorActions", [("blue", _("Display incoming calls"))]))
1023                 # TRANSLATORS: keep it short, this is a help text
1024                 self.helpList.append((self["setupActions"], "ColorActions", [("green", _("Display outgoing calls"))]))
1025
1026                 self["statusbar"] = Label(_("Getting calls from FRITZ!Box..."))
1027                 self.list = []
1028                 self["entries"] = List(self.list)
1029                 #=======================================================================
1030                 # fontSize = scaleV(22, 18)
1031                 # fontHeight = scaleV(24, 20)
1032                 # self["entries"].l.setFont(0, gFont("Regular", fontSize))
1033                 # self["entries"].l.setItemHeight(fontHeight)
1034                 #=======================================================================
1035                 debug("[FritzDisplayCalls] init: '''%s'''" % config.plugins.FritzCall.fbfCalls.value)
1036                 self.display(config.plugins.FritzCall.fbfCalls.value)
1037                 self.onLayoutFinish.append(self.setWindowTitle)
1038
1039         def setWindowTitle(self):
1040                 # TRANSLATORS: this is a window title.
1041                 self.setTitle(_("Phone calls"))
1042
1043         def ok(self):
1044                 self.close()
1045
1046         def display(self, which=None):
1047                 debug("[FritzDisplayCalls] display")
1048                 if which:
1049                         config.plugins.FritzCall.fbfCalls.value = which
1050                         config.plugins.FritzCall.fbfCalls.save()
1051                 else:
1052                         which = config.plugins.FritzCall.fbfCalls.value
1053                 fritzbox.getCalls(self, lambda x: self.gotCalls(x, which), which)
1054
1055         def gotCalls(self, listOfCalls, which):
1056                 debug("[FritzDisplayCalls] gotCalls")
1057                 self.updateStatus(fbfCallsChoices[which] + " (" + str(len(listOfCalls)) + ")")
1058
1059                 directout = LoadPixmap(resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/images/callout.png"))
1060                 directin = LoadPixmap(resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/images/callin.png"))
1061                 directfailed = LoadPixmap(resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/images/callinfailed.png"))
1062                 def pixDir(direct):
1063                         if direct == FBF_OUT_CALLS:
1064                                 direct = directout
1065                         elif direct == FBF_IN_CALLS:
1066                                 direct = directin
1067                         else:
1068                                 direct = directfailed
1069                         return direct
1070
1071                 # debug("[FritzDisplayCalls] gotCalls: %s" %repr(listOfCalls))
1072                 self.list = [(number, date[:6] + ' ' + date[9:14], pixDir(direct), remote, length, here) for (number, date, direct, remote, length, here) in listOfCalls]
1073                 self["entries"].setList(self.list)
1074                 #=======================================================================
1075                 # if len(self.list) > 1:
1076                 #       self["entries"].setIndex(1)
1077                 #=======================================================================
1078
1079         def updateStatus(self, text):
1080                 if self.has_key("statusbar"):
1081                         self["statusbar"].setText(_("Getting calls from FRITZ!Box...") + ' ' + text)
1082
1083         def showEntry(self):
1084                 debug("[FritzDisplayCalls] showEntry")
1085                 cur = self["entries"].getCurrent()
1086                 if cur:
1087                         if cur[0]:
1088                                 # debug("[FritzDisplayCalls] showEntry %s" % (cur[0]))
1089                                 number = cur[0]
1090                                 fullname = phonebook.search(cur[0])
1091                                 if fullname:
1092                                         # we have a name for this number
1093                                         name = fullname
1094                                         self.session.open(FritzOfferAction, self, number, name)
1095                                 elif cur[3]:
1096                                         name = cur[3]
1097                                         self.session.open(FritzOfferAction, self, number, name)
1098                                 else:
1099                                         # we don't
1100                                         fullname = resolveNumberWithAvon(number, config.plugins.FritzCall.country.value)
1101                                         if fullname:
1102                                                 name = fullname
1103                                                 self.session.open(FritzOfferAction, self, number, name)
1104                                         else:
1105                                                 self.session.open(FritzOfferAction, self, number)
1106                         else:
1107                                 # we do not even have a number...
1108                                 self.session.open(MessageBox,
1109                                                   _("UNKNOWN"),
1110                                                   type=MessageBox.TYPE_INFO)
1111
1112
1113 class FritzOfferAction(Screen):
1114
1115         def __init__(self, session, parent, number, name=""):
1116                 # the layout will completely be recalculated in finishLayout
1117                 self.skin = """
1118                         <screen name="FritzOfferAction" title="Do what?" >
1119                                 <widget name="text" size="%d,%d" font="Regular;%d" />
1120                                 <widget name="FacePixmap" size="%d,%d" alphatest="on" />
1121                                 <widget name="key_red_p" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
1122                                 <widget name="key_green_p" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
1123                                 <widget name="key_yellow_p" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
1124                                 <widget name="key_red" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
1125                                 <widget name="key_green" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
1126                                 <widget name="key_yellow" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
1127                         </screen>""" % (
1128                                                         DESKTOP_WIDTH, DESKTOP_HEIGHT, # set maximum size
1129                                                         scaleH(22,21), # text
1130                                                         DESKTOP_WIDTH, DESKTOP_HEIGHT, # set maximum size
1131                                                         "skin_default/buttons/red.png",
1132                                                         "skin_default/buttons/green.png",
1133                                                         "skin_default/buttons/yellow.png",
1134                                                         ) 
1135                 debug("[FritzOfferAction] init: %s, %s" %(__(number), __(name)))
1136                 Screen.__init__(self, session)
1137         
1138                 # TRANSLATORS: keep it short, this is a button
1139                 self["key_red"] = Button(_("Lookup"))
1140                 # TRANSLATORS: keep it short, this is a button
1141                 self["key_green"] = Button(_("Call"))
1142                 # TRANSLATORS: keep it short, this is a button
1143                 self["key_yellow"] = Button(_("Save"))
1144                 # TRANSLATORS: keep it short, this is a button
1145                 # self["key_blue"] = Button(_("Search"))
1146
1147                 self["FritzOfferActions"] = ActionMap(["OkCancelActions", "ColorActions"],
1148                 {
1149                         "red": self._lookup,
1150                         "green": self._call,
1151                         "yellow": self._add,
1152                         "cancel": self._exit,
1153                         "ok": self._exit, }, - 2)
1154
1155                 self._session = session
1156                 if config.plugins.FritzCall.internal.value and len(number) > 3 and number[0] == "0":
1157                         number = number[1:]
1158                 self._number = number
1159                 self._name = name.replace("\n", ", ")
1160                 self["text"] = Label(number + "\n\n" + name.replace(", ", "\n"))
1161                 self._parent = parent
1162                 self._lookupState = 0
1163                 self["key_red_p"] = Pixmap()
1164                 self["key_green_p"] = Pixmap()
1165                 self["key_yellow_p"] = Pixmap()
1166                 self["FacePixmap"] = Pixmap()
1167                 self.onLayoutFinish.append(self._finishLayout)
1168                 self.onLayoutFinish.append(self.setWindowTitle)
1169
1170         def setWindowTitle(self):
1171                 # TRANSLATORS: this is a window title.
1172                 self.setTitle(_("Do what?"))
1173
1174         def _finishLayout(self):
1175                 # pylint: disable=W0142
1176                 debug("[FritzCall] FritzOfferAction/finishLayout number: %s/%s" % (__(self._number), __(self._name)))
1177
1178                 faceFile = findFace(self._number, self._name)
1179                 picPixmap = LoadPixmap(faceFile)
1180                 if not picPixmap:       # that means most probably, that the picture is not 8 bit...
1181                         Notifications.AddNotification(MessageBox, _("Found picture\n\n%s\n\nBut did not load. Probably not PNG, 8-bit") %faceFile, type = MessageBox.TYPE_ERROR)
1182                         picPixmap = LoadPixmap(resolveFilename(SCOPE_SKIN_IMAGE, "skin_default/icons/input_error.png"))
1183                 picSize = picPixmap.size()
1184                 self["FacePixmap"].instance.setPixmap(picPixmap)
1185
1186                 noButtons = 3
1187                 # recalculate window size
1188                 textSize = self["text"].getSize()
1189                 textSize = (textSize[0]+20, textSize[1]+20) # don't know, why, but size is too small
1190                 debug("[FritzCall] FritzOfferAction/finishLayout textsize: %s/%s" % textSize)
1191                 textSize = eSize(*textSize)
1192                 width = max(scaleH(620, 545), noButtons*145, picSize.width() + textSize.width() + 30)
1193                 height = max(picSize.height()+5, textSize.height()+5, scaleV(-1, 136)) + 5 + 40 + 5
1194                 buttonsGap = (width-noButtons*140)/(noButtons+1)
1195                 buttonsVPos = height-40-5
1196                 wSize = (width, height)
1197                 wSize = eSize(*wSize)
1198
1199                 # center the smaller vertically
1200                 hGap = (width-picSize.width()-textSize.width())/3
1201                 picPos = (hGap, (height-50-picSize.height())/2+5)
1202                 textPos = (hGap+picSize.width()+hGap, (height-50-textSize.height())/2+5)
1203
1204                 # resize screen
1205                 self.instance.resize(wSize)
1206                 # resize text
1207                 self["text"].instance.resize(textSize)
1208                 # resize pixmap
1209                 self["FacePixmap"].instance.resize(picSize)
1210                 # move buttons
1211                 buttonPos = (buttonsGap, buttonsVPos)
1212                 self["key_red_p"].instance.move(ePoint(*buttonPos))
1213                 self["key_red"].instance.move(ePoint(*buttonPos))
1214                 buttonPos = (buttonsGap+140+buttonsGap, buttonsVPos)
1215                 self["key_green_p"].instance.move(ePoint(*buttonPos))
1216                 self["key_green"].instance.move(ePoint(*buttonPos))
1217                 buttonPos = (buttonsGap+140+buttonsGap+140+buttonsGap, buttonsVPos)
1218                 self["key_yellow_p"].instance.move(ePoint(*buttonPos))
1219                 self["key_yellow"].instance.move(ePoint(*buttonPos))
1220                 # move text
1221                 self["text"].instance.move(ePoint(*textPos))
1222                 # move pixmap
1223                 self["FacePixmap"].instance.move(ePoint(*picPos))
1224                 # center window
1225                 self.instance.move(ePoint((DESKTOP_WIDTH-wSize.width())/2, (DESKTOP_HEIGHT-wSize.height())/2))
1226
1227         def _setTextAndResize(self, message):
1228                 # pylint: disable=W0142
1229                 self["text"].instance.resize(eSize(*(DESKTOP_WIDTH, DESKTOP_HEIGHT)))
1230                 self["text"].setText(self._number + "\n\n" + message)
1231                 self._finishLayout()
1232
1233         def _lookup(self):
1234                 phonebookLocation = config.plugins.FritzCall.phonebookLocation.value
1235                 if self._lookupState == 0:
1236                         self._lookupState = 1
1237                         self._setTextAndResize(_("Reverse searching..."))
1238                         ReverseLookupAndNotifier(self._number, self._lookedUp, "UTF-8", config.plugins.FritzCall.country.value)
1239                         return
1240                 if self._lookupState == 1 and os.path.exists(os.path.join(phonebookLocation, "PhoneBook.csv")):
1241                         self._setTextAndResize(_("Searching in Outlook export..."))
1242                         self._lookupState = 2
1243                         self._lookedUp(self._number, FritzOutlookCSV.findNumber(self._number, os.path.join(phonebookLocation, "PhoneBook.csv"))) #@UndefinedVariable
1244                         return
1245                 else:
1246                         self._lookupState = 2
1247                 if self._lookupState == 2 and os.path.exists(os.path.join(phonebookLocation, "PhoneBook.ldif")):
1248                         self._setTextAndResize(_("Searching in LDIF..."))
1249                         self._lookupState = 0
1250                         FritzLDIF.FindNumber(self._number, open(os.path.join(phonebookLocation, "PhoneBook.ldif")), self._lookedUp)
1251                         return
1252                 else:
1253                         self._lookupState = 0
1254                         self._lookup()
1255
1256         def _lookedUp(self, number, name):
1257                 name = handleReverseLookupResult(name)
1258                 if not name:
1259                         if self._lookupState == 1:
1260                                 name = _("No result from reverse lookup")
1261                         elif self._lookupState == 2:
1262                                 name = _("No result from Outlook export")
1263                         else:
1264                                 name = _("No result from LDIF")
1265                 self._name = name
1266                 self._number = number
1267                 debug("[FritzOfferAction] lookedUp: " + str(name.replace(", ", "\n")))
1268                 self._setTextAndResize(str(name.replace(", ", "\n")))
1269
1270         def _call(self):
1271                 if fritzbox:
1272                         debug("[FritzOfferAction] call: %s" %self._number)
1273                         self.session.open(MessageBox, _("Calling %s") %self._number, type=MessageBox.TYPE_INFO)
1274                         fritzbox.dial(self._number)
1275                 else:
1276                         debug("[FritzOfferAction] call: no fritzbox object?!?!")
1277                         self.session.open(MessageBox, _("FRITZ!Box not available for calling"), type=MessageBox.TYPE_INFO)
1278
1279         def _add(self):
1280                 debug("[FritzOfferAction] add: %s, %s" %(self._number, self._name))
1281                 phonebook.FritzDisplayPhonebook(self._session).add(self._parent, self._number, self._name)
1282                 self._exit()
1283
1284         def _exit(self):
1285                 self.close()
1286
1287 OneHour = 60*60*1000
1288 # OneHour = 1000
1289 class FritzCallPhonebook:
1290         def __init__(self):
1291                 debug("[FritzCallPhonebook] init")
1292                 # Beware: strings in phonebook.phonebook have to be in utf-8!
1293                 self.phonebook = {}
1294                 if config.plugins.FritzCall.reloadPhonebookTime.value > 0:
1295                         debug("[FritzCallPhonebook] start timer with " + repr(config.plugins.FritzCall.reloadPhonebookTime.value))
1296                         self.loop = eTimer()
1297                         
1298                         # newer OE versions don't have the callback
1299                         try:
1300                                 self.loop_conn = self.loop.timeout.connect(self.reload)
1301                         except AttributeError:
1302                                 self.loop.callback.append(self.reload)
1303                                 
1304                         self.loop.start(config.plugins.FritzCall.reloadPhonebookTime.value*OneHour, False)
1305                 self.reload()
1306
1307         def reload(self):
1308                 debug("[FritzCallPhonebook] reload " + time.ctime())
1309
1310                 # Beware: strings in phonebook.phonebook have to be in utf-8!
1311                 self.phonebook = {}
1312
1313                 if not config.plugins.FritzCall.enable.value:
1314                         return
1315
1316                 phonebookFilename = os.path.join(config.plugins.FritzCall.phonebookLocation.value, "PhoneBook.txt")
1317                 if config.plugins.FritzCall.phonebook.value and os.path.exists(phonebookFilename):
1318                         debug("[FritzCallPhonebook] reload: read " + phonebookFilename)
1319                         phonebookTxtCorrupt = False
1320                         self.phonebook = {}
1321                         for line in open(phonebookFilename):
1322                                 try:
1323                                         # Beware: strings in phonebook.phonebook have to be in utf-8!
1324                                         line = line.decode("utf-8")
1325                                 except UnicodeDecodeError: # this is just for the case, somebody wrote latin1 chars into PhoneBook.txt
1326                                         try:
1327                                                 line = line.decode("iso-8859-1")
1328                                                 debug("[FritzCallPhonebook] Fallback to ISO-8859-1 in %s" % line)
1329                                                 phonebookTxtCorrupt = True
1330                                         except UnicodeDecodeError:
1331                                                 debug("[FritzCallPhonebook] Could not parse internal Phonebook Entry %s" % line)
1332                                                 phonebookTxtCorrupt = True
1333                                 line = line.encode("utf-8")
1334                                 elems = line.split('#')
1335                                 if len(elems) == 2:
1336                                         try:
1337                                                 # debug("[FritzCallPhonebook] reload: Adding '''%s''' with '''%s''' from internal phonebook!" % (__(elems[1].strip()), __(elems[0], False)))
1338                                                 self.phonebook[elems[0]] = elems[1]
1339                                         except ValueError: # how could this possibly happen?!?!
1340                                                 debug("[FritzCallPhonebook] Could not parse internal Phonebook Entry %s" % line)
1341                                                 phonebookTxtCorrupt = True
1342                                 else:
1343                                         debug("[FritzCallPhonebook] Could not parse internal Phonebook Entry %s" % line)
1344                                         phonebookTxtCorrupt = True
1345                                         
1346                                 #===============================================================
1347                                 # found = re.match("^(\d+)#(.*)$", line)
1348                                 # if found:
1349                                 #       try:
1350                                 #               self.phonebook[found.group(1)] = found.group(2)
1351                                 #       except ValueError: # how could this possibly happen?!?!
1352                                 #               debug("[FritzCallPhonebook] Could not parse internal Phonebook Entry %s" % line)
1353                                 #               phonebookTxtCorrupt = True
1354                                 # else:
1355                                 #       debug("[FritzCallPhonebook] Could not parse internal Phonebook Entry %s" % line)
1356                                 #       phonebookTxtCorrupt = True
1357                                 #===============================================================
1358
1359                         if phonebookTxtCorrupt:
1360                                 # dump phonebook to PhoneBook.txt
1361                                 debug("[FritzCallPhonebook] dump Phonebook.txt")
1362                                 try:
1363                                         os.rename(phonebookFilename, phonebookFilename + ".bck")
1364                                         fNew = open(phonebookFilename, 'w')
1365                                         # Beware: strings in phonebook.phonebook are utf-8!
1366                                         for (number, name) in self.phonebook.iteritems():
1367                                                 # Beware: strings in PhoneBook.txt have to be in utf-8!
1368                                                 fNew.write(number + "#" + name.encode("utf-8"))
1369                                         fNew.close()
1370                                 except (IOError, OSError):
1371                                         debug("[FritzCallPhonebook] error renaming or writing to %s" %phonebookFilename)
1372
1373                 if fritzbox and config.plugins.FritzCall.fritzphonebook.value:
1374                         debug("[FritzCallPhonebook] config.plugins.FritzCall.fritzphonebook.value %s" %repr(config.plugins.FritzCall.fritzphonebook.value))
1375                         fritzbox.loadFritzBoxPhonebook(self)
1376
1377 #===============================================================================
1378 #               #
1379 #               # read entries from Outlook export
1380 #               #
1381 #               # not reliable with coding yet
1382 #               # 
1383 #               # import csv exported from Outlook 2007 with csv(Windows)
1384 #               csvFilename = "/tmp/PhoneBook.csv"
1385 #               if config.plugins.FritzCall.phonebook.value and os.path.exists(csvFilename):
1386 #                       try:
1387 #                               readOutlookCSV(csvFilename, self.add)
1388 #                               os.rename(csvFilename, csvFilename + ".done")
1389 #                       except ImportError:
1390 #                               debug("[FritzCallPhonebook] CSV import failed" %line)
1391 #===============================================================================
1392
1393                 
1394 #===============================================================================
1395 #               #
1396 #               # read entries from LDIF
1397 #               #
1398 #               # import ldif exported from Thunderbird 2.0.0.19
1399 #               ldifFilename = "/tmp/PhoneBook.ldif"
1400 #               if config.plugins.FritzCall.phonebook.value and os.path.exists(ldifFilename):
1401 #                       try:
1402 #                               parser = MyLDIF(open(ldifFilename), self.add)
1403 #                               parser.parse()
1404 #                               os.rename(ldifFilename, ldifFilename + ".done")
1405 #                       except ImportError:
1406 #                               debug("[FritzCallPhonebook] LDIF import failed" %line)
1407 #===============================================================================
1408
1409         def search(self, number, default=None, extended=True):
1410                 # debug("[FritzCallPhonebook] Searching for %s" %number)
1411                 name = ""
1412                 if not self.phonebook or not number:
1413                         return name
1414
1415                 if config.plugins.FritzCall.prefix.value:
1416                         prefix = config.plugins.FritzCall.prefix.value
1417                         if number[0] != '0':
1418                                 number = prefix + number
1419                                 # debug("[FritzCallPhonebook] search: added prefix: %s" %number)
1420                         elif number[:len(prefix)] == prefix and self.phonebook.has_key(number[len(prefix):]):
1421                                 # debug("[FritzCallPhonebook] search: same prefix")
1422                                 name = self.phonebook[number[len(prefix):]]
1423                                 # debug("[FritzCallPhonebook] search: result: %s" %name)
1424                 else:
1425                         prefix = ""
1426                                 
1427                 if not name and self.phonebook.has_key(number):
1428                         name = self.phonebook[number]
1429
1430                 if not name and default:
1431                         name = default
1432
1433                 if not name and extended and config.plugins.FritzCall.FritzExtendedSearchNames.value:
1434                         for k in range(len(number)-1, 0, -1):
1435                                 # debug("[FritzCallPhonebook] extended search: check: %s" %number[:k])
1436                                 name = self.search(number[:k], default, False)
1437                                 if name:
1438                                         # debug("[FritzCallPhonebook] search result for shortened number: %s" % name)
1439                                         break
1440
1441                 return name.replace(", ", "\n").strip()
1442
1443         def add(self, number, name):
1444                 '''
1445                 
1446                 @param number: number of entry
1447                 @param name: name of entry, has to be in utf-8
1448                 '''
1449                 debug("[FritzCallPhonebook] add")
1450                 name = name.replace("\n", ", ").replace('#','') # this is just for safety reasons. add should only be called with newlines converted into commas
1451                 self.remove(number)
1452                 self.phonebook[number] = name
1453                 if number and number != 0:
1454                         if config.plugins.FritzCall.phonebook.value:
1455                                 try:
1456                                         name = name.strip() + "\n"
1457                                         string = "%s#%s" % (number, name)
1458                                         # Beware: strings in PhoneBook.txt have to be in utf-8!
1459                                         f = open(os.path.join(config.plugins.FritzCall.phonebookLocation.value, "PhoneBook.txt"), 'a')
1460                                         f.write(string)
1461                                         f.close()
1462                                         debug("[FritzCallPhonebook] added %s with %s to Phonebook.txt" % (number, name.strip()))
1463                                         return True
1464         
1465                                 except IOError:
1466                                         return False
1467
1468         def remove(self, number):
1469                 if number in self.phonebook:
1470                         debug("[FritzCallPhonebook] remove entry in phonebook")
1471                         del self.phonebook[number]
1472                         if config.plugins.FritzCall.phonebook.value:
1473                                 try:
1474                                         phonebookFilename = os.path.join(config.plugins.FritzCall.phonebookLocation.value, "PhoneBook.txt")
1475                                         debug("[FritzCallPhonebook] remove entry in Phonebook.txt")
1476                                         fOld = open(phonebookFilename, 'r')
1477                                         fNew = open(phonebookFilename + str(os.getpid()), 'w')
1478                                         line = fOld.readline()
1479                                         while (line):
1480                                                 elems = line.split('#')
1481                                                 if len(elems) == 2 and not elems[0] == number:
1482                                                         fNew.write(line)
1483                                                 line = fOld.readline()
1484                                         fOld.close()
1485                                         fNew.close()
1486                                         # os.remove(phonebookFilename)
1487                                         eBackgroundFileEraser.getInstance().erase(phonebookFilename)
1488                                         os.rename(phonebookFilename + str(os.getpid()), phonebookFilename)
1489                                         debug("[FritzCallPhonebook] removed %s from Phonebook.txt" % number)
1490                                         return True
1491         
1492                                 except (IOError, OSError):
1493                                         debug("[FritzCallPhonebook] error removing %s from %s" %(number, phonebookFilename))
1494                 return False
1495
1496         class FritzDisplayPhonebook(Screen, HelpableScreen, NumericalTextInput):
1497         
1498                 def __init__(self, session):
1499                         self.entriesWidth = DESKTOP_WIDTH * scaleH(75, 85)/100
1500                         self.height = DESKTOP_HEIGHT * 0.75
1501                         numberFieldWidth = scaleH(220, 160)
1502                         fieldWidth = self.entriesWidth -5 -numberFieldWidth -10
1503                         fontSize = scaleV(22, 18)
1504                         fontHeight = scaleV(24, 20)
1505                         buttonGap = (self.entriesWidth-4*140)/5
1506                         debug("[FritzDisplayPhonebook] width: " + str(self.entriesWidth))
1507                         self.skin = """
1508                                 <screen name="FritzDisplayPhonebook" position="center,center" size="%d,%d" title="Phonebook" >
1509                                         <eLabel position="0,0" size="%d,2" backgroundColor="#aaaaaa" />
1510                                         <widget source="entries" render="Listbox" position="%d,%d" size="%d,%d" scrollbarMode="showOnDemand" transparent="1">
1511                                                 <convert type="TemplatedMultiContent">
1512                                                         {"template": [
1513                                                                         MultiContentEntryText(pos = (%d,%d), size = (%d,%d), font=0, flags = RT_HALIGN_LEFT, text = 1), # index 0 is the name, index 1 is shortname
1514                                                                         MultiContentEntryText(pos = (%d,%d), size = (%d,%d), font=0, flags = RT_HALIGN_LEFT, text = 2), # index 2 is number
1515                                                                 ],
1516                                                         "fonts": [gFont("Regular", %d)],
1517                                                         "itemHeight": %d
1518                                                         }
1519                                                 </convert>
1520                                         </widget>
1521                                         <eLabel position="0,%d" size="%d,2" backgroundColor="#aaaaaa" />
1522                                         <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
1523                                         <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
1524                                         <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
1525                                         <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
1526                                         <widget name="key_red" position="%d,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;%d" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
1527                                         <widget name="key_green" position="%d,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;%d" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
1528                                         <widget name="key_yellow" position="%d,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;%d" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
1529                                         <widget name="key_blue" position="%d,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;%d" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
1530                                 </screen>""" % (
1531                                                 # scaleH(90, 75), scaleV(100, 73), # position 
1532                                                 self.entriesWidth, self.height, # size
1533                                                 self.entriesWidth, # eLabel width
1534                                                 scaleH(40, 5), scaleV(20, 5), # entries position
1535                                                 self.entriesWidth-scaleH(40, 5), self.height-scaleV(20, 5)-5-5-40, # entries size
1536                                                 0, 0, fieldWidth, scaleH(24,20), # name pos/size
1537                                                 fieldWidth +5, 0, numberFieldWidth, scaleH(24,20), # dir pos/size
1538                                                 fontSize, # fontsize
1539                                                 fontHeight, # itemHeight
1540                                                 self.height-40-5, # eLabel position vertical
1541                                                 self.entriesWidth, # eLabel width
1542                                                 buttonGap, self.height-40, "skin_default/buttons/red.png", # ePixmap red
1543                                                 2*buttonGap+140, self.height-40, "skin_default/buttons/green.png", # ePixmap green
1544                                                 3*buttonGap+2*140, self.height-40, "skin_default/buttons/yellow.png", # ePixmap yellow
1545                                                 4*buttonGap+3*140, self.height-40, "skin_default/buttons/blue.png", # ePixmap blue
1546                                                 buttonGap, self.height-40, scaleV(22, 21), # widget red
1547                                                 2*buttonGap+140, self.height-40, scaleV(22, 21), # widget green
1548                                                 3*buttonGap+2*140, self.height-40, scaleV(22, 21), # widget yellow
1549                                                 4*buttonGap+3*140, self.height-40, scaleV(22, 21), # widget blue
1550                                                 )
1551         
1552                         # debug("[FritzDisplayCalls] skin: " + self.skin)
1553                         Screen.__init__(self, session)
1554                         NumericalTextInput.__init__(self)
1555                         HelpableScreen.__init__(self)
1556                 
1557                         # TRANSLATORS: keep it short, this is a button
1558                         self["key_red"] = Button(_("Delete"))
1559                         # TRANSLATORS: keep it short, this is a button
1560                         self["key_green"] = Button(_("New"))
1561                         # TRANSLATORS: keep it short, this is a button
1562                         self["key_yellow"] = Button(_("Edit"))
1563                         # TRANSLATORS: keep it short, this is a button
1564                         self["key_blue"] = Button(_("Search"))
1565         
1566                         self["setupActions"] = ActionMap(["OkCancelActions", "ColorActions"],
1567                         {
1568                                 "red": self.delete,
1569                                 "green": self.add,
1570                                 "yellow": self.edit,
1571                                 "blue": self.search,
1572                                 "cancel": self.exit,
1573                                 "ok": self.showEntry, }, - 2)
1574         
1575                         # TRANSLATORS: keep it short, this is a help text
1576                         self.helpList.append((self["setupActions"], "OkCancelActions", [("ok", _("Show details of entry"))]))
1577                         # TRANSLATORS: keep it short, this is a help text
1578                         self.helpList.append((self["setupActions"], "OkCancelActions", [("cancel", _("Quit"))]))
1579                         # TRANSLATORS: keep it short, this is a help text
1580                         self.helpList.append((self["setupActions"], "ColorActions", [("red", _("Delete entry"))]))
1581                         # TRANSLATORS: keep it short, this is a help text
1582                         self.helpList.append((self["setupActions"], "ColorActions", [("green", _("Add entry to phonebook"))]))
1583                         # TRANSLATORS: keep it short, this is a help text
1584                         self.helpList.append((self["setupActions"], "ColorActions", [("yellow", _("Edit selected entry"))]))
1585                         # TRANSLATORS: keep it short, this is a help text
1586                         self.helpList.append((self["setupActions"], "ColorActions", [("blue", _("Search (case insensitive)"))]))
1587         
1588                         self["entries"] = List([])
1589                         debug("[FritzDisplayPhonebook] displayPhonebook init")
1590                         self.help_window = None
1591                         self.sortlist = []
1592                         self.onLayoutFinish.append(self.setWindowTitle)
1593                         self.display()
1594
1595                 def setWindowTitle(self):
1596                         # TRANSLATORS: this is a window title.
1597                         self.setTitle(_("Phonebook"))
1598
1599                 def display(self, filterNumber=""):
1600                         debug("[FritzDisplayPhonebook] displayPhonebook/display")
1601                         self.sortlist = []
1602                         # Beware: strings in phonebook.phonebook are utf-8!
1603                         sortlistHelp = sorted((name.lower(), name, number) for (number, name) in phonebook.phonebook.iteritems())
1604                         for (low, name, number) in sortlistHelp:
1605                                 if number == "01234567890":
1606                                         continue
1607                                 try:
1608                                         low = low.decode("utf-8")
1609                                 except UnicodeDecodeError:  # this should definitely not happen
1610                                         try:
1611                                                 low = low.decode("iso-8859-1")
1612                                         except UnicodeDecodeError:
1613                                                 debug("[FritzDisplayPhonebook] displayPhonebook/display: corrupt phonebook entry for %s" % number)
1614                                                 # self.session.open(MessageBox, _("Corrupt phonebook entry\nfor number %s\nDeleting.") %number, type = MessageBox.TYPE_ERROR)
1615                                                 phonebook.remove(number)
1616                                                 continue
1617                                 else:
1618                                         if filterNumber:
1619                                                 filterNumber = filterNumber.lower()
1620                                                 if low.find(filterNumber) == - 1:
1621                                                         continue
1622                                         name = name.strip().decode("utf-8")
1623                                         number = number.strip().decode("utf-8")
1624                                         comma = name.find(',')
1625                                         if comma != -1:
1626                                                 shortname = name[:comma]
1627                                         else:
1628                                                 shortname = name
1629                                         number = number.encode("utf-8", "replace")
1630                                         name = name.encode("utf-8", "replace")
1631                                         shortname = shortname.encode('utf-8', 'replace')
1632                                         self.sortlist.append((name, shortname, number))
1633                                 
1634                         self["entries"].setList(self.sortlist)
1635         
1636                 def showEntry(self):
1637                         cur = self["entries"].getCurrent()
1638                         if cur:
1639                                 debug("[FritzDisplayPhonebook] displayPhonebook/showEntry %s" % (repr(cur)))
1640                                 number = cur[2]
1641                                 name = cur[0]
1642                                 self.session.open(FritzOfferAction, self, number, name)
1643         
1644                 def delete(self):
1645                         cur = self["entries"].getCurrent()
1646                         if cur:
1647                                 debug("[FritzDisplayPhonebook] displayPhonebook/delete %s" % (repr(cur)))
1648                                 self.session.openWithCallback(
1649                                         self.deleteConfirmed,
1650                                         MessageBox,
1651                                         _("Do you really want to delete entry for\n\n%(number)s\n\n%(name)s?") 
1652                                         % { 'number':str(cur[2]), 'name':str(cur[0]).replace(", ", "\n") }
1653                                                                 )
1654                         else:
1655                                 self.session.open(MessageBox, _("No entry selected"), MessageBox.TYPE_INFO)
1656         
1657                 def deleteConfirmed(self, ret):
1658                         debug("[FritzDisplayPhonebook] displayPhonebook/deleteConfirmed")
1659                         #
1660                         # if ret: delete number from sortlist, delete number from phonebook.phonebook and write it to disk
1661                         #
1662                         cur = self["entries"].getCurrent()
1663                         if cur:
1664                                 if ret:
1665                                         # delete number from sortlist, delete number from phonebook.phonebook and write it to disk
1666                                         debug("[FritzDisplayPhonebook] displayPhonebook/deleteConfirmed %s" % (repr(cur)))
1667                                         phonebook.remove(cur[2])
1668                                         self.display()
1669                                 # else:
1670                                         # self.session.open(MessageBox, _("Not deleted."), MessageBox.TYPE_INFO)
1671                         else:
1672                                 self.session.open(MessageBox, _("No entry selected"), MessageBox.TYPE_INFO)
1673         
1674                 def add(self, parent=None, number="", name=""):
1675                         class AddScreen(Screen, ConfigListScreen):
1676                                 '''ConfiglistScreen with two ConfigTexts for Name and Number'''
1677         
1678                                 def __init__(self, session, parent, number="", name=""):
1679                                         #
1680                                         # setup screen with two ConfigText and OK and ABORT button
1681                                         # 
1682                                         noButtons = 2
1683                                         width = max(scaleH(-1, 570), noButtons*140)
1684                                         height = scaleV(-1, 100) # = 5 + 126 + 40 + 5; 6 lines of text possible
1685                                         buttonsGap = (width-noButtons*140)/(noButtons+1)
1686                                         buttonsVPos = height-40-5
1687                                         self.skin = """
1688                                                 <screen position="center,center" size="%d,%d" title="Add entry to phonebook" >
1689                                                 <widget name="config" position="5,5" size="%d,%d" scrollbarMode="showOnDemand" />
1690                                                 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
1691                                                 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
1692                                                 <widget name="key_red" position="%d,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
1693                                                 <widget name="key_green" position="%d,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
1694                                                 </screen>""" % (
1695                                                                                 width, height,
1696                                                                                 width - 5 - 5, height - 5 - 40 - 5,
1697                                                                                 buttonsGap, buttonsVPos, "skin_default/buttons/red.png",
1698                                                                                 buttonsGap+140+buttonsGap, buttonsVPos, "skin_default/buttons/green.png",
1699                                                                                 buttonsGap, buttonsVPos,
1700                                                                                 buttonsGap+140+buttonsGap, buttonsVPos,
1701                                                                                 )
1702                                         Screen.__init__(self, session)
1703                                         self.session = session
1704                                         self.parent = parent
1705                                         # TRANSLATORS: keep it short, this is a button
1706                                         self["key_red"] = Button(_("Cancel"))
1707                                         # TRANSLATORS: keep it short, this is a button
1708                                         self["key_green"] = Button(_("OK"))
1709                                         self["setupActions"] = ActionMap(["SetupActions", "ColorActions"],
1710                                         {
1711                                                 "cancel": self.cancel,
1712                                                 "red": self.cancel,
1713                                                 "green": self.add,
1714                                                 "ok": self.add,
1715                                         }, - 2)
1716         
1717                                         self.list = [ ]
1718                                         ConfigListScreen.__init__(self, self.list, session=session)
1719                                         self.name = name
1720                                         self.number = number
1721                                         config.plugins.FritzCall.name.value = name
1722                                         config.plugins.FritzCall.number.value = number
1723                                         self.list.append(getConfigListEntry(_("Name"), config.plugins.FritzCall.name))
1724                                         self.list.append(getConfigListEntry(_("Number"), config.plugins.FritzCall.number))
1725                                         self["config"].list = self.list
1726                                         self["config"].l.setList(self.list)
1727                                         self.onLayoutFinish.append(self.setWindowTitle)
1728                         
1729                                 def setWindowTitle(self):
1730                                         # TRANSLATORS: this is a window title.
1731                                         self.setTitle(_("Add entry to phonebook"))
1732
1733                                 def add(self):
1734                                         # get texts from Screen
1735                                         # add (number,name) to sortlist and phonebook.phonebook and disk
1736                                         self.name = config.plugins.FritzCall.name.value
1737                                         self.number = config.plugins.FritzCall.number.value
1738                                         if not self.number or not self.name:
1739                                                 self.session.open(MessageBox, _("Entry incomplete."), type=MessageBox.TYPE_ERROR)
1740                                                 return
1741                                         # add (number,name) to sortlist and phonebook.phonebook and disk
1742         #                                       oldname = phonebook.search(self.number)
1743         #                                       if oldname:
1744         #                                               self.session.openWithCallback(
1745         #                                                       self.overwriteConfirmed,
1746         #                                                       MessageBox,
1747         #                                                       _("Do you really want to overwrite entry for %(number)s\n\n%(name)s\n\nwith\n\n%(newname)s?")
1748         #                                                       % {
1749         #                                                       'number':self.number,
1750         #                                                       'name': oldname,
1751         #                                                       'newname':self.name.replace(", ","\n")
1752         #                                                       }
1753         #                                                       )
1754         #                                               self.close()
1755         #                                               return
1756                                         phonebook.add(self.number, self.name)
1757                                         self.close()
1758                                         self.parent.display()
1759         
1760                                 def overwriteConfirmed(self, ret):
1761                                         if ret:
1762                                                 phonebook.remove(self.number)
1763                                                 phonebook.add(self.number, self.name)
1764                                                 self.parent.display()
1765         
1766                                 def cancel(self):
1767                                         self.close()
1768         
1769                         debug("[FritzDisplayPhonebook] displayPhonebook/add")
1770                         if not parent:
1771                                 parent = self
1772                         self.session.open(AddScreen, parent, number, name)
1773         
1774                 def edit(self):
1775                         debug("[FritzDisplayPhonebook] displayPhonebook/edit")
1776                         cur = self["entries"].getCurrent()
1777                         if cur is None:
1778                                 self.session.open(MessageBox, _("No entry selected"), MessageBox.TYPE_INFO)
1779                         else:
1780                                 self.add(self, cur[2], cur[0])
1781         
1782                 def search(self):
1783                         debug("[FritzDisplayPhonebook] displayPhonebook/search")
1784                         self.help_window = self.session.instantiateDialog(NumericalTextInputHelpDialog, self)
1785                         self.help_window.show()
1786                         # VirtualKeyboard instead of InputBox?
1787                         self.session.openWithCallback(self.doSearch, InputBox, _("Enter Search Terms"), _("Search phonebook"))
1788         
1789                 def doSearch(self, searchTerms):
1790                         if not searchTerms:
1791                                 searchTerms = ""
1792                         debug("[FritzDisplayPhonebook] displayPhonebook/doSearch: " + searchTerms)
1793                         if self.help_window:
1794                                 self.session.deleteDialog(self.help_window)
1795                                 self.help_window = None
1796                         self.display(searchTerms)
1797         
1798                 def exit(self):
1799                         self.close()
1800
1801 phonebook = FritzCallPhonebook()
1802
1803 class FritzCallSetup(Screen, ConfigListScreen, HelpableScreen):
1804
1805         def __init__(self, session, args=None): #@UnusedVariable # pylint: disable=W0613
1806                 self.width = scaleH(20+4*(140+90)+2*(35+40)+20, 4*140+2*35)
1807                 width = self.width
1808                 debug("[FritzCallSetup] width: " + str(self.width))
1809                 self.skin = """
1810                         <screen name="FritzCallSetup" position="center,center" size="%d,%d" title="FritzCall Setup" >
1811                         <eLabel position="0,0" size="%d,2" backgroundColor="#aaaaaa" />
1812                         <widget name="consideration" position="%d,%d" halign="center" size="%d,%d" font="Regular;%d" backgroundColor="#20040404" transparent="1" />
1813                         <eLabel position="0,%d" size="%d,2" backgroundColor="#aaaaaa" />
1814                         <widget name="config" position="%d,%d" size="%d,%d" scrollbarMode="showOnDemand" backgroundColor="#20040404" transparent="1" />
1815                         <eLabel position="0,%d" size="%d,2" backgroundColor="#aaaaaa" />
1816                         <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
1817                         <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
1818                         <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
1819                         <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
1820                         <widget name="key_red" position="%d,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;%d" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
1821                         <widget name="key_green" position="%d,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;%d" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
1822                         <widget name="key_yellow" position="%d,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;%d" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
1823                         <widget name="key_blue" position="%d,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;%d" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
1824                         <ePixmap position="%d,%d" zPosition="4" size="35,25" pixmap="%s" transparent="1" alphatest="on" />
1825                         <ePixmap position="%d,%d" zPosition="4" size="35,25" pixmap="%s" transparent="1" alphatest="on" />
1826                         </screen>""" % (
1827                                                 # (DESKTOP_WIDTH-width)/2, scaleV(100, 73), # position 
1828                                                 width, scaleV(560, 430), # size
1829                                                 width, # eLabel width
1830                                                 scaleH(40, 20), scaleV(10, 5), # consideration position
1831                                                 scaleH(width-80, width-40), scaleV(25, 45), # consideration size
1832                                                 scaleV(22, 20), # consideration font size
1833                                                 scaleV(40, 50), # eLabel position vertical
1834                                                 width, # eLabel width
1835                                                 scaleH(40, 5), scaleV(60, 57), # config position
1836                                                 scaleH(width-80, width-10), scaleV(453, 328), # config size
1837                                                 scaleV(518, 390), # eLabel position vertical
1838                                                 width, # eLabel width
1839                                                 scaleH(20, 0), scaleV(525, 395), "skin_default/buttons/red.png", # pixmap red
1840                                                 scaleH(20+140+90, 140), scaleV(525, 395), "skin_default/buttons/green.png", # pixmap green
1841                                                 scaleH(20+2*(140+90), 2*140), scaleV(525, 395), "skin_default/buttons/yellow.png", # pixmap yellow
1842                                                 scaleH(20+3*(140+90), 3*140), scaleV(525, 395), "skin_default/buttons/blue.png", # pixmap blue
1843                                                 scaleH(20, 0), scaleV(525, 395), scaleV(21, 21), # widget red
1844                                                 scaleH(20+(140+90), 140), scaleV(525, 395), scaleV(21, 21), # widget green
1845                                                 scaleH(20+2*(140+90), 2*140), scaleV(525, 395), scaleV(21, 21), # widget yellow
1846                                                 scaleH(20+3*(140+90), 3*140), scaleV(525, 395), scaleV(21, 21), # widget blue
1847                                                 scaleH(20+4*(140+90), 4*140), scaleV(532, 402), "skin_default/buttons/key_info.png", # button info
1848                                                 scaleH(20+4*(140+90)+(35+40), 4*140+35), scaleV(532, 402), "skin_default/buttons/key_menu.png", # button menu
1849                                                                                                         )
1850
1851                 Screen.__init__(self, session)
1852                 HelpableScreen.__init__(self)
1853                 self.session = session
1854
1855                 self["consideration"] = Label(_("You need to enable the monitoring on your FRITZ!Box by dialing #96*5*!"))
1856                 self.list = []
1857
1858                 # Initialize Buttons
1859                 # TRANSLATORS: keep it short, this is a button
1860                 self["key_red"] = Button(_("Cancel"))
1861                 # TRANSLATORS: keep it short, this is a button
1862                 self["key_green"] = Button(_("OK"))
1863                 # TRANSLATORS: keep it short, this is a button
1864                 self["key_yellow"] = Button(_("Phone calls"))
1865                 # TRANSLATORS: keep it short, this is a button
1866                 self["key_blue"] = Button(_("Phonebook"))
1867                 # TRANSLATORS: keep it short, this is a button
1868                 self["key_info"] = Button(_("About FritzCall"))
1869                 # TRANSLATORS: keep it short, this is a button
1870                 self["key_menu"] = Button(_("FRITZ!Box Fon Status"))
1871
1872                 self["setupActions"] = ActionMap(["ColorActions", "OkCancelActions", "MenuActions", "EPGSelectActions"],
1873                 {
1874                         "red": self.cancel,
1875                         "green": self.save,
1876                         "yellow": self.displayCalls,
1877                         "blue": self.displayPhonebook,
1878                         "cancel": self.cancel,
1879                         "ok": self.save,
1880                         "menu": self.menu,
1881                         "info": self.about,
1882                 }, - 2)
1883
1884                 # TRANSLATORS: keep it short, this is a help text
1885                 self.helpList.append((self["setupActions"], "ColorActions", [("red", _("quit"))]))
1886                 # TRANSLATORS: keep it short, this is a help text
1887                 self.helpList.append((self["setupActions"], "ColorActions", [("green", _("save and quit"))]))
1888                 # TRANSLATORS: keep it short, this is a help text
1889                 self.helpList.append((self["setupActions"], "ColorActions", [("yellow", _("display calls"))]))
1890                 # TRANSLATORS: keep it short, this is a help text
1891                 self.helpList.append((self["setupActions"], "ColorActions", [("blue", _("display phonebook"))]))
1892                 # TRANSLATORS: keep it short, this is a help text
1893                 self.helpList.append((self["setupActions"], "OkCancelActions", [("ok", _("save and quit"))]))
1894                 # TRANSLATORS: keep it short, this is a help text
1895                 self.helpList.append((self["setupActions"], "OkCancelActions", [("cancel", _("quit"))]))
1896                 # TRANSLATORS: keep it short, this is a help text
1897                 self.helpList.append((self["setupActions"], "MenuActions", [("menu", _("FRITZ!Box Fon Status"))]))
1898                 # TRANSLATORS: keep it short, this is a help text
1899                 self.helpList.append((self["setupActions"], "EPGSelectActions", [("info", _("About FritzCall"))]))
1900
1901                 ConfigListScreen.__init__(self, self.list, session=session)
1902
1903                 # get new list of locations for PhoneBook.txt
1904                 self.createSetup()
1905                 self.onLayoutFinish.append(self.setWindowTitle)
1906
1907         def setWindowTitle(self):
1908                 # TRANSLATORS: this is a window title.
1909                 self.setTitle(_("FritzCall Setup") + " (" + "$Revision: 1039 $"[1: - 1] + "$Date: 2014-11-15 16:13:49 +0100 (Sat, 15 Nov 2014) $"[7:23] + ")")
1910
1911         def keyLeft(self):
1912                 ConfigListScreen.keyLeft(self)
1913                 self.createSetup()
1914
1915         def keyRight(self):
1916                 ConfigListScreen.keyRight(self)
1917                 self.createSetup()
1918
1919         def createSetup(self):
1920                 self.list = [ ]
1921                 self.list.append(getConfigListEntry(_("Call monitoring"), config.plugins.FritzCall.enable))
1922                 if config.plugins.FritzCall.enable.value:
1923                         self.list.append(getConfigListEntry(_("FRITZ!Box FON address (Name or IP)"), config.plugins.FritzCall.hostname))
1924                         self.list.append(getConfigListEntry(_("FRITZ!Box FON firmware version"), config.plugins.FritzCall.fwVersion))
1925
1926                         self.list.append(getConfigListEntry(_("Show after Standby"), config.plugins.FritzCall.afterStandby))
1927
1928                         self.list.append(getConfigListEntry(_("Show only calls for specific MSN"), config.plugins.FritzCall.filter))
1929                         if config.plugins.FritzCall.filter.value:
1930                                 self.list.append(getConfigListEntry(_("MSN to show (separated by ,)"), config.plugins.FritzCall.filtermsn))
1931                                 self.list.append(getConfigListEntry(_("Filter also list of calls"), config.plugins.FritzCall.filterCallList))
1932                         self.list.append(getConfigListEntry(_("Mute on call"), config.plugins.FritzCall.muteOnCall))
1933
1934                         self.list.append(getConfigListEntry(_("Show Outgoing Calls"), config.plugins.FritzCall.showOutgoing))
1935                         # not only for outgoing: config.plugins.FritzCall.showOutgoing.value:
1936                         self.list.append(getConfigListEntry(_("Areacode to add to calls without one (if necessary)"), config.plugins.FritzCall.prefix))
1937                         self.list.append(getConfigListEntry(_("Timeout for Call Notifications (seconds)"), config.plugins.FritzCall.timeout))
1938                         self.list.append(getConfigListEntry(_("Reverse Lookup Caller ID (select country below)"), config.plugins.FritzCall.lookup))
1939                         if config.plugins.FritzCall.lookup.value:
1940                                 self.list.append(getConfigListEntry(_("Country"), config.plugins.FritzCall.country))
1941
1942                         if config.plugins.FritzCall.fwVersion.value != None:
1943                                 if config.plugins.FritzCall.fwVersion.value == "05.50":
1944                                         self.list.append(getConfigListEntry(_("Name of WLAN guest network"), config.plugins.FritzCall.guestSSID))
1945                                         self.list.append(getConfigListEntry(_("Secure WLAN guest network"), config.plugins.FritzCall.guestSecure))
1946                                         self.list.append(getConfigListEntry(_("Password of WLAN guest network"), config.plugins.FritzCall.guestPassword))
1947                                         self.list.append(getConfigListEntry(_("User name Accessing FRITZ!Box"), config.plugins.FritzCall.username))
1948                                 # TODO: make password unreadable?
1949                                 self.list.append(getConfigListEntry(_("Password Accessing FRITZ!Box"), config.plugins.FritzCall.password))
1950                                 self.list.append(getConfigListEntry(_("Extension number to initiate call on"), config.plugins.FritzCall.extension))
1951                                 self.list.append(getConfigListEntry(_("Read PhoneBook from FRITZ!Box"), config.plugins.FritzCall.fritzphonebook))
1952                                 if config.plugins.FritzCall.fritzphonebook.value:
1953                                         self.list.append(getConfigListEntry(_("FRITZ!Box PhoneBook to read"), config.plugins.FritzCall.fritzphonebookName))
1954                                         self.list.append(getConfigListEntry(_("Append type of number"), config.plugins.FritzCall.showType))
1955                                         self.list.append(getConfigListEntry(_("Append shortcut number"), config.plugins.FritzCall.showShortcut))
1956                                         self.list.append(getConfigListEntry(_("Append vanity name"), config.plugins.FritzCall.showVanity))
1957                         else:
1958                                 config.plugins.FritzCall.fritzphonebook.value = False
1959
1960                         if config.plugins.FritzCall.phonebook.value or config.plugins.FritzCall.fritzphonebook.value:
1961                                 self.list.append(getConfigListEntry(_("Reload interval for phonebooks (hours)"), config.plugins.FritzCall.reloadPhonebookTime))
1962
1963                         self.list.append(getConfigListEntry(_("Use internal PhoneBook"), config.plugins.FritzCall.phonebook))
1964                         if config.plugins.FritzCall.phonebook.value:
1965                                 if config.plugins.FritzCall.lookup.value:
1966                                         self.list.append(getConfigListEntry(_("Automatically add new Caller to PhoneBook"), config.plugins.FritzCall.addcallers))
1967                         self.list.append(getConfigListEntry(_("PhoneBook and Faces Location"), config.plugins.FritzCall.phonebookLocation))
1968
1969                         if config.plugins.FritzCall.phonebook.value or config.plugins.FritzCall.fritzphonebook.value:
1970                                 self.list.append(getConfigListEntry(_("Extended Search for names"), config.plugins.FritzCall.FritzExtendedSearchNames))
1971                         self.list.append(getConfigListEntry(_("Extended Search for faces"), config.plugins.FritzCall.FritzExtendedSearchFaces))
1972
1973                         self.list.append(getConfigListEntry(_("Strip Leading 0"), config.plugins.FritzCall.internal))
1974                         # self.list.append(getConfigListEntry(_("Default display mode for FRITZ!Box calls"), config.plugins.FritzCall.fbfCalls))
1975                         self.list.append(getConfigListEntry(_("Display connection infos"), config.plugins.FritzCall.connectionVerbose))
1976                         self.list.append(getConfigListEntry(_("Ignore callers with no phone number"), config.plugins.FritzCall.ignoreUnknown))
1977                         self.list.append(getConfigListEntry(_("Debug"), config.plugins.FritzCall.debug))
1978
1979                 self["config"].list = self.list
1980                 self["config"].l.setList(self.list)
1981
1982         def save(self):
1983 #               debug("[FritzCallSetup] save"
1984                 if self["config"].getCurrent()[1] == config.plugins.FritzCall.phonebookLocation:
1985                         self.session.openWithCallback(self.LocationBoxClosed, LocationBox, _("PhoneBook and Faces Location"), currDir=config.plugins.FritzCall.phonebookLocation.value)
1986                 else:
1987                         for x in self["config"].list:
1988                                 x[1].save()
1989                         if config.plugins.FritzCall.phonebookLocation.isChanged() or config.plugins.FritzCall.reloadPhonebookTime.isChanged():
1990                                 global phonebook
1991                                 phonebook.reload()
1992                         if fritz_call:
1993                                 if config.plugins.FritzCall.enable.value:
1994                                         fritz_call.connect()
1995                                 else:
1996                                         fritz_call.shutdown()
1997                         self.close()
1998
1999         def LocationBoxClosed(self, path):
2000                 if path is not None:
2001                         config.plugins.FritzCall.phonebookLocation.setValue(path)
2002
2003         def cancel(self):
2004 #               debug("[FritzCallSetup] cancel"
2005                 for x in self["config"].list:
2006                         x[1].cancel()
2007                 self.close()
2008
2009         def displayCalls(self):
2010                 if config.plugins.FritzCall.enable.value:
2011                         if fritzbox and config.plugins.FritzCall.fwVersion.value:
2012                                 self.session.open(FritzDisplayCalls)
2013                         else:
2014                                 self.session.open(MessageBox, _("Cannot get calls from FRITZ!Box"), type=MessageBox.TYPE_INFO)
2015                 else:
2016                         self.session.open(MessageBox, _("Plugin not enabled"), type=MessageBox.TYPE_INFO)
2017
2018         def displayPhonebook(self):
2019                 if phonebook:
2020                         if config.plugins.FritzCall.enable.value:
2021                                 self.session.open(phonebook.FritzDisplayPhonebook)
2022                         else:
2023                                 self.session.open(MessageBox, _("Plugin not enabled"), type=MessageBox.TYPE_INFO)
2024                 else:
2025                         self.session.open(MessageBox, _("No phonebook"), type=MessageBox.TYPE_INFO)
2026
2027         def about(self):
2028                 self.session.open(FritzAbout)
2029
2030         def menu(self):
2031                 if config.plugins.FritzCall.enable.value:
2032                         if fritzbox and fritzbox.info:
2033                                 self.session.open(FritzMenu)
2034                         else:
2035                                 self.session.open(MessageBox, _("Cannot get infos from FRITZ!Box yet\nStill initialising or wrong firmware version"), type=MessageBox.TYPE_INFO)
2036                 else:
2037                         self.session.open(MessageBox, _("Plugin not enabled"), type=MessageBox.TYPE_INFO)
2038
2039 standbyMode = False
2040
2041 class FritzCallList:
2042         def __init__(self):
2043                 self.callList = [ ]
2044         
2045         def add(self, event, date, number, caller, phone):
2046                 debug("[FritzCallList] add: %s %s" % (number, caller))
2047                 if len(self.callList) > 10:
2048                         if self.callList[0] != "Start":
2049                                 self.callList[0] = "Start"
2050                         del self.callList[1]
2051
2052                 self.callList.append((event, number, date, caller, phone))
2053         
2054         def display(self):
2055                 debug("[FritzCallList] display")
2056                 global standbyMode
2057                 standbyMode = False
2058                 # Standby.inStandby.onClose.remove(self.display) object does not exist anymore...
2059                 # build screen from call list
2060                 text = "\n"
2061
2062                 if not self.callList:
2063                         text = _("no calls") 
2064                 else:
2065                         if self.callList[0] == "Start":
2066                                 text = text + _("Last 10 calls:\n")
2067                                 del self.callList[0]
2068         
2069                         for call in self.callList:
2070                                 (event, number, date, caller, phone) = call
2071                                 if event == "RING":
2072                                         direction = "->"
2073                                 else:
2074                                         direction = "<-"
2075         
2076                                 # shorten the date info
2077                                 date = date[:6] + date[9:14]
2078         
2079                                 # our phone could be of the form "0123456789 (home)", then we only take "home"
2080                                 oBrack = phone.find('(')
2081                                 cBrack = phone.find(')')
2082                                 if oBrack != -1 and cBrack != -1:
2083                                         phone = phone[oBrack+1:cBrack]
2084         
2085                                 # should not happen, for safety reasons
2086                                 if not caller:
2087                                         caller = _("UNKNOWN")
2088                                 
2089                                 #  if we have an unknown number, show the number
2090                                 if caller == _("UNKNOWN") and number != "":
2091                                         caller = number
2092                                 else:
2093                                         # strip off the address part of the remote caller/callee, if there is any
2094                                         nl = caller.find('\n')
2095                                         if nl != -1:
2096                                                 caller = caller[:nl]
2097                                         elif caller[0] == '[' and caller[-1] == ']':
2098                                                 # that means, we've got an unknown number with a city added from avon.dat 
2099                                                 if (len(number) + 1 + len(caller) + len(phone)) <= 40:
2100                                                         caller = number + ' ' + caller
2101                                                 else:
2102                                                         caller = number
2103         
2104                                 while (len(caller) + len(phone)) > 40:
2105                                         if len(caller) > len(phone):
2106                                                 caller = caller[: - 1]
2107                                         else:
2108                                                 phone = phone[: - 1]
2109         
2110                                 text = text + "%s %s %s %s\n" % (date, caller, direction, phone)
2111                                 debug("[FritzCallList] display: '%s %s %s %s'" % (date, caller, direction, phone))
2112
2113                 # display screen
2114                 Notifications.AddNotification(MessageBox, text, type=MessageBox.TYPE_INFO)
2115                 # TODO please HELP: from where can I get a session?
2116                 # my_global_session.open(FritzDisplayCalls, text)
2117                 self.callList = [ ]
2118
2119 callList = FritzCallList()
2120
2121 def findFace(number, name):
2122         # debug("[FritzCall] findFace number/name: %s/%s" % (number, name))
2123         if name:
2124                 sep = name.find(',')
2125                 if sep != -1:
2126                         name = name[:sep]
2127                 sep = name.find('\n')
2128                 if sep != -1:
2129                         name = name[:sep]
2130         else:
2131                 name = _("UNKNOWN")
2132         # debug("[FritzCall] findFace looking for: %s" %name)
2133
2134         facesDir = os.path.join(config.plugins.FritzCall.phonebookLocation.value, "FritzCallFaces")
2135         # debug("[FritzCall] findFace looking in: %s" %facesDir)
2136         facesFile = None
2137
2138         if not os.path.isdir(facesDir):
2139                 debug("[FritzCall] findFace facesdir does not exist: %s" %facesDir)
2140         else:
2141                 files = os.listdir(facesDir)
2142                 # debug("[FritzCall] findFace listdir: %s" %repr(files))
2143                 myFiles = [f for f in files if re.match(re.escape(number) + "\.[png|PNG]", f)]
2144                 if not myFiles:
2145                         myFiles = [f for f in files if re.match(re.escape(name) + "\.[png|PNG]", f)]
2146         
2147                 if not myFiles:
2148                         sep = name.find(' (')
2149                         if sep != -1:
2150                                 name = name[:sep]
2151                         myFiles = [f for f in files if re.match(re.escape(name) + "\.[png|PNG]", f)]
2152         
2153                 if myFiles:
2154                         # debug("[FritzCall] findFace found: %s" %repr(myFiles))
2155                         facesFile = os.path.join(facesDir, myFiles[0])
2156         
2157                 if not facesFile and config.plugins.FritzCall.FritzExtendedSearchFaces.value:
2158                         for k in range(len(number)-1, 0, -1):
2159                                 # debug("[FritzCall] findFace extended search: %s" %number[:k])
2160                                 myFiles = [f for f in files if re.match(re.escape(number[:k]) + "\.[png|PNG]", f)]
2161                                 if myFiles:
2162                                         facesFile = os.path.join(facesDir, myFiles[0])
2163                                         break
2164
2165         if not facesFile:
2166                 facesFile = resolveFilename(SCOPE_SKIN_IMAGE, "skin_default/icons/input_info.png")
2167
2168         debug("[FritzCall] findFace result: %s" % (__(facesFile)))
2169         return facesFile
2170
2171 class MessageBoxPixmap(Screen):
2172         def __init__(self, session, text, number = "", name = "", timeout = -1):
2173                 self.skin = """
2174         <screen name="MessageBoxPixmap" position="center,center" size="600,10" title="New Call">
2175                 <widget name="text" position="115,8" size="520,0" font="Regular;%d" />
2176                 <widget name="InfoPixmap" pixmap="%s" position="5,5" size="100,100" alphatest="on" />
2177         </screen>
2178                 """ % (
2179                         # scaleH(350, 60), scaleV(175, 245),
2180                         scaleV(24, 22), resolveFilename(SCOPE_SKIN_IMAGE, "skin_default/icons/input_info.png")
2181                         )
2182                 debug("[FritzCall] MessageBoxPixmap number: %s" % number)
2183                 Screen.__init__(self, session)
2184                 # MessageBox.__init__(self, session, text, type=MessageBox.TYPE_INFO, timeout=timeout)
2185                 self["text"] = Label(text)
2186                 self["InfoPixmap"] = Pixmap()
2187                 self._session = session
2188                 self._number = number
2189                 self._name = name
2190                 self._timerRunning = False
2191                 self._timer = None
2192                 self._timeout = timeout
2193                 self._origTitle = None
2194                 self._initTimeout()
2195                 self.onLayoutFinish.append(self._finishLayout)
2196                 self["actions"] = ActionMap(["OkCancelActions"],
2197                 {
2198                         "cancel": self._exit,
2199                         "ok": self._exit, }, - 2)
2200
2201         def _finishLayout(self):
2202                 # pylint: disable=W0142
2203                 debug("[FritzCall] MessageBoxPixmap/setInfoPixmap number: %s/%s" % (self._number, self._name))
2204
2205                 self.setTitle(_("New call"))
2206
2207                 faceFile = findFace(self._number, self._name)
2208                 picPixmap = LoadPixmap(faceFile)
2209                 if not picPixmap:       # that means most probably, that the picture is not 8 bit...
2210                         Notifications.AddNotification(MessageBox, _("Found picture\n\n%s\n\nBut did not load. Probably not PNG, 8-bit") %faceFile, type = MessageBox.TYPE_ERROR)
2211                         picPixmap = LoadPixmap(resolveFilename(SCOPE_SKIN_IMAGE, "skin_default/icons/input_error.png"))
2212                 picSize = picPixmap.size()
2213                 self["InfoPixmap"].instance.setPixmap(picPixmap)
2214
2215                 # recalculate window size
2216                 textSize = self["text"].getSize()
2217                 textSize = (textSize[0]+20, textSize[1]+20) # don't know, why, but size is too small
2218                 textSize = eSize(*textSize)
2219                 width = max(scaleH(600, 280), picSize.width() + textSize.width() + 30)
2220                 height = max(scaleV(300, 250), picSize.height()+10, textSize.height()+10)
2221                 wSize = (width, height)
2222                 wSize = eSize(*wSize)
2223
2224                 # center the smaller vertically
2225                 hGap = (width-picSize.width()-textSize.width())/3
2226                 picPos = (hGap, (height-picSize.height())/2+1)
2227                 textPos = (hGap+picSize.width()+hGap, (height-textSize.height())/2+1)
2228
2229                 # resize screen
2230                 self.instance.resize(wSize)
2231                 # resize text
2232                 self["text"].instance.resize(textSize)
2233                 # resize pixmap
2234                 self["InfoPixmap"].instance.resize(picSize)
2235                 # move text
2236                 self["text"].instance.move(ePoint(*textPos))
2237                 # move pixmap
2238                 self["InfoPixmap"].instance.move(ePoint(*picPos))
2239                 # center window
2240                 self.instance.move(ePoint((DESKTOP_WIDTH-wSize.width())/2, (DESKTOP_HEIGHT-wSize.height())/2))
2241
2242         def _initTimeout(self):
2243                 if self._timeout > 0:
2244                         self._timer = eTimer()
2245                         
2246                         # newer OE versions don't have the callback
2247                         try:
2248                                 self._timer_conn = self._timer.timeout.connect(self._timerTick)
2249                         except AttributeError:
2250                                 self._timer.callback.append(self._timerTick)
2251
2252                         self.onExecBegin.append(self._startTimer)
2253                         self._origTitle = None
2254                         if self.execing:
2255                                 self._timerTick()
2256                         else:
2257                                 self.onShown.append(self.__onShown)
2258                         self._timerRunning = True
2259                 else:
2260                         self._timerRunning = False
2261
2262         def __onShown(self):
2263                 self.onShown.remove(self.__onShown)
2264                 self._timerTick()
2265
2266         def _startTimer(self):
2267                 self._timer.start(1000)
2268
2269 #===============================================================================
2270 #       def stopTimer(self):
2271 #               if self._timerRunning:
2272 #                       del self._timer
2273 #                       self.setTitle(self._origTitle)
2274 #                       self._timerRunning = False
2275 #===============================================================================
2276
2277         def _timerTick(self):
2278                 if self.execing:
2279                         self._timeout -= 1
2280                         if self._origTitle is None:
2281                                 self._origTitle = self.instance.getTitle()
2282                         self.setTitle(self._origTitle + " (" + str(self._timeout) + ")")
2283                         if self._timeout == 0:
2284                                 self._timer.stop()
2285                                 self._timerRunning = False
2286                                 self._exit()
2287
2288         def _exit(self):
2289                 self.close()
2290
2291 def runUserActionScript(event, date, number, caller, phone):
2292         # user exit
2293         # call FritzCallserAction.sh in the same dir as Phonebook.txt with the following parameters:
2294         # event: "RING" (incomning) or "CALL" (outgoing)
2295         # date of event, format: "dd.mm.yy hh.mm.ss"
2296         # telephone number which is calling/is called
2297         # caller's name and address, format Name\n Street\n ZIP City
2298         # line/number which is called/which is used for calling
2299         userActionScript = os.path.join(config.plugins.FritzCall.phonebookLocation.value, "FritzCallUserAction.sh")
2300         if os.path.exists(userActionScript) and os.access(userActionScript, os.X_OK):
2301                 cmd = userActionScript + ' "' + event + '" "' + date + '" "' + number + '" "' + caller + '" "' + phone + '"'
2302                 debug("[FritzCall] runUserActionScript: calling: %s" % cmd)
2303                 eConsoleAppContainer().execute(cmd)
2304
2305 userActionList = [runUserActionScript]
2306 def registerUserAction(fun):
2307         #===========================================================================
2308         # other plugins can register a function, which is then called for each displayed call
2309         # it must take the arguments event,date,number,caller,phone
2310         #
2311         #example:
2312         # def FritzCallEvent(event,date,number,caller,phone):
2313         # ......
2314         # 
2315         # try:
2316         #       from Plugins.Extensions.FritzCall.plugin import registerUserAction as FritzCallRegisterUserAction
2317         #       FritzCallRegisterUserAction(FritzCallEvent)
2318         # except:
2319         #       print "import of FritzCall failed"
2320         #===========================================================================
2321         debug("[FritzCall] registerUserAction: register: %s" % fun.__name__)
2322         userActionList.append(fun)
2323                         
2324 mutedOnConnID = None
2325 def notifyCall(event, date, number, caller, phone, connID):
2326         if Standby.inStandby is None or config.plugins.FritzCall.afterStandby.value == "each":
2327                 if event == "RING":
2328                         global mutedOnConnID
2329                         if config.plugins.FritzCall.muteOnCall.value and not mutedOnConnID:
2330                                 debug("[FritzCall] mute on connID: %s" % connID)
2331                                 mutedOnConnID = connID
2332                                 # eDVBVolumecontrol.getInstance().volumeMute() # with this, we get no mute icon...
2333                                 if not eDVBVolumecontrol.getInstance().isMuted():
2334                                         globalActionMap.actions["volumeMute"]()
2335                         text = _("Incoming Call on %(date)s at %(time)s from\n---------------------------------------------\n%(number)s\n%(caller)s\n---------------------------------------------\nto: %(phone)s") % { 'date':date[:8], 'time':date[9:], 'number':number, 'caller':caller, 'phone':phone }
2336                 else:
2337                         text = _("Outgoing Call on %(date)s at %(time)s to\n---------------------------------------------\n%(number)s\n%(caller)s\n---------------------------------------------\nfrom: %(phone)s") % { 'date':date[:8], 'time':date[9:], 'number':number, 'caller':caller, 'phone':phone }
2338                 debug("[FritzCall] notifyCall:\n%s" % text)
2339                 # Notifications.AddNotification(MessageBox, text, type=MessageBox.TYPE_INFO, timeout=config.plugins.FritzCall.timeout.value)
2340                 Notifications.AddNotification(MessageBoxPixmap, text, number=number, name=caller, timeout=config.plugins.FritzCall.timeout.value)
2341         elif config.plugins.FritzCall.afterStandby.value == "inList":
2342                 #
2343                 # if not yet done, register function to show call list
2344                 global standbyMode
2345                 if not standbyMode :
2346                         standbyMode = True
2347                         Standby.inStandby.onHide.append(callList.display) #@UndefinedVariable
2348                 # add text/timeout to call list
2349                 callList.add(event, date, number, caller, phone)
2350                 debug("[FritzCall] notifyCall: added to callList")
2351         else: # this is the "None" case
2352                 debug("[FritzCall] notifyCall: standby and no show")
2353
2354         for fun in userActionList:
2355                 debug("[FritzCall] notifyCall: call user action: %s" % fun.__name__)
2356                 fun(event, date, number, caller, phone)
2357
2358
2359 #===============================================================================
2360 #               We need a separate class for each invocation of reverseLookup to retain
2361 #               the necessary data for the notification
2362 #===============================================================================
2363
2364 countries = { }
2365 reverselookupMtime = 0
2366
2367 class FritzReverseLookupAndNotifier:
2368         def __init__(self, event, number, caller, phone, date, connID):
2369                 '''
2370                 
2371                 Initiate a reverse lookup for the given number in the configured country
2372                 
2373                 @param event: CALL or RING
2374                 @param number: number to be looked up
2375                 @param caller: caller including name and address
2376                 @param phone: Number (and name) of or own phone
2377                 @param date: date of call
2378                 '''
2379                 debug("[FritzReverseLookupAndNotifier] reverse Lookup for %s!" % number)
2380                 self.event = event
2381                 self.number = number
2382                 self.caller = caller
2383                 self.phone = phone
2384                 self.date = date
2385                 self.connID = connID
2386
2387                 if number[0] != "0":
2388                         self.notifyAndReset(number, caller)
2389                         return
2390
2391                 ReverseLookupAndNotifier(number, self.notifyAndReset, "UTF-8", config.plugins.FritzCall.country.value)
2392
2393         def notifyAndReset(self, number, caller):
2394                 '''
2395                 
2396                 this gets called with the result of the reverse lookup
2397                 
2398                 @param number: number
2399                 @param caller: name and address of remote. it comes in with name, address and city separated by commas
2400                 '''
2401                 debug("[FritzReverseLookupAndNotifier] got: " + caller)
2402                 self.number = number
2403 #===============================================================================
2404 #               if not caller and os.path.exists(config.plugins.FritzCall.phonebookLocation.value + "/PhoneBook.csv"):
2405 #                       caller = FritzOutlookCSV.findNumber(number, config.plugins.FritzCall.phonebookLo