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