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