1 # -*- coding: utf-8 -*-
2 #===============================================================================
7 #==============================
8 from Screens.Screen import Screen #@UnresolvedImport
9 from Screens.MessageBox import MessageBox #@UnresolvedImport
10 from Screens.NumericalTextInputHelpDialog import NumericalTextInputHelpDialog #@UnresolvedImport
11 from Screens.InputBox import InputBox #@UnresolvedImport
12 from Screens import Standby #@UnresolvedImport
13 from Screens.HelpMenu import HelpableScreen #@UnresolvedImport
15 from enigma import eListboxPythonMultiContent, gFont, RT_HALIGN_LEFT, RT_HALIGN_RIGHT #@UnresolvedImport
17 from Components.MenuList import MenuList #@UnresolvedImport
18 from Components.ActionMap import ActionMap #@UnresolvedImport
19 from Components.Label import Label #@UnresolvedImport
20 from Components.Button import Button #@UnresolvedImport
21 from Components.config import config, ConfigSubsection, ConfigSelection, ConfigEnableDisable, getConfigListEntry, ConfigText, ConfigInteger #@UnresolvedImport
23 from Components.config import ConfigPassword
25 ConfigPassword = ConfigText
26 from Components.ConfigList import ConfigListScreen #@UnresolvedImport
28 from Plugins.Plugin import PluginDescriptor #@UnresolvedImport
29 from Tools import Notifications #@UnresolvedImport
30 from Tools.NumericalTextInput import NumericalTextInput #@UnresolvedImport
31 from Tools.Directories import resolveFilename, SCOPE_PLUGINS, SCOPE_SKIN_IMAGE #@UnresolvedImport
32 from Tools.LoadPixmap import LoadPixmap #@UnresolvedImport
34 from twisted.internet import reactor #@UnresolvedImport
35 from twisted.internet.protocol import ReconnectingClientFactory #@UnresolvedImport
36 from twisted.protocols.basic import LineReceiver #@UnresolvedImport
37 from twisted.web.client import getPage #@UnresolvedImport
39 from urllib import urlencode
42 from nrzuname import ReverseLookupAndNotifier, html2unicode
43 import FritzOutlookCSV, FritzLDIF
44 from . import _, debug #@UnresolvedImport
46 from enigma import getDesktop #@UnresolvedImport
47 DESKTOP_WIDTH = getDesktop(0).size().width()
48 DESKTOP_HEIGHT = getDesktop(0).size().height()
49 DESKTOP_SKIN = config.skin.primary_skin.value.replace("/skin.xml", "")
50 XXX = 0 # TODO: Platzhalter für fullscreen SD skin
53 # It returns the first value, if HD (1280x720),
54 # the second if SD (720x576),
55 # else something scaled accordingly
58 return scale(y2, y1, 1280, 720, DESKTOP_WIDTH)
60 return scale(y2, y1, 720, 576, DESKTOP_HEIGHT)
61 def scale(y2, y1, x2, x1, x):
62 return (y2 - y1) * (x - x1) / (x2 - x1) + y1
64 my_global_session = None
66 config.plugins.FritzCall = ConfigSubsection()
67 config.plugins.FritzCall.enable = ConfigEnableDisable(default=False)
68 config.plugins.FritzCall.muteOnCall = ConfigEnableDisable(default=False)
69 config.plugins.FritzCall.hostname = ConfigText(default="fritz.box", fixed_size=False)
70 config.plugins.FritzCall.afterStandby = ConfigSelection(choices=[("none", _("show nothing")), ("inList", _("show as list")), ("each", _("show each call"))])
71 config.plugins.FritzCall.filter = ConfigEnableDisable(default=False)
72 config.plugins.FritzCall.filtermsn = ConfigText(default="", fixed_size=False)
73 config.plugins.FritzCall.filtermsn.setUseableChars('0123456789,')
74 config.plugins.FritzCall.showOutgoing = ConfigEnableDisable(default=False)
75 config.plugins.FritzCall.timeout = ConfigInteger(default=15, limits=(0, 60))
76 config.plugins.FritzCall.lookup = ConfigEnableDisable(default=False)
77 config.plugins.FritzCall.internal = ConfigEnableDisable(default=False)
78 config.plugins.FritzCall.fritzphonebook = ConfigEnableDisable(default=False)
79 config.plugins.FritzCall.phonebook = ConfigEnableDisable(default=False)
80 config.plugins.FritzCall.addcallers = ConfigEnableDisable(default=False)
81 config.plugins.FritzCall.phonebookLocation = ConfigSelection(choices=[("/etc/enigma2", _("Flash")), ("/media/usb", _("USB Stick")), ("/media/cf", _("CF Drive")), ("/media/hdd", _("Harddisk"))])
82 config.plugins.FritzCall.password = ConfigPassword(default="", fixed_size=False)
83 config.plugins.FritzCall.extension = ConfigText(default='1', fixed_size=False)
84 config.plugins.FritzCall.extension.setUseableChars('0123456789')
85 config.plugins.FritzCall.showType = ConfigEnableDisable(default=True)
86 config.plugins.FritzCall.showShortcut = ConfigEnableDisable(default=False)
87 config.plugins.FritzCall.showVanity = ConfigEnableDisable(default=False)
88 config.plugins.FritzCall.prefix = ConfigText(default="", fixed_size=False)
89 config.plugins.FritzCall.prefix.setUseableChars('0123456789')
90 config.plugins.FritzCall.fullscreen = ConfigEnableDisable(default=False)
91 config.plugins.FritzCall.debug = ConfigEnableDisable(default=False)
94 ("0049", _("Germany")),
95 ("0031", _("The Netherlands")),
96 ("0033", _("France")),
98 ("0041", _("Switzerland")),
99 ("0043", _("Austria"))
101 config.plugins.FritzCall.country = ConfigSelection(choices=countryCodes)
105 FBF_MISSED_CALLS = "2"
107 fbfCallsChoices = {FBF_ALL_CALLS: _("All calls"),
108 FBF_IN_CALLS: _("Incoming calls"),
109 FBF_MISSED_CALLS: _("Missed calls"),
110 FBF_OUT_CALLS: _("Outgoing calls")
112 config.plugins.FritzCall.fbfCalls = ConfigSelection(choices=fbfCallsChoices)
114 config.plugins.FritzCall.name = ConfigText(default="", fixed_size=False)
115 config.plugins.FritzCall.number = ConfigText(default="", fixed_size=False)
116 config.plugins.FritzCall.number.setUseableChars('0123456789')
120 os.remove("/tmp/FritzDebug.log")
124 class FritzAbout(Screen):
126 width = 5 + 150 + 20 + textFieldWidth + 5 + 175 + 5
127 height = 5 + 175 + 5 + 25 + 5
128 # TRANSLATORS: this is a window title. Avoid the use of non ascii chars
130 <screen name="FritzAbout" position="%d,%d" size="%d,%d" title="%s" >
131 <widget name="text" position="175,%d" size="%d,%d" font="Regular;%d" />
132 <ePixmap position="5,37" size="150,110" pixmap="%s" transparent="1" alphatest="blend" />
133 <ePixmap position="%d,5" size="175,175" pixmap="%s" transparent="1" alphatest="blend" />
134 <widget name="url" position="10,185" size="%d,25" font="Regular;%d" />
136 (DESKTOP_WIDTH - width) / 2, (DESKTOP_HEIGHT - height) / 2, # position
137 width, height, # size
138 _("About FritzCall"), # title
139 (height-scaleV(150,130)) / 2, # text vertical position
141 scaleV(150,130), # text height
142 scaleV(24,21), # text font size
143 resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/images/fritz.png"), # 150x110
144 5 + 150 + 5 + textFieldWidth + 5, # qr code horizontal offset
145 resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/images/website.png"), # 175x175
146 width-20, # url width
147 scaleV(24,21) # url font size
150 def __init__(self, session):
151 Screen.__init__(self, session)
152 self["aboutActions"] = ActionMap(["OkCancelActions"],
157 self["text"] = Label(
158 "FritzCall Plugin" + "\n\n" +
159 "$Author$"[1:-2] + "\n" +
160 "$Revision$"[1:-2] + "\n" +
161 "$Date$"[1:23] + "\n"
163 self["url"] = Label("http://wiki.blue-panel.com/index.php/FritzCall")
171 debug("[FritzCallFBF] __init__")
172 self.callScreen = None
173 self.loggedIn = False
177 self.callType = config.plugins.FritzCall.fbfCalls.value
179 def notify(self, text):
180 debug("[FritzCallFBF] notify")
182 debug("[FritzCallFBF] notify: try to close callScreen")
183 self.callScreen.close()
184 self.callScreen = None
185 Notifications.AddNotification(MessageBox, text, type=MessageBox.TYPE_ERROR, timeout=config.plugins.FritzCall.timeout.value)
187 def errorLogin(self, error):
188 text = _("FRITZ!Box Login failed! - Error: %s") % error
191 def _gotPageLogin(self, html):
192 # debug("[FritzCallPhonebook] _gotPageLogin"
193 # workaround: exceptions in gotPage-callback were ignored
195 self.callScreen.updateStatus(_("Getting calls from FRITZ!Box...") + _("login verification"))
197 debug("[FritzCallFBF] _gotPageLogin: verify login")
198 found = re.match('.*<p class="errorMessage">FEHLER: Das angegebene Kennwort', html, re.S)
200 text = _("FRITZ!Box Login failed! - Wrong Password!")
204 self.callScreen.updateStatus(_("Getting calls from FRITZ!Box...") + _("login ok"))
207 import traceback, sys
208 traceback.print_exc(file=sys.stdout)
211 def login(self, callback=None):
212 debug("[FritzCallFBF] Login")
213 if config.plugins.FritzCall.password.value != "":
215 self.callScreen.updateStatus(_("Getting calls from FRITZ!Box...") + _("login"))
216 parms = "login:command/password=%s" % (config.plugins.FritzCall.password.value)
217 url = "http://%s/cgi-bin/webcm" % (config.plugins.FritzCall.hostname.value)
220 headers={'Content-Type': "application/x-www-form-urlencoded", 'Content-Length': str(len(parms))
221 }, postdata=parms).addCallback(self._gotPageLogin).addCallback(callback).addErrback(self.errorLogin)
225 def errorLoad(self, error):
226 text = _("Could not load phonebook from FRITZ!Box - Error: %s") % error
229 def _gotPageLoad(self, html):
230 debug("[FritzCallFBF] _gotPageLoad")
231 # workaround: exceptions in gotPage-callback were ignored
233 self.parseFritzBoxPhonebook(html)
235 import traceback, sys
236 traceback.print_exc(file=sys.stdout)
239 def loadFritzBoxPhonebook(self):
240 debug("[FritzCallFBF] loadFritzBoxPhonebook")
241 if config.plugins.FritzCall.fritzphonebook.value:
242 debug("[FritzCallFBF] loadFritzBoxPhonebook: logging in")
243 self.login(self._loadFritzBoxPhonebook)
245 def _loadFritzBoxPhonebook(self, html=None):
246 parms = urlencode({'getpage':'../html/de/menus/menu2.html', 'var:lang':'de', 'var:pagename':'fonbuch', 'var:menu':'fon'})
247 url = "http://%s/cgi-bin/webcm?%s" % (config.plugins.FritzCall.hostname.value, parms)
249 getPage(url).addCallback(self._gotPageLoad).addErrback(self.errorLoad)
251 def parseFritzBoxPhonebook(self, html):
252 debug("[FritzCallFBF] parseFritzBoxPhonebook")
254 if re.search('TrFonName', html):
255 #===============================================================================
256 # New Style: 7170 / 7270 (FW 54.04.58, 54.04.63-11941)
257 # 7141 (FW 40.04.68) 22.03.2009
258 # 7170 (FW 29.04.70) 22.03.2009
259 # 7270: (FW 54.04.70)
260 # We expect one line with TrFonName followed by several lines with
261 # TrFonNr(Type,Number,Shortcut,Vanity), which all belong to the name in TrFonName.
262 #===============================================================================
263 html = html2unicode(html.decode('utf-8')).encode('utf-8')
264 entrymask = re.compile('(TrFonName\("[^"]+", "[^"]+", "[^"]*"\);.*?)TrFon1\(\)', re.S)
265 entries = entrymask.finditer(html)
266 for entry in entries:
267 # debug(entry.group(1)
268 # TrFonName (id, name, category)
269 found = re.match('TrFonName\("[^"]*", "([^"]+)", "[^"]*"\);', entry.group(1))
271 name = found.group(1).strip().replace(',','')
274 # TrFonNr (type, rufnr, code, vanity)
275 detailmask = re.compile('TrFonNr\("([^"]*)", "([^"]*)", "([^"]*)", "([^"]*)"\);', re.S)
276 details = detailmask.finditer(entry.group(1))
277 for found in details:
278 thisnumber = found.group(2).strip()
280 debug("[FritzCallFBF] Ignoring entry with empty number for '''%s'''" % (name))
284 type = found.group(1)
285 if config.plugins.FritzCall.showType.value:
287 thisname = thisname + " (" + _("mobile") + ")"
289 thisname = thisname + " (" + _("home") + ")"
291 thisname = thisname + " (" + _("work") + ")"
293 if config.plugins.FritzCall.showShortcut.value and found.group(3):
294 thisname = thisname + ", " + _("Shortcut") + ": " + found.group(3)
295 if config.plugins.FritzCall.showVanity.value and found.group(4):
296 thisname = thisname + ", " + _("Vanity") + ": " + found.group(4)
298 debug("[FritzCallFBF] Adding '''%s''' with '''%s''' from FRITZ!Box Phonebook!" % (thisname.strip(), thisnumber))
299 # Beware: strings in phonebook.phonebook have to be in utf-8!
300 phonebook.phonebook[thisnumber] = thisname
302 elif re.search('TrFon', html):
303 #===============================================================================
304 # Old Style: 7050 (FW 14.04.33)
305 # We expect one line with TrFon(No,Name,Number,Shortcut,Vanity)
306 # Encoding should be plain Ascii...
307 #===============================================================================
308 entrymask = re.compile('TrFon\("[^"]*", "([^"]*)", "([^"]*)", "([^"]*)", "([^"]*)"\)', re.S)
309 entries = entrymask.finditer(html)
310 for found in entries:
311 name = found.group(1).strip().replace(',','')
312 # debug("[FritzCallFBF] pos: %s name: %s" %(found.group(0),name))
313 thisnumber = found.group(2).strip()
314 if config.plugins.FritzCall.showShortcut.value and found.group(3):
315 name = name + ", " + _("Shortcut") + ": " + found.group(3)
316 if config.plugins.FritzCall.showVanity.value and found.group(4):
317 name = name + ", " + _("Vanity") + ": " + found.group(4)
319 name = html2unicode(unicode(name)).encode('utf-8')
320 debug("[FritzCallFBF] Adding '''%s''' with '''%s''' from FRITZ!Box Phonebook!" % (name, thisnumber))
321 # Beware: strings in phonebook.phonebook have to be in utf-8!
322 phonebook.phonebook[thisnumber] = name
324 debug("[FritzCallFBF] ignoring empty number for %s" % name)
327 self.notify(_("Could not parse FRITZ!Box Phonebook entry"))
329 def errorCalls(self, error):
330 text = _("Could not load calls from FRITZ!Box - Error: %s") % error
333 def _gotPageCalls(self, csv=""):
334 def _resolveNumber(number):
336 if config.plugins.FritzCall.internal.value and len(number) > 3 and number[0] == "0": number = number[1:]
338 if config.plugins.FritzCall.country.value == '0049':
339 if re.match('^0100\d\d', number):
341 elif re.match('^010\d\d', number):
343 if config.plugins.FritzCall.prefix.value and number and number[0] != '0': # should only happen for outgoing
344 number = config.plugins.FritzCall.prefix.value + number
345 name = phonebook.search(number)
347 found = re.match('(.*?)\n.*', name)
349 name = found.group(1)
352 number = _("UNKNOWN")
353 # if len(number) > 20: number = number[:20]
357 debug("[FritzCallFBF] _gotPageCalls: got csv, setting callList")
359 self.callScreen.updateStatus(_("Getting calls from FRITZ!Box...") + _("done"))
360 # check for error: wrong password or password not set... TODO
361 found = re.search('Melden Sie sich mit dem Kennwort der FRITZ!Box an', csv)
363 text = _("You need to set the password of the FRITZ!Box\nin the configuration dialog to display calls\n\nIt could be a communication issue, just try again.")
364 # self.session.open(MessageBox, text, MessageBox.TYPE_ERROR, timeout=config.plugins.FritzCall.timeout.value)
368 csv = csv.decode('iso-8859-1', 'replace').encode('utf-8', 'replace')
369 lines = csv.splitlines()
370 self.callList = lines
372 debug("[FritzCallFBF] _gotPageCalls: got no csv, but have callList")
374 self.callScreen.updateStatus(_("Getting calls from FRITZ!Box...") + _("done, using last list"))
375 lines = self.callList
377 debug("[FritzCallFBF] _gotPageCalls: got no csv, no callList, leaving")
383 # Typ;Datum;Name;Rufnummer;Nebenstelle;Eigene Rufnummer;Dauer
384 found = re.match("^(" + self.callType + ");([^;]*);([^;]*);([^;]*);([^;]*);([^;]*)", line)
386 direct = found.group(1)
387 date = found.group(2)
388 remote = _resolveNumber(found.group(4))
389 if not remote and direct != FBF_OUT_CALLS and found.group(3):
390 remote = found.group(3)
391 found1 = re.match('Internet: (.*)', found.group(6))
393 here = _resolveNumber(found1.group(1))
395 here = _resolveNumber(found.group(6))
397 # strip CbC prefix for Germany
398 number = found.group(4)
399 if config.plugins.FritzCall.country.value == '0049':
400 if re.match('^0100\d\d', number):
402 elif re.match('^010\d\d', number):
404 if config.plugins.FritzCall.prefix.value and number and number[0] != '0': # should only happen for outgoing
405 number = config.plugins.FritzCall.prefix.value + number
406 callList.append((number, date, here, direct, remote))
408 # debug("[FritzCallFBF] _gotPageCalls result:\n" + text
410 if self.Callback is not None:
411 # debug("[FritzCallFBF] _gotPageCalls call callback with\n" + text
412 self.Callback(callList)
414 self.callScreen = None
416 def getCalls(self, callScreen, callback, type):
418 # call sequence must be:
420 # - getPage -> _gotPageLogin
421 # - loginCallback (_getCalls)
422 # - getPage -> _getCalls1
423 debug("[FritzCallFBF] getCalls")
424 self.callScreen = callScreen
426 self.Callback = callback
427 if (time.time() - self.timestamp) > 180:
428 debug("[FritzCallFBF] getCalls: outdated data, login and get new ones")
429 self.timestamp = time.time()
430 self.login(self._getCalls)
431 elif not self.callList:
432 debug("[FritzCallFBF] getCalls: time is ok, but no callList")
435 debug("[FritzCallFBF] getCalls: time is ok, callList is ok")
438 def _getCalls(self, html=None):
440 # we need this to fill Anrufliste.csv
441 # http://repeater1/cgi-bin/webcm?getpage=../html/de/menus/menu2.html&var:lang=de&var:menu=fon&var:pagename=foncalls
443 debug("[FritzCallFBF] _getCalls")
445 self.callScreen.updateStatus(_("Getting calls from FRITZ!Box...") + _("preparing"))
446 parms = urlencode({'getpage':'../html/de/menus/menu2.html', 'var:lang':'de', 'var:pagename':'foncalls', 'var:menu':'fon'})
447 url = "http://%s/cgi-bin/webcm?%s" % (config.plugins.FritzCall.hostname.value, parms)
448 getPage(url).addCallback(self._getCalls1).addErrback(self.errorCalls)
450 def _getCalls1(self, html=""):
452 # finally we should have successfully lgged in and filled the csv
454 debug("[FritzCallFBF] _getCalls1")
456 self.callScreen.updateStatus(_("Getting calls from FRITZ!Box...") + _("finishing"))
457 parms = urlencode({'getpage':'../html/de/FRITZ!Box_Anrufliste.csv'})
458 url = "http://%s/cgi-bin/webcm?%s" % (config.plugins.FritzCall.hostname.value, parms)
459 getPage(url).addCallback(self._gotPageCalls).addErrback(self.errorCalls)
461 def dial(self, number):
462 ''' initiate a call to number '''
464 self.login(self._dial)
466 def _dial(self, html=None):
467 url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
469 'getpage':'../html/de/menus/menu2.html',
471 # 'name':'uiPostForm',
472 'login:command/password': config.plugins.FritzCall.password.value,
473 'var:pagename':'fonbuch',
475 'telcfg:settings/UseClickToDial':'1',
476 'telcfg:settings/DialPort':config.plugins.FritzCall.extension.value,
477 'telcfg:command/Dial':self.number
479 debug("[FritzCallFBF] dial url: '" + url + "' parms: '" + parms + "'")
482 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
484 'Content-Type': "application/x-www-form-urlencoded",
485 'Content-Length': str(len(parms))},
486 postdata=parms).addCallback(self._okDial).addErrback(self._errorDial)
488 def _okDial(self, html):
489 debug("[FritzCallFBF] okDial")
490 linkP = open("/tmp/FritzCallDialOK.htm", "w")
494 def _errorDial(self, error):
495 debug("[FritzCallFBF] errorDial: $s" % error)
496 linkP = open("/tmp/FritzCallDialError.htm", "w")
499 text = _("Dialling failed - Error: %s") % error
503 ''' hangup call on port; not used for now '''
504 url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
506 #'getpage':'../html/de/menus/menu2.html',
509 'login:command/password': config.plugins.FritzCall.password.value,
510 #'var:pagename':'fonbuch',
512 'telcfg:settings/UseClickToDial':'1',
513 'telcfg:settings/DialPort':config.plugins.FritzCall.extension.value,
514 'telcfg:command/Hangup':''
516 debug("[FritzCallFBF] hangup url: '" + url + "' parms: '" + parms + "'")
520 'Content-Type': "application/x-www-form-urlencoded",
521 'Content-Length': str(len(parms))},
524 fritzbox = FritzCallFBF()
527 class FritzDisplayCalls(Screen, HelpableScreen):
530 def __init__(self, session, text=""):
531 if config.plugins.FritzCall.fullscreen.value:
532 self.width = DESKTOP_WIDTH
533 self.height = DESKTOP_HEIGHT
535 if os.path.exists(resolveFilename(SCOPE_SKIN_IMAGE, DESKTOP_SKIN + "/menu/back-main.png")):
536 backMainPng = DESKTOP_SKIN + "/menu/back-main.png"
537 elif os.path.exists(resolveFilename(SCOPE_SKIN_IMAGE, "Kerni-HD1/menu/back-main.png")):
538 backMainPng = "Kerni-HD1/menu/back-main.png"
540 backMainLine = """<ePixmap position="0,0" zPosition="-10" size="%d,%d" pixmap="%s" transparent="1" />""" % (self.width, self.height, backMainPng)
543 debug("[FritzDisplayCalls] backMainLine: " + backMainLine)
545 # TRANSLATORS: this is a window title. Avoid the use of non ascii chars
547 <screen name="FritzDisplayCalls" position="0,0" size="%d,%d" title="%s" flags="wfNoBorder">
549 <widget source="global.CurrentTime" render="Label" position="%d,%d" size="%d,%d" font="Regular;%d" halign="right" backgroundColor="#0b67a2" transparent="1">
550 <convert type="ClockToText">Default</convert>
552 <widget source="global.CurrentTime" render="Label" position="%d,%d" size="%d,%d" font="Regular;%d" halign="right" backgroundColor="#0b67a2" transparent="1">
553 <convert type="ClockToText">Date</convert>
555 <eLabel text="%s" position="%d,%d" size="%d,%d" font="Regular;%d" halign="center" backgroundColor="#0b67a2" transparent="1"/>
557 <widget name="statusbar" position="%d,%d" size="%d,%d" font="Regular;%d" backgroundColor="#353e575e" transparent="1" />
558 <widget name="entries" position="%d,%d" size="%d,%d" scrollbarMode="showOnDemand" transparent="1" />
560 <ePixmap pixmap="skin_default/buttons/red.png" position="%d,%d" size="%d,%d" alphatest="on" />
561 <ePixmap pixmap="skin_default/buttons/green.png" position="%d,%d" size="%d,%d" alphatest="on" />
562 <ePixmap pixmap="skin_default/buttons/yellow.png" position="%d,%d" size="%d,%d" alphatest="on" />
563 <ePixmap pixmap="skin_default/buttons/blue.png" position="%d,%d" size="%d,%d" alphatest="on" />
564 <widget name="key_red" position="%d,%d" size="%d,%d" zPosition="1" font="Regular;%d" halign="left" backgroundColor="black" transparent="1" />
565 <widget name="key_green" position="%d,%d" size="%d,%d" zPosition="1" font="Regular;%d" halign="left" backgroundColor="black" transparent="1" />
566 <widget name="key_yellow" position="%d,%d" size="%d,%d" zPosition="1" font="Regular;%d" halign="left" backgroundColor="black" transparent="1" />
567 <widget name="key_blue" position="%d,%d" size="%d,%d" zPosition="1" font="Regular;%d" halign="left" backgroundColor="black" transparent="1" />
568 <ePixmap position="%d,%d" size="%d,%d" zPosition="2" pixmap="%s" transparent="1" alphatest="blend" />
570 self.width, self.height, _("Phone calls"),
572 scaleH(1130, XXX), scaleV(40, XXX), scaleH(80, XXX), scaleV(26, XXX), scaleV(26, XXX), # time
573 scaleH(900, XXX), scaleV(70, XXX), scaleH(310, XXX), scaleV(22, XXX), scaleV(20, XXX), # date
574 "FritzCall " + _("Phone calls"), scaleH(500, XXX), scaleV(63, XXX), scaleH(330, XXX), scaleV(30, XXX), scaleV(27, XXX), # eLabel
575 scaleH(80, XXX), scaleV(150, XXX), scaleH(280, XXX), scaleV(200, XXX), scaleV(22, XXX), # statusbar
576 scaleH(420, XXX), scaleV(120, XXX), scaleH(790, XXX), scaleV(438, XXX), # entries
577 scaleH(450, XXX), scaleV(588, XXX), scaleH(21, XXX), scaleV(21, XXX), # red
578 scaleH(640, XXX), scaleV(588, XXX), scaleH(21, XXX), scaleV(21, XXX), # green
579 scaleH(830, XXX), scaleV(588, XXX), scaleH(21, XXX), scaleV(21, XXX), # yellow
580 scaleH(1020, XXX), scaleV(588, XXX), scaleH(21, XXX), scaleV(21, XXX), # blue
581 scaleH(480, XXX), scaleV(587, XXX), scaleH(160, XXX), scaleV(22, XXX), scaleV(20, XXX), # red
582 scaleH(670, XXX), scaleV(587, XXX), scaleH(160, XXX), scaleV(22, XXX), scaleV(20, XXX), # green
583 scaleH(860, XXX), scaleV(587, XXX), scaleH(160, XXX), scaleV(22, XXX), scaleV(20, XXX), # yellow
584 scaleH(1050, XXX), scaleV(587, XXX), scaleH(160, XXX), scaleV(22, XXX), scaleV(20, XXX), # blue
585 scaleH(120, XXX), scaleV(430, XXX), scaleH(150, XXX), scaleV(110, XXX), resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/images/fritz.png") # Fritz Logo size and pixmap
588 self.width = scaleH(1100, 570)
589 debug("[FritzDisplayCalls] width: " + str(self.width))
590 # TRANSLATORS: this is a window title. Avoid the use of non ascii chars
592 <screen name="FritzDisplayCalls" position="%d,%d" size="%d,%d" title="%s" >
593 <eLabel position="0,0" size="%d,2" backgroundColor="#aaaaaa" />
594 <widget name="statusbar" position="%d,%d" size="%d,%d" font="Regular;%d" backgroundColor="#aaaaaa" transparent="1" />
595 <eLabel position="0,%d" size="%d,2" backgroundColor="#aaaaaa" />
596 <widget name="entries" position="%d,%d" size="%d,%d" scrollbarMode="showOnDemand" backgroundColor="#aaaaaa" transparent="1" />
597 <eLabel position="0,%d" size="%d,2" backgroundColor="#aaaaaa" />
598 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
599 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
600 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
601 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/blue.png" transparent="1" alphatest="on" />
602 <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" />
603 <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" />
604 <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" />
605 <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" />
607 scaleH(90, 75), scaleV(100, 78), # position
608 scaleH(1100, 570), scaleV(560, 430), # size
610 scaleH(1100, 570), # eLabel width
611 scaleH(40, 5), scaleV(10, 5), # statusbar position
612 scaleH(1050, 560), scaleV(25, 22), # statusbar size
613 scaleV(22, 21), # statusbar font size
614 scaleV(40, 28), # eLabel position vertical
615 scaleH(1100, 570), # eLabel width
616 scaleH(40, 5), scaleV(55, 40), # entries position
617 scaleH(1040, 560), scaleV(458, 340), # entries size
618 scaleV(518, 390), # eLabel position vertical
619 scaleH(1100, 570), # eLabel width
620 scaleH(20, 5), scaleV(525, 395), # widget red
621 scaleH(290, 145), scaleV(525, 395), # widget green
622 scaleH(560, 285), scaleV(525, 395), # widget yellow
623 scaleH(830, 425), scaleV(525, 395), # widget blue
624 scaleH(20, 5), scaleV(525, 395), scaleV(24, 21), # widget red
625 scaleH(290, 145), scaleV(525, 395), scaleV(24, 21), # widget green
626 scaleH(560, 285), scaleV(525, 395), scaleV(24, 21), # widget yellow
627 scaleH(830, 425), scaleV(525, 395), scaleV(24, 21), # widget blue
630 Screen.__init__(self, session)
631 HelpableScreen.__init__(self)
633 # TRANSLATORS: keep it short, this is a button
634 self["key_yellow"] = Button(_("All"))
635 # TRANSLATORS: keep it short, this is a button
636 self["key_red"] = Button(_("Missed"))
637 # TRANSLATORS: keep it short, this is a button
638 self["key_blue"] = Button(_("Incoming"))
639 # TRANSLATORS: keep it short, this is a button
640 self["key_green"] = Button(_("Outgoing"))
642 self["setupActions"] = ActionMap(["OkCancelActions", "ColorActions"],
644 "yellow": self.displayAllCalls,
645 "red": self.displayMissedCalls,
646 "blue": self.displayInCalls,
647 "green": self.displayOutCalls,
649 "ok": self.showEntry, }, - 2)
651 # TRANSLATORS: this is a help text, keep it short
652 self.helpList.append((self["setupActions"], "OkCancelActions", [("ok", _("Show details of entry"))]))
653 # TRANSLATORS: this is a help text, keep it short
654 self.helpList.append((self["setupActions"], "OkCancelActions", [("cancel", _("Quit"))]))
655 # TRANSLATORS: this is a help text, keep it short
656 self.helpList.append((self["setupActions"], "ColorActions", [("yellow", _("Display all calls"))]))
657 # TRANSLATORS: this is a help text, keep it short
658 self.helpList.append((self["setupActions"], "ColorActions", [("red", _("Display missed calls"))]))
659 # TRANSLATORS: this is a help text, keep it short
660 self.helpList.append((self["setupActions"], "ColorActions", [("blue", _("Display incoming calls"))]))
661 # TRANSLATORS: this is a help text, keep it short
662 self.helpList.append((self["setupActions"], "ColorActions", [("green", _("Display outgoing calls"))]))
664 self["statusbar"] = Label(_("Getting calls from FRITZ!Box..."))
665 self["entries"] = MenuList([], True, content=eListboxPythonMultiContent)
666 fontSize = scaleV(22, 18)
667 fontHeight = scaleV(24, 20)
668 self["entries"].l.setFont(0, gFont("Regular", fontSize))
669 self["entries"].l.setItemHeight(fontHeight)
671 debug("[FritzDisplayCalls] init: '''%s'''" % config.plugins.FritzCall.fbfCalls.value)
677 def displayAllCalls(self):
678 debug("[FritzDisplayCalls] displayAllCalls")
679 self.display(FBF_ALL_CALLS)
681 def displayMissedCalls(self):
682 debug("[FritzDisplayCalls] displayMissedCalls")
683 self.display(FBF_MISSED_CALLS)
685 def displayInCalls(self):
686 debug("[FritzDisplayCalls] displayInCalls")
687 self.display(FBF_IN_CALLS)
689 def displayOutCalls(self):
690 debug("[FritzDisplayCalls] displayOutCalls")
691 self.display(FBF_OUT_CALLS)
693 def display(self, which=config.plugins.FritzCall.fbfCalls.value):
694 debug("[FritzDisplayCalls] display")
695 config.plugins.FritzCall.fbfCalls.value = which
696 config.plugins.FritzCall.fbfCalls.save()
697 self.header = fbfCallsChoices[which]
698 fritzbox.getCalls(self, self.gotCalls, which)
700 def gotCalls(self, callList):
701 debug("[FritzDisplayCalls] gotCalls")
702 self.updateStatus(self.header + " (" + str(len(callList)) + ")")
704 for (number, date, remote, direct, here) in callList:
705 found = re.match("(\d\d.\d\d.)\d\d( \d\d:\d\d)", date)
706 if found: date = found.group(1) + found.group(2)
707 if direct == FBF_OUT_CALLS:
708 dir = LoadPixmap(resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/images/callout.png"))
709 elif direct == FBF_IN_CALLS:
710 dir = LoadPixmap(resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/images/callin.png"))
712 dir = LoadPixmap(resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/images/callinfailed.png"))
713 dateFieldWidth = scaleH(150,100)
715 remoteFieldWidth = scaleH(250,100)
716 scrollbarWidth = scaleH(90,45)
717 fieldWidth = self.width -dateFieldWidth -5 -dirFieldWidth -5 -remoteFieldWidth -scrollbarWidth -5
718 # debug("[FritzDisplayCalls] gotCalls: d: %d; f: %d; d: %d; r: %d" %(dateFieldWidth, fieldWidth, dirFieldWidth, remoteFieldWidth))
719 sortlist.append([number,
720 (eListboxPythonMultiContent.TYPE_TEXT, 0, 0, dateFieldWidth, scaleV(24,20), 0, RT_HALIGN_LEFT, date),
721 (eListboxPythonMultiContent.TYPE_PIXMAP_ALPHATEST, dateFieldWidth+5, 0, dirFieldWidth, 16, dir),
722 (eListboxPythonMultiContent.TYPE_TEXT, dateFieldWidth+5+dirFieldWidth+5, 0, fieldWidth, scaleV(24,20), 0, RT_HALIGN_LEFT, here),
723 (eListboxPythonMultiContent.TYPE_TEXT, dateFieldWidth+5+dirFieldWidth+5+fieldWidth+5, 0, remoteFieldWidth, scaleV(24,20), 0, RT_HALIGN_RIGHT, remote)
726 self["entries"].setList(sortlist)
728 def updateStatus(self, text):
729 self["statusbar"].setText(text)
732 debug("[FritzDisplayCalls] showEntry")
733 cur = self["entries"].getCurrent()
736 debug("[FritzDisplayCalls] showEntry %s" % (cur[0]))
738 fullname = phonebook.search(cur[0])
740 # we have a name for this number
742 self.session.open(FritzOfferAction, self, number, name)
745 self.session.open(FritzOfferAction, self, number)
747 # we do not even have a number...
748 self.session.open(MessageBox,
750 type=MessageBox.TYPE_INFO)
753 class FritzOfferAction(Screen):
754 # TRANSLATORS: this is a window title. Avoid the use of non ascii chars
755 width = 430 # = 5 + 3x140 + 5; 3 Buttons
756 height = 176 # = 5 + 126 + 40 + 5; 6 lines of text possible
758 <screen name="FritzOfferAction" position="%d,%d" size="%d,%d" title="%s" >
759 <widget name="text" position="5,5" size="%d,%d" font="Regular;21" />
760 <ePixmap position="5,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
761 <ePixmap position="145,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
762 <ePixmap position="285,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
763 <widget name="key_red" position="5,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
764 <widget name="key_green" position="145,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
765 <widget name="key_yellow" position="285,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
767 (DESKTOP_WIDTH - width) / 2,
768 (DESKTOP_HEIGHT - height) / 2,
774 height - 5 - 40, height - 5 - 40, height - 5 - 40, height - 5 - 40, height - 5 - 40, height - 5 - 40 # Buttons
777 def __init__(self, session, parent, number, name=""):
778 debug("[FritzOfferAction] init: %s, %s" %(number, name))
779 Screen.__init__(self, session)
781 # TRANSLATORS: keep it short, this is a button
782 self["key_red"] = Button(_("Lookup"))
783 # TRANSLATORS: keep it short, this is a button
784 self["key_green"] = Button(_("Call"))
785 # TRANSLATORS: keep it short, this is a button
786 self["key_yellow"] = Button(_("Save"))
787 # TRANSLATORS: keep it short, this is a button
788 # self["key_blue"] = Button(_("Search"))
790 self["FritzOfferActions"] = ActionMap(["OkCancelActions", "ColorActions"],
796 "ok": self.exit, }, - 2)
798 self["text"] = Label(number + "\n\n" + name.replace(", ", "\n"))
799 self.actualNumber = number
800 self.actualName = name.replace("\n", ", ")
805 phonebookLocation = config.plugins.FritzCall.phonebookLocation.value
806 if self.lookupState == 0:
808 self["text"].setText(self.actualNumber + "\n\n" + _("Reverse searching..."))
809 ReverseLookupAndNotifier(self.actualNumber, self.lookedUp, "UTF-8", config.plugins.FritzCall.country.value)
811 if self.lookupState == 1 and os.path.exists(phonebookLocation + "/PhoneBook.csv"):
812 self["text"].setText(self.actualNumber + "\n\n" + _("Searching in Outlook export..."))
814 self.lookedUp(self.actualNumber, FritzOutlookCSV.findNumber(self.actualNumber, phonebookLocation + "/PhoneBook.csv")) #@UndefinedVariable
818 if self.lookupState == 2 and os.path.exists(phonebookLocation + "/PhoneBook.ldif"):
819 self["text"].setText(self.actualNumber + "\n\n" + _("Searching in LDIF..."))
821 FritzLDIF.findNumber(self.actualNumber, open(phonebookLocation + "/PhoneBook.ldif"), self.lookedUp)
827 def lookedUp(self, number, name):
829 if self.lookupState == 1:
830 name = _("No result from reverse lookup")
831 elif self.lookupState == 2:
832 name = _("No result from Outlook export")
834 name = _("No result from LDIF")
835 self.actualNumber = number
836 self.actualName = name
837 message = number + "\n\n" + name.replace(", ", "\n")
838 self["text"].setText(str(message))
841 debug("[FritzOfferAction] add: %s" %self.actualNumber)
842 fritzbox.dial(self.actualNumber)
846 debug("[FritzOfferAction] add: %s, %s" %(self.actualNumber, self.actualName))
847 phonebook.FritzDisplayPhonebook(self.session).add(self.parent, self.actualNumber, self.actualName)
854 class FritzCallPhonebook:
856 debug("[FritzCallPhonebook] init")
857 # Beware: strings in phonebook.phonebook have to be in utf-8!
862 debug("[FritzCallPhonebook] reload")
863 # Beware: strings in phonebook.phonebook have to be in utf-8!
866 if not config.plugins.FritzCall.enable.value:
869 phonebookFilename = config.plugins.FritzCall.phonebookLocation.value + "/PhoneBook.txt"
870 if config.plugins.FritzCall.phonebook.value and os.path.exists(phonebookFilename):
871 debug("[FritzCallPhonebook] reload: read " + phonebookFilename)
872 phonebookTxtCorrupt = False
873 for line in open(phonebookFilename):
875 # Beware: strings in phonebook.phonebook have to be in utf-8!
876 line = line.decode("utf-8")
877 except UnicodeDecodeError: # this is just for the case, somebody wrote latin1 chars into PhoneBook.txt
879 line = line.decode("iso-8859-1")
880 debug("[FritzCallPhonebook] Fallback to ISO-8859-1 in %s" % line)
881 phonebookTxtCorrupt = True
883 debug("[FritzCallPhonebook] Could not parse internal Phonebook Entry %s" % line)
884 phonebookTxtCorrupt = True
885 line = line.encode("utf-8")
886 if re.match("^\d+#.*$", line):
888 number, name = line.split("#")
889 if not self.phonebook.has_key(number):
890 # Beware: strings in phonebook.phonebook have to be in utf-8!
891 self.phonebook[number] = name
892 except ValueError: # how could this possibly happen?!?!
893 debug("[FritzCallPhonebook] Could not parse internal Phonebook Entry %s" % line)
894 phonebookTxtCorrupt = True
896 debug("[FritzCallPhonebook] Could not parse internal Phonebook Entry %s" % line)
897 phonebookTxtCorrupt = True
899 if phonebookTxtCorrupt:
900 # dump phonebook to PhoneBook.txt
901 debug("[FritzCallPhonebook] dump Phonebook.txt")
902 os.rename(phonebookFilename, phonebookFilename + ".bck")
903 fNew = open(phonebookFilename, 'w')
904 # Beware: strings in phonebook.phonebook are utf-8!
905 for (number, name) in self.phonebook.iteritems():
906 # Beware: strings in PhoneBook.txt have to be in utf-8!
907 fNew.write(number + "#" + name.encode("utf-8"))
910 #===============================================================================
912 # # read entries from Outlook export
914 # # not reliable with coding yet
916 # # import csv exported from Outlook 2007 with csv(Windows)
917 # csvFilename = "/tmp/PhoneBook.csv"
918 # if config.plugins.FritzCall.phonebook.value and os.path.exists(csvFilename):
920 # readOutlookCSV(csvFilename, self.add)
921 # os.rename(csvFilename, csvFilename + ".done")
922 # except ImportError:
923 # debug("[FritzCallPhonebook] CSV import failed" %line)
924 #===============================================================================
927 #===============================================================================
929 # # read entries from LDIF
931 # # import ldif exported from Thunderbird 2.0.0.19
932 # ldifFilename = "/tmp/PhoneBook.ldif"
933 # if config.plugins.FritzCall.phonebook.value and os.path.exists(ldifFilename):
935 # parser = MyLDIF(open(ldifFilename), self.add)
937 # os.rename(ldifFilename, ldifFilename + ".done")
938 # except ImportError:
939 # debug("[FritzCallPhonebook] LDIF import failed" %line)
940 #===============================================================================
942 if config.plugins.FritzCall.fritzphonebook.value:
943 fritzbox.loadFritzBoxPhonebook()
945 if DESKTOP_WIDTH <> 1280 or DESKTOP_HEIGHT <> 720:
946 config.plugins.FritzCall.fullscreen.value = False
948 def search(self, number):
949 # debug("[FritzCallPhonebook] Searching for %s" %number
951 if config.plugins.FritzCall.phonebook.value or config.plugins.FritzCall.fritzphonebook.value:
952 if self.phonebook.has_key(number):
953 name = self.phonebook[number].replace(", ", "\n").strip()
956 def add(self, number, name):
959 @param number: number of entry
960 @param name: name of entry, has to be in utf-8
962 debug("[FritzCallPhonebook] add")
963 name = name.replace("\n", ", ").replace('#','') # this is just for safety reasons. add should only be called with newlines converted into commas
965 self.phonebook[number] = name;
966 if number and number <> 0:
967 if config.plugins.FritzCall.phonebook.value:
969 name = name.strip() + "\n"
970 string = "%s#%s" % (number, name)
971 # Beware: strings in PhoneBook.txt have to be in utf-8!
972 f = open(config.plugins.FritzCall.phonebookLocation.value + "/PhoneBook.txt", 'a')
975 debug("[FritzCallPhonebook] added %s with %s to Phonebook.txt" % (number, name.strip()))
981 def remove(self, number):
982 if number in self.phonebook:
983 debug("[FritzCallPhonebook] remove entry in phonebook")
984 del self.phonebook[number]
985 if config.plugins.FritzCall.phonebook.value:
987 phonebookFilename = config.plugins.FritzCall.phonebookLocation.value + "/PhoneBook.txt"
988 debug("[FritzCallPhonebook] remove entry in Phonebook.txt")
989 fOld = open(phonebookFilename, 'r')
990 fNew = open(phonebookFilename + str(os.getpid()), 'w')
991 line = fOld.readline()
993 if not re.match("^" + number + "#.*$", line):
995 line = fOld.readline()
998 os.remove(phonebookFilename)
999 os.rename(phonebookFilename + str(os.getpid()), phonebookFilename)
1000 debug("[FritzCallPhonebook] removed %s from Phonebook.txt" % number)
1007 class FritzDisplayPhonebook(Screen, HelpableScreen, NumericalTextInput):
1009 def __init__(self, session):
1010 if config.plugins.FritzCall.fullscreen.value:
1011 self.width = DESKTOP_WIDTH
1012 self.height = DESKTOP_HEIGHT
1014 if os.path.exists(resolveFilename(SCOPE_SKIN_IMAGE, DESKTOP_SKIN + "/menu/back-main.png")):
1015 backMainPng = DESKTOP_SKIN + "/menu/back-main.png"
1016 elif os.path.exists(resolveFilename(SCOPE_SKIN_IMAGE, "Kerni-HD1/menu/back-main.png")):
1017 backMainPng = "Kerni-HD1/menu/back-main.png"
1019 backMainLine = """<ePixmap position="0,0" zPosition="-10" size="%d,%d" pixmap="%s" transparent="1" />""" % (self.width, self.height, backMainPng)
1022 debug("[FritzDisplayPhonebook] backMainLine: " + backMainLine)
1024 # TRANSLATORS: this is a window title. Avoid the use of non ascii chars
1026 <screen name="FritzdisplayPhonebook" position="0,0" size="%d,%d" title="%s" flags="wfNoBorder">
1028 <widget source="global.CurrentTime" render="Label" position="%d,%d" size="%d,%d" font="Regular;%d" halign="right" backgroundColor="#0b67a2" transparent="1">
1029 <convert type="ClockToText">Default</convert>
1031 <widget source="global.CurrentTime" render="Label" position="%d,%d" size="%d,%d" font="Regular;%d" halign="right" backgroundColor="#0b67a2" transparent="1">
1032 <convert type="ClockToText">Date</convert>
1034 <eLabel text="%s" position="%d,%d" size="%d,%d" font="Regular;%d" halign="center" backgroundColor="#0b67a2" transparent="1"/>
1036 <widget name="entries" position="%d,%d" size="%d,%d" scrollbarMode="showOnDemand" transparent="1" />
1038 <ePixmap pixmap="skin_default/buttons/red.png" position="%d,%d" size="%d,%d" alphatest="on" />
1039 <ePixmap pixmap="skin_default/buttons/green.png" position="%d,%d" size="%d,%d" alphatest="on" />
1040 <ePixmap pixmap="skin_default/buttons/yellow.png" position="%d,%d" size="%d,%d" alphatest="on" />
1041 <ePixmap pixmap="skin_default/buttons/blue.png" position="%d,%d" size="%d,%d" alphatest="on" />
1042 <widget name="key_red" position="%d,%d" size="%d,%d" zPosition="1" font="Regular;%d" halign="left" backgroundColor="black" transparent="1" />
1043 <widget name="key_green" position="%d,%d" size="%d,%d" zPosition="1" font="Regular;%d" halign="left" backgroundColor="black" transparent="1" />
1044 <widget name="key_yellow" position="%d,%d" size="%d,%d" zPosition="1" font="Regular;%d" halign="left" backgroundColor="black" transparent="1" />
1045 <widget name="key_blue" position="%d,%d" size="%d,%d" zPosition="1" font="Regular;%d" halign="left" backgroundColor="black" transparent="1" />
1046 <ePixmap position="%d,%d" size="%d,%d" zPosition="2" pixmap="%s" transparent="1" alphatest="blend" />
1048 self.width, self.height, _("Phonebook"),
1050 scaleH(1130, XXX), scaleV(40, XXX), scaleH(80, XXX), scaleV(26, XXX), scaleV(26, XXX), # time
1051 scaleH(900, XXX), scaleV(70, XXX), scaleH(310, XXX), scaleV(22, XXX), scaleV(20, XXX), # date
1052 "FritzCall " + _("Phonebook"), scaleH(80, XXX), scaleV(63, XXX), scaleH(300, XXX), scaleV(30, XXX), scaleV(27, XXX), # eLabel
1053 scaleH(420, XXX), scaleV(120, XXX), scaleH(790, XXX), scaleV(438, XXX), # entries
1054 scaleH(450, XXX), scaleV(588, XXX), scaleH(21, XXX), scaleV(21, XXX), # red
1055 scaleH(640, XXX), scaleV(588, XXX), scaleH(21, XXX), scaleV(21, XXX), # green
1056 scaleH(830, XXX), scaleV(588, XXX), scaleH(21, XXX), scaleV(21, XXX), # yellow
1057 scaleH(1020, XXX), scaleV(588, XXX), scaleH(21, XXX), scaleV(21, XXX), # blue
1058 scaleH(480, XXX), scaleV(587, XXX), scaleH(160, XXX), scaleV(22, XXX), scaleV(20, XXX), # red
1059 scaleH(670, XXX), scaleV(587, XXX), scaleH(160, XXX), scaleV(22, XXX), scaleV(20, XXX), # green
1060 scaleH(860, XXX), scaleV(587, XXX), scaleH(160, XXX), scaleV(22, XXX), scaleV(20, XXX), # yellow
1061 scaleH(1050, XXX), scaleV(587, XXX), scaleH(160, XXX), scaleV(22, XXX), scaleV(20, XXX), # blue
1062 scaleH(120, XXX), scaleV(430, XXX), scaleH(150, XXX), scaleV(110, XXX), resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/images/fritz.png") # Fritz Logo size and pixmap
1065 self.width = scaleH(1100, 570)
1066 debug("[FritzDisplayPhonebook] width: " + str(self.width))
1067 # TRANSLATORS: this is a window title. Avoid the use of non ascii chars
1069 <screen name="FritzDisplayPhonebook" position="%d,%d" size="%d,%d" title="%s" >
1070 <eLabel position="0,0" size="%d,2" backgroundColor="#aaaaaa" />
1071 <widget name="entries" position="%d,%d" size="%d,%d" scrollbarMode="showOnDemand" backgroundColor="#20040404" transparent="1" />
1072 <eLabel position="0,%d" size="%d,2" backgroundColor="#aaaaaa" />
1073 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
1074 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
1075 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
1076 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/blue.png" transparent="1" alphatest="on" />
1077 <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" />
1078 <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" />
1079 <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" />
1080 <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" />
1082 scaleH(90, 75), scaleV(100, 73), # position
1083 scaleH(1100, 570), scaleV(560, 430), # size
1085 scaleH(1100, 570), # eLabel width
1086 scaleH(40, 5), scaleV(20, 5), # entries position
1087 scaleH(1040, 560), scaleV(488, 380), # entries size
1088 scaleV(518, 390), # eLabel position vertical
1089 scaleH(1100, 570), # eLabel width
1090 scaleH(20, 5), scaleV(525, 395), # ePixmap red
1091 scaleH(290, 145), scaleV(525, 395), # ePixmap green
1092 scaleH(560, 285), scaleV(525, 395), # ePixmap yellow
1093 scaleH(830, 425), scaleV(525, 395), # ePixmap blue
1094 scaleH(20, 5), scaleV(525, 395), scaleV(24, 21), # widget red
1095 scaleH(290, 145), scaleV(525, 395), scaleV(24, 21), # widget green
1096 scaleH(560, 285), scaleV(525, 395), scaleV(24, 21), # widget yellow
1097 scaleH(830, 425), scaleV(525, 395), scaleV(24, 21), # widget blue
1100 Screen.__init__(self, session)
1101 NumericalTextInput.__init__(self)
1102 HelpableScreen.__init__(self)
1104 # TRANSLATORS: keep it short, this is a button
1105 self["key_red"] = Button(_("Delete"))
1106 # TRANSLATORS: keep it short, this is a button
1107 self["key_green"] = Button(_("New"))
1108 # TRANSLATORS: keep it short, this is a button
1109 self["key_yellow"] = Button(_("Edit"))
1110 # TRANSLATORS: keep it short, this is a button
1111 self["key_blue"] = Button(_("Search"))
1113 self["setupActions"] = ActionMap(["OkCancelActions", "ColorActions"],
1117 "yellow": self.edit,
1118 "blue": self.search,
1119 "cancel": self.exit,
1120 "ok": self.showEntry, }, - 2)
1122 # TRANSLATORS: this is a help text, keep it short
1123 self.helpList.append((self["setupActions"], "OkCancelActions", [("ok", _("Show details of entry"))]))
1124 # TRANSLATORS: this is a help text, keep it short
1125 self.helpList.append((self["setupActions"], "OkCancelActions", [("cancel", _("Quit"))]))
1126 # TRANSLATORS: this is a help text, keep it short
1127 self.helpList.append((self["setupActions"], "ColorActions", [("red", _("Delete entry"))]))
1128 # TRANSLATORS: this is a help text, keep it short
1129 self.helpList.append((self["setupActions"], "ColorActions", [("green", _("Add entry to phonebook"))]))
1130 # TRANSLATORS: this is a help text, keep it short
1131 self.helpList.append((self["setupActions"], "ColorActions", [("yellow", _("Edit selected entry"))]))
1132 # TRANSLATORS: this is a help text, keep it short
1133 self.helpList.append((self["setupActions"], "ColorActions", [("blue", _("Search (case insensitive)"))]))
1135 self["entries"] = MenuList([], True, content=eListboxPythonMultiContent)
1136 fontSize = scaleV(22, 18)
1137 fontHeight = scaleV(24, 20)
1138 self["entries"].l.setFont(0, gFont("Regular", fontSize))
1139 self["entries"].l.setItemHeight(fontHeight)
1140 debug("[FritzCallPhonebook] displayPhonebook init")
1143 def display(self, filter=""):
1144 debug("[FritzCallPhonebook] displayPhonebook/display")
1146 # Beware: strings in phonebook.phonebook are utf-8!
1147 sortlistHelp = sorted((name.lower(), name, number) for (number, name) in phonebook.phonebook.iteritems())
1148 for (low, name, number) in sortlistHelp:
1149 if number == "01234567890":
1152 low = low.decode("utf-8")
1153 except (UnicodeDecodeError, UnicodeEncodeError): # this should definitely not happen
1155 low = low.decode("iso-8859-1")
1157 debug("[FritzCallPhonebook] displayPhonebook/display: corrupt phonebook entry for %s" % number)
1158 # self.session.open(MessageBox, _("Corrupt phonebook entry\nfor number %s\nDeleting.") %number, type = MessageBox.TYPE_ERROR)
1159 phonebook.remove(number)
1163 filter = filter.lower()
1164 if low.find(filter) == - 1:
1166 name = name.strip().decode("utf-8")
1167 number = number.strip().decode("utf-8")
1168 found = re.match("([^,]*),.*", name) # strip address information from the name part
1170 shortname = found.group(1)
1173 numberFieldWidth = scaleV(200,150)
1174 fieldWidth = self.width -5 -numberFieldWidth -10 -scaleH(90,45)
1175 number = number.encode("utf-8", "replace")
1176 name = name.encode("utf-8", "replace")
1177 shortname = shortname.encode('utf-8', 'replace')
1178 self.sortlist.append([(number,
1180 (eListboxPythonMultiContent.TYPE_TEXT, 0, 0, fieldWidth, scaleH(24,20), 0, RT_HALIGN_LEFT, shortname),
1181 (eListboxPythonMultiContent.TYPE_TEXT, fieldWidth +5, 0, numberFieldWidth, scaleH(24,20), 0, RT_HALIGN_LEFT, number)
1184 self["entries"].setList(self.sortlist)
1186 def showEntry(self):
1187 cur = self["entries"].getCurrent()
1189 debug("[FritzCallPhonebook] displayPhonebook/showEntry (%s,%s)" % (cur[0][0], cur[0][1]))
1192 self.session.open(FritzOfferAction, self, number, name)
1195 cur = self["entries"].getCurrent()
1197 debug("[FritzCallPhonebook] displayPhonebook/delete " + cur[0][0])
1198 self.session.openWithCallback(
1199 self.deleteConfirmed,
1201 _("Do you really want to delete entry for\n\n%(number)s\n\n%(name)s?")
1202 % { 'number':str(cur[0][0]), 'name':str(cur[0][1]).replace(", ", "\n") }
1205 self.session.open(MessageBox, _("No entry selected"), MessageBox.TYPE_INFO)
1207 def deleteConfirmed(self, ret):
1208 debug("[FritzCallPhonebook] displayPhonebook/deleteConfirmed")
1210 # if ret: delete number from sortlist, delete number from phonebook.phonebook and write it to disk
1212 cur = self["entries"].getCurrent()
1215 # delete number from sortlist, delete number from phonebook.phonebook and write it to disk
1216 debug("[FritzCallPhonebook] displayPhonebook/deleteConfirmed: remove " + cur[0][0])
1217 phonebook.remove(cur[0][0])
1220 # self.session.open(MessageBox, _("Not deleted."), MessageBox.TYPE_INFO)
1222 self.session.open(MessageBox, _("No entry selected"), MessageBox.TYPE_INFO)
1224 def add(self, parent=None, number="", name=""):
1225 class addScreen(Screen, ConfigListScreen):
1226 '''ConfiglistScreen with two ConfigTexts for Name and Number'''
1229 # TRANSLATORS: this is a window title. Avoid the use of non ascii chars
1231 <screen position="%d,%d" size="%d,%d" title="%s" >
1232 <widget name="config" position="5,5" size="%d,%d" scrollbarMode="showOnDemand" />
1233 <ePixmap position="145,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
1234 <ePixmap position="285,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
1235 <widget name="key_red" position="145,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
1236 <widget name="key_green" position="285,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
1238 (DESKTOP_WIDTH - width) / 2,
1239 (DESKTOP_HEIGHT - height) / 2,
1242 _("Add entry to phonebook"),
1244 height - 5 - 40 - 5,
1245 height - 40 - 5, height - 40 - 5, height - 40 - 5, height - 40 - 5
1249 def __init__(self, session, parent, number="", name=""):
1251 # setup screen with two ConfigText and OK and ABORT button
1253 Screen.__init__(self, session)
1254 self.session = session
1255 self.parent = parent
1256 # TRANSLATORS: keep it short, this is a button
1257 self["key_red"] = Button(_("Cancel"))
1258 # TRANSLATORS: keep it short, this is a button
1259 self["key_green"] = Button(_("OK"))
1260 self["setupActions"] = ActionMap(["SetupActions", "ColorActions"],
1262 "cancel": self.cancel,
1269 ConfigListScreen.__init__(self, self.list, session=session)
1270 config.plugins.FritzCall.name.value = name
1271 config.plugins.FritzCall.number.value = number
1272 self.list.append(getConfigListEntry(_("Name"), config.plugins.FritzCall.name))
1273 self.list.append(getConfigListEntry(_("Number"), config.plugins.FritzCall.number))
1274 self["config"].list = self.list
1275 self["config"].l.setList(self.list)
1278 # get texts from Screen
1279 # add (number,name) to sortlist and phonebook.phonebook and disk
1280 self.number = config.plugins.FritzCall.number.value
1281 self.name = config.plugins.FritzCall.name.value
1282 if not self.number or not self.name:
1283 self.session.open(MessageBox, _("Entry incomplete."), type=MessageBox.TYPE_ERROR)
1285 # add (number,name) to sortlist and phonebook.phonebook and disk
1286 # oldname = phonebook.search(self.number)
1288 # self.session.openWithCallback(
1289 # self.overwriteConfirmed,
1291 # _("Do you really want to overwrite entry for %(number)s\n\n%(name)s\n\nwith\n\n%(newname)s?")
1293 # 'number':self.number,
1295 # 'newname':self.name.replace(", ","\n")
1300 phonebook.add(self.number, self.name)
1302 self.parent.display()
1304 def overwriteConfirmed(self, ret):
1306 phonebook.remove(self.number)
1307 phonebook.add(self.number, self.name)
1308 self.parent.display()
1313 debug("[FritzCallPhonebook] displayPhonebook/add")
1316 self.session.open(addScreen, parent, number, name)
1319 debug("[FritzCallPhonebook] displayPhonebook/edit")
1320 cur = self["entries"].getCurrent()
1322 self.session.open(MessageBox, _("No entry selected"), MessageBox.TYPE_INFO)
1324 (number, name) = cur[0]
1325 self.add(self, number, name)
1328 debug("[FritzCallPhonebook] displayPhonebook/search")
1329 self.help_window = self.session.instantiateDialog(NumericalTextInputHelpDialog, self)
1330 self.help_window.show()
1331 self.session.openWithCallback(self.doSearch, InputBox, _("Enter Search Terms"), _("Search phonebook"))
1333 def doSearch(self, searchTerms):
1334 if not searchTerms: searchTerms = ""
1335 debug("[FritzCallPhonebook] displayPhonebook/doSearch: " + searchTerms)
1336 if self.help_window:
1337 self.session.deleteDialog(self.help_window)
1338 self.help_window = None
1339 self.display(searchTerms)
1344 phonebook = FritzCallPhonebook()
1347 class FritzCallSetup(Screen, ConfigListScreen, HelpableScreen):
1349 def __init__(self, session, args=None):
1350 if config.plugins.FritzCall.fullscreen.value:
1351 self.width = DESKTOP_WIDTH
1352 self.height = DESKTOP_HEIGHT
1355 if os.path.exists(resolveFilename(SCOPE_SKIN_IMAGE, DESKTOP_SKIN + "/menu/back-main.png")):
1356 backMainPng = DESKTOP_SKIN + "/menu/back-main.png"
1357 elif os.path.exists(resolveFilename(SCOPE_SKIN_IMAGE, "Kerni-HD1/menu/back-main.png")):
1358 backMainPng = "Kerni-HD1/menu/back-main.png"
1360 backMainLine = """<ePixmap position="0,0" zPosition="-10" size="%d,%d" pixmap="%s" transparent="1" />""" % (self.width, self.height, backMainPng)
1363 debug("[FritzCallSetup] backMainLine: " + backMainLine)
1364 # TRANSLATORS: this is a window title. Avoid the use of non ascii chars
1366 <screen name="FritzCallSetup" position="0,0" size="%d,%d" title="%s" flags="wfNoBorder">
1368 <widget source="global.CurrentTime" render="Label" position="%d,%d" size="%d,%d" font="Regular;%d" halign="right" backgroundColor="#0b67a2" transparent="1">
1369 <convert type="ClockToText">Default</convert>
1371 <widget source="global.CurrentTime" render="Label" position="%d,%d" size="%d,%d" font="Regular;%d" halign="right" backgroundColor="#0b67a2" transparent="1">
1372 <convert type="ClockToText">Date</convert>
1374 <eLabel text="%s" position="%d,%d" size="%d,%d" font="Regular;%d" halign="center" backgroundColor="#0b67a2" transparent="1"/>
1376 <widget name="consideration" position="%d,%d" size="%d,%d" font="Regular;%d" halign="center" backgroundColor="#353e575e" transparent="1" />
1377 <widget name="config" position="%d,%d" size="%d,%d" scrollbarMode="showOnDemand" transparent="1" />
1379 <ePixmap pixmap="skin_default/buttons/red.png" position="%d,%d" size="%d,%d" alphatest="on" />
1380 <ePixmap pixmap="skin_default/buttons/green.png" position="%d,%d" size="%d,%d" alphatest="on" />
1381 <ePixmap pixmap="skin_default/buttons/yellow.png" position="%d,%d" size="%d,%d" alphatest="on" />
1382 <ePixmap pixmap="skin_default/buttons/blue.png" position="%d,%d" size="%d,%d" alphatest="on" />
1383 <widget name="key_red" position="%d,%d" size="%d,%d" zPosition="1" font="Regular;%d" halign="left" backgroundColor="black" transparent="1" />
1384 <widget name="key_green" position="%d,%d" size="%d,%d" zPosition="1" font="Regular;%d" halign="left" backgroundColor="black" transparent="1" />
1385 <widget name="key_yellow" position="%d,%d" size="%d,%d" zPosition="1" font="Regular;%d" halign="left" backgroundColor="black" transparent="1" />
1386 <widget name="key_blue" position="%d,%d" size="%d,%d" zPosition="1" font="Regular;%d" halign="left" backgroundColor="black" transparent="1" />
1387 <ePixmap position="%d,%d" size="%d,%d" zPosition="2" pixmap="%s" transparent="1" alphatest="blend" />
1389 self.width, self.height, _("FritzCall Setup"),
1391 scaleH(1130, XXX), scaleV(40, XXX), scaleH(80, XXX), scaleV(26, XXX), scaleV(26, XXX), # time
1392 scaleH(900, XXX), scaleV(70, XXX), scaleH(310, XXX), scaleV(22, XXX), scaleV(20, XXX), # date
1393 _("FritzCall Setup"), scaleH(500, XXX), scaleV(63, XXX), scaleH(330, XXX), scaleV(30, XXX), scaleV(27, XXX), # eLabel
1394 scaleH(80, XXX), scaleV(150, XXX), scaleH(250, XXX), scaleV(200, XXX), scaleV(22, XXX), # consideration
1395 scaleH(420, XXX), scaleV(125, XXX), scaleH(790, XXX), scaleV(428, XXX), # config
1396 scaleH(450, XXX), scaleV(588, XXX), scaleH(21, XXX), scaleV(21, XXX), # red
1397 scaleH(640, XXX), scaleV(588, XXX), scaleH(21, XXX), scaleV(21, XXX), # green
1398 scaleH(830, XXX), scaleV(588, XXX), scaleH(21, XXX), scaleV(21, XXX), # yellow
1399 scaleH(1020, XXX), scaleV(588, XXX), scaleH(21, XXX), scaleV(21, XXX), # blue
1400 scaleH(480, XXX), scaleV(587, XXX), scaleH(160, XXX), scaleV(22, XXX), scaleV(20, XXX), # red
1401 scaleH(670, XXX), scaleV(587, XXX), scaleH(160, XXX), scaleV(22, XXX), scaleV(20, XXX), # green
1402 scaleH(860, XXX), scaleV(587, XXX), scaleH(160, XXX), scaleV(22, XXX), scaleV(20, XXX), # yellow
1403 scaleH(1050, XXX), scaleV(587, XXX), scaleH(160, XXX), scaleV(22, XXX), scaleV(20, XXX), # blue
1404 scaleH(120, XXX), scaleV(430, XXX), scaleH(150, XXX), scaleV(110, XXX), resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/images/fritz.png") # Fritz Logo size and pixmap
1407 self.width = scaleH(1100, 570)
1408 debug("[FritzCallSetup] width: " + str(self.width))
1409 # TRANSLATORS: this is a window title. Avoid the use of non ascii chars
1411 <screen name="FritzCallSetup" position="%d,%d" size="%d,%d" title="%s" >
1412 <eLabel position="0,0" size="%d,2" backgroundColor="#aaaaaa" />
1413 <widget name="consideration" position="%d,%d" halign="center" size="%d,%d" font="Regular;%d" backgroundColor="#20040404" transparent="1" />
1414 <eLabel position="0,%d" size="%d,2" backgroundColor="#aaaaaa" />
1415 <widget name="config" position="%d,%d" size="%d,%d" scrollbarMode="showOnDemand" backgroundColor="#20040404" transparent="1" />
1416 <eLabel position="0,%d" size="%d,2" backgroundColor="#aaaaaa" />
1417 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
1418 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
1419 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
1420 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/blue.png" transparent="1" alphatest="on" />
1421 <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" />
1422 <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" />
1423 <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" />
1424 <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" />
1426 scaleH(90, 75), scaleV(100, 73), # position
1427 scaleH(1100, 570), scaleV(560, 430), # size
1428 _("FritzCall Setup") +
1429 " (" + "$Revision$"[1: - 1] +
1430 "$Date$"[7:23] + ")",
1431 scaleH(1100, 570), # eLabel width
1432 scaleH(40, 20), scaleV(10, 5), # consideration position
1433 scaleH(1050, 530), scaleV(25, 45), # consideration size
1434 scaleV(22, 20), # consideration font size
1435 scaleV(40, 50), # eLabel position vertical
1436 scaleH(1100, 570), # eLabel width
1437 scaleH(40, 5), scaleV(60, 57), # config position
1438 scaleH(1040, 560), scaleV(453, 328), # config size
1439 scaleV(518, 390), # eLabel position vertical
1440 scaleH(1100, 570), # eLabel width
1441 scaleH(20, 5), scaleV(525, 395), # widget red
1442 scaleH(290, 145), scaleV(525, 395), # widget green
1443 scaleH(560, 285), scaleV(525, 395), # widget yellow
1444 scaleH(830, 425), scaleV(525, 395), # widget blue
1445 scaleH(20, 5), scaleV(525, 395), scaleV(24, 21), # widget red
1446 scaleH(290, 145), scaleV(525, 395), scaleV(24, 21), # widget green
1447 scaleH(560, 285), scaleV(525, 395), scaleV(24, 21), # widget yellow
1448 scaleH(830, 425), scaleV(525, 395), scaleV(24, 21), # widget blue
1451 Screen.__init__(self, session)
1452 HelpableScreen.__init__(self)
1453 self.session = session
1455 self["consideration"] = Label(_("You need to enable the monitoring on your FRITZ!Box by dialing #96*5*!"))
1458 # Initialize Buttons
1459 # TRANSLATORS: keep it short, this is a button
1460 self["key_red"] = Button(_("Cancel"))
1461 # TRANSLATORS: keep it short, this is a button
1462 self["key_green"] = Button(_("OK"))
1463 # TRANSLATORS: keep it short, this is a button
1464 self["key_yellow"] = Button(_("Phone calls"))
1465 # TRANSLATORS: keep it short, this is a button
1466 self["key_blue"] = Button(_("Phonebook"))
1468 self["setupActions"] = ActionMap(["SetupActions", "ColorActions", "MenuActions"],
1472 "yellow": self.displayCalls,
1473 "blue": self.displayPhonebook,
1474 "cancel": self.cancel,
1481 # TRANSLATORS: this is a help text, keep it short
1482 self.helpList.append((self["setupActions"], "SetupActions", [("ok", _("save and quit"))]))
1483 # TRANSLATORS: this is a help text, keep it short
1484 self.helpList.append((self["setupActions"], "SetupActions", [("save", _("save and quit"))]))
1485 # TRANSLATORS: this is a help text, keep it short
1486 self.helpList.append((self["setupActions"], "SetupActions", [("cancel", _("quit"))]))
1487 # TRANSLATORS: this is a help text, keep it short
1488 self.helpList.append((self["setupActions"], "ColorActions", [("red", _("quit"))]))
1489 # TRANSLATORS: this is a help text, keep it short
1490 self.helpList.append((self["setupActions"], "ColorActions", [("green", _("save and quit"))]))
1491 # TRANSLATORS: this is a help text, keep it short
1492 self.helpList.append((self["setupActions"], "ColorActions", [("yellow", _("display calls"))]))
1493 # TRANSLATORS: this is a help text, keep it short
1494 self.helpList.append((self["setupActions"], "ColorActions", [("blue", _("display phonebook"))]))
1495 # TRANSLATORS: this is a help text, keep it short
1496 self.helpList.append((self["setupActions"], "MenuActions", [("info", _("About FritzCall"))]))
1497 # TRANSLATORS: this is a help text, keep it short
1498 self.helpList.append((self["setupActions"], "MenuActions", [("menu", _("About FritzCall"))]))
1500 ConfigListScreen.__init__(self, self.list, session=session)
1505 ConfigListScreen.keyLeft(self)
1509 ConfigListScreen.keyRight(self)
1512 def createSetup(self):
1514 self.list.append(getConfigListEntry(_("Call monitoring"), config.plugins.FritzCall.enable))
1515 if config.plugins.FritzCall.enable.value:
1516 self.list.append(getConfigListEntry(_("Mute on call"), config.plugins.FritzCall.muteOnCall))
1517 self.list.append(getConfigListEntry(_("FRITZ!Box FON address (Name or IP)"), config.plugins.FritzCall.hostname))
1519 self.list.append(getConfigListEntry(_("Show after Standby"), config.plugins.FritzCall.afterStandby))
1521 self.list.append(getConfigListEntry(_("Show Calls for specific MSN"), config.plugins.FritzCall.filter))
1522 if config.plugins.FritzCall.filter.value:
1523 self.list.append(getConfigListEntry(_("MSN to show (separated by ,)"), config.plugins.FritzCall.filtermsn))
1525 self.list.append(getConfigListEntry(_("Show Outgoing Calls"), config.plugins.FritzCall.showOutgoing))
1526 if config.plugins.FritzCall.showOutgoing.value:
1527 self.list.append(getConfigListEntry(_("Areacode to add to Outgoing Calls (if necessary)"), config.plugins.FritzCall.prefix))
1528 self.list.append(getConfigListEntry(_("Timeout for Call Notifications (seconds)"), config.plugins.FritzCall.timeout))
1529 self.list.append(getConfigListEntry(_("Reverse Lookup Caller ID (select country below)"), config.plugins.FritzCall.lookup))
1530 if config.plugins.FritzCall.lookup.value:
1531 self.list.append(getConfigListEntry(_("Country"), config.plugins.FritzCall.country))
1533 self.list.append(getConfigListEntry(_("Password Accessing FRITZ!Box"), config.plugins.FritzCall.password))
1534 self.list.append(getConfigListEntry(_("Extension number to initiate call on"), config.plugins.FritzCall.extension))
1535 self.list.append(getConfigListEntry(_("Read PhoneBook from FRITZ!Box"), config.plugins.FritzCall.fritzphonebook))
1536 if config.plugins.FritzCall.fritzphonebook.value:
1537 self.list.append(getConfigListEntry(_("Append type of number"), config.plugins.FritzCall.showType))
1538 self.list.append(getConfigListEntry(_("Append shortcut number"), config.plugins.FritzCall.showShortcut))
1539 self.list.append(getConfigListEntry(_("Append vanity name"), config.plugins.FritzCall.showVanity))
1541 self.list.append(getConfigListEntry(_("Use internal PhoneBook"), config.plugins.FritzCall.phonebook))
1542 if config.plugins.FritzCall.phonebook.value:
1543 self.list.append(getConfigListEntry(_("PhoneBook Location"), config.plugins.FritzCall.phonebookLocation))
1544 if config.plugins.FritzCall.lookup.value:
1545 self.list.append(getConfigListEntry(_("Automatically add new Caller to PhoneBook"), config.plugins.FritzCall.addcallers))
1547 self.list.append(getConfigListEntry(_("Strip Leading 0"), config.plugins.FritzCall.internal))
1548 # self.list.append(getConfigListEntry(_("Default display mode for FRITZ!Box calls"), config.plugins.FritzCall.fbfCalls))
1549 if DESKTOP_WIDTH == 1280 and DESKTOP_HEIGHT == 720:
1550 self.list.append(getConfigListEntry(_("Full screen display"), config.plugins.FritzCall.fullscreen))
1551 self.list.append(getConfigListEntry(_("Debug"), config.plugins.FritzCall.debug))
1553 self["config"].list = self.list
1554 self["config"].l.setList(self.list)
1557 # debug("[FritzCallSetup] save"
1558 for x in self["config"].list:
1560 if fritz_call is not None:
1561 fritz_call.connect()
1562 debug("[FritzCallSetup] called phonebook.reload()")
1567 # debug("[FritzCallSetup] cancel"
1568 for x in self["config"].list:
1572 def displayCalls(self):
1573 self.session.open(FritzDisplayCalls)
1575 def displayPhonebook(self):
1576 self.session.open(phonebook.FritzDisplayPhonebook)
1579 self.session.open(FritzAbout)
1584 class FritzCallList:
1588 def add(self, event, date, number, caller, phone):
1589 debug("[FritzCallList] add")
1590 if len(self.callList) > 10:
1591 if self.callList[0] != "Start":
1592 self.callList[0] = "Start"
1593 del self.callList[1]
1595 self.callList.append((event, number, date, caller, phone))
1598 debug("[FritzCallList] display")
1600 global my_global_session
1602 # Standby.inStandby.onClose.remove(self.display) object does not exist anymore...
1603 # build screen from call list
1605 if self.callList[0] == "Start":
1606 text = text + _("Last 10 calls:\n")
1607 del self.callList[0]
1609 for call in self.callList:
1610 (event, number, date, caller, phone) = call
1616 # shorten the date info
1617 found = re.match(".*(\d\d.\d\d.)\d\d( \d\d:\d\d)", date)
1618 if found: date = found.group(1) + found.group(2)
1620 # our phone could be of the form "0123456789 (home)", then we only take "home"
1621 found = re.match(".*\((.*)\)", phone)
1622 if found: phone = found.group(1)
1624 # if we have an unknown number, show the number
1625 if caller == _("UNKNOWN") and number != "":
1628 # strip off the address part of the remote number, if there is any
1629 found = re.match("(.*)\n.*", caller)
1630 if found: caller = found.group(1)
1632 while (len(caller) + len(phone)) > 40:
1633 if len(caller) > len(phone):
1634 caller = caller[: - 1]
1636 phone = phone[: - 1]
1638 text = text + "%s %s %s %s\n" % (date, caller, direction, phone)
1640 debug("[FritzCallList] display: '%s %s %s %s'" % (date, caller, direction, phone))
1642 Notifications.AddNotification(MessageBox, text, type=MessageBox.TYPE_INFO)
1643 # my_global_session.open(FritzDisplayCalls, text) # TODO please HELP: from where can I get a session?
1647 callList = FritzCallList()
1649 from GlobalActions import globalActionMap #@UnresolvedImport
1650 def notifyCall(event, date, number, caller, phone):
1651 if Standby.inStandby is None or config.plugins.FritzCall.afterStandby.value == "each":
1652 if config.plugins.FritzCall.muteOnCall.value:
1653 globalActionMap.actions["volumeMute"]()
1655 text = _("Incoming Call on %(date)s from\n---------------------------------------------\n%(number)s\n%(caller)s\n---------------------------------------------\nto: %(phone)s") % { 'date':date, 'number':number, 'caller':caller, 'phone':phone }
1657 text = _("Outgoing Call on %(date)s to\n---------------------------------------------\n%(number)s\n%(caller)s\n---------------------------------------------\nfrom: %(phone)s") % { 'date':date, 'number':number, 'caller':caller, 'phone':phone }
1658 debug("[FritzCall] notifyCall:\n%s" % text)
1659 Notifications.AddNotification(MessageBox, text, type=MessageBox.TYPE_INFO, timeout=config.plugins.FritzCall.timeout.value)
1660 elif config.plugins.FritzCall.afterStandby.value == "inList":
1662 # if not yet done, register function to show call list
1664 if not standbyMode :
1666 Standby.inStandby.onHide.append(callList.display)
1667 # add text/timeout to call list
1668 callList.add(event, date, number, caller, phone)
1669 debug("[FritzCall] notifyCall: added to callList")
1670 else: # this is the "None" case
1671 debug("[FritzCall] notifyCall: standby and no show")
1674 #===============================================================================
1675 # We need a separate class for each invocation of reverseLookup to retain
1676 # the necessary data for the notification
1677 #===============================================================================
1680 reverselookupMtime = 0
1682 class FritzReverseLookupAndNotifier:
1683 def __init__(self, event, number, caller, phone, date):
1686 Initiate a reverse lookup for the given number in the configured country
1688 @param event: CALL or RING
1689 @param number: number to be looked up
1690 @param caller: caller including name and address
1691 @param phone: Number (and name) of or own phone
1692 @param date: date of call
1694 debug("[FritzReverseLookupAndNotifier] reverse Lookup for %s!" % number)
1696 self.number = number
1697 self.caller = caller
1701 if number[0] != "0":
1702 self.notifyAndReset(number, caller)
1705 ReverseLookupAndNotifier(number, self.notifyAndReset, "UTF-8", config.plugins.FritzCall.country.value)
1707 def notifyAndReset(self, number, caller):
1710 this gets called with the result of the reverse lookup
1712 @param number: number
1713 @param caller: name and address of remote. it comes in with name, address and city separated by commas
1715 debug("[FritzReverseLookupAndNotifier] got: " + caller)
1716 #===============================================================================
1717 # if not caller and os.path.exists(config.plugins.FritzCall.phonebookLocation.value + "/PhoneBook.csv"):
1718 # caller = FritzOutlookCSV.findNumber(number, config.plugins.FritzCall.phonebookLocation.value + "/PhoneBook.csv") #@UndefinedVariable
1719 # debug("[FritzReverseLookupAndNotifier] got from Outlook csv: " + caller)
1720 #===============================================================================
1721 #===============================================================================
1722 # if not caller and os.path.exists(config.plugins.FritzCall.phonebookLocation.value + "/PhoneBook.ldif"):
1723 # caller = FritzLDIF.findNumber(number, open(config.plugins.FritzCall.phonebookLocation.value + "/PhoneBook.ldif"))
1724 # debug("[FritzReverseLookupAndNotifier] got from ldif: " + caller)
1725 #===============================================================================
1728 self.caller = caller.replace(", ", "\n").replace('#','')
1729 if self.number != 0 and config.plugins.FritzCall.addcallers.value and self.event == "RING":
1730 debug("[FritzReverseLookupAndNotifier] add to phonebook")
1731 phonebook.add(self.number, self.caller)
1733 self.caller = _("UNKNOWN")
1734 notifyCall(self.event, self.date, self.number, self.caller, self.phone)
1735 # kill that object...
1737 class FritzProtocol(LineReceiver):
1739 debug("[FritzProtocol] " + "$Revision$"[1:-1] + "$Date$"[7:23] + " starting")
1742 def resetValues(self):
1743 debug("[FritzProtocol] resetValues")
1749 def notifyAndReset(self, timeout=config.plugins.FritzCall.timeout.value):
1750 notifyCall(self.event, self.date, self.number, self.caller, self.phone)
1753 def lineReceived(self, line):
1754 debug("[FritzProtocol] lineReceived: %s" % line)
1755 #15.07.06 00:38:54;CALL;1;4;<from/extern>;<to/our msn>;
1756 #15.07.06 00:38:58;DISCONNECT;1;0;
1757 #15.07.06 00:39:22;RING;0;<from/extern>;<to/our msn>;
1758 #15.07.06 00:39:27;DISCONNECT;0;0;
1760 (self.date, self.event) = a[0:2]
1762 if self.event == "RING" or (self.event == "CALL" and config.plugins.FritzCall.showOutgoing.value):
1765 if self.event == "RING":
1770 debug("[FritzProtocol] lineReceived phone: '''%s''' number: '''%s'''" % (phone, number))
1772 filtermsns = config.plugins.FritzCall.filtermsn.value.split(",")
1773 for i in range(len(filtermsns)):
1774 filtermsns[i] = filtermsns[i].strip()
1775 if not (config.plugins.FritzCall.filter.value and phone not in filtermsns):
1776 debug("[FritzProtocol] lineReceived no filter hit")
1777 phonename = phonebook.search(phone) # do we have a name for the number of our side?
1778 if phonename is not None:
1779 self.phone = "%s (%s)" % (phone, phonename)
1783 if config.plugins.FritzCall.internal.value and len(number) > 3 and number[0] == "0":
1784 debug("[FritzProtocol] lineReceived: strip leading 0")
1785 self.number = number[1:]
1787 self.number = number
1788 if self.event == "CALL" and self.number[0] != '0': # should only happen for outgoing
1789 debug("[FritzProtocol] lineReceived: add local prefix")
1790 self.number = config.plugins.FritzCall.prefix.value + self.number
1792 # check, whether we are in Germany and number has call-by-call prefix. If so strip it
1793 if self.event == "CALL" and config.plugins.FritzCall.country.value == '0049':
1794 if re.match('^0100\d\d', self.number):
1795 debug("[FritzProtocol] lineReceived: strip CbC 0100.. prefix")
1796 self.number = self.number[6:]
1797 elif re.match('^010\d\d', self.number):
1798 debug("[FritzProtocol] lineReceived: strip CbC 010.. prefix")
1799 self.number = self.number[5:]
1801 if self.number is not "":
1802 debug("[FritzProtocol] lineReceived phonebook.search: %s" % self.number)
1803 self.caller = phonebook.search(self.number)
1804 debug("[FritzProtocol] lineReceived phonebook.search reault: %s" % self.caller)
1805 if (self.caller is None) and config.plugins.FritzCall.lookup.value:
1806 FritzReverseLookupAndNotifier(self.event, self.number, self.caller, self.phone, self.date)
1807 return # reverselookup is supposed to handle the message itself
1809 if self.caller is None:
1810 self.caller = _("UNKNOWN")
1812 self.notifyAndReset()
1814 class FritzClientFactory(ReconnectingClientFactory):
1819 self.hangup_ok = False
1821 def startedConnecting(self, connector):
1822 Notifications.AddNotification(MessageBox, _("Connecting to FRITZ!Box..."), type=MessageBox.TYPE_INFO, timeout=2)
1824 def buildProtocol(self, addr):
1825 Notifications.AddNotification(MessageBox, _("Connected to FRITZ!Box!"), type=MessageBox.TYPE_INFO, timeout=4)
1827 return FritzProtocol()
1829 def clientConnectionLost(self, connector, reason):
1830 if not self.hangup_ok:
1831 Notifications.AddNotification(MessageBox, _("Connection to FRITZ!Box! lost\n (%s)\nretrying...") % reason.getErrorMessage(), type=MessageBox.TYPE_INFO, timeout=config.plugins.FritzCall.timeout.value)
1832 ReconnectingClientFactory.clientConnectionLost(self, connector, reason)
1834 def clientConnectionFailed(self, connector, reason):
1835 Notifications.AddNotification(MessageBox, _("Connecting to FRITZ!Box failed\n (%s)\nretrying...") % reason.getErrorMessage(), type=MessageBox.TYPE_INFO, timeout=config.plugins.FritzCall.timeout.value)
1836 ReconnectingClientFactory.clientConnectionFailed(self, connector, reason)
1846 if config.plugins.FritzCall.enable.value:
1847 f = FritzClientFactory()
1848 self.d = (f, reactor.connectTCP(config.plugins.FritzCall.hostname.value, 1012, f)) #@UndefinedVariable
1855 if self.d is not None:
1856 self.d[0].hangup_ok = True
1857 self.d[0].stopTrying()
1858 self.d[1].disconnect()
1861 def displayCalls(session, servicelist=None):
1862 session.open(FritzDisplayCalls)
1864 def displayPhonebook(session, servicelist=None):
1865 session.open(phonebook.FritzDisplayPhonebook)
1868 session.open(FritzCallSetup)
1872 def autostart(reason, **kwargs):
1875 # ouch, this is a hack
1876 if kwargs.has_key("session"):
1877 global my_global_session
1878 my_global_session = kwargs["session"]
1881 debug("[FRITZ!Call] - Autostart")
1883 fritz_call = FritzCall()
1885 fritz_call.shutdown()
1888 def Plugins(**kwargs):
1889 what = _("Display FRITZ!box-Fon calls on screen")
1890 what_calls = _("Phone calls")
1891 what_phonebook = _("Phonebook")
1892 return [ PluginDescriptor(name="FritzCall", description=what, where=PluginDescriptor.WHERE_PLUGINMENU, icon="plugin.png", fnc=main),
1893 PluginDescriptor(name=what_calls, description=what_calls, where=PluginDescriptor.WHERE_EXTENSIONSMENU, fnc=displayCalls),
1894 PluginDescriptor(name=what_phonebook, description=what_phonebook, where=PluginDescriptor.WHERE_EXTENSIONSMENU, fnc=displayPhonebook),
1895 PluginDescriptor(where=[PluginDescriptor.WHERE_SESSIONSTART, PluginDescriptor.WHERE_AUTOSTART], fnc=autostart) ]