1 # -*- coding: utf-8 -*-
6 $Date: 2012-12-21 16:54:18 +0100 (Fr, 21 Dez 2012) $
7 $Id: plugin.py 734 2012-12-21 15:54:18Z michael $
10 from Screens.Screen import Screen
11 from Screens.MessageBox import MessageBox
12 from Screens.NumericalTextInputHelpDialog import NumericalTextInputHelpDialog
13 from Screens.InputBox import InputBox
14 from Screens import Standby
15 from Screens.HelpMenu import HelpableScreen
17 from enigma import eTimer, eSize, ePoint #@UnresolvedImport # pylint: disable=E0611
18 from enigma import eDVBVolumecontrol, eConsoleAppContainer, eBackgroundFileEraser #@UnresolvedImport # pylint: disable=E0611
19 #BgFileEraser = eBackgroundFileEraser.getInstance()
20 #BgFileEraser.erase("blabla.txt")
22 from Components.ActionMap import ActionMap
23 from Components.Label import Label
24 from Components.Button import Button
25 from Components.Pixmap import Pixmap
26 from Components.Sources.List import List
27 from Components.config import config, ConfigSubsection, ConfigSelection, ConfigEnableDisable, getConfigListEntry, ConfigText, ConfigInteger
28 from Components.ConfigList import ConfigListScreen
29 from Components.Harddisk import harddiskmanager
31 from Components.config import ConfigPassword
33 ConfigPassword = ConfigText
35 from Plugins.Plugin import PluginDescriptor
36 from Tools import Notifications
37 from Tools.NumericalTextInput import NumericalTextInput
38 from Tools.Directories import resolveFilename, SCOPE_PLUGINS, SCOPE_SKIN_IMAGE, SCOPE_CONFIG, SCOPE_MEDIA
39 from Tools.LoadPixmap import LoadPixmap
40 from GlobalActions import globalActionMap # for muting
42 from twisted.internet import reactor #@UnresolvedImport
43 from twisted.internet.protocol import ReconnectingClientFactory #@UnresolvedImport
44 from twisted.protocols.basic import LineReceiver #@UnresolvedImport
46 import re, time, os, traceback
48 from nrzuname import ReverseLookupAndNotifier
49 import FritzOutlookCSV, FritzLDIF
50 from . import _, initDebug, debug #@UnresolvedImport # pylint: disable=E0611,F0401
52 from enigma import getDesktop
53 DESKTOP_WIDTH = getDesktop(0).size().width()
54 DESKTOP_HEIGHT = getDesktop(0).size().height()
58 # It returns the first value, if HD (1280x720),
59 # the second if SD (720x576),
60 # else something scaled accordingly
61 # if one of the parameters is -1, scale proportionally
68 return scale(y2, y1, 1280, 720, DESKTOP_WIDTH)
74 return scale(y2, y1, 720, 576, DESKTOP_HEIGHT)
75 def scale(y2, y1, x2, x1, x):
76 return (y2 - y1) * (x - x1) / (x2 - x1) + y1
78 my_global_session = None
80 config.plugins.FritzCall = ConfigSubsection()
81 config.plugins.FritzCall.fwVersion = ConfigSelection(choices=[("none", _("not configured")), ("old", _("before 05.27")), ("05.27", "05.27,05.28"), "05.50"])
82 config.plugins.FritzCall.debug = ConfigEnableDisable(default=False)
83 #config.plugins.FritzCall.muteOnCall = ConfigSelection(choices=[(None, _("no")), ("ring", _("on ring")), ("connect", _("on connect"))])
84 #config.plugins.FritzCall.muteOnCall = ConfigSelection(choices=[(None, _("no")), ("ring", _("on ring"))])
85 config.plugins.FritzCall.muteOnCall = ConfigEnableDisable(default=False)
86 config.plugins.FritzCall.hostname = ConfigText(default="fritz.box", fixed_size=False)
87 config.plugins.FritzCall.afterStandby = ConfigSelection(choices=[("none", _("show nothing")), ("inList", _("show as list")), ("each", _("show each call"))])
88 config.plugins.FritzCall.filter = ConfigEnableDisable(default=False)
89 config.plugins.FritzCall.filtermsn = ConfigText(default="", fixed_size=False)
90 config.plugins.FritzCall.filtermsn.setUseableChars('0123456789,')
91 config.plugins.FritzCall.filterCallList = ConfigEnableDisable(default=True)
92 config.plugins.FritzCall.showOutgoing = ConfigEnableDisable(default=False)
93 config.plugins.FritzCall.timeout = ConfigInteger(default=15, limits=(0, 60))
94 config.plugins.FritzCall.lookup = ConfigEnableDisable(default=False)
95 config.plugins.FritzCall.internal = ConfigEnableDisable(default=False)
96 config.plugins.FritzCall.fritzphonebook = ConfigEnableDisable(default=False)
97 config.plugins.FritzCall.phonebook = ConfigEnableDisable(default=False)
98 config.plugins.FritzCall.addcallers = ConfigEnableDisable(default=False)
99 config.plugins.FritzCall.enable = ConfigEnableDisable(default=False)
100 config.plugins.FritzCall.username = ConfigText(default='BoxAdmin', fixed_size=False)
101 config.plugins.FritzCall.password = ConfigPassword(default="", fixed_size=False)
102 config.plugins.FritzCall.extension = ConfigText(default='1', fixed_size=False)
103 config.plugins.FritzCall.extension.setUseableChars('0123456789')
104 config.plugins.FritzCall.showType = ConfigEnableDisable(default=True)
105 config.plugins.FritzCall.showShortcut = ConfigEnableDisable(default=False)
106 config.plugins.FritzCall.showVanity = ConfigEnableDisable(default=False)
107 config.plugins.FritzCall.prefix = ConfigText(default="", fixed_size=False)
108 config.plugins.FritzCall.prefix.setUseableChars('0123456789')
109 config.plugins.FritzCall.connectionVerbose = ConfigEnableDisable(default=True)
110 config.plugins.FritzCall.ignoreUnknown = ConfigEnableDisable(default=False)
111 config.plugins.FritzCall.reloadPhonebookTime = ConfigInteger(default=8, limits=(0, 99))
114 def getMountedDevs():
115 def handleMountpoint(loc):
116 # debug("[FritzCall] handleMountpoint: %s" %repr(loc))
120 #=======================================================================
121 # if os.path.exists(os.path.join(mp, "PhoneBook.txt")):
122 # if os.access(os.path.join(mp, "PhoneBook.txt"), os.W_OK):
128 # desc = loc[1] + desc
129 #=======================================================================
131 return (mp, desc + " (" + mp + ")")
133 mountedDevs = [(resolveFilename(SCOPE_CONFIG), _("Flash")),
134 (resolveFilename(SCOPE_MEDIA, "cf"), _("Compact Flash")),
135 (resolveFilename(SCOPE_MEDIA, "usb"), _("USB Device"))]
136 mountedDevs += map(lambda p: (p.mountpoint, (_(p.description) if p.description else "")), harddiskmanager.getMountedPartitions(True))
137 mediaDir = resolveFilename(SCOPE_MEDIA)
138 for p in os.listdir(mediaDir):
139 if os.path.join(mediaDir, p) not in [path[0] for path in mountedDevs]:
140 mountedDevs.append((os.path.join(mediaDir, p), _("Media directory")))
141 debug("[FritzCall] getMountedDevs1: %s" %repr(mountedDevs))
142 mountedDevs = filter(lambda path: os.path.isdir(path[0]) and os.access(path[0], os.W_OK|os.X_OK), mountedDevs)
143 # put this after the write/executable check, that is far too slow...
144 netDir = resolveFilename(SCOPE_MEDIA, "net")
145 if os.path.isdir(netDir):
146 mountedDevs += map(lambda p: (os.path.join(netDir, p), _("Network mount")), os.listdir(netDir))
147 mountedDevs = map(handleMountpoint, mountedDevs)
149 config.plugins.FritzCall.phonebookLocation = ConfigSelection(choices=getMountedDevs())
152 ("0049", _("Germany")),
153 ("0031", _("The Netherlands")),
154 ("0033", _("France")),
155 ("0039", _("Italy")),
156 ("0041", _("Switzerland")),
157 ("0043", _("Austria"))
159 config.plugins.FritzCall.country = ConfigSelection(choices=countryCodes)
163 FBF_MISSED_CALLS = "2"
165 fbfCallsChoices = {FBF_ALL_CALLS: _("All calls"),
166 FBF_IN_CALLS: _("Incoming calls"),
167 FBF_MISSED_CALLS: _("Missed calls"),
168 FBF_OUT_CALLS: _("Outgoing calls")
170 config.plugins.FritzCall.fbfCalls = ConfigSelection(choices=fbfCallsChoices)
172 config.plugins.FritzCall.name = ConfigText(default="", fixed_size=False)
173 config.plugins.FritzCall.number = ConfigText(default="", fixed_size=False)
174 config.plugins.FritzCall.number.setUseableChars('0123456789')
182 avonFileName = resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/avon.dat")
183 if os.path.exists(avonFileName):
184 for line in open(avonFileName):
185 line = line.decode("iso-8859-1").encode('utf-8')
188 parts = line.split(':')
190 avon[parts[0].replace('-','').replace('*','').replace('/','')] = parts[1]
192 def resolveNumberWithAvon(number, countrycode):
193 if not number or number[0] != '0':
196 countrycode = countrycode.replace('00','+')
197 if number[:2] == '00':
198 normNumber = '+' + number[2:]
199 elif number[:1] == '0':
200 normNumber = countrycode + number[1:]
201 else: # this should can not happen, but safety first
204 # debug('normNumer: ' + normNumber)
205 for i in reversed(range(min(10, len(number)))):
206 if avon.has_key(normNumber[:i]):
207 return '[' + avon[normNumber[:i]].strip() + ']'
210 def handleReverseLookupResult(name):
211 found = re.match("NA: ([^;]*);VN: ([^;]*);STR: ([^;]*);HNR: ([^;]*);PLZ: ([^;]*);ORT: ([^;]*)", name)
213 ( name, firstname, street, streetno, zipcode, city ) = (found.group(1),
221 name += ' ' + firstname
222 if street or streetno or zipcode or city:
227 name += ' ' + streetno
228 if (street or streetno) and (zipcode or city):
231 name += zipcode + ' ' + city
238 from xml.dom.minidom import parse
241 callbycallFileName = resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/callbycall_world.xml")
242 if os.path.exists(callbycallFileName):
243 dom = parse(callbycallFileName)
244 for top in dom.getElementsByTagName("callbycalls"):
245 for cbc in top.getElementsByTagName("country"):
246 code = cbc.getAttribute("code").replace("+","00")
247 cbcInfos[code] = cbc.getElementsByTagName("callbycall")
249 debug("[FritzCall] initCbC: callbycallFileName does not exist?!?!")
251 def stripCbCPrefix(number, countrycode):
252 if number and number[:2] != "00" and cbcInfos.has_key(countrycode):
253 for cbc in cbcInfos[countrycode]:
254 if len(cbc.getElementsByTagName("length"))<1 or len(cbc.getElementsByTagName("prefix"))<1:
255 debug("[FritzCall] stripCbCPrefix: entries for " + countrycode + " %s invalid")
257 length = int(cbc.getElementsByTagName("length")[0].childNodes[0].data)
258 prefix = cbc.getElementsByTagName("prefix")[0].childNodes[0].data
259 # if re.match('^'+prefix, number):
260 if number[:len(prefix)] == prefix:
261 return number[length:]
266 class FritzAbout(Screen):
268 def __init__(self, session):
269 textFieldWidth = scaleV(350, 250)
270 width = 5 + 150 + 20 + textFieldWidth + 5 + 175 + 5
271 height = 5 + 175 + 5 + 25 + 5
273 <screen name="FritzAbout" position="center,center" size="%d,%d" title="About FritzCall" >
274 <widget name="text" position="175,%d" size="%d,%d" font="Regular;%d" />
275 <ePixmap position="5,37" size="150,110" pixmap="%s" transparent="1" alphatest="blend" />
276 <ePixmap position="%d,5" size="175,175" pixmap="%s" transparent="1" alphatest="blend" />
277 <widget name="url" position="20,185" size="%d,25" font="Regular;%d" />
279 width, height, # size
280 (height-scaleV(150,130)) / 2, # text vertical position
282 scaleV(150,130), # text height
283 scaleV(24,21), # text font size
284 resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/images/fritz.png"), # 150x110
285 5 + 150 + 5 + textFieldWidth + 5, # qr code horizontal offset
286 resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/images/website.png"), # 175x175
287 width-40, # url width
288 scaleV(24,21) # url font size
290 Screen.__init__(self, session)
291 self["aboutActions"] = ActionMap(["OkCancelActions"],
296 self["text"] = Label(
297 "FritzCall Plugin" + "\n\n" +
298 "$Author: michael $"[1:-2] + "\n" +
299 "$Revision: 734 $"[1:-2] + "\n" +
300 "$Date: 2012-12-21 16:54:18 +0100 (Fr, 21 Dez 2012) $"[1:23] + "\n"
302 self["url"] = Label("http://wiki.blue-panel.com/index.php/FritzCall")
303 self.onLayoutFinish.append(self.setWindowTitle)
305 def setWindowTitle(self):
306 # TRANSLATORS: this is a window title.
307 self.setTitle(_("About FritzCall"))
314 from FritzCallFBF import FBF_dectActive, FBF_faxActive, FBF_rufumlActive, FBF_tamActive
316 class FritzMenu(Screen, HelpableScreen):
317 def __init__(self, session):
318 fontSize = scaleV(24, 21) # indeed this is font size +2
319 noButtons = 2 # reset, wlan
321 if not fritzbox or not fritzbox.info:
324 if fritzbox.info[FBF_tamActive]:
325 noButtons += 1 # toggle mailboxes
326 width = max(DESKTOP_WIDTH - scaleH(500, 250), noButtons*140+(noButtons+1)*10)
327 # boxInfo 2 lines, gap, internet 2 lines, gap, dsl/wlan each 1 line, gap, buttons
328 height = 5 + 2*fontSize + 10 + 2*fontSize + 10 + 2*fontSize + 10 + 40 + 5
329 if fritzbox.info[FBF_tamActive] is not None:
331 if fritzbox.info[FBF_dectActive] is not None:
333 if fritzbox.info[FBF_faxActive] is not None:
335 if fritzbox.info[FBF_rufumlActive] is not None:
337 buttonsGap = (width-noButtons*140)/(noButtons+1)
338 buttonsVPos = height-40-5
341 if fritzbox.info[FBF_tamActive] is not None:
343 <widget name="FBFMailbox" position="%d,%d" size="%d,%d" font="Regular;%d" />
344 <widget name="mailbox_inactive" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
345 <widget name="mailbox_active" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
346 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
347 <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" />
349 40, 5+2*fontSize+10+varLinePos*fontSize+10, # position mailbox
350 width-40-20, fontSize, # size mailbox
352 "skin_default/buttons/button_green_off.png",
353 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button mailbox
354 "skin_default/buttons/button_green.png",
355 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button mailbox
356 noButtons*buttonsGap+(noButtons-1)*140, buttonsVPos,
357 noButtons*buttonsGap+(noButtons-1)*140, buttonsVPos,
363 if fritzbox.info[FBF_dectActive] is not None:
365 <widget name="FBFDect" position="%d,%d" size="%d,%d" font="Regular;%d" />
366 <widget name="dect_inactive" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
367 <widget name="dect_active" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
369 40, 5+2*fontSize+10+varLinePos*fontSize+10, # position dect
370 width-40-20, fontSize, # size dect
372 "skin_default/buttons/button_green_off.png",
373 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button dect
374 "skin_default/buttons/button_green.png",
375 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button dect
381 if fritzbox.info[FBF_faxActive] is not None:
383 <widget name="FBFFax" position="%d,%d" size="%d,%d" font="Regular;%d" />
384 <widget name="fax_inactive" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
385 <widget name="fax_active" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
387 40, 5+2*fontSize+10+varLinePos*fontSize+10, # position dect
388 width-40-20, fontSize, # size dect
390 "skin_default/buttons/button_green_off.png",
391 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button dect
392 "skin_default/buttons/button_green.png",
393 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button dect
399 if fritzbox.info[FBF_rufumlActive] is not None:
401 <widget name="FBFRufuml" position="%d,%d" size="%d,%d" font="Regular;%d" />
402 <widget name="rufuml_inactive" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
403 <widget name="rufuml_active" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
405 40, 5+2*fontSize+10+varLinePos*fontSize+10, # position dect
406 width-40-20, fontSize, # size dect
408 "skin_default/buttons/button_green_off.png",
409 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button dect
410 "skin_default/buttons/button_green.png",
411 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button dect
418 <screen name="FritzMenu" position="center,center" size="%d,%d" title="FRITZ!Box Fon Status" >
419 <widget name="FBFInfo" position="%d,%d" size="%d,%d" font="Regular;%d" />
420 <widget name="FBFInternet" position="%d,%d" size="%d,%d" font="Regular;%d" />
421 <widget name="internet_inactive" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
422 <widget name="internet_active" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
423 <widget name="FBFDsl" position="%d,%d" size="%d,%d" font="Regular;%d" />
424 <widget name="dsl_inactive" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
425 <widget name="dsl_active" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
426 <widget name="FBFWlan" position="%d,%d" size="%d,%d" font="Regular;%d" />
427 <widget name="wlan_inactive" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
428 <widget name="wlan_active" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
433 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
434 <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" />
435 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
436 <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" />
438 width, height, # size
439 40, 5, # position info
440 width-2*40, 2*fontSize, # size info
442 40, 5+2*fontSize+10, # position internet
443 width-40, 2*fontSize, # size internet
445 "skin_default/buttons/button_green_off.png",
446 20, 5+2*fontSize+10+(fontSize-16)/2, # position button internet
447 "skin_default/buttons/button_green.png",
448 20, 5+2*fontSize+10+(fontSize-16)/2, # position button internet
449 40, 5+2*fontSize+10+2*fontSize+10, # position dsl
450 width-40-20, fontSize, # size dsl
452 "skin_default/buttons/button_green_off.png",
453 20, 5+2*fontSize+10+2*fontSize+10+(fontSize-16)/2, # position button dsl
454 "skin_default/buttons/button_green.png",
455 20, 5+2*fontSize+10+2*fontSize+10+(fontSize-16)/2, # position button dsl
456 40, 5+2*fontSize+10+3*fontSize+10, # position wlan
457 width-40-20, fontSize, # size wlan
459 "skin_default/buttons/button_green_off.png",
460 20, 5+2*fontSize+10+3*fontSize+10+(fontSize-16)/2, # position button wlan
461 "skin_default/buttons/button_green.png",
462 20, 5+2*fontSize+10+3*fontSize+10+(fontSize-16)/2, # position button wlan
467 buttonsGap, buttonsVPos, "skin_default/buttons/red.png", buttonsGap, buttonsVPos,
468 buttonsGap+140+buttonsGap, buttonsVPos, "skin_default/buttons/green.png", buttonsGap+140+buttonsGap, buttonsVPos,
471 Screen.__init__(self, session)
472 HelpableScreen.__init__(self)
473 # TRANSLATORS: keep it short, this is a button
474 self["key_red"] = Button(_("Reset"))
475 # TRANSLATORS: keep it short, this is a button
476 self["key_green"] = Button(_("Toggle WLAN"))
477 self._mailboxActive = False
478 if fritzbox.info[FBF_tamActive] is not None:
479 # TRANSLATORS: keep it short, this is a button
480 self["key_yellow"] = Button(_("Toggle Mailbox"))
481 self["menuActions"] = ActionMap(["OkCancelActions", "ColorActions", "NumberActions", "EPGSelectActions"],
483 "cancel": self._exit,
486 "green": self._toggleWlan,
487 "yellow": (lambda: self._toggleMailbox(-1)),
488 "0": (lambda: self._toggleMailbox(0)),
489 "1": (lambda: self._toggleMailbox(1)),
490 "2": (lambda: self._toggleMailbox(2)),
491 "3": (lambda: self._toggleMailbox(3)),
492 "4": (lambda: self._toggleMailbox(4)),
493 "info": self._getInfo,
495 # TRANSLATORS: keep it short, this is a help text
496 self.helpList.append((self["menuActions"], "ColorActions", [("yellow", _("Toggle all mailboxes"))]))
497 # TRANSLATORS: keep it short, this is a help text
498 self.helpList.append((self["menuActions"], "NumberActions", [("0", _("Toggle 1. mailbox"))]))
499 # TRANSLATORS: keep it short, this is a help text
500 self.helpList.append((self["menuActions"], "NumberActions", [("1", _("Toggle 2. mailbox"))]))
501 # TRANSLATORS: keep it short, this is a help text
502 self.helpList.append((self["menuActions"], "NumberActions", [("2", _("Toggle 3. mailbox"))]))
503 # TRANSLATORS: keep it short, this is a help text
504 self.helpList.append((self["menuActions"], "NumberActions", [("3", _("Toggle 4. mailbox"))]))
505 # TRANSLATORS: keep it short, this is a help text
506 self.helpList.append((self["menuActions"], "NumberActions", [("4", _("Toggle 5. mailbox"))]))
507 self["FBFMailbox"] = Label(_('Mailbox'))
508 self["mailbox_inactive"] = Pixmap()
509 self["mailbox_active"] = Pixmap()
510 self["mailbox_active"].hide()
512 self["menuActions"] = ActionMap(["OkCancelActions", "ColorActions", "EPGSelectActions"],
514 "cancel": self._exit,
516 "green": self._toggleWlan,
518 "info": self._getInfo,
521 # TRANSLATORS: keep it short, this is a help text
522 self.helpList.append((self["menuActions"], "OkCancelActions", [("cancel", _("Quit"))]))
523 # TRANSLATORS: keep it short, this is a help text
524 self.helpList.append((self["menuActions"], "OkCancelActions", [("ok", _("Quit"))]))
525 # TRANSLATORS: keep it short, this is a help text
526 self.helpList.append((self["menuActions"], "ColorActions", [("green", _("Toggle WLAN"))]))
527 # TRANSLATORS: keep it short, this is a help text
528 self.helpList.append((self["menuActions"], "ColorActions", [("red", _("Reset"))]))
529 # TRANSLATORS: keep it short, this is a help text
530 self.helpList.append((self["menuActions"], "EPGSelectActions", [("info", _("Refresh status"))]))
532 self["FBFInfo"] = Label(_('Getting status from FRITZ!Box Fon...'))
534 self["FBFInternet"] = Label('Internet')
535 self["internet_inactive"] = Pixmap()
536 self["internet_active"] = Pixmap()
537 self["internet_active"].hide()
539 self["FBFDsl"] = Label('DSL')
540 self["dsl_inactive"] = Pixmap()
541 self["dsl_inactive"].hide()
542 self["dsl_active"] = Pixmap()
543 self["dsl_active"].hide()
545 self["FBFWlan"] = Label('WLAN ')
546 self["wlan_inactive"] = Pixmap()
547 self["wlan_inactive"].hide()
548 self["wlan_active"] = Pixmap()
549 self["wlan_active"].hide()
550 self._wlanActive = False
552 if fritzbox.info[FBF_dectActive] is not None:
553 self["FBFDect"] = Label('DECT')
554 self["dect_inactive"] = Pixmap()
555 self["dect_active"] = Pixmap()
556 self["dect_active"].hide()
558 if fritzbox.info[FBF_faxActive] is not None:
559 self["FBFFax"] = Label('Fax')
560 self["fax_inactive"] = Pixmap()
561 self["fax_active"] = Pixmap()
562 self["fax_active"].hide()
564 if fritzbox.info[FBF_rufumlActive] is not None:
565 self["FBFRufuml"] = Label(_('Call redirection'))
566 self["rufuml_inactive"] = Pixmap()
567 self["rufuml_active"] = Pixmap()
568 self["rufuml_active"].hide()
570 self._timer = eTimer()
571 self._timer.callback.append(self._getInfo)
572 self.onShown.append(lambda: self._timer.start(5000))
573 self.onHide.append(self._timer.stop)
575 self.onLayoutFinish.append(self.setWindowTitle)
577 def setWindowTitle(self):
578 # TRANSLATORS: this is a window title.
579 self.setTitle(_("FRITZ!Box Fon Status"))
583 fritzbox.getInfo(self._fillMenu)
585 def _fillMenu(self, status):
586 (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive) = status
588 self._wlanActive = (wlanState[0] == '1')
589 self._mailboxActive = False
591 if not self.has_key("FBFInfo"): # screen is closed already
595 self["FBFInfo"].setText(boxInfo.replace(', ', '\n'))
597 self["FBFInfo"].setText('BoxInfo ' + _('Status not available'))
601 self["FBFInternet"].setText('Internet ' + _('IP Address:') + ' ' + ipAddress + '\n' + _('Connected since') + ' ' + upTime)
603 self["FBFInternet"].setText('Internet ' + _('IP Address:') + ' ' + ipAddress)
604 self["internet_inactive"].hide()
605 self["internet_active"].show()
607 self["internet_active"].hide()
608 self["internet_inactive"].show()
611 if dslState[0] == '5':
612 self["dsl_inactive"].hide()
613 self["dsl_active"].show()
615 self["FBFDsl"].setText('DSL ' + dslState[1])
617 self["dsl_active"].hide()
618 self["dsl_inactive"].show()
620 self["FBFDsl"].setText('DSL ' + _('Status not available'))
621 self["dsl_active"].hide()
622 self["dsl_inactive"].hide()
625 if wlanState[0 ] == '1':
626 self["wlan_inactive"].hide()
627 self["wlan_active"].show()
629 if wlanState[1] == '0':
630 message += ' ' + _('not encrypted')
632 message += ' ' + _('encrypted')
634 if wlanState[2] == '0':
635 message = message + ', ' + _('no device active')
636 elif wlanState[2] == '1':
637 message = message + ', ' + _('one device active')
639 message = message + ', ' + wlanState[2] + ' ' + _('devices active')
640 self["FBFWlan"].setText(message)
642 self["wlan_active"].hide()
643 self["wlan_inactive"].show()
644 self["FBFWlan"].setText('WLAN')
646 self["FBFWlan"].setText('WLAN ' + _('Status not available'))
647 self["wlan_active"].hide()
648 self["wlan_inactive"].hide()
650 if fritzbox.info[FBF_tamActive]:
651 if not tamActive or tamActive[0] == 0:
652 self._mailboxActive = False
653 self["mailbox_active"].hide()
654 self["mailbox_inactive"].show()
655 self["FBFMailbox"].setText(_('No mailbox active'))
657 self._mailboxActive = True
659 for i in range(min(len(tamActive)-1, 5)):
661 message = message + str(i) + ','
663 message = '(' + message[:-1] + ')'
664 self["mailbox_inactive"].hide()
665 self["mailbox_active"].show()
666 if tamActive[0] == 1:
667 self["FBFMailbox"].setText(_('One mailbox active') + ' ' + message)
669 self["FBFMailbox"].setText(str(tamActive[0]) + ' ' + _('mailboxes active') + ' ' + message)
671 if fritzbox.info[FBF_dectActive] and dectActive and self.has_key("dect_inactive"):
672 self["dect_inactive"].hide()
673 self["dect_active"].show()
675 self["FBFDect"].setText(_('No DECT phone registered'))
678 self["FBFDect"].setText(_('One DECT phone registered'))
680 self["FBFDect"].setText(str(dectActive) + ' ' + _('DECT phones registered'))
682 if fritzbox.info[FBF_faxActive] and faxActive:
683 self["fax_inactive"].hide()
684 self["fax_active"].show()
685 self["FBFFax"].setText(_('Software fax active'))
687 if fritzbox.info[FBF_rufumlActive] is not None and rufumlActive is not None:
688 if rufumlActive == 0:
689 self["rufuml_active"].hide()
690 self["rufuml_inactive"].show()
691 self["FBFRufuml"].setText(_('No call redirection active'))
693 self["rufuml_inactive"].hide()
694 self["rufuml_active"].show()
695 if rufumlActive == 1:
696 self["FBFRufuml"].setText(_('One call redirection active'))
698 self["FBFRufuml"].setText(str(rufumlActive) + ' ' + _('call redirections active'))
701 debug("[FritzCallFBF] _fillMenu: " + traceback.format_exc())
703 def _toggleWlan(self):
705 debug("[FritzMenu] toggleWlan off")
706 fritzbox.changeWLAN('0')
708 debug("[FritzMenu] toggleWlan off")
709 fritzbox.changeWLAN('1')
711 def _toggleMailbox(self, which):
712 debug("[FritzMenu] toggleMailbox")
713 if fritzbox.info[FBF_tamActive]:
714 debug("[FritzMenu] toggleMailbox off")
715 fritzbox.changeMailbox(which)
726 class FritzDisplayCalls(Screen, HelpableScreen):
728 def __init__(self, session, text=""): #@UnusedVariable # pylint: disable=W0613
729 self.width = DESKTOP_WIDTH * scaleH(75, 85)/100
730 self.height = DESKTOP_HEIGHT * 0.75
731 dateFieldWidth = scaleH(180, 105)
733 lengthFieldWidth = scaleH(55, 45)
734 scrollbarWidth = scaleH(35, 35)
735 entriesWidth = self.width -scaleH(40, 5) -5
736 hereFieldWidth = entriesWidth -dirFieldWidth -5 -dateFieldWidth -5 -lengthFieldWidth -scrollbarWidth
737 fieldWidth = entriesWidth -dirFieldWidth -5 -5 -scrollbarWidth
738 fontSize = scaleV(22, 20)
739 itemHeight = 2*fontSize+5
740 entriesHeight = self.height -scaleV(15, 10) -5 -fontSize -5 -5 -5 -40 -5
741 buttonGap = (self.width -4*140)/5
742 buttonV = self.height -40
743 debug("[FritzDisplayCalls] width: " + str(self.width))
745 <screen name="FritzDisplayCalls" position="center,center" size="%d,%d" title="Phone calls" >
746 <eLabel position="0,0" size="%d,2" backgroundColor="#aaaaaa" />
747 <widget name="statusbar" position="%d,%d" size="%d,%d" font="Regular;%d" backgroundColor="#aaaaaa" transparent="1" />
748 <eLabel position="0,%d" size="%d,2" backgroundColor="#aaaaaa" />
749 <widget source="entries" render="Listbox" position="%d,%d" size="%d,%d" scrollbarMode="showOnDemand" transparent="1">
750 <convert type="TemplatedMultiContent">
752 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
753 MultiContentEntryPixmapAlphaTest(pos = (%d,%d), size = (%d,%d), png = 2), # index 1 i direction pixmap
754 MultiContentEntryText(pos = (%d,%d), size = (%d,%d), font=1, flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER, text = 3), # index 2 is remote name/number
755 MultiContentEntryText(pos = (%d,%d), size = (%d,%d), font=0, flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER, text = 4), # index 3 is length of call
756 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
758 "fonts": [gFont("Regular", %d), gFont("Regular", %d)],
763 <eLabel position="0,%d" size="%d,2" backgroundColor="#aaaaaa" />
764 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
765 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
766 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
767 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
768 <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" />
769 <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" />
770 <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" />
771 <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" />
773 # scaleH(90, 75), scaleV(100, 78), # position
774 self.width, self.height, # size
775 self.width, # eLabel width
776 scaleH(40, 5), scaleV(10, 5), # statusbar position
777 self.width, fontSize+5, # statusbar size
778 scaleV(21, 21), # statusbar font size
779 scaleV(10, 5)+5+fontSize+5, # eLabel position vertical
780 self.width, # eLabel width
781 scaleH(40, 5), scaleV(10, 5)+5+fontSize+5+5, # entries position
782 entriesWidth, entriesHeight, # entries size
783 5+dirFieldWidth+5, fontSize+5, dateFieldWidth, fontSize, # date pos/size
784 5, (itemHeight-dirFieldWidth)/2, dirFieldWidth, dirFieldWidth, # dir pos/size
785 5+dirFieldWidth+5, 5, fieldWidth, fontSize, # caller pos/size
786 2+dirFieldWidth+2+dateFieldWidth+5, fontSize+5, lengthFieldWidth, fontSize, # length pos/size
787 2+dirFieldWidth+2+dateFieldWidth+5+lengthFieldWidth+5, fontSize+5, hereFieldWidth, fontSize, # my number pos/size
788 fontSize-4, fontSize, # fontsize
789 itemHeight, # itemHeight
790 buttonV-5, # eLabel position vertical
791 self.width, # eLabel width
792 buttonGap, buttonV, "skin_default/buttons/red.png", # widget red
793 2*buttonGap+140, buttonV, "skin_default/buttons/green.png", # widget green
794 3*buttonGap+2*140, buttonV, "skin_default/buttons/yellow.png", # widget yellow
795 4*buttonGap+3*140, buttonV, "skin_default/buttons/blue.png", # widget blue
796 buttonGap, buttonV, scaleV(22, 21), # widget red
797 2*buttonGap+140, buttonV, scaleV(22, 21), # widget green
798 3*buttonGap+2*140, buttonV, scaleV(22, 21), # widget yellow
799 4*buttonGap+3*140, buttonV, scaleV(22, 21), # widget blue
801 # debug("[FritzDisplayCalls] skin: " + self.skin)
802 Screen.__init__(self, session)
803 HelpableScreen.__init__(self)
805 # TRANSLATORS: keep it short, this is a button
806 self["key_yellow"] = Button(_("All"))
807 # TRANSLATORS: keep it short, this is a button
808 self["key_red"] = Button(_("Missed"))
809 # TRANSLATORS: keep it short, this is a button
810 self["key_blue"] = Button(_("Incoming"))
811 # TRANSLATORS: keep it short, this is a button
812 self["key_green"] = Button(_("Outgoing"))
814 self["setupActions"] = ActionMap(["OkCancelActions", "ColorActions"],
816 "yellow": (lambda: self.display(FBF_ALL_CALLS)),
817 "red": (lambda: self.display(FBF_MISSED_CALLS)),
818 "blue": (lambda: self.display(FBF_IN_CALLS)),
819 "green": (lambda: self.display(FBF_OUT_CALLS)),
821 "ok": self.showEntry, }, - 2)
823 # TRANSLATORS: keep it short, this is a help text
824 self.helpList.append((self["setupActions"], "OkCancelActions", [("ok", _("Show details of entry"))]))
825 # TRANSLATORS: keep it short, this is a help text
826 self.helpList.append((self["setupActions"], "OkCancelActions", [("cancel", _("Quit"))]))
827 # TRANSLATORS: keep it short, this is a help text
828 self.helpList.append((self["setupActions"], "ColorActions", [("yellow", _("Display all calls"))]))
829 # TRANSLATORS: keep it short, this is a help text
830 self.helpList.append((self["setupActions"], "ColorActions", [("red", _("Display missed calls"))]))
831 # TRANSLATORS: keep it short, this is a help text
832 self.helpList.append((self["setupActions"], "ColorActions", [("blue", _("Display incoming calls"))]))
833 # TRANSLATORS: keep it short, this is a help text
834 self.helpList.append((self["setupActions"], "ColorActions", [("green", _("Display outgoing calls"))]))
836 self["statusbar"] = Label(_("Getting calls from FRITZ!Box..."))
838 self["entries"] = List(self.list)
839 #=======================================================================
840 # fontSize = scaleV(22, 18)
841 # fontHeight = scaleV(24, 20)
842 # self["entries"].l.setFont(0, gFont("Regular", fontSize))
843 # self["entries"].l.setItemHeight(fontHeight)
844 #=======================================================================
845 debug("[FritzDisplayCalls] init: '''%s'''" % config.plugins.FritzCall.fbfCalls.value)
846 self.display(config.plugins.FritzCall.fbfCalls.value)
847 self.onLayoutFinish.append(self.setWindowTitle)
849 def setWindowTitle(self):
850 # TRANSLATORS: this is a window title.
851 self.setTitle(_("Phone calls"))
856 def display(self, which=None):
857 debug("[FritzDisplayCalls] display")
859 config.plugins.FritzCall.fbfCalls.value = which
860 config.plugins.FritzCall.fbfCalls.save()
862 which = config.plugins.FritzCall.fbfCalls.value
863 fritzbox.getCalls(self, lambda x: self.gotCalls(x, which), which)
865 def gotCalls(self, listOfCalls, which):
866 debug("[FritzDisplayCalls] gotCalls")
867 self.updateStatus(fbfCallsChoices[which] + " (" + str(len(listOfCalls)) + ")")
869 directout = LoadPixmap(resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/images/callout.png"))
870 directin = LoadPixmap(resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/images/callin.png"))
871 directfailed = LoadPixmap(resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/images/callinfailed.png"))
873 if direct == FBF_OUT_CALLS:
875 elif direct == FBF_IN_CALLS:
878 direct = directfailed
881 # debug("[FritzDisplayCalls] gotCalls: %s" %repr(listOfCalls))
882 self.list = [(number, date[:6] + ' ' + date[9:14], pixDir(direct), remote, length, here) for (number, date, direct, remote, length, here) in listOfCalls]
883 self["entries"].setList(self.list)
884 #=======================================================================
885 # if len(self.list) > 1:
886 # self["entries"].setIndex(1)
887 #=======================================================================
889 def updateStatus(self, text):
890 if self.has_key("statusbar"):
891 self["statusbar"].setText(_("Getting calls from FRITZ!Box...") + ' ' + text)
894 debug("[FritzDisplayCalls] showEntry")
895 cur = self["entries"].getCurrent()
898 debug("[FritzDisplayCalls] showEntry %s" % (cur[0]))
900 fullname = phonebook.search(cur[0])
902 # we have a name for this number
904 self.session.open(FritzOfferAction, self, number, name)
907 self.session.open(FritzOfferAction, self, number, name)
910 fullname = resolveNumberWithAvon(number, config.plugins.FritzCall.country.value)
913 self.session.open(FritzOfferAction, self, number, name)
915 self.session.open(FritzOfferAction, self, number)
917 # we do not even have a number...
918 self.session.open(MessageBox,
920 type=MessageBox.TYPE_INFO)
923 class FritzOfferAction(Screen):
925 def __init__(self, session, parent, number, name=""):
926 # the layout will completely be recalculated in finishLayout
928 <screen name="FritzOfferAction" title="Do what?" >
929 <widget name="text" size="%d,%d" font="Regular;%d" />
930 <widget name="FacePixmap" size="%d,%d" alphatest="on" />
931 <widget name="key_red_p" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
932 <widget name="key_green_p" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
933 <widget name="key_yellow_p" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
934 <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" />
935 <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" />
936 <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" />
938 DESKTOP_WIDTH, DESKTOP_HEIGHT, # set maximum size
939 scaleH(22,21), # text
940 DESKTOP_WIDTH, DESKTOP_HEIGHT, # set maximum size
941 "skin_default/buttons/red.png",
942 "skin_default/buttons/green.png",
943 "skin_default/buttons/yellow.png",
945 debug("[FritzOfferAction] init: %s, %s" %(number, name))
946 Screen.__init__(self, session)
948 # TRANSLATORS: keep it short, this is a button
949 self["key_red"] = Button(_("Lookup"))
950 # TRANSLATORS: keep it short, this is a button
951 self["key_green"] = Button(_("Call"))
952 # TRANSLATORS: keep it short, this is a button
953 self["key_yellow"] = Button(_("Save"))
954 # TRANSLATORS: keep it short, this is a button
955 # self["key_blue"] = Button(_("Search"))
957 self["FritzOfferActions"] = ActionMap(["OkCancelActions", "ColorActions"],
962 "cancel": self._exit,
963 "ok": self._exit, }, - 2)
965 self._session = session
966 if config.plugins.FritzCall.internal.value and len(number) > 3 and number[0] == "0":
968 self._number = number
969 self._name = name.replace("\n", ", ")
970 self["text"] = Label(number + "\n\n" + name.replace(", ", "\n"))
971 self._parent = parent
972 self._lookupState = 0
973 self["key_red_p"] = Pixmap()
974 self["key_green_p"] = Pixmap()
975 self["key_yellow_p"] = Pixmap()
976 self["FacePixmap"] = Pixmap()
977 self.onLayoutFinish.append(self._finishLayout)
978 self.onLayoutFinish.append(self.setWindowTitle)
980 def setWindowTitle(self):
981 # TRANSLATORS: this is a window title.
982 self.setTitle(_("Do what?"))
984 def _finishLayout(self):
985 # pylint: disable=W0142
986 debug("[FritzCall] FritzOfferAction/finishLayout number: %s/%s" % (self._number, self._name))
988 faceFile = findFace(self._number, self._name)
989 picPixmap = LoadPixmap(faceFile)
990 if not picPixmap: # that means most probably, that the picture is not 8 bit...
991 Notifications.AddNotification(MessageBox, _("Found picture\n\n%s\n\nBut did not load. Probably not PNG, 8-bit") %faceFile, type = MessageBox.TYPE_ERROR)
992 picPixmap = LoadPixmap(resolveFilename(SCOPE_SKIN_IMAGE, "skin_default/icons/input_error.png"))
993 picSize = picPixmap.size()
994 self["FacePixmap"].instance.setPixmap(picPixmap)
997 # recalculate window size
998 textSize = self["text"].getSize()
999 textSize = (textSize[0]+20, textSize[1]+20) # don't know, why, but size is too small
1000 debug("[FritzCall] FritzOfferAction/finishLayout textsize: %s/%s" % textSize)
1001 textSize = eSize(*textSize)
1002 width = max(scaleH(620, 545), noButtons*145, picSize.width() + textSize.width() + 30)
1003 height = max(picSize.height()+5, textSize.height()+5, scaleV(-1, 136)) + 5 + 40 + 5
1004 buttonsGap = (width-noButtons*140)/(noButtons+1)
1005 buttonsVPos = height-40-5
1006 wSize = (width, height)
1007 wSize = eSize(*wSize)
1009 # center the smaller vertically
1010 hGap = (width-picSize.width()-textSize.width())/3
1011 picPos = (hGap, (height-50-picSize.height())/2+5)
1012 textPos = (hGap+picSize.width()+hGap, (height-50-textSize.height())/2+5)
1015 self.instance.resize(wSize)
1017 self["text"].instance.resize(textSize)
1019 self["FacePixmap"].instance.resize(picSize)
1021 buttonPos = (buttonsGap, buttonsVPos)
1022 self["key_red_p"].instance.move(ePoint(*buttonPos))
1023 self["key_red"].instance.move(ePoint(*buttonPos))
1024 buttonPos = (buttonsGap+140+buttonsGap, buttonsVPos)
1025 self["key_green_p"].instance.move(ePoint(*buttonPos))
1026 self["key_green"].instance.move(ePoint(*buttonPos))
1027 buttonPos = (buttonsGap+140+buttonsGap+140+buttonsGap, buttonsVPos)
1028 self["key_yellow_p"].instance.move(ePoint(*buttonPos))
1029 self["key_yellow"].instance.move(ePoint(*buttonPos))
1031 self["text"].instance.move(ePoint(*textPos))
1033 self["FacePixmap"].instance.move(ePoint(*picPos))
1035 self.instance.move(ePoint((DESKTOP_WIDTH-wSize.width())/2, (DESKTOP_HEIGHT-wSize.height())/2))
1037 def _setTextAndResize(self, message):
1038 # pylint: disable=W0142
1039 self["text"].instance.resize(eSize(*(DESKTOP_WIDTH, DESKTOP_HEIGHT)))
1040 self["text"].setText(self._number + "\n\n" + message)
1041 self._finishLayout()
1044 phonebookLocation = config.plugins.FritzCall.phonebookLocation.value
1045 if self._lookupState == 0:
1046 self._lookupState = 1
1047 self._setTextAndResize(_("Reverse searching..."))
1048 ReverseLookupAndNotifier(self._number, self._lookedUp, "UTF-8", config.plugins.FritzCall.country.value)
1050 if self._lookupState == 1 and os.path.exists(os.path.join(phonebookLocation, "PhoneBook.csv")):
1051 self._setTextAndResize(_("Searching in Outlook export..."))
1052 self._lookupState = 2
1053 self._lookedUp(self._number, FritzOutlookCSV.findNumber(self._number, os.path.join(phonebookLocation, "PhoneBook.csv"))) #@UndefinedVariable
1056 self._lookupState = 2
1057 if self._lookupState == 2 and os.path.exists(os.path.join(phonebookLocation, "PhoneBook.ldif")):
1058 self._setTextAndResize(_("Searching in LDIF..."))
1059 self._lookupState = 0
1060 FritzLDIF.FindNumber(self._number, open(os.path.join(phonebookLocation, "PhoneBook.ldif")), self._lookedUp)
1063 self._lookupState = 0
1066 def _lookedUp(self, number, name):
1067 name = handleReverseLookupResult(name)
1069 if self._lookupState == 1:
1070 name = _("No result from reverse lookup")
1071 elif self._lookupState == 2:
1072 name = _("No result from Outlook export")
1074 name = _("No result from LDIF")
1076 self._number = number
1077 debug("[FritzOfferAction] lookedUp: " + str(name.replace(", ", "\n")))
1078 self._setTextAndResize(str(name.replace(", ", "\n")))
1082 debug("[FritzOfferAction] call: %s" %self._number)
1083 self.session.open(MessageBox, _("Calling %s") %self._number, type=MessageBox.TYPE_INFO)
1084 fritzbox.dial(self._number)
1086 debug("[FritzOfferAction] call: no fritzbox object?!?!")
1087 self.session.open(MessageBox, _("FRITZ!Box not available for calling"), type=MessageBox.TYPE_INFO)
1090 debug("[FritzOfferAction] add: %s, %s" %(self._number, self._name))
1091 phonebook.FritzDisplayPhonebook(self._session).add(self._parent, self._number, self._name)
1098 class FritzCallPhonebook:
1100 debug("[FritzCallPhonebook] init")
1101 # Beware: strings in phonebook.phonebook have to be in utf-8!
1103 if config.plugins.FritzCall.reloadPhonebookTime.value > 0:
1104 self.loop = eTimer()
1105 self.loop.callback.append(self.startReload)
1106 self.loop.start(config.plugins.FritzCall.reloadPhonebookTime.value*60*60*1000, 1)
1109 def startReload(self):
1111 debug("[FritzCallPhonebook] reloading phonebooks " + time.ctime())
1113 self.loop.start(config.plugins.FritzCall.reloadPhonebookTime.value*60*60*1000, 1)
1116 debug("[FritzCallPhonebook] reload")
1117 # Beware: strings in phonebook.phonebook have to be in utf-8!
1120 if not config.plugins.FritzCall.enable.value:
1123 phonebookFilename = os.path.join(config.plugins.FritzCall.phonebookLocation.value, "PhoneBook.txt")
1124 if config.plugins.FritzCall.phonebook.value and os.path.exists(phonebookFilename):
1125 debug("[FritzCallPhonebook] reload: read " + phonebookFilename)
1126 phonebookTxtCorrupt = False
1128 for line in open(phonebookFilename):
1130 # Beware: strings in phonebook.phonebook have to be in utf-8!
1131 line = line.decode("utf-8")
1132 except UnicodeDecodeError: # this is just for the case, somebody wrote latin1 chars into PhoneBook.txt
1134 line = line.decode("iso-8859-1")
1135 debug("[FritzCallPhonebook] Fallback to ISO-8859-1 in %s" % line)
1136 phonebookTxtCorrupt = True
1137 except UnicodeDecodeError:
1138 debug("[FritzCallPhonebook] Could not parse internal Phonebook Entry %s" % line)
1139 phonebookTxtCorrupt = True
1140 line = line.encode("utf-8")
1141 elems = line.split('#')
1144 debug("[FritzCallPhonebook] reload: Adding '''%s''' with '''%s''' from internal phonebook!" % (elems[1].strip(), elems[0]))
1145 self.phonebook[elems[0]] = elems[1]
1146 except ValueError: # how could this possibly happen?!?!
1147 debug("[FritzCallPhonebook] Could not parse internal Phonebook Entry %s" % line)
1148 phonebookTxtCorrupt = True
1150 debug("[FritzCallPhonebook] Could not parse internal Phonebook Entry %s" % line)
1151 phonebookTxtCorrupt = True
1153 #===============================================================
1154 # found = re.match("^(\d+)#(.*)$", line)
1157 # self.phonebook[found.group(1)] = found.group(2)
1158 # except ValueError: # how could this possibly happen?!?!
1159 # debug("[FritzCallPhonebook] Could not parse internal Phonebook Entry %s" % line)
1160 # phonebookTxtCorrupt = True
1162 # debug("[FritzCallPhonebook] Could not parse internal Phonebook Entry %s" % line)
1163 # phonebookTxtCorrupt = True
1164 #===============================================================
1166 if phonebookTxtCorrupt:
1167 # dump phonebook to PhoneBook.txt
1168 debug("[FritzCallPhonebook] dump Phonebook.txt")
1170 os.rename(phonebookFilename, phonebookFilename + ".bck")
1171 fNew = open(phonebookFilename, 'w')
1172 # Beware: strings in phonebook.phonebook are utf-8!
1173 for (number, name) in self.phonebook.iteritems():
1174 # Beware: strings in PhoneBook.txt have to be in utf-8!
1175 fNew.write(number + "#" + name.encode("utf-8"))
1177 except (IOError, OSError):
1178 debug("[FritzCallPhonebook] error renaming or writing to %s" %phonebookFilename)
1180 if fritzbox and config.plugins.FritzCall.fritzphonebook.value:
1181 fritzbox.loadFritzBoxPhonebook(self)
1183 #===============================================================================
1185 # # read entries from Outlook export
1187 # # not reliable with coding yet
1189 # # import csv exported from Outlook 2007 with csv(Windows)
1190 # csvFilename = "/tmp/PhoneBook.csv"
1191 # if config.plugins.FritzCall.phonebook.value and os.path.exists(csvFilename):
1193 # readOutlookCSV(csvFilename, self.add)
1194 # os.rename(csvFilename, csvFilename + ".done")
1195 # except ImportError:
1196 # debug("[FritzCallPhonebook] CSV import failed" %line)
1197 #===============================================================================
1200 #===============================================================================
1202 # # read entries from LDIF
1204 # # import ldif exported from Thunderbird 2.0.0.19
1205 # ldifFilename = "/tmp/PhoneBook.ldif"
1206 # if config.plugins.FritzCall.phonebook.value and os.path.exists(ldifFilename):
1208 # parser = MyLDIF(open(ldifFilename), self.add)
1210 # os.rename(ldifFilename, ldifFilename + ".done")
1211 # except ImportError:
1212 # debug("[FritzCallPhonebook] LDIF import failed" %line)
1213 #===============================================================================
1215 def search(self, number):
1216 # debug("[FritzCallPhonebook] Searching for %s" %number)
1218 if not self.phonebook or not number:
1221 if config.plugins.FritzCall.prefix.value:
1222 prefix = config.plugins.FritzCall.prefix.value
1223 if number[0] != '0':
1224 number = prefix + number
1225 # debug("[FritzCallPhonebook] search: added prefix: %s" %number)
1226 elif number[:len(prefix)] == prefix and self.phonebook.has_key(number[len(prefix):]):
1227 # debug("[FritzCallPhonebook] search: same prefix")
1228 name = self.phonebook[number[len(prefix):]]
1229 # debug("[FritzCallPhonebook] search: result: %s" %name)
1233 if not name and self.phonebook.has_key(number):
1234 name = self.phonebook[number]
1236 return name.replace(", ", "\n").strip()
1238 def add(self, number, name):
1241 @param number: number of entry
1242 @param name: name of entry, has to be in utf-8
1244 debug("[FritzCallPhonebook] add")
1245 name = name.replace("\n", ", ").replace('#','') # this is just for safety reasons. add should only be called with newlines converted into commas
1247 self.phonebook[number] = name
1248 if number and number != 0:
1249 if config.plugins.FritzCall.phonebook.value:
1251 name = name.strip() + "\n"
1252 string = "%s#%s" % (number, name)
1253 # Beware: strings in PhoneBook.txt have to be in utf-8!
1254 f = open(os.path.join(config.plugins.FritzCall.phonebookLocation.value, "PhoneBook.txt"), 'a')
1257 debug("[FritzCallPhonebook] added %s with %s to Phonebook.txt" % (number, name.strip()))
1263 def remove(self, number):
1264 if number in self.phonebook:
1265 debug("[FritzCallPhonebook] remove entry in phonebook")
1266 del self.phonebook[number]
1267 if config.plugins.FritzCall.phonebook.value:
1269 phonebookFilename = os.path.join(config.plugins.FritzCall.phonebookLocation.value, "PhoneBook.txt")
1270 debug("[FritzCallPhonebook] remove entry in Phonebook.txt")
1271 fOld = open(phonebookFilename, 'r')
1272 fNew = open(phonebookFilename + str(os.getpid()), 'w')
1273 line = fOld.readline()
1275 elems = line.split('#')
1276 if len(elems) == 2 and not elems[0] == number:
1278 line = fOld.readline()
1281 # os.remove(phonebookFilename)
1282 eBackgroundFileEraser.getInstance().erase(phonebookFilename)
1283 os.rename(phonebookFilename + str(os.getpid()), phonebookFilename)
1284 debug("[FritzCallPhonebook] removed %s from Phonebook.txt" % number)
1287 except (IOError, OSError):
1288 debug("[FritzCallPhonebook] error removing %s from %s" %(number, phonebookFilename))
1291 class FritzDisplayPhonebook(Screen, HelpableScreen, NumericalTextInput):
1293 def __init__(self, session):
1294 self.entriesWidth = DESKTOP_WIDTH * scaleH(75, 85)/100
1295 self.height = DESKTOP_HEIGHT * 0.75
1296 numberFieldWidth = scaleH(220, 160)
1297 fieldWidth = self.entriesWidth -5 -numberFieldWidth -10
1298 fontSize = scaleV(22, 18)
1299 fontHeight = scaleV(24, 20)
1300 buttonGap = (self.entriesWidth-4*140)/5
1301 debug("[FritzDisplayPhonebook] width: " + str(self.entriesWidth))
1303 <screen name="FritzDisplayPhonebook" position="center,center" size="%d,%d" title="Phonebook" >
1304 <eLabel position="0,0" size="%d,2" backgroundColor="#aaaaaa" />
1305 <widget source="entries" render="Listbox" position="%d,%d" size="%d,%d" scrollbarMode="showOnDemand" transparent="1">
1306 <convert type="TemplatedMultiContent">
1308 MultiContentEntryText(pos = (%d,%d), size = (%d,%d), font=0, flags = RT_HALIGN_LEFT, text = 1), # index 0 is the name, index 1 is shortname
1309 MultiContentEntryText(pos = (%d,%d), size = (%d,%d), font=0, flags = RT_HALIGN_LEFT, text = 2), # index 2 is number
1311 "fonts": [gFont("Regular", %d)],
1316 <eLabel position="0,%d" size="%d,2" backgroundColor="#aaaaaa" />
1317 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
1318 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
1319 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
1320 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
1321 <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" />
1322 <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" />
1323 <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" />
1324 <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" />
1326 # scaleH(90, 75), scaleV(100, 73), # position
1327 self.entriesWidth, self.height, # size
1328 self.entriesWidth, # eLabel width
1329 scaleH(40, 5), scaleV(20, 5), # entries position
1330 self.entriesWidth-scaleH(40, 5), self.height-scaleV(20, 5)-5-5-40, # entries size
1331 0, 0, fieldWidth, scaleH(24,20), # name pos/size
1332 fieldWidth +5, 0, numberFieldWidth, scaleH(24,20), # dir pos/size
1333 fontSize, # fontsize
1334 fontHeight, # itemHeight
1335 self.height-40-5, # eLabel position vertical
1336 self.entriesWidth, # eLabel width
1337 buttonGap, self.height-40, "skin_default/buttons/red.png", # ePixmap red
1338 2*buttonGap+140, self.height-40, "skin_default/buttons/green.png", # ePixmap green
1339 3*buttonGap+2*140, self.height-40, "skin_default/buttons/yellow.png", # ePixmap yellow
1340 4*buttonGap+3*140, self.height-40, "skin_default/buttons/blue.png", # ePixmap blue
1341 buttonGap, self.height-40, scaleV(22, 21), # widget red
1342 2*buttonGap+140, self.height-40, scaleV(22, 21), # widget green
1343 3*buttonGap+2*140, self.height-40, scaleV(22, 21), # widget yellow
1344 4*buttonGap+3*140, self.height-40, scaleV(22, 21), # widget blue
1347 # debug("[FritzDisplayCalls] skin: " + self.skin)
1348 Screen.__init__(self, session)
1349 NumericalTextInput.__init__(self)
1350 HelpableScreen.__init__(self)
1352 # TRANSLATORS: keep it short, this is a button
1353 self["key_red"] = Button(_("Delete"))
1354 # TRANSLATORS: keep it short, this is a button
1355 self["key_green"] = Button(_("New"))
1356 # TRANSLATORS: keep it short, this is a button
1357 self["key_yellow"] = Button(_("Edit"))
1358 # TRANSLATORS: keep it short, this is a button
1359 self["key_blue"] = Button(_("Search"))
1361 self["setupActions"] = ActionMap(["OkCancelActions", "ColorActions"],
1365 "yellow": self.edit,
1366 "blue": self.search,
1367 "cancel": self.exit,
1368 "ok": self.showEntry, }, - 2)
1370 # TRANSLATORS: keep it short, this is a help text
1371 self.helpList.append((self["setupActions"], "OkCancelActions", [("ok", _("Show details of entry"))]))
1372 # TRANSLATORS: keep it short, this is a help text
1373 self.helpList.append((self["setupActions"], "OkCancelActions", [("cancel", _("Quit"))]))
1374 # TRANSLATORS: keep it short, this is a help text
1375 self.helpList.append((self["setupActions"], "ColorActions", [("red", _("Delete entry"))]))
1376 # TRANSLATORS: keep it short, this is a help text
1377 self.helpList.append((self["setupActions"], "ColorActions", [("green", _("Add entry to phonebook"))]))
1378 # TRANSLATORS: keep it short, this is a help text
1379 self.helpList.append((self["setupActions"], "ColorActions", [("yellow", _("Edit selected entry"))]))
1380 # TRANSLATORS: keep it short, this is a help text
1381 self.helpList.append((self["setupActions"], "ColorActions", [("blue", _("Search (case insensitive)"))]))
1383 self["entries"] = List([])
1384 debug("[FritzCallPhonebook] displayPhonebook init")
1385 self.help_window = None
1387 self.onLayoutFinish.append(self.setWindowTitle)
1390 def setWindowTitle(self):
1391 # TRANSLATORS: this is a window title.
1392 self.setTitle(_("Phonebook"))
1394 def display(self, filterNumber=""):
1395 debug("[FritzCallPhonebook] displayPhonebook/display")
1397 # Beware: strings in phonebook.phonebook are utf-8!
1398 sortlistHelp = sorted((name.lower(), name, number) for (number, name) in phonebook.phonebook.iteritems())
1399 for (low, name, number) in sortlistHelp:
1400 if number == "01234567890":
1403 low = low.decode("utf-8")
1404 except UnicodeDecodeError: # this should definitely not happen
1406 low = low.decode("iso-8859-1")
1407 except UnicodeDecodeError:
1408 debug("[FritzCallPhonebook] displayPhonebook/display: corrupt phonebook entry for %s" % number)
1409 # self.session.open(MessageBox, _("Corrupt phonebook entry\nfor number %s\nDeleting.") %number, type = MessageBox.TYPE_ERROR)
1410 phonebook.remove(number)
1414 filterNumber = filterNumber.lower()
1415 if low.find(filterNumber) == - 1:
1417 name = name.strip().decode("utf-8")
1418 number = number.strip().decode("utf-8")
1419 comma = name.find(',')
1421 shortname = name[:comma]
1424 number = number.encode("utf-8", "replace")
1425 name = name.encode("utf-8", "replace")
1426 shortname = shortname.encode('utf-8', 'replace')
1427 self.sortlist.append((name, shortname, number))
1429 self["entries"].setList(self.sortlist)
1431 def showEntry(self):
1432 cur = self["entries"].getCurrent()
1434 debug("[FritzCallPhonebook] displayPhonebook/showEntry %s" % (repr(cur)))
1437 self.session.open(FritzOfferAction, self, number, name)
1440 cur = self["entries"].getCurrent()
1442 debug("[FritzCallPhonebook] displayPhonebook/delete %s" % (repr(cur)))
1443 self.session.openWithCallback(
1444 self.deleteConfirmed,
1446 _("Do you really want to delete entry for\n\n%(number)s\n\n%(name)s?")
1447 % { 'number':str(cur[2]), 'name':str(cur[0]).replace(", ", "\n") }
1450 self.session.open(MessageBox, _("No entry selected"), MessageBox.TYPE_INFO)
1452 def deleteConfirmed(self, ret):
1453 debug("[FritzCallPhonebook] displayPhonebook/deleteConfirmed")
1455 # if ret: delete number from sortlist, delete number from phonebook.phonebook and write it to disk
1457 cur = self["entries"].getCurrent()
1460 # delete number from sortlist, delete number from phonebook.phonebook and write it to disk
1461 debug("[FritzCallPhonebook] displayPhonebook/deleteConfirmed %s" % (repr(cur)))
1462 phonebook.remove(cur[2])
1465 # self.session.open(MessageBox, _("Not deleted."), MessageBox.TYPE_INFO)
1467 self.session.open(MessageBox, _("No entry selected"), MessageBox.TYPE_INFO)
1469 def add(self, parent=None, number="", name=""):
1470 class AddScreen(Screen, ConfigListScreen):
1471 '''ConfiglistScreen with two ConfigTexts for Name and Number'''
1473 def __init__(self, session, parent, number="", name=""):
1475 # setup screen with two ConfigText and OK and ABORT button
1478 width = max(scaleH(-1, 570), noButtons*140)
1479 height = scaleV(-1, 100) # = 5 + 126 + 40 + 5; 6 lines of text possible
1480 buttonsGap = (width-noButtons*140)/(noButtons+1)
1481 buttonsVPos = height-40-5
1483 <screen position="center,center" size="%d,%d" title="Add entry to phonebook" >
1484 <widget name="config" position="5,5" size="%d,%d" scrollbarMode="showOnDemand" />
1485 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
1486 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
1487 <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" />
1488 <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" />
1491 width - 5 - 5, height - 5 - 40 - 5,
1492 buttonsGap, buttonsVPos, "skin_default/buttons/red.png",
1493 buttonsGap+140+buttonsGap, buttonsVPos, "skin_default/buttons/green.png",
1494 buttonsGap, buttonsVPos,
1495 buttonsGap+140+buttonsGap, buttonsVPos,
1497 Screen.__init__(self, session)
1498 self.session = session
1499 self.parent = parent
1500 # TRANSLATORS: keep it short, this is a button
1501 self["key_red"] = Button(_("Cancel"))
1502 # TRANSLATORS: keep it short, this is a button
1503 self["key_green"] = Button(_("OK"))
1504 self["setupActions"] = ActionMap(["SetupActions", "ColorActions"],
1506 "cancel": self.cancel,
1513 ConfigListScreen.__init__(self, self.list, session=session)
1515 self.number = number
1516 config.plugins.FritzCall.name.value = name
1517 config.plugins.FritzCall.number.value = number
1518 self.list.append(getConfigListEntry(_("Name"), config.plugins.FritzCall.name))
1519 self.list.append(getConfigListEntry(_("Number"), config.plugins.FritzCall.number))
1520 self["config"].list = self.list
1521 self["config"].l.setList(self.list)
1522 self.onLayoutFinish.append(self.setWindowTitle)
1524 def setWindowTitle(self):
1525 # TRANSLATORS: this is a window title.
1526 self.setTitle(_("Add entry to phonebook"))
1529 # get texts from Screen
1530 # add (number,name) to sortlist and phonebook.phonebook and disk
1531 self.name = config.plugins.FritzCall.name.value
1532 self.number = config.plugins.FritzCall.number.value
1533 if not self.number or not self.name:
1534 self.session.open(MessageBox, _("Entry incomplete."), type=MessageBox.TYPE_ERROR)
1536 # add (number,name) to sortlist and phonebook.phonebook and disk
1537 # oldname = phonebook.search(self.number)
1539 # self.session.openWithCallback(
1540 # self.overwriteConfirmed,
1542 # _("Do you really want to overwrite entry for %(number)s\n\n%(name)s\n\nwith\n\n%(newname)s?")
1544 # 'number':self.number,
1546 # 'newname':self.name.replace(", ","\n")
1551 phonebook.add(self.number, self.name)
1553 self.parent.display()
1555 def overwriteConfirmed(self, ret):
1557 phonebook.remove(self.number)
1558 phonebook.add(self.number, self.name)
1559 self.parent.display()
1564 debug("[FritzCallPhonebook] displayPhonebook/add")
1567 self.session.open(AddScreen, parent, number, name)
1570 debug("[FritzCallPhonebook] displayPhonebook/edit")
1571 cur = self["entries"].getCurrent()
1573 self.session.open(MessageBox, _("No entry selected"), MessageBox.TYPE_INFO)
1575 self.add(self, cur[2], cur[0])
1578 debug("[FritzCallPhonebook] displayPhonebook/search")
1579 self.help_window = self.session.instantiateDialog(NumericalTextInputHelpDialog, self)
1580 self.help_window.show()
1581 # VirtualKeyboard instead of InputBox?
1582 self.session.openWithCallback(self.doSearch, InputBox, _("Enter Search Terms"), _("Search phonebook"))
1584 def doSearch(self, searchTerms):
1587 debug("[FritzCallPhonebook] displayPhonebook/doSearch: " + searchTerms)
1588 if self.help_window:
1589 self.session.deleteDialog(self.help_window)
1590 self.help_window = None
1591 self.display(searchTerms)
1596 phonebook = FritzCallPhonebook()
1600 class FritzCallSetup(Screen, ConfigListScreen, HelpableScreen):
1602 def __init__(self, session, args=None): #@UnusedVariable # pylint: disable=W0613
1603 self.width = scaleH(20+4*(140+90)+2*(35+40)+20, 4*140+2*35)
1605 debug("[FritzCallSetup] width: " + str(self.width))
1607 <screen name="FritzCallSetup" position="center,center" size="%d,%d" title="FritzCall Setup" >
1608 <eLabel position="0,0" size="%d,2" backgroundColor="#aaaaaa" />
1609 <widget name="consideration" position="%d,%d" halign="center" size="%d,%d" font="Regular;%d" backgroundColor="#20040404" transparent="1" />
1610 <eLabel position="0,%d" size="%d,2" backgroundColor="#aaaaaa" />
1611 <widget name="config" position="%d,%d" size="%d,%d" scrollbarMode="showOnDemand" backgroundColor="#20040404" transparent="1" />
1612 <eLabel position="0,%d" size="%d,2" backgroundColor="#aaaaaa" />
1613 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
1614 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
1615 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
1616 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
1617 <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" />
1618 <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" />
1619 <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" />
1620 <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" />
1621 <ePixmap position="%d,%d" zPosition="4" size="35,25" pixmap="%s" transparent="1" alphatest="on" />
1622 <ePixmap position="%d,%d" zPosition="4" size="35,25" pixmap="%s" transparent="1" alphatest="on" />
1624 # (DESKTOP_WIDTH-width)/2, scaleV(100, 73), # position
1625 width, scaleV(560, 430), # size
1626 width, # eLabel width
1627 scaleH(40, 20), scaleV(10, 5), # consideration position
1628 scaleH(width-80, width-40), scaleV(25, 45), # consideration size
1629 scaleV(22, 20), # consideration font size
1630 scaleV(40, 50), # eLabel position vertical
1631 width, # eLabel width
1632 scaleH(40, 5), scaleV(60, 57), # config position
1633 scaleH(width-80, width-10), scaleV(453, 328), # config size
1634 scaleV(518, 390), # eLabel position vertical
1635 width, # eLabel width
1636 scaleH(20, 0), scaleV(525, 395), "skin_default/buttons/red.png", # pixmap red
1637 scaleH(20+140+90, 140), scaleV(525, 395), "skin_default/buttons/green.png", # pixmap green
1638 scaleH(20+2*(140+90), 2*140), scaleV(525, 395), "skin_default/buttons/yellow.png", # pixmap yellow
1639 scaleH(20+3*(140+90), 3*140), scaleV(525, 395), "skin_default/buttons/blue.png", # pixmap blue
1640 scaleH(20, 0), scaleV(525, 395), scaleV(21, 21), # widget red
1641 scaleH(20+(140+90), 140), scaleV(525, 395), scaleV(21, 21), # widget green
1642 scaleH(20+2*(140+90), 2*140), scaleV(525, 395), scaleV(21, 21), # widget yellow
1643 scaleH(20+3*(140+90), 3*140), scaleV(525, 395), scaleV(21, 21), # widget blue
1644 scaleH(20+4*(140+90), 4*140), scaleV(532, 402), "skin_default/buttons/key_info.png", # button info
1645 scaleH(20+4*(140+90)+(35+40), 4*140+35), scaleV(532, 402), "skin_default/buttons/key_menu.png", # button menu
1648 Screen.__init__(self, session)
1649 HelpableScreen.__init__(self)
1650 self.session = session
1652 self["consideration"] = Label(_("You need to enable the monitoring on your FRITZ!Box by dialing #96*5*!"))
1655 # Initialize Buttons
1656 # TRANSLATORS: keep it short, this is a button
1657 self["key_red"] = Button(_("Cancel"))
1658 # TRANSLATORS: keep it short, this is a button
1659 self["key_green"] = Button(_("OK"))
1660 # TRANSLATORS: keep it short, this is a button
1661 self["key_yellow"] = Button(_("Phone calls"))
1662 # TRANSLATORS: keep it short, this is a button
1663 self["key_blue"] = Button(_("Phonebook"))
1664 # TRANSLATORS: keep it short, this is a button
1665 self["key_info"] = Button(_("About FritzCall"))
1666 # TRANSLATORS: keep it short, this is a button
1667 self["key_menu"] = Button(_("FRITZ!Box Fon Status"))
1669 self["setupActions"] = ActionMap(["ColorActions", "OkCancelActions", "MenuActions", "EPGSelectActions"],
1673 "yellow": self.displayCalls,
1674 "blue": self.displayPhonebook,
1675 "cancel": self.cancel,
1681 # TRANSLATORS: keep it short, this is a help text
1682 self.helpList.append((self["setupActions"], "ColorActions", [("red", _("quit"))]))
1683 # TRANSLATORS: keep it short, this is a help text
1684 self.helpList.append((self["setupActions"], "ColorActions", [("green", _("save and quit"))]))
1685 # TRANSLATORS: keep it short, this is a help text
1686 self.helpList.append((self["setupActions"], "ColorActions", [("yellow", _("display calls"))]))
1687 # TRANSLATORS: keep it short, this is a help text
1688 self.helpList.append((self["setupActions"], "ColorActions", [("blue", _("display phonebook"))]))
1689 # TRANSLATORS: keep it short, this is a help text
1690 self.helpList.append((self["setupActions"], "OkCancelActions", [("ok", _("save and quit"))]))
1691 # TRANSLATORS: keep it short, this is a help text
1692 self.helpList.append((self["setupActions"], "OkCancelActions", [("cancel", _("quit"))]))
1693 # TRANSLATORS: keep it short, this is a help text
1694 self.helpList.append((self["setupActions"], "MenuActions", [("menu", _("FRITZ!Box Fon Status"))]))
1695 # TRANSLATORS: keep it short, this is a help text
1696 self.helpList.append((self["setupActions"], "EPGSelectActions", [("info", _("About FritzCall"))]))
1698 ConfigListScreen.__init__(self, self.list, session=session)
1700 # get new list of locations for PhoneBook.txt
1701 self._mountedDevs = getMountedDevs()
1703 self.onLayoutFinish.append(self.setWindowTitle)
1705 def setWindowTitle(self):
1706 # TRANSLATORS: this is a window title.
1707 self.setTitle(_("FritzCall Setup") + " (" + "$Revision: 734 $"[1: - 1] + "$Date: 2012-12-21 16:54:18 +0100 (Fr, 21 Dez 2012) $"[7:23] + ")")
1710 ConfigListScreen.keyLeft(self)
1714 ConfigListScreen.keyRight(self)
1717 def createSetup(self):
1719 self.list.append(getConfigListEntry(_("Call monitoring"), config.plugins.FritzCall.enable))
1720 if config.plugins.FritzCall.enable.value:
1721 self.list.append(getConfigListEntry(_("FRITZ!Box FON address (Name or IP)"), config.plugins.FritzCall.hostname))
1722 self.list.append(getConfigListEntry(_("FRITZ!Box FON firmware version"), config.plugins.FritzCall.fwVersion))
1724 self.list.append(getConfigListEntry(_("Show after Standby"), config.plugins.FritzCall.afterStandby))
1726 self.list.append(getConfigListEntry(_("Show only calls for specific MSN"), config.plugins.FritzCall.filter))
1727 if config.plugins.FritzCall.filter.value:
1728 self.list.append(getConfigListEntry(_("MSN to show (separated by ,)"), config.plugins.FritzCall.filtermsn))
1729 self.list.append(getConfigListEntry(_("Filter also list of calls"), config.plugins.FritzCall.filterCallList))
1730 self.list.append(getConfigListEntry(_("Mute on call"), config.plugins.FritzCall.muteOnCall))
1732 self.list.append(getConfigListEntry(_("Show Outgoing Calls"), config.plugins.FritzCall.showOutgoing))
1733 # not only for outgoing: config.plugins.FritzCall.showOutgoing.value:
1734 self.list.append(getConfigListEntry(_("Areacode to add to calls without one (if necessary)"), config.plugins.FritzCall.prefix))
1735 self.list.append(getConfigListEntry(_("Timeout for Call Notifications (seconds)"), config.plugins.FritzCall.timeout))
1736 self.list.append(getConfigListEntry(_("Reverse Lookup Caller ID (select country below)"), config.plugins.FritzCall.lookup))
1737 if config.plugins.FritzCall.lookup.value:
1738 self.list.append(getConfigListEntry(_("Country"), config.plugins.FritzCall.country))
1740 if config.plugins.FritzCall.fwVersion.value == "05.50":
1741 self.list.append(getConfigListEntry(_("User name Accessing FRITZ!Box"), config.plugins.FritzCall.username))
1742 # TODO: make password unreadable?
1743 self.list.append(getConfigListEntry(_("Password Accessing FRITZ!Box"), config.plugins.FritzCall.password))
1744 self.list.append(getConfigListEntry(_("Extension number to initiate call on"), config.plugins.FritzCall.extension))
1745 self.list.append(getConfigListEntry(_("Read PhoneBook from FRITZ!Box"), config.plugins.FritzCall.fritzphonebook))
1746 if config.plugins.FritzCall.fritzphonebook.value:
1747 self.list.append(getConfigListEntry(_("Append type of number"), config.plugins.FritzCall.showType))
1748 self.list.append(getConfigListEntry(_("Append shortcut number"), config.plugins.FritzCall.showShortcut))
1749 self.list.append(getConfigListEntry(_("Append vanity name"), config.plugins.FritzCall.showVanity))
1751 self.list.append(getConfigListEntry(_("Use internal PhoneBook"), config.plugins.FritzCall.phonebook))
1752 if config.plugins.FritzCall.phonebook.value:
1753 if config.plugins.FritzCall.phonebookLocation.value in self._mountedDevs:
1754 config.plugins.FritzCall.phonebookLocation.setChoices(self._mountedDevs, config.plugins.FritzCall.phonebookLocation.value)
1756 config.plugins.FritzCall.phonebookLocation.setChoices(self._mountedDevs)
1757 path = config.plugins.FritzCall.phonebookLocation.value
1758 # check whether we can write to PhoneBook.txt
1759 if os.path.exists(os.path.join(path[0], "PhoneBook.txt")):
1760 if not os.access(os.path.join(path[0], "PhoneBook.txt"), os.W_OK):
1761 debug("[FritzCallSetup] createSetup: %s/PhoneBook.txt not writable, resetting to default" %(path[0]))
1762 config.plugins.FritzCall.phonebookLocation.setChoices(self._mountedDevs)
1763 elif not (os.path.isdir(path[0]) and os.access(path[0], os.W_OK|os.X_OK)):
1764 debug("[FritzCallSetup] createSetup: directory %s not writable, resetting to default" %(path[0]))
1765 config.plugins.FritzCall.phonebookLocation.setChoices(self._mountedDevs)
1767 self.list.append(getConfigListEntry(_("PhoneBook Location"), config.plugins.FritzCall.phonebookLocation))
1768 if config.plugins.FritzCall.lookup.value:
1769 self.list.append(getConfigListEntry(_("Automatically add new Caller to PhoneBook"), config.plugins.FritzCall.addcallers))
1771 if config.plugins.FritzCall.phonebook.value or config.plugins.FritzCall.fritzphonebook.value:
1772 self.list.append(getConfigListEntry(_("Reload interval for phonebooks (hours)"), config.plugins.FritzCall.reloadPhonebookTime))
1774 self.list.append(getConfigListEntry(_("Strip Leading 0"), config.plugins.FritzCall.internal))
1775 # self.list.append(getConfigListEntry(_("Default display mode for FRITZ!Box calls"), config.plugins.FritzCall.fbfCalls))
1776 self.list.append(getConfigListEntry(_("Display connection infos"), config.plugins.FritzCall.connectionVerbose))
1777 self.list.append(getConfigListEntry(_("Ignore callers with no phone number"), config.plugins.FritzCall.ignoreUnknown))
1778 self.list.append(getConfigListEntry(_("Debug"), config.plugins.FritzCall.debug))
1780 self["config"].list = self.list
1781 self["config"].l.setList(self.list)
1784 # debug("[FritzCallSetup] save"
1785 for x in self["config"].list:
1787 if config.plugins.FritzCall.phonebookLocation.isChanged():
1789 phonebook = FritzCallPhonebook()
1791 if config.plugins.FritzCall.enable.value:
1792 fritz_call.connect()
1794 fritz_call.shutdown()
1798 # debug("[FritzCallSetup] cancel"
1799 for x in self["config"].list:
1803 def displayCalls(self):
1804 if config.plugins.FritzCall.enable.value:
1806 self.session.open(FritzDisplayCalls)
1808 self.session.open(MessageBox, _("Cannot get calls from FRITZ!Box"), type=MessageBox.TYPE_INFO)
1810 self.session.open(MessageBox, _("Plugin not active"), type=MessageBox.TYPE_INFO)
1812 def displayPhonebook(self):
1814 if config.plugins.FritzCall.enable.value:
1815 self.session.open(phonebook.FritzDisplayPhonebook)
1817 self.session.open(MessageBox, _("Plugin not active"), type=MessageBox.TYPE_INFO)
1819 self.session.open(MessageBox, _("No phonebook"), type=MessageBox.TYPE_INFO)
1822 self.session.open(FritzAbout)
1825 if config.plugins.FritzCall.enable.value:
1826 if fritzbox and fritzbox.info:
1827 self.session.open(FritzMenu)
1829 self.session.open(MessageBox, _("Cannot get infos from FRITZ!Box"), type=MessageBox.TYPE_INFO)
1831 self.session.open(MessageBox, _("Plugin not active"), type=MessageBox.TYPE_INFO)
1835 class FritzCallList:
1839 def add(self, event, date, number, caller, phone):
1840 debug("[FritzCallList] add: %s %s" % (number, caller))
1841 if len(self.callList) > 10:
1842 if self.callList[0] != "Start":
1843 self.callList[0] = "Start"
1844 del self.callList[1]
1846 self.callList.append((event, number, date, caller, phone))
1849 debug("[FritzCallList] display")
1852 # Standby.inStandby.onClose.remove(self.display) object does not exist anymore...
1853 # build screen from call list
1856 if not self.callList:
1857 text = _("no calls")
1859 if self.callList[0] == "Start":
1860 text = text + _("Last 10 calls:\n")
1861 del self.callList[0]
1863 for call in self.callList:
1864 (event, number, date, caller, phone) = call
1870 # shorten the date info
1871 date = date[:6] + date[9:14]
1873 # our phone could be of the form "0123456789 (home)", then we only take "home"
1874 oBrack = phone.find('(')
1875 cBrack = phone.find(')')
1876 if oBrack != -1 and cBrack != -1:
1877 phone = phone[oBrack+1:cBrack]
1879 # should not happen, for safety reasons
1881 caller = _("UNKNOWN")
1883 # if we have an unknown number, show the number
1884 if caller == _("UNKNOWN") and number != "":
1887 # strip off the address part of the remote caller/callee, if there is any
1888 nl = caller.find('\n')
1890 caller = caller[:nl]
1891 elif caller[0] == '[' and caller[-1] == ']':
1892 # that means, we've got an unknown number with a city added from avon.dat
1893 if (len(number) + 1 + len(caller) + len(phone)) <= 40:
1894 caller = number + ' ' + caller
1898 while (len(caller) + len(phone)) > 40:
1899 if len(caller) > len(phone):
1900 caller = caller[: - 1]
1902 phone = phone[: - 1]
1904 text = text + "%s %s %s %s\n" % (date, caller, direction, phone)
1905 debug("[FritzCallList] display: '%s %s %s %s'" % (date, caller, direction, phone))
1908 Notifications.AddNotification(MessageBox, text, type=MessageBox.TYPE_INFO)
1909 # TODO please HELP: from where can I get a session?
1910 # my_global_session.open(FritzDisplayCalls, text)
1913 callList = FritzCallList()
1915 def findFace(number, name):
1916 debug("[FritzCall] findFace number/name: %s/%s" % (number, name))
1918 sep = name.find(',')
1921 sep = name.find('\n')
1927 facesDir = os.path.join(config.plugins.FritzCall.phonebookLocation.value, "FritzCallFaces")
1928 numberFile = os.path.join(facesDir, number)
1929 nameFile = os.path.join(facesDir, name)
1931 if number and os.path.exists(numberFile):
1932 facesFile = numberFile
1933 elif number and os.path.exists(numberFile + ".png"):
1934 facesFile = numberFile + ".png"
1935 elif number and os.path.exists(numberFile + ".PNG"):
1936 facesFile = numberFile + ".PNG"
1937 elif name and os.path.exists(nameFile + ".png"):
1938 facesFile = nameFile + ".png"
1939 elif name and os.path.exists(nameFile + ".PNG"):
1940 facesFile = nameFile + ".PNG"
1942 sep = name.find(' (')
1945 nameFile = os.path.join(facesDir, name)
1947 if name and os.path.exists(nameFile + ".png"):
1948 facesFile = nameFile + ".png"
1949 elif name and os.path.exists(nameFile + ".PNG"):
1950 facesFile = nameFile + ".PNG"
1952 facesFile = resolveFilename(SCOPE_SKIN_IMAGE, "skin_default/icons/input_info.png")
1954 debug("[FritzCall] findFace result: %s" % (facesFile))
1957 class MessageBoxPixmap(Screen):
1958 def __init__(self, session, text, number = "", name = "", timeout = -1):
1960 <screen name="MessageBoxPixmap" position="center,center" size="600,10" title="New Call">
1961 <widget name="text" position="115,8" size="520,0" font="Regular;%d" />
1962 <widget name="InfoPixmap" pixmap="%s" position="5,5" size="100,100" alphatest="on" />
1965 # scaleH(350, 60), scaleV(175, 245),
1966 scaleV(24, 22), resolveFilename(SCOPE_SKIN_IMAGE, "skin_default/icons/input_info.png")
1968 debug("[FritzCall] MessageBoxPixmap number: %s" % number)
1969 Screen.__init__(self, session)
1970 # MessageBox.__init__(self, session, text, type=MessageBox.TYPE_INFO, timeout=timeout)
1971 self["text"] = Label(text)
1972 self["InfoPixmap"] = Pixmap()
1973 self._session = session
1974 self._number = number
1976 self._timerRunning = False
1978 self._timeout = timeout
1979 self._origTitle = None
1981 self.onLayoutFinish.append(self._finishLayout)
1982 self["actions"] = ActionMap(["OkCancelActions"],
1984 "cancel": self._exit,
1985 "ok": self._exit, }, - 2)
1987 def _finishLayout(self):
1988 # pylint: disable=W0142
1989 debug("[FritzCall] MessageBoxPixmap/setInfoPixmap number: %s/%s" % (self._number, self._name))
1991 self.setTitle(_("New call"))
1993 faceFile = findFace(self._number, self._name)
1994 picPixmap = LoadPixmap(faceFile)
1995 if not picPixmap: # that means most probably, that the picture is not 8 bit...
1996 Notifications.AddNotification(MessageBox, _("Found picture\n\n%s\n\nBut did not load. Probably not PNG, 8-bit") %faceFile, type = MessageBox.TYPE_ERROR)
1997 picPixmap = LoadPixmap(resolveFilename(SCOPE_SKIN_IMAGE, "skin_default/icons/input_error.png"))
1998 picSize = picPixmap.size()
1999 self["InfoPixmap"].instance.setPixmap(picPixmap)
2001 # recalculate window size
2002 textSize = self["text"].getSize()
2003 textSize = (textSize[0]+20, textSize[1]+20) # don't know, why, but size is too small
2004 textSize = eSize(*textSize)
2005 width = max(scaleH(600, 280), picSize.width() + textSize.width() + 30)
2006 height = max(scaleV(300, 250), picSize.height()+10, textSize.height()+10)
2007 wSize = (width, height)
2008 wSize = eSize(*wSize)
2010 # center the smaller vertically
2011 hGap = (width-picSize.width()-textSize.width())/3
2012 picPos = (hGap, (height-picSize.height())/2+1)
2013 textPos = (hGap+picSize.width()+hGap, (height-textSize.height())/2+1)
2016 self.instance.resize(wSize)
2018 self["text"].instance.resize(textSize)
2020 self["InfoPixmap"].instance.resize(picSize)
2022 self["text"].instance.move(ePoint(*textPos))
2024 self["InfoPixmap"].instance.move(ePoint(*picPos))
2026 self.instance.move(ePoint((DESKTOP_WIDTH-wSize.width())/2, (DESKTOP_HEIGHT-wSize.height())/2))
2028 def _initTimeout(self):
2029 if self._timeout > 0:
2030 self._timer = eTimer()
2031 self._timer.callback.append(self._timerTick)
2032 self.onExecBegin.append(self._startTimer)
2033 self._origTitle = None
2037 self.onShown.append(self.__onShown)
2038 self._timerRunning = True
2040 self._timerRunning = False
2042 def __onShown(self):
2043 self.onShown.remove(self.__onShown)
2046 def _startTimer(self):
2047 self._timer.start(1000)
2049 #===============================================================================
2050 # def stopTimer(self):
2051 # if self._timerRunning:
2053 # self.setTitle(self._origTitle)
2054 # self._timerRunning = False
2055 #===============================================================================
2057 def _timerTick(self):
2060 if self._origTitle is None:
2061 self._origTitle = self.instance.getTitle()
2062 self.setTitle(self._origTitle + " (" + str(self._timeout) + ")")
2063 if self._timeout == 0:
2065 self._timerRunning = False
2071 def runUserActionScript(event, date, number, caller, phone):
2073 # call FritzCallserAction.sh in the same dir as Phonebook.txt with the following parameters:
2074 # event: "RING" (incomning) or "CALL" (outgoing)
2075 # date of event, format: "dd.mm.yy hh.mm.ss"
2076 # telephone number which is calling/is called
2077 # caller's name and address, format Name\n Street\n ZIP City
2078 # line/number which is called/which is used for calling
2079 userActionScript = os.path.join(config.plugins.FritzCall.phonebookLocation.value, "FritzCallUserAction.sh")
2080 if os.path.exists(userActionScript) and os.access(userActionScript, os.X_OK):
2081 cmd = userActionScript + ' "' + event + '" "' + date + '" "' + number + '" "' + caller + '" "' + phone + '"'
2082 debug("[FritzCall] runUserActionScript: calling: %s" % cmd)
2083 eConsoleAppContainer().execute(cmd)
2085 userActionList = [runUserActionScript]
2086 def registerUserAction(fun):
2087 #===========================================================================
2088 # other plugins can register a function, which is then called for each displayed call
2089 # it must take the arguments event,date,number,caller,phone
2092 # def FritzCallEvent(event,date,number,caller,phone):
2096 # from Plugins.Extensions.FritzCall.plugin import registerUserAction as FritzCallRegisterUserAction
2097 # FritzCallRegisterUserAction(FritzCallEvent)
2099 # print "import of FritzCall failed"
2100 #===========================================================================
2101 debug("[FritzCall] registerUserAction: register: %s" % fun.__name__)
2102 userActionList.append(fun)
2104 mutedOnConnID = None
2105 def notifyCall(event, date, number, caller, phone, connID):
2106 if Standby.inStandby is None or config.plugins.FritzCall.afterStandby.value == "each":
2108 global mutedOnConnID
2109 if config.plugins.FritzCall.muteOnCall.value and not mutedOnConnID:
2110 debug("[FritzCall] mute on connID: %s" % connID)
2111 mutedOnConnID = connID
2112 # eDVBVolumecontrol.getInstance().volumeMute() # with this, we get no mute icon...
2113 if not eDVBVolumecontrol.getInstance().isMuted():
2114 globalActionMap.actions["volumeMute"]()
2115 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 }
2117 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 }
2118 debug("[FritzCall] notifyCall:\n%s" % text)
2119 # Notifications.AddNotification(MessageBox, text, type=MessageBox.TYPE_INFO, timeout=config.plugins.FritzCall.timeout.value)
2120 Notifications.AddNotification(MessageBoxPixmap, text, number=number, name=caller, timeout=config.plugins.FritzCall.timeout.value)
2121 elif config.plugins.FritzCall.afterStandby.value == "inList":
2123 # if not yet done, register function to show call list
2125 if not standbyMode :
2127 Standby.inStandby.onHide.append(callList.display) #@UndefinedVariable
2128 # add text/timeout to call list
2129 callList.add(event, date, number, caller, phone)
2130 debug("[FritzCall] notifyCall: added to callList")
2131 else: # this is the "None" case
2132 debug("[FritzCall] notifyCall: standby and no show")
2134 for fun in userActionList:
2135 debug("[FritzCall] notifyCall: call user action: %s" % fun.__name__)
2136 fun(event, date, number, caller, phone)
2139 #===============================================================================
2140 # We need a separate class for each invocation of reverseLookup to retain
2141 # the necessary data for the notification
2142 #===============================================================================
2145 reverselookupMtime = 0
2147 class FritzReverseLookupAndNotifier:
2148 def __init__(self, event, number, caller, phone, date, connID):
2151 Initiate a reverse lookup for the given number in the configured country
2153 @param event: CALL or RING
2154 @param number: number to be looked up
2155 @param caller: caller including name and address
2156 @param phone: Number (and name) of or own phone
2157 @param date: date of call
2159 debug("[FritzReverseLookupAndNotifier] reverse Lookup for %s!" % number)
2161 self.number = number
2162 self.caller = caller
2165 self.connID = connID
2167 if number[0] != "0":
2168 self.notifyAndReset(number, caller)
2171 ReverseLookupAndNotifier(number, self.notifyAndReset, "UTF-8", config.plugins.FritzCall.country.value)
2173 def notifyAndReset(self, number, caller):
2176 this gets called with the result of the reverse lookup
2178 @param number: number
2179 @param caller: name and address of remote. it comes in with name, address and city separated by commas
2181 debug("[FritzReverseLookupAndNotifier] got: " + caller)
2182 self.number = number
2183 #===============================================================================
2184 # if not caller and os.path.exists(config.plugins.FritzCall.phonebookLocation.value + "/PhoneBook.csv"):
2185 # caller = FritzOutlookCSV.findNumber(number, config.plugins.FritzCall.phonebookLocation.value + "/PhoneBook.csv") #@UndefinedVariable
2186 # debug("[FritzReverseLookupAndNotifier] got from Outlook csv: " + caller)
2187 #===============================================================================
2188 #===============================================================================
2189 # if not caller and os.path.exists(config.plugins.FritzCall.phonebookLocation.value + "/PhoneBook.ldif"):
2190 # caller = FritzLDIF.findNumber(number, open(config.plugins.FritzCall.phonebookLocation.value + "/PhoneBook.ldif"))
2191 # debug("[FritzReverseLookupAndNotifier] got from ldif: " + caller)
2192 #===============================================================================
2194 name = handleReverseLookupResult(caller)
2196 self.caller = name.replace(", ", "\n").replace('#','')
2197 # TODO: I don't know, why we store only for incoming calls...
2198 # if self.number != 0 and config.plugins.FritzCall.addcallers.value and self.event == "RING":
2199 if self.number != 0 and config.plugins.FritzCall.addcallers.value:
2200 debug("[FritzReverseLookupAndNotifier] add to phonebook")
2201 phonebook.add(self.number, self.caller)
2203 name = resolveNumberWithAvon(self.number, config.plugins.FritzCall.country.value)
2205 self.caller = _("UNKNOWN")
2208 notifyCall(self.event, self.date, self.number, self.caller, self.phone, self.connID)
2209 # kill that object...
2211 class FritzProtocol(LineReceiver):
2213 debug("[FritzProtocol] " + "$Revision: 734 $"[1:-1] + "$Date: 2012-12-21 16:54:18 +0100 (Fr, 21 Dez 2012) $"[7:23] + " starting")
2214 global mutedOnConnID
2215 mutedOnConnID = None
2223 def resetValues(self):
2224 debug("[FritzProtocol] resetValues")
2232 def notifyAndReset(self):
2233 notifyCall(self.event, self.date, self.number, self.caller, self.phone, self.connID)
2236 def lineReceived(self, line):
2237 debug("[FritzProtocol] lineReceived: %s" % line)
2238 #15.07.06 00:38:54;CALL;1;4;<from/our msn>;<to/extern>;
2239 #15.07.06 00:38:58;DISCONNECT;1;0;
2240 #15.07.06 00:39:22;RING;0;<from/extern>;<to/our msn>;
2241 #15.07.06 00:39:27;DISCONNECT;0;0;
2242 anEvent = line.split(';')
2243 (self.date, self.event) = anEvent[0:2]
2244 self.connID = anEvent[2]
2246 filtermsns = config.plugins.FritzCall.filtermsn.value.split(",")
2247 for i in range(len(filtermsns)):
2248 filtermsns[i] = filtermsns[i].strip()
2250 if config.plugins.FritzCall.ignoreUnknown.value:
2251 if self.event == "RING":
2253 debug("[FritzProtocol] lineReceived: call from unknown phone; skipping")
2255 elif not anEvent[5]:
2256 debug("[FritzProtocol] lineReceived: call to unknown phone; skipping")
2259 # debug("[FritzProtocol] Volcontrol dir: %s" % dir(eDVBVolumecontrol.getInstance()))
2260 # debug("[FritzCall] unmute on connID: %s?" %self.connID)
2261 global mutedOnConnID
2262 if self.event == "DISCONNECT" and config.plugins.FritzCall.muteOnCall.value and mutedOnConnID == self.connID:
2263 debug("[FritzCall] unmute on connID: %s!" % self.connID)
2264 mutedOnConnID = None
2265 # eDVBVolumecontrol.getInstance().volumeUnMute()
2266 if eDVBVolumecontrol.getInstance().isMuted():
2267 globalActionMap.actions["volumeMute"]()
2268 # not supported so far, because, taht would mean muting on EVERY connect, regardless of RING or CALL or filter active
2269 #=======================================================================
2270 # elif self.event == "CONNECT" and config.plugins.FritzCall.muteOnCall.value == "connect":
2271 # debug("[FritzCall] mute on connID: %s" % self.connID)
2272 # mutedOnConnID = self.connID
2273 # # eDVBVolumecontrol.getInstance().volumeMute() # with this, we get no mute icon...
2274 # if not eDVBVolumecontrol.getInstance().isMuted():
2275 # globalActionMap.actions["volumeMute"]()
2276 #=======================================================================
2277 elif self.event == "RING" or (self.event == "CALL" and config.plugins.FritzCall.showOutgoing.value):
2279 if fritzbox and fritzbox.blacklist:
2280 if self.event == "RING":
2282 if number in fritzbox.blacklist[0]:
2283 debug("[FritzProtocol] lineReceived phone: '''%s''' blacklisted number: '''%s'''" % (phone, number))
2287 if number in fritzbox.blacklist[1]:
2288 debug("[FritzProtocol] lineReceived phone: '''%s''' blacklisted number: '''%s'''" % (phone, number))
2291 debug("[FritzProtocol] lineReceived phone: '''%s''' number: '''%s'''" % (phone, number))
2293 if not (config.plugins.FritzCall.filter.value and phone not in filtermsns):
2294 debug("[FritzProtocol] lineReceived no filter hit")
2296 phonename = phonebook.search(phone) # do we have a name for the number of our side?
2298 self.phone = "%s (%s)" % (phone, phonename)
2302 self.phone = _("UNKNOWN")
2305 debug("[FritzProtocol] lineReceived: no number")
2306 self.number = _("number suppressed")
2307 self.caller = _("UNKNOWN")
2309 if config.plugins.FritzCall.internal.value and len(number) > 3 and number[0] == "0":
2310 debug("[FritzProtocol] lineReceived: strip leading 0")
2311 self.number = number[1:]
2313 self.number = number
2314 if self.event == "CALL" and self.number[0] != '0': # should only happen for outgoing
2315 debug("[FritzProtocol] lineReceived: add local prefix")
2316 self.number = config.plugins.FritzCall.prefix.value + self.number
2318 # strip CbC prefixes
2319 if self.event == "CALL":
2320 number = stripCbCPrefix(self.number, config.plugins.FritzCall.country.value)
2322 debug("[FritzProtocol] lineReceived phonebook.search: %s" % self.number)
2323 self.caller = phonebook.search(self.number)
2324 debug("[FritzProtocol] lineReceived phonebook.search reault: %s" % self.caller)
2326 if config.plugins.FritzCall.lookup.value:
2327 FritzReverseLookupAndNotifier(self.event, self.number, self.caller, self.phone, self.date, self.connID)
2328 return # reverselookup is supposed to handle the message itself
2330 self.caller = _("UNKNOWN")
2332 self.notifyAndReset()
2334 class FritzClientFactory(ReconnectingClientFactory):
2339 self.hangup_ok = False
2340 def startedConnecting(self, connector): #@UnusedVariable # pylint: disable=W0613
2341 if not config.plugins.FritzCall.fwVersion.value:
2342 Notifications.AddNotification(MessageBox, _("FRITZ!Box firmware version not configured! Please set it in the configuration."), type=MessageBox.TYPE_INFO, timeout=0)
2344 if config.plugins.FritzCall.connectionVerbose.value:
2345 debug("[FRITZ!FritzClientFactory] - startedConnecting")
2346 Notifications.AddNotification(MessageBox, _("Connecting to FRITZ!Box..."), type=MessageBox.TYPE_INFO, timeout=2)
2348 def buildProtocol(self, addr): #@UnusedVariable # pylint: disable=W0613
2349 global fritzbox, phonebook
2350 if config.plugins.FritzCall.connectionVerbose.value:
2351 debug("[FRITZ!FritzClientFactory] - buildProtocol")
2352 Notifications.AddNotification(MessageBox, _("Connected to FRITZ!Box!"), type=MessageBox.TYPE_INFO, timeout=4)
2357 # TODO: swithc between FBF FW versions...
2358 if config.plugins.FritzCall.fwVersion.value == "old":
2359 fritzbox = FritzCallFBF.FritzCallFBF()
2360 elif config.plugins.FritzCall.fwVersion.value == "05.27":
2361 fritzbox = FritzCallFBF.FritzCallFBF_05_27()
2362 elif config.plugins.FritzCall.fwVersion.value == "05.50":
2363 fritzbox = FritzCallFBF.FritzCallFBF_05_50()
2365 Notifications.AddNotification(MessageBox, _("FRITZ!Box firmware version not configured! Please set it in the configuration."), type=MessageBox.TYPE_INFO, timeout=0)
2366 phonebook = FritzCallPhonebook()
2367 return FritzProtocol()
2369 def clientConnectionLost(self, connector, reason):
2371 if not self.hangup_ok and config.plugins.FritzCall.connectionVerbose.value:
2372 debug("[FRITZ!FritzClientFactory] - clientConnectionLost")
2373 Notifications.AddNotification(MessageBox, _("Connection to FRITZ!Box! lost\n (%s)\nretrying...") % reason.getErrorMessage(), type=MessageBox.TYPE_INFO, timeout=config.plugins.FritzCall.timeout.value)
2374 ReconnectingClientFactory.clientConnectionLost(self, connector, reason)
2375 # config.plugins.FritzCall.enable.value = False
2378 def clientConnectionFailed(self, connector, reason):
2380 if config.plugins.FritzCall.connectionVerbose.value:
2381 Notifications.AddNotification(MessageBox, _("Connecting to FRITZ!Box failed\n (%s)\nretrying...") % reason.getErrorMessage(), type=MessageBox.TYPE_INFO, timeout=config.plugins.FritzCall.timeout.value)
2382 ReconnectingClientFactory.clientConnectionFailed(self, connector, reason)
2383 # config.plugins.FritzCall.enable.value = False
2390 if config.plugins.FritzCall.enable.value:
2395 if config.plugins.FritzCall.enable.value:
2396 fact = FritzClientFactory()
2397 self.desc = (fact, reactor.connectTCP(config.plugins.FritzCall.hostname.value, 1012, fact)) #@UndefinedVariable # pylint: disable=E1101
2403 if self.desc is not None:
2404 self.desc[0].hangup_ok = True
2405 self.desc[0].stopTrying()
2406 self.desc[1].disconnect()
2409 def displayCalls(session, servicelist=None): #@UnusedVariable # pylint: disable=W0613
2410 if config.plugins.FritzCall.enable.value:
2412 session.open(FritzDisplayCalls)
2414 Notifications.AddNotification(MessageBox, _("Cannot get calls from FRITZ!Box"), type=MessageBox.TYPE_INFO)
2416 Notifications.AddNotification(MessageBox, _("Plugin not active"), type=MessageBox.TYPE_INFO)
2418 def displayPhonebook(session, servicelist=None): #@UnusedVariable # pylint: disable=W0613
2420 if config.plugins.FritzCall.enable.value:
2421 session.open(phonebook.FritzDisplayPhonebook)
2423 Notifications.AddNotification(MessageBox, _("Plugin not active"), type=MessageBox.TYPE_INFO)
2425 Notifications.AddNotification(MessageBox, _("No phonebook"), type=MessageBox.TYPE_INFO)
2427 def displayFBFStatus(session, servicelist=None): #@UnusedVariable # pylint: disable=W0613
2428 if config.plugins.FritzCall.enable.value:
2429 if fritzbox and fritzbox.info:
2430 session.open(FritzMenu)
2432 Notifications.AddNotification(MessageBox, _("Cannot get infos from FRITZ!Box"), type=MessageBox.TYPE_INFO)
2434 Notifications.AddNotification(MessageBox, _("Plugin not active"), type=MessageBox.TYPE_INFO)
2436 def main(session, servicelist=None):
2437 session.open(FritzCallSetup)
2441 def autostart(reason, **kwargs):
2444 # ouch, this is a hack
2445 if kwargs.has_key("session"):
2446 global my_global_session
2447 my_global_session = kwargs["session"]
2450 debug("[FRITZ!Call] - Autostart")
2452 fritz_call = FritzCall()
2454 fritz_call.shutdown()
2457 def Plugins(**kwargs): #@UnusedVariable # pylint: disable=W0613,C0103
2458 what = _("Display FRITZ!box-Fon calls on screen")
2459 what_calls = _("Phone calls")
2460 what_phonebook = _("Phonebook")
2461 what_status = _("FRITZ!Box Fon Status")
2462 return [ PluginDescriptor(name="FritzCall", description=what, where=PluginDescriptor.WHERE_PLUGINMENU, icon="plugin.png", fnc=main),
2463 PluginDescriptor(name=what_calls, description=what_calls, where=PluginDescriptor.WHERE_EXTENSIONSMENU, fnc=displayCalls),
2464 PluginDescriptor(name=what_phonebook, description=what_phonebook, where=PluginDescriptor.WHERE_EXTENSIONSMENU, fnc=displayPhonebook),
2465 PluginDescriptor(name=what_status, description=what_status, where=PluginDescriptor.WHERE_EXTENSIONSMENU, fnc=displayFBFStatus),
2466 PluginDescriptor(where=[PluginDescriptor.WHERE_SESSIONSTART, PluginDescriptor.WHERE_AUTOSTART], fnc=autostart) ]