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