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