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