1 # -*- coding: utf-8 -*-
5 $Date: 2011-01-15 16:17:12 +0100 (Sa, 15. Jan 2011) $
6 $Id: plugin.py 640 2011-01-15 15:17:12Z michael $
8 from Screens.Screen import Screen
9 from Screens.MessageBox import MessageBox
10 from Screens.NumericalTextInputHelpDialog import NumericalTextInputHelpDialog
11 from Screens.InputBox import InputBox
12 from Screens import Standby
13 from Screens.HelpMenu import HelpableScreen
15 from enigma import eTimer, eSize, ePoint #@UnresolvedImport # pylint: disable=E0611
16 from enigma import eDVBVolumecontrol
17 from enigma import eBackgroundFileEraser
18 #BgFileEraser = eBackgroundFileEraser.getInstance()
19 #BgFileEraser.erase("blabla.txt")
21 from Components.ActionMap import ActionMap
22 from Components.Label import Label
23 from Components.Button import Button
24 from Components.Pixmap import Pixmap
25 from Components.Sources.List import List
26 from Components.config import config, ConfigSubsection, ConfigSelection, ConfigEnableDisable, getConfigListEntry, ConfigText, ConfigInteger
27 from Components.ConfigList import ConfigListScreen
28 from Components.Harddisk import harddiskmanager
30 from Components.config import ConfigPassword
32 ConfigPassword = ConfigText
34 from Plugins.Plugin import PluginDescriptor
35 from Tools import Notifications
36 from Tools.NumericalTextInput import NumericalTextInput
37 from Tools.Directories import resolveFilename, SCOPE_PLUGINS, SCOPE_SKIN_IMAGE, SCOPE_CONFIG, SCOPE_MEDIA
38 from Tools.LoadPixmap import LoadPixmap
39 from GlobalActions import globalActionMap # for muting
41 from twisted.internet import reactor #@UnresolvedImport
42 from twisted.internet.protocol import ReconnectingClientFactory #@UnresolvedImport
43 from twisted.protocols.basic import LineReceiver #@UnresolvedImport
44 from twisted.web.client import getPage #@UnresolvedImport
46 from urllib import urlencode
47 import re, time, os, hashlib, traceback
49 from nrzuname import ReverseLookupAndNotifier, html2unicode
50 import FritzOutlookCSV, FritzLDIF
51 from . import _, initDebug, debug #@UnresolvedImport # pylint: disable=E0611,F0401
53 from enigma import getDesktop
54 DESKTOP_WIDTH = getDesktop(0).size().width()
55 DESKTOP_HEIGHT = getDesktop(0).size().height()
59 # It returns the first value, if HD (1280x720),
60 # the second if SD (720x576),
61 # else something scaled accordingly
62 # if one of the parameters is -1, scale proportionally
69 return scale(y2, y1, 1280, 720, DESKTOP_WIDTH)
75 return scale(y2, y1, 720, 576, DESKTOP_HEIGHT)
76 def scale(y2, y1, x2, x1, x):
77 return (y2 - y1) * (x - x1) / (x2 - x1) + y1
79 my_global_session = None
81 config.plugins.FritzCall = ConfigSubsection()
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.password = ConfigPassword(default="", fixed_size=False)
101 config.plugins.FritzCall.extension = ConfigText(default='1', fixed_size=False)
102 config.plugins.FritzCall.extension.setUseableChars('0123456789')
103 config.plugins.FritzCall.showType = ConfigEnableDisable(default=True)
104 config.plugins.FritzCall.showShortcut = ConfigEnableDisable(default=False)
105 config.plugins.FritzCall.showVanity = ConfigEnableDisable(default=False)
106 config.plugins.FritzCall.prefix = ConfigText(default="", fixed_size=False)
107 config.plugins.FritzCall.prefix.setUseableChars('0123456789')
108 config.plugins.FritzCall.connectionVerbose = ConfigEnableDisable(default=True)
111 def getMountedDevs():
112 def handleMountpoint(loc):
113 # debug("[FritzCall] handleMountpoint: %s" %repr(loc))
117 #=======================================================================
118 # if os.path.exists(os.path.join(mp, "PhoneBook.txt")):
119 # if os.access(os.path.join(mp, "PhoneBook.txt"), os.W_OK):
125 # desc = loc[1] + desc
126 #=======================================================================
128 return (mp, desc + " (" + mp + ")")
130 mountedDevs = [(resolveFilename(SCOPE_CONFIG), _("Flash")),
131 (resolveFilename(SCOPE_MEDIA, "cf"), _("Compact Flash")),
132 (resolveFilename(SCOPE_MEDIA, "usb"), _("USB Device"))]
133 mountedDevs += map(lambda p: (p.mountpoint, (_(p.description) if p.description else "")), harddiskmanager.getMountedPartitions(True))
134 mediaDir = resolveFilename(SCOPE_MEDIA)
135 for p in os.listdir(mediaDir):
136 if os.path.join(mediaDir, p) not in [path[0] for path in mountedDevs]:
137 mountedDevs.append((os.path.join(mediaDir, p), _("Media directory")))
138 debug("[FritzCall] getMountedDevs1: %s" %repr(mountedDevs))
139 mountedDevs = filter(lambda path: os.path.isdir(path[0]) and os.access(path[0], os.W_OK|os.X_OK), mountedDevs)
140 # put this after the write/executable check, that is far too slow...
141 netDir = resolveFilename(SCOPE_MEDIA, "net")
142 if os.path.isdir(netDir):
143 mountedDevs += map(lambda p: (os.path.join(netDir, p), _("Network mount")), os.listdir(netDir))
144 mountedDevs = map(handleMountpoint, mountedDevs)
146 config.plugins.FritzCall.phonebookLocation = ConfigSelection(choices=getMountedDevs())
149 ("0049", _("Germany")),
150 ("0031", _("The Netherlands")),
151 ("0033", _("France")),
152 ("0039", _("Italy")),
153 ("0041", _("Switzerland")),
154 ("0043", _("Austria"))
156 config.plugins.FritzCall.country = ConfigSelection(choices=countryCodes)
160 FBF_MISSED_CALLS = "2"
162 fbfCallsChoices = {FBF_ALL_CALLS: _("All calls"),
163 FBF_IN_CALLS: _("Incoming calls"),
164 FBF_MISSED_CALLS: _("Missed calls"),
165 FBF_OUT_CALLS: _("Outgoing calls")
167 config.plugins.FritzCall.fbfCalls = ConfigSelection(choices=fbfCallsChoices)
169 config.plugins.FritzCall.name = ConfigText(default="", fixed_size=False)
170 config.plugins.FritzCall.number = ConfigText(default="", fixed_size=False)
171 config.plugins.FritzCall.number.setUseableChars('0123456789')
179 avonFileName = resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/avon.dat")
180 if os.path.exists(avonFileName):
181 for line in open(avonFileName):
182 line = line.decode("iso-8859-1").encode('utf-8')
185 parts = line.split(':')
187 avon[parts[0].replace('-','').replace('*','').replace('/','')] = parts[1]
189 def resolveNumberWithAvon(number, countrycode):
190 if not number or number[0] != '0':
193 countrycode = countrycode.replace('00','+')
194 if number[:2] == '00':
195 normNumber = '+' + number[2:]
196 elif number[:1] == '0':
197 normNumber = countrycode + number[1:]
198 else: # this should can not happen, but safety first
201 # debug('normNumer: ' + normNumber)
202 for i in reversed(range(min(10, len(number)))):
203 if avon.has_key(normNumber[:i]):
204 return '[' + avon[normNumber[:i]].strip() + ']'
207 def handleReverseLookupResult(name):
208 found = re.match("NA: ([^;]*);VN: ([^;]*);STR: ([^;]*);HNR: ([^;]*);PLZ: ([^;]*);ORT: ([^;]*)", name)
210 ( name, firstname, street, streetno, zipcode, city ) = (found.group(1),
218 name += ' ' + firstname
219 if street or streetno or zipcode or city:
224 name += ' ' + streetno
225 if (street or streetno) and (zipcode or city):
228 name += zipcode + ' ' + city
235 from xml.dom.minidom import parse
238 callbycallFileName = resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/callbycall_world.xml")
239 if os.path.exists(callbycallFileName):
240 dom = parse(callbycallFileName)
241 for top in dom.getElementsByTagName("callbycalls"):
242 for cbc in top.getElementsByTagName("country"):
243 code = cbc.getAttribute("code").replace("+","00")
244 cbcInfos[code] = cbc.getElementsByTagName("callbycall")
246 debug("[FritzCall] initCbC: callbycallFileName does not exist?!?!")
248 def stripCbCPrefix(number, countrycode):
249 if number and number[:2] != "00" and cbcInfos.has_key(countrycode):
250 for cbc in cbcInfos[countrycode]:
251 if len(cbc.getElementsByTagName("length"))<1 or len(cbc.getElementsByTagName("prefix"))<1:
252 debug("[FritzCall] stripCbCPrefix: entries for " + countrycode + " %s invalid")
254 length = int(cbc.getElementsByTagName("length")[0].childNodes[0].data)
255 prefix = cbc.getElementsByTagName("prefix")[0].childNodes[0].data
256 # if re.match('^'+prefix, number):
257 if number[:len(prefix)] == prefix:
258 return number[length:]
261 class FritzAbout(Screen):
263 def __init__(self, session):
264 textFieldWidth = scaleV(350, 250)
265 width = 5 + 150 + 20 + textFieldWidth + 5 + 175 + 5
266 height = 5 + 175 + 5 + 25 + 5
268 <screen name="FritzAbout" position="center,center" size="%d,%d" title="About FritzCall" >
269 <widget name="text" position="175,%d" size="%d,%d" font="Regular;%d" />
270 <ePixmap position="5,37" size="150,110" pixmap="%s" transparent="1" alphatest="blend" />
271 <ePixmap position="%d,5" size="175,175" pixmap="%s" transparent="1" alphatest="blend" />
272 <widget name="url" position="20,185" size="%d,25" font="Regular;%d" />
274 width, height, # size
275 (height-scaleV(150,130)) / 2, # text vertical position
277 scaleV(150,130), # text height
278 scaleV(24,21), # text font size
279 resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/images/fritz.png"), # 150x110
280 5 + 150 + 5 + textFieldWidth + 5, # qr code horizontal offset
281 resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/images/website.png"), # 175x175
282 width-40, # url width
283 scaleV(24,21) # url font size
285 Screen.__init__(self, session)
286 self["aboutActions"] = ActionMap(["OkCancelActions"],
291 self["text"] = Label(
292 "FritzCall Plugin" + "\n\n" +
293 "$Author: michael $"[1:-2] + "\n" +
294 "$Revision: 640 $"[1:-2] + "\n" +
295 "$Date: 2011-01-15 16:17:12 +0100 (Sa, 15. Jan 2011) $"[1:23] + "\n"
297 self["url"] = Label("http://wiki.blue-panel.com/index.php/FritzCall")
298 self.onLayoutFinish.append(self.setWindowTitle)
300 def setWindowTitle(self):
301 # TRANSLATORS: this is a window title.
302 self.setTitle(_("About FritzCall"))
319 debug("[FritzCallFBF] __init__")
320 self._callScreen = None
321 self._md5LoginTimestamp = None
322 self._md5Sid = '0000000000000000'
323 self._callTimestamp = 0
325 self._callType = config.plugins.FritzCall.fbfCalls.value
326 self._phoneBookID = '0'
327 self.info = None # (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive)
329 self.blacklist = ([], [])
332 def _notify(self, text):
333 debug("[FritzCallFBF] notify: " + text)
334 self._md5LoginTimestamp = None
336 debug("[FritzCallFBF] notify: try to close callScreen")
337 self._callScreen.close()
338 self._callScreen = None
339 Notifications.AddNotification(MessageBox, text, type=MessageBox.TYPE_ERROR, timeout=config.plugins.FritzCall.timeout.value)
341 def _login(self, callback=None):
342 debug("[FritzCallFBF] _login")
344 self._callScreen.updateStatus(_("login"))
345 if self._md5LoginTimestamp and ((time.time() - self._md5LoginTimestamp) < float(9.5*60)) and self._md5Sid != '0000000000000000': # new login after 9.5 minutes inactivity
346 debug("[FritzCallFBF] _login: renew timestamp: " + time.ctime(self._md5LoginTimestamp) + " time: " + time.ctime())
347 self._md5LoginTimestamp = time.time()
350 debug("[FritzCallFBF] _login: not logged in or outdated login")
351 # http://fritz.box/cgi-bin/webcm?getpage=../html/login_sid.xml
352 parms = urlencode({'getpage':'../html/login_sid.xml'})
353 url = "http://%s/cgi-bin/webcm" % (config.plugins.FritzCall.hostname.value)
354 debug("[FritzCallFBF] _login: '" + url + "' parms: '" + parms + "'")
357 headers={'Content-Type': "application/x-www-form-urlencoded", 'Content-Length': str(len(parms))
358 }, postdata=parms).addCallback(lambda x: self._md5Login(callback,x)).addErrback(lambda x:self._oldLogin(callback,x))
360 def _oldLogin(self, callback, error):
361 debug("[FritzCallFBF] _oldLogin: " + repr(error))
362 self._md5LoginTimestamp = None
363 if config.plugins.FritzCall.password.value != "":
364 parms = "login:command/password=%s" % (config.plugins.FritzCall.password.value)
365 url = "http://%s/cgi-bin/webcm" % (config.plugins.FritzCall.hostname.value)
366 debug("[FritzCallFBF] _oldLogin: '" + url + "' parms: '" + parms + "'")
369 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
370 headers={'Content-Type': "application/x-www-form-urlencoded", 'Content-Length': str(len(parms))
371 }, postdata=parms).addCallback(self._gotPageLogin).addCallback(callback).addErrback(self._errorLogin)
373 debug("[FritzCallFBF] _oldLogin: no password, calling " + repr(callback))
376 def _md5Login(self, callback, sidXml):
377 def buildResponse(challenge, text):
378 debug("[FritzCallFBF] _md5Login7buildResponse: challenge: " + challenge + ' text: ' + text)
379 text = (challenge + '-' + text).decode('utf-8','ignore').encode('utf-16-le')
380 for i in range(len(text)):
381 if ord(text[i]) > 255:
385 debug("[FritzCallFBF] md5Login/buildResponse: " + md5.hexdigest())
386 return challenge + '-' + md5.hexdigest()
388 debug("[FritzCallFBF] _md5Login")
389 found = re.match('.*<SID>([^<]*)</SID>', sidXml, re.S)
391 self._md5Sid = found.group(1)
392 debug("[FritzCallFBF] _md5Login: SID "+ self._md5Sid)
394 debug("[FritzCallFBF] _md5Login: no sid! That must be an old firmware.")
395 self._oldLogin(callback, 'No error')
398 debug("[FritzCallFBF] _md5Login: renew timestamp: " + time.ctime(self._md5LoginTimestamp) + " time: " + time.ctime())
399 self._md5LoginTimestamp = time.time()
400 if sidXml.find('<iswriteaccess>0</iswriteaccess>') != -1:
401 debug("[FritzCallFBF] _md5Login: logging in")
402 found = re.match('.*<Challenge>([^<]*)</Challenge>', sidXml, re.S)
404 challenge = found.group(1)
405 debug("[FritzCallFBF] _md5Login: challenge " + challenge)
408 debug("[FritzCallFBF] _md5Login: login necessary and no challenge! That is terribly wrong.")
410 'getpage':'../html/de/menus/menu2.html', # 'var:pagename':'home', 'var:menu':'home',
411 'login:command/response': buildResponse(challenge, config.plugins.FritzCall.password.value),
413 url = "http://%s/cgi-bin/webcm" % (config.plugins.FritzCall.hostname.value)
414 debug("[FritzCallFBF] _md5Login: '" + url + "' parms: '" + parms + "'")
417 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
418 headers={'Content-Type': "application/x-www-form-urlencoded", 'Content-Length': str(len(parms))
419 }, postdata=parms).addCallback(self._gotPageLogin).addCallback(callback).addErrback(self._errorLogin)
420 elif callback: # we assume value 1 here, no login necessary
421 debug("[FritzCallFBF] _md5Login: no login necessary")
424 def _gotPageLogin(self, html):
426 self._callScreen.updateStatus(_("login verification"))
427 debug("[FritzCallFBF] _gotPageLogin: verify login")
428 start = html.find('<p class="errorMessage">FEHLER: ')
430 start = start + len('<p class="errorMessage">FEHLER: ')
431 text = _("FRITZ!Box - Error logging in\n\n") + html[start : html.find('</p>', start)]
435 self._callScreen.updateStatus(_("login ok"))
437 found = re.match('.*<input type="hidden" name="sid" value="([^\"]*)"', html, re.S)
439 self._md5Sid = found.group(1)
440 debug("[FritzCallFBF] _gotPageLogin: found sid: " + self._md5Sid)
442 def _errorLogin(self, error):
444 debug("[FritzCallFBF] _errorLogin: %s" % (error))
445 text = _("FRITZ!Box - Error logging in: %s\nDisabling plugin.") % error.getErrorMessage()
446 # config.plugins.FritzCall.enable.value = False
451 if self._md5LoginTimestamp:
452 self._md5LoginTimestamp = None
454 'getpage':'../html/de/menus/menu2.html', # 'var:pagename':'home', 'var:menu':'home',
455 'login:command/logout':'bye bye Fritz'
457 url = "http://%s/cgi-bin/webcm" % (config.plugins.FritzCall.hostname.value)
458 debug("[FritzCallFBF] logout: '" + url + "' parms: '" + parms + "'")
461 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
462 headers={'Content-Type': "application/x-www-form-urlencoded", 'Content-Length': str(len(parms))
463 }, postdata=parms).addErrback(self._errorLogout)
465 def _errorLogout(self, error):
466 debug("[FritzCallFBF] _errorLogout: %s" % (error))
467 text = _("FRITZ!Box - Error logging out: %s") % error.getErrorMessage()
470 def loadFritzBoxPhonebook(self):
471 debug("[FritzCallFBF] loadFritzBoxPhonebook")
472 if config.plugins.FritzCall.fritzphonebook.value:
473 self._phoneBookID = '0'
474 debug("[FritzCallFBF] loadFritzBoxPhonebook: logging in")
475 self._login(self._loadFritzBoxPhonebook)
477 def _loadFritzBoxPhonebook(self, html):
479 #===================================================================
480 # found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)
482 # self._errorLoad('Login: ' + found.group(1))
484 #===================================================================
485 start = html.find('<p class="errorMessage">FEHLER: ')
487 start = start + len('<p class="errorMessage">FEHLER: ')
488 self._errorLoad('Login: ' + html[start, html.find('</p>', start)])
491 'getpage':'../html/de/menus/menu2.html',
493 'var:pagename':'fonbuch',
496 'telcfg:settings/Phonebook/Books/Select':self._phoneBookID, # this selects always the first phonbook
498 url = "http://%s/cgi-bin/webcm" % (config.plugins.FritzCall.hostname.value)
499 debug("[FritzCallFBF] _loadFritzBoxPhonebook: '" + url + "' parms: '" + parms + "'")
502 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
503 headers={'Content-Type': "application/x-www-form-urlencoded", 'Content-Length': str(len(parms))
504 }, postdata=parms).addCallback(self._parseFritzBoxPhonebook).addErrback(self._errorLoad)
506 def _parseFritzBoxPhonebook(self, html):
507 debug("[FritzCallFBF] _parseFritzBoxPhonebook")
509 # first, let us get the charset
510 found = re.match('.*<meta http-equiv=content-type content="text/html; charset=([^"]*)">', html, re.S)
512 charset = found.group(1)
513 debug("[FritzCallFBF] _parseFritzBoxPhonebook: found charset: " + charset)
514 html = html2unicode(html.decode(charset), charset).encode('utf-8') # this looks silly, but has to be
515 else: # this is kind of emergency conversion...
517 debug("[FritzCallFBF] _parseFritzBoxPhonebook: try charset utf-8")
519 html = html2unicode(html.decode('utf-8'), 'utf-8').encode('utf-8') # this looks silly, but has to be
520 except UnicodeDecodeError:
521 debug("[FritzCallFBF] _parseFritzBoxPhonebook: try charset iso-8859-1")
522 charset = 'iso-8859-1'
523 html = html2unicode(html.decode('iso-8859-1'), 'iso-8859-1').encode('utf-8') # this looks silly, but has to be
525 # if re.search('document.write\(TrFon1\(\)', html):
526 if html.find('document.write(TrFon1()') != -1:
527 #===============================================================================
528 # New Style: 7270 (FW 54.04.58, 54.04.63-11941, 54.04.70, 54.04.74-14371, 54.04.76, PHONE Labor 54.04.80-16624)
529 # 7170 (FW 29.04.70) 22.03.2009
530 # 7141 (FW 40.04.68) 22.03.2009
531 # We expect one line with TrFonName followed by several lines with
532 # TrFonNr(Type,Number,Shortcut,Vanity), which all belong to the name in TrFonName.
533 #===============================================================================
534 debug("[FritzCallFBF] _parseFritzBoxPhonebook: discovered newer firmware")
535 found = re.match('.*<input type="hidden" name="telcfg:settings/Phonebook/Books/Name(\d+)" value="[Dd]reambox" id="uiPostPhonebookName\d+" disabled>', html, re.S)
537 phoneBookID = found.group(1)
538 debug("[FritzCallFBF] _parseFritzBoxPhonebook: found dreambox phonebook with id: " + phoneBookID)
539 if self._phoneBookID != phoneBookID:
540 self._phoneBookID = phoneBookID
541 debug("[FritzCallFBF] _parseFritzBoxPhonebook: reload phonebook")
542 self._loadFritzBoxPhonebook(self._phoneBookID) # reload with dreambox phonebook
545 entrymask = re.compile('(TrFonName\("[^"]+", "[^"]+", "[^"]*"(?:, "[^"]*")?\);.*?)document.write\(TrFon1\(\)', re.S)
546 entries = entrymask.finditer(html)
547 for entry in entries:
548 # TrFonName (id, name, category)
549 # TODO: replace re.match?
550 found = re.match('TrFonName\("[^"]*", "([^"]+)", "[^"]*"(?:, "[^"]*")?\);', entry.group(1))
552 debug("[FritzCallFBF] _parseFritzBoxPhonebook: name: %s" %found.group(1))
553 name = found.group(1).replace(',','').strip()
555 debug("[FritzCallFBF] _parseFritzBoxPhonebook: could not find name")
557 # TrFonNr (type, rufnr, code, vanity)
558 detailmask = re.compile('TrFonNr\("([^"]*)", "([^"]*)", "([^"]*)", "([^"]*)"\);', re.S)
559 details = detailmask.finditer(entry.group(1))
560 for found in details:
561 thisnumber = found.group(2).strip()
563 debug("[FritzCallFBF] Ignoring entry with empty number for '''%s'''" % (name))
567 callType = found.group(1)
568 if config.plugins.FritzCall.showType.value:
569 if callType == "mobile":
570 thisname = thisname + " (" + _("mobile") + ")"
571 elif callType == "home":
572 thisname = thisname + " (" + _("home") + ")"
573 elif callType == "work":
574 thisname = thisname + " (" + _("work") + ")"
576 if config.plugins.FritzCall.showShortcut.value and found.group(3):
577 thisname = thisname + ", " + _("Shortcut") + ": " + found.group(3)
578 if config.plugins.FritzCall.showVanity.value and found.group(4):
579 thisname = thisname + ", " + _("Vanity") + ": " + found.group(4)
581 debug("[FritzCallFBF] Adding '''%s''' with '''%s''' from FRITZ!Box Phonebook!" % (thisname.strip(), thisnumber))
582 # Beware: strings in phonebook.phonebook have to be in utf-8!
583 phonebook.phonebook[thisnumber] = thisname
585 # elif re.search('document.write\(TrFon\(', html):
586 elif html.find('document.write(TrFon(') != -1:
587 #===============================================================================
588 # Old Style: 7050 (FW 14.04.33)
589 # We expect one line with TrFon(No,Name,Number,Shortcut,Vanity)
590 # Encoding should be plain Ascii...
591 #===============================================================================
592 entrymask = re.compile('TrFon\("[^"]*", "([^"]*)", "([^"]*)", "([^"]*)", "([^"]*)"\)', re.S)
593 entries = entrymask.finditer(html)
594 for found in entries:
595 name = found.group(1).strip().replace(',','')
596 # debug("[FritzCallFBF] pos: %s name: %s" %(found.group(0),name))
597 thisnumber = found.group(2).strip()
598 if config.plugins.FritzCall.showShortcut.value and found.group(3):
599 name = name + ", " + _("Shortcut") + ": " + found.group(3)
600 if config.plugins.FritzCall.showVanity.value and found.group(4):
601 name = name + ", " + _("Vanity") + ": " + found.group(4)
603 # name = name.encode('utf-8')
604 debug("[FritzCallFBF] Adding '''%s''' with '''%s''' from FRITZ!Box Phonebook!" % (name, thisnumber))
605 # Beware: strings in phonebook.phonebook have to be in utf-8!
606 phonebook.phonebook[thisnumber] = name
608 debug("[FritzCallFBF] ignoring empty number for %s" % name)
610 elif self._md5Sid == '0000000000000000': # retry, it could be a race condition
611 debug("[FritzCallFBF] _parseFritzBoxPhonebook: retry loading phonebook")
612 self.loadFritzBoxPhonebook()
614 self._notify(_("Could not parse FRITZ!Box Phonebook entry"))
616 def _errorLoad(self, error):
617 debug("[FritzCallFBF] _errorLoad: %s" % (error))
618 text = _("FRITZ!Box - Could not load phonebook: %s") % error.getErrorMessage()
621 def getCalls(self, callScreen, callback, callType):
623 # call sequence must be:
625 # - getPage -> _gotPageLogin
626 # - loginCallback (_getCalls)
627 # - getPage -> _getCalls1
628 debug("[FritzCallFBF] getCalls")
629 self._callScreen = callScreen
630 self._callType = callType
631 if (time.time() - self._callTimestamp) > 180:
632 debug("[FritzCallFBF] getCalls: outdated data, login and get new ones: " + time.ctime(self._callTimestamp) + " time: " + time.ctime())
633 self._callTimestamp = time.time()
634 self._login(lambda x:self._getCalls(callback, x))
635 elif not self._callList:
636 debug("[FritzCallFBF] getCalls: time is ok, but no callList")
637 self._getCalls1(callback)
639 debug("[FritzCallFBF] getCalls: time is ok, callList is ok")
640 self._gotPageCalls(callback)
642 def _getCalls(self, callback, html):
644 #===================================================================
645 # found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)
647 # self._errorCalls('Login: ' + found.group(1))
649 #===================================================================
650 start = html.find('<p class="errorMessage">FEHLER: ')
652 start = start + len('<p class="errorMessage">FEHLER: ')
653 self._errorCalls('Login: ' + html[start, html.find('</p>', start)])
656 # we need this to fill Anrufliste.csv
657 # http://repeater1/cgi-bin/webcm?getpage=../html/de/menus/menu2.html&var:lang=de&var:menu=fon&var:pagename=foncalls
659 debug("[FritzCallFBF] _getCalls")
661 #===================================================================
662 # found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)
664 # text = _("FRITZ!Box - Error logging in: %s") + found.group(1)
667 #===================================================================
668 start = html.find('<p class="errorMessage">FEHLER: ')
670 start = start + len('<p class="errorMessage">FEHLER: ')
671 self._notify(_("FRITZ!Box - Error logging in: %s") + html[start, html.find('</p>', start)])
675 self._callScreen.updateStatus(_("preparing"))
676 parms = urlencode({'getpage':'../html/de/menus/menu2.html', 'var:lang':'de', 'var:pagename':'foncalls', 'var:menu':'fon', 'sid':self._md5Sid})
677 url = "http://%s/cgi-bin/webcm?%s" % (config.plugins.FritzCall.hostname.value, parms)
678 getPage(url).addCallback(lambda x:self._getCalls1(callback)).addErrback(self._errorCalls) #@UnusedVariable # pylint: disable=W0613
680 def _getCalls1(self, callback):
682 # finally we should have successfully lgged in and filled the csv
684 debug("[FritzCallFBF] _getCalls1")
686 self._callScreen.updateStatus(_("finishing"))
687 parms = urlencode({'getpage':'../html/de/FRITZ!Box_Anrufliste.csv', 'sid':self._md5Sid})
688 url = "http://%s/cgi-bin/webcm?%s" % (config.plugins.FritzCall.hostname.value, parms)
689 getPage(url).addCallback(lambda x:self._gotPageCalls(callback, x)).addErrback(self._errorCalls)
691 def _gotPageCalls(self, callback, csv=""):
692 def resolveNumber(number, default=None):
694 if config.plugins.FritzCall.internal.value and len(number) > 3 and number[0] == "0":
697 number = stripCbCPrefix(number, config.plugins.FritzCall.country.value)
698 if config.plugins.FritzCall.prefix.value and number and number[0] != '0': # should only happen for outgoing
699 number = config.plugins.FritzCall.prefix.value + number
700 name = phonebook.search(number)
702 #===========================================================
703 # found = re.match('(.*?)\n.*', name)
705 # name = found.group(1)
706 #===========================================================
707 end = name.find('\n')
714 name = resolveNumberWithAvon(number, config.plugins.FritzCall.country.value)
716 number = number + ' ' + name
718 number = _("UNKNOWN")
719 # if len(number) > 20: number = number[:20]
723 debug("[FritzCallFBF] _gotPageCalls: got csv, setting callList")
725 self._callScreen.updateStatus(_("done"))
726 if csv.find('Melden Sie sich mit dem Kennwort der FRITZ!Box an') != -1:
727 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.")
728 # self.session.open(MessageBox, text, MessageBox.TYPE_ERROR, timeout=config.plugins.FritzCall.timeout.value)
732 csv = csv.decode('iso-8859-1', 'replace').encode('utf-8', 'replace')
733 lines = csv.splitlines()
734 self._callList = lines
736 debug("[FritzCallFBF] _gotPageCalls: got no csv, but have callList")
738 self._callScreen.updateStatus(_("done, using last list"))
739 lines = self._callList
741 debug("[FritzCallFBF] _gotPageCalls: got no csv, no callList, laving")
745 if config.plugins.FritzCall.filter.value and config.plugins.FritzCall.filterCallList.value:
746 filtermsns = map(lambda x: x.strip(), config.plugins.FritzCall.filtermsn.value.split(","))
747 debug("[FritzCallFBF] _gotPageCalls: filtermsns %s" % (repr(filtermsns)))
749 # Typ;Datum;Name;Rufnummer;Nebenstelle;Eigene Rufnummer;Dauer
750 # 0 ;1 ;2 ;3 ;4 ;5 ;6
751 lines = map(lambda line: line.split(';'), lines)
752 lines = filter(lambda line: (len(line)==7 and (line[0]=="Typ" or self._callType == '.' or line[0] == self._callType)), lines)
755 # debug("[FritzCallFBF] _gotPageCalls: line %s" % (line))
759 if config.plugins.FritzCall.phonebook.value and line[2]:
760 remote = resolveNumber(line[3], line[2] + " (FBF)")
762 remote = resolveNumber(line[3], line[2])
764 start = here.find('Internet: ')
766 start += len('Internet: ')
770 if direct != "Typ" and config.plugins.FritzCall.filter.value and config.plugins.FritzCall.filterCallList.value:
771 # debug("[FritzCallFBF] _gotPageCalls: check %s" % (here))
772 if here not in filtermsns:
773 # debug("[FritzCallFBF] _gotPageCalls: skip %s" % (here))
775 here = resolveNumber(here, line[4])
777 number = stripCbCPrefix(line[3], config.plugins.FritzCall.country.value)
778 if config.plugins.FritzCall.prefix.value and number and number[0] != '0': # should only happen for outgoing
779 number = config.plugins.FritzCall.prefix.value + number
780 callListL.append((number, date, direct, remote, length, here))
783 # debug("[FritzCallFBF] _gotPageCalls call callback with\n" + text
785 self._callScreen = None
787 def _errorCalls(self, error):
788 debug("[FritzCallFBF] _errorCalls: %s" % (error))
789 text = _("FRITZ!Box - Could not load calls: %s") % error.getErrorMessage()
792 def dial(self, number):
793 ''' initiate a call to number '''
794 self._login(lambda x: self._dial(number, x))
796 def _dial(self, number, html):
798 #===================================================================
799 # found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)
801 # self._errorDial('Login: ' + found.group(1))
803 #===================================================================
804 start = html.find('<p class="errorMessage">FEHLER: ')
806 start = start + len('<p class="errorMessage">FEHLER: ')
807 self._errorDial('Login: ' + html[start, html.find('</p>', start)])
809 url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
811 'getpage':'../html/de/menus/menu2.html',
812 'var:pagename':'fonbuch',
814 'telcfg:settings/UseClickToDial':'1',
815 'telcfg:settings/DialPort':config.plugins.FritzCall.extension.value,
816 'telcfg:command/Dial':number,
819 debug("[FritzCallFBF] dial url: '" + url + "' parms: '" + parms + "'")
822 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
824 'Content-Type': "application/x-www-form-urlencoded",
825 'Content-Length': str(len(parms))},
826 postdata=parms).addCallback(self._okDial).addErrback(self._errorDial)
828 def _okDial(self, html): #@UnusedVariable # pylint: disable=W0613
829 debug("[FritzCallFBF] okDial")
831 def _errorDial(self, error):
832 debug("[FritzCallFBF] errorDial: $s" % error)
833 text = _("FRITZ!Box - Dialling failed: %s") % error.getErrorMessage()
836 def changeWLAN(self, statusWLAN):
837 ''' get status info from FBF '''
838 debug("[FritzCallFBF] changeWLAN start")
839 if not statusWLAN or (statusWLAN != '1' and statusWLAN != '0'):
841 self._login(lambda x: self._changeWLAN(statusWLAN, x))
843 def _changeWLAN(self, statusWLAN, html):
845 #===================================================================
846 # found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)
848 # self._errorChangeWLAN('Login: ' + found.group(1))
850 #===================================================================
851 start = html.find('<p class="errorMessage">FEHLER: ')
853 start = start + len('<p class="errorMessage">FEHLER: ')
854 self._errorChangeWLAN('Login: ' + html[start, html.find('</p>', start)])
856 url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
858 'getpage':'../html/de/menus/menu2.html',
860 'var:pagename':'wlan',
862 'wlan:settings/ap_enabled':str(statusWLAN),
865 debug("[FritzCallFBF] changeWLAN url: '" + url + "' parms: '" + parms + "'")
868 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
870 'Content-Type': "application/x-www-form-urlencoded",
871 'Content-Length': str(len(parms))},
872 postdata=parms).addCallback(self._okChangeWLAN).addErrback(self._errorChangeWLAN)
874 def _okChangeWLAN(self, html): #@UnusedVariable # pylint: disable=W0613
875 debug("[FritzCallFBF] _okChangeWLAN")
877 def _errorChangeWLAN(self, error):
878 debug("[FritzCallFBF] _errorChangeWLAN: $s" % error)
879 text = _("FRITZ!Box - Failed changing WLAN: %s") % error.getErrorMessage()
882 def changeMailbox(self, whichMailbox):
883 ''' switch mailbox on/off '''
884 debug("[FritzCallFBF] changeMailbox start: " + str(whichMailbox))
885 self._login(lambda x: self._changeMailbox(whichMailbox, x))
887 def _changeMailbox(self, whichMailbox, html):
889 #===================================================================
890 # found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)
892 # self._errorChangeMailbox('Login: ' + found.group(1))
894 #===================================================================
895 start = html.find('<p class="errorMessage">FEHLER: ')
897 start = start + len('<p class="errorMessage">FEHLER: ')
898 self._errorChangeMailbox('Login: ' + html[start, html.find('</p>', start)])
900 debug("[FritzCallFBF] _changeMailbox")
901 url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
902 if whichMailbox == -1:
904 if self.info[FBF_tamActive][i+1]:
909 'tam:settings/TAM'+str(i)+'/Active':state,
912 debug("[FritzCallFBF] changeMailbox url: '" + url + "' parms: '" + parms + "'")
915 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
917 'Content-Type': "application/x-www-form-urlencoded",
918 'Content-Length': str(len(parms))},
919 postdata=parms).addCallback(self._okChangeMailbox).addErrback(self._errorChangeMailbox)
920 elif whichMailbox > 4:
921 debug("[FritzCallFBF] changeMailbox invalid mailbox number")
923 if self.info[FBF_tamActive][whichMailbox+1]:
928 'tam:settings/TAM'+str(whichMailbox)+'/Active':state,
931 debug("[FritzCallFBF] changeMailbox url: '" + url + "' parms: '" + parms + "'")
934 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
936 'Content-Type': "application/x-www-form-urlencoded",
937 'Content-Length': str(len(parms))},
938 postdata=parms).addCallback(self._okChangeMailbox).addErrback(self._errorChangeMailbox)
940 def _okChangeMailbox(self, html): #@UnusedVariable # pylint: disable=W0613
941 debug("[FritzCallFBF] _okChangeMailbox")
943 def _errorChangeMailbox(self, error):
944 debug("[FritzCallFBF] _errorChangeMailbox: $s" % error)
945 text = _("FRITZ!Box - Failed changing Mailbox: %s") % error.getErrorMessage()
948 def getInfo(self, callback):
949 ''' get status info from FBF '''
950 debug("[FritzCallFBF] getInfo")
951 self._login(lambda x:self._getInfo(callback, x))
953 def _getInfo(self, callback, html):
954 # http://192.168.178.1/cgi-bin/webcm?getpage=../html/de/menus/menu2.html&var:lang=de&var:pagename=home&var:menu=home
955 debug("[FritzCallFBF] _getInfo: verify login")
957 #===================================================================
958 # found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)
960 # self._errorGetInfo('Login: ' + found.group(1))
962 #===================================================================
963 start = html.find('<p class="errorMessage">FEHLER: ')
965 start = start + len('<p class="errorMessage">FEHLER: ')
966 self._errorGetInfo('Login: ' + html[start, html.find('</p>', start)])
969 url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
971 'getpage':'../html/de/menus/menu2.html',
973 'var:pagename':'home',
977 debug("[FritzCallFBF] _getInfo url: '" + url + "' parms: '" + parms + "'")
980 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
982 'Content-Type': "application/x-www-form-urlencoded",
983 'Content-Length': str(len(parms))},
984 postdata=parms).addCallback(lambda x:self._okGetInfo(callback,x)).addErrback(self._errorGetInfo)
986 def _okGetInfo(self, callback, html):
989 (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive) = self.info
991 (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive) = (None, None, None, None, None, None, None, None, None)
993 debug("[FritzCallFBF] _okGetInfo/readinfo")
994 found = re.match('.*<table class="tborder" id="tProdukt">\s*<tr>\s*<td style="padding-top:2px;">([^<]*)</td>\s*<td style="padding-top:2px;text-align:right;">\s*([^\s]*)\s*</td>', html, re.S)
996 boxInfo = found.group(1)+ ', ' + found.group(2)
997 boxInfo = boxInfo.replace(' ',' ')
998 # debug("[FritzCallFBF] _okGetInfo Boxinfo: " + boxInfo)
1000 found = re.match('.*<p class="ac">([^<]*)</p>', html, re.S)
1002 # debug("[FritzCallFBF] _okGetInfo Boxinfo: " + found.group(1))
1003 boxInfo = found.group(1)
1005 if html.find('home_coninf.txt') != -1:
1006 url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
1008 'getpage':'../html/de/home/home_coninf.txt',
1011 # debug("[FritzCallFBF] get coninfo: url: '" + url + "' parms: '" + parms + "'")
1014 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
1016 'Content-Type': "application/x-www-form-urlencoded",
1017 'Content-Length': str(len(parms))},
1018 postdata=parms).addCallback(lambda x:self._okSetConInfo(callback,x)).addErrback(self._errorGetInfo)
1020 found = re.match('.*if \(isNaN\(jetzt\)\)\s*return "";\s*var str = "([^"]*)";', html, re.S)
1022 # debug("[FritzCallFBF] _okGetInfo Uptime: " + found.group(1))
1023 upTime = found.group(1)
1025 found = re.match('.*str = g_pppSeit \+"([^<]*)<br>"\+mldIpAdr;', html, re.S)
1027 # debug("[FritzCallFBF] _okGetInfo Uptime: " + found.group(1))
1028 upTime = found.group(1)
1030 found = re.match(".*IpAdrDisplay\('([.\d]+)'\)", html, re.S)
1032 # debug("[FritzCallFBF] _okGetInfo IpAdrDisplay: " + found.group(1))
1033 ipAddress = found.group(1)
1035 if html.find('g_tamActive') != -1:
1036 entries = re.compile('if \("(\d)" == "1"\) {\s*g_tamActive \+= 1;\s*}', re.S).finditer(html)
1037 tamActive = [0, False, False, False, False, False]
1039 for entry in entries:
1040 state = entry.group(1)
1045 # debug("[FritzCallFBF] _okGetInfo tamActive: " + str(tamActive))
1047 if html.find('home_dect.txt') != -1:
1048 url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
1050 'getpage':'../html/de/home/home_dect.txt',
1053 # debug("[FritzCallFBF] get coninfo: url: '" + url + "' parms: '" + parms + "'")
1056 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
1058 'Content-Type': "application/x-www-form-urlencoded",
1059 'Content-Length': str(len(parms))},
1060 postdata=parms).addCallback(lambda x:self._okSetDect(callback,x)).addErrback(self._errorGetInfo)
1062 if html.find('countDect2') != -1:
1063 entries = re.compile('if \("1" == "1"\) countDect2\+\+;', re.S).findall(html)
1064 dectActive = len(entries)
1065 # debug("[FritzCallFBF] _okGetInfo dectActive: " + str(dectActive))
1067 found = re.match('.*var g_intFaxActive = "0";\s*if \("1" != ""\) {\s*g_intFaxActive = "1";\s*}\s*', html, re.S)
1070 # debug("[FritzCallFBF] _okGetInfo faxActive")
1072 if html.find('cntRufumleitung') != -1:
1073 entries = re.compile('mode = "1";\s*ziel = "[^"]+";\s*if \(mode == "1" \|\| ziel != ""\)\s*{\s*g_RufumleitungAktiv = true;', re.S).findall(html)
1074 rufumlActive = len(entries)
1075 entries = re.compile('if \("([^"]*)"=="([^"]*)"\) isAllIncoming\+\+;', re.S).finditer(html)
1077 for entry in entries:
1078 # debug("[FritzCallFBF] _okGetInfo rufumlActive add isAllIncoming")
1079 if entry.group(1) == entry.group(2):
1081 if isAllIncoming == 2 and rufumlActive > 0:
1083 # debug("[FritzCallFBF] _okGetInfo rufumlActive: " + str(rufumlActive))
1085 # /cgi-bin/webcm?getpage=../html/de/home/home_dsl.txt
1086 # { "dsl_carrier_state": "5", "umts_enabled": "0", "ata_mode": "0", "isusbgsm": "", "dsl_ds_nrate": "3130", "dsl_us_nrate": "448", "hint_dsl_no_cable": "0", "wds_enabled": "0", "wds_hop": "0", "isata": "" }
1087 if html.find('home_dsl.txt') != -1:
1088 url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
1090 'getpage':'../html/de/home/home_dsl.txt',
1093 # debug("[FritzCallFBF] get dsl state: url: '" + url + "' parms: '" + parms + "'")
1096 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
1098 'Content-Type': "application/x-www-form-urlencoded",
1099 'Content-Length': str(len(parms))},
1100 postdata=parms).addCallback(lambda x:self._okSetDslState(callback,x)).addErrback(self._errorGetInfo)
1102 found = re.match('.*function DslStateDisplay \(state\){\s*var state = "(\d+)";', html, re.S)
1104 # debug("[FritzCallFBF] _okGetInfo DslState: " + found.group(1))
1105 dslState = [ found.group(1), None ] # state, speed
1106 found = re.match('.*function DslStateDisplay \(state\){\s*var state = "\d+";.*?if \("3130" != "0"\) str = "([^"]*)";', html, re.S)
1108 # debug("[FritzCallFBF] _okGetInfo DslSpeed: " + found.group(1).strip())
1109 dslState[1] = found.group(1).strip()
1111 # /cgi-bin/webcm?getpage=../html/de/home/home_wlan.txt
1112 # { "ap_enabled": "1", "active_stations": "0", "encryption": "4", "wireless_stickandsurf_enabled": "0", "is_macfilter_active": "0", "wmm_enabled": "1", "wlan_state": [ "end" ] }
1113 if html.find('home_wlan.txt') != -1:
1114 url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
1116 'getpage':'../html/de/home/home_wlan.txt',
1119 # debug("[FritzCallFBF] get wlan state: url: '" + url + "' parms: '" + parms + "'")
1122 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
1124 'Content-Type': "application/x-www-form-urlencoded",
1125 'Content-Length': str(len(parms))},
1126 postdata=parms).addCallback(lambda x:self._okSetWlanState(callback,x)).addErrback(self._errorGetInfo)
1128 found = re.match('.*function WlanStateLed \(state\){.*?return StateLed\("(\d+)"\);\s*}', html, re.S)
1130 # debug("[FritzCallFBF] _okGetInfo WlanState: " + found.group(1))
1131 wlanState = [ found.group(1), 0, 0 ] # state, encryption, number of devices
1132 found = re.match('.*var (?:g_)?encryption = "(\d+)";', html, re.S)
1134 # debug("[FritzCallFBF] _okGetInfo WlanEncrypt: " + found.group(1))
1135 wlanState[1] = found.group(1)
1137 return (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive)
1139 debug("[FritzCallFBF] _okGetInfo")
1140 info = readInfo(html)
1141 debug("[FritzCallFBF] _okGetInfo info: " + str(info))
1146 def _okSetDect(self, callback, html):
1147 # debug("[FritzCallFBF] _okSetDect: " + html)
1148 # found = re.match('.*"connection_status":"(\d+)".*"connection_ip":"([.\d]+)".*"connection_detail":"([^"]+)".*"connection_uptime":"([^"]+)"', html, re.S)
1149 if html.find('"dect_enabled": "1"') != -1:
1150 # debug("[FritzCallFBF] _okSetDect: dect_enabled")
1151 found = re.match('.*"dect_device_list":.*\[([^\]]*)\]', html, re.S)
1153 # debug("[FritzCallFBF] _okSetDect: dect_device_list: %s" %(found.group(1)))
1154 entries = re.compile('"1"', re.S).findall(found.group(1))
1155 dectActive = len(entries)
1156 (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dummy, faxActive, rufumlActive) = self.info
1157 self.info = (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive)
1158 debug("[FritzCallFBF] _okSetDect info: " + str(self.info))
1162 def _okSetConInfo(self, callback, html):
1163 # debug("[FritzCallFBF] _okSetConInfo: " + html)
1164 # found = re.match('.*"connection_status":"(\d+)".*"connection_ip":"([.\d]+)".*"connection_detail":"([^"]+)".*"connection_uptime":"([^"]+)"', html, re.S)
1165 found = re.match('.*"connection_ip": "([.\d]+)".*"connection_uptime": "([^"]+)"', html, re.S)
1167 # debug("[FritzCallFBF] _okSetConInfo: connection_ip: %s upTime: %s" %( found.group(1), found.group(2)))
1168 ipAddress = found.group(1)
1169 upTime = found.group(2)
1170 (boxInfo, dummy, dummy, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive) = self.info
1171 self.info = (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive)
1172 debug("[FritzCallFBF] _okSetWlanState info: " + str(self.info))
1174 found = re.match('.*_ip": "([.\d]+)".*"connection_uptime": "([^"]+)"', html, re.S)
1176 # debug("[FritzCallFBF] _okSetConInfo: _ip: %s upTime: %s" %( found.group(1), found.group(2)))
1177 ipAddress = found.group(1)
1178 upTime = found.group(2)
1179 (boxInfo, dummy, dummy, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive) = self.info
1180 self.info = (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive)
1181 debug("[FritzCallFBF] _okSetWlanState info: " + str(self.info))
1185 def _okSetWlanState(self, callback, html):
1186 # debug("[FritzCallFBF] _okSetWlanState: " + html)
1187 found = re.match('.*"ap_enabled": "(\d+)"', html, re.S)
1189 # debug("[FritzCallFBF] _okSetWlanState: ap_enabled: " + found.group(1))
1190 wlanState = [ found.group(1), None, None ]
1191 found = re.match('.*"encryption": "(\d+)"', html, re.S)
1193 # debug("[FritzCallFBF] _okSetWlanState: encryption: " + found.group(1))
1194 wlanState[1] = found.group(1)
1195 found = re.match('.*"active_stations": "(\d+)"', html, re.S)
1197 # debug("[FritzCallFBF] _okSetWlanState: active_stations: " + found.group(1))
1198 wlanState[2] = found.group(1)
1199 (boxInfo, upTime, ipAddress, dummy, dslState, tamActive, dectActive, faxActive, rufumlActive) = self.info
1200 self.info = (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive)
1201 debug("[FritzCallFBF] _okSetWlanState info: " + str(self.info))
1205 def _okSetDslState(self, callback, html):
1206 # debug("[FritzCallFBF] _okSetDslState: " + html)
1207 found = re.match('.*"dsl_carrier_state": "(\d+)"', html, re.S)
1209 # debug("[FritzCallFBF] _okSetDslState: dsl_carrier_state: " + found.group(1))
1210 dslState = [ found.group(1), None ]
1211 found = re.match('.*"dsl_ds_nrate": "(\d+)"', html, re.S)
1213 # debug("[FritzCallFBF] _okSetDslState: dsl_ds_nrate: " + found.group(1))
1214 dslState[1] = found.group(1)
1215 found = re.match('.*"dsl_us_nrate": "(\d+)"', html, re.S)
1217 # debug("[FritzCallFBF] _okSetDslState: dsl_us_nrate: " + found.group(1))
1218 dslState[1] = dslState[1] + '/' + found.group(1)
1219 (boxInfo, upTime, ipAddress, wlanState, dummy, tamActive, dectActive, faxActive, rufumlActive) = self.info
1220 self.info = (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive)
1221 debug("[FritzCallFBF] _okSetDslState info: " + str(self.info))
1225 def _errorGetInfo(self, error):
1226 debug("[FritzCallFBF] _errorGetInfo: %s" % (error))
1227 text = _("FRITZ!Box - Error getting status: %s") % error.getErrorMessage()
1229 # linkP = open("/tmp/FritzCall_errorGetInfo.htm", "w")
1230 # linkP.write(error)
1234 self._login(self._reset)
1236 def _reset(self, html):
1237 # POSTDATA=getpage=../html/reboot.html&errorpage=../html/de/menus/menu2.html&var:lang=de&var:pagename=home&var:errorpagename=home&var:menu=home&var:pagemaster=&time:settings/time=1242207340%2C-120&var:tabReset=0&logic:command/reboot=../gateway/commands/saveconfig.html
1239 #===================================================================
1240 # found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)
1242 # self._errorReset('Login: ' + found.group(1))
1244 #===================================================================
1245 start = html.find('<p class="errorMessage">FEHLER: ')
1247 start = start + len('<p class="errorMessage">FEHLER: ')
1248 self._errorReset('Login: ' + html[start, html.find('</p>', start)])
1250 if self._callScreen:
1251 self._callScreen.close()
1252 url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
1254 'getpage':'../html/reboot.html',
1256 'var:pagename':'reset',
1257 'var:menu':'system',
1258 'logic:command/reboot':'../gateway/commands/saveconfig.html',
1261 debug("[FritzCallFBF] _reset url: '" + url + "' parms: '" + parms + "'")
1264 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
1266 'Content-Type': "application/x-www-form-urlencoded",
1267 'Content-Length': str(len(parms))},
1270 def _okReset(self, html): #@UnusedVariable # pylint: disable=W0613
1271 debug("[FritzCallFBF] _okReset")
1273 def _errorReset(self, error):
1274 debug("[FritzCallFBF] _errorReset: %s" % (error))
1275 text = _("FRITZ!Box - Error resetting: %s") % error.getErrorMessage()
1278 def readBlacklist(self):
1279 self._login(self._readBlacklist)
1281 def _readBlacklist(self, html):
1283 #===================================================================
1284 # found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)
1286 # self._errorBlacklist('Login: ' + found.group(1))
1288 #===================================================================
1289 start = html.find('<p class="errorMessage">FEHLER: ')
1291 start = start + len('<p class="errorMessage">FEHLER: ')
1292 self._errorBlacklist('Login: ' + html[start, html.find('</p>', start)])
1294 # http://fritz.box/cgi-bin/webcm?getpage=../html/de/menus/menu2.html&var:lang=de&var:menu=fon&var:pagename=sperre
1295 url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
1297 'getpage':'../html/de/menus/menu2.html',
1299 'var:pagename':'sperre',
1303 debug("[FritzCallFBF] _readBlacklist url: '" + url + "' parms: '" + parms + "'")
1306 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
1308 'Content-Type': "application/x-www-form-urlencoded",
1309 'Content-Length': str(len(parms))},
1310 postdata=parms).addCallback(self._okBlacklist).addErrback(self._errorBlacklist)
1312 def _okBlacklist(self, html):
1313 debug("[FritzCallFBF] _okBlacklist")
1314 entries = re.compile('<script type="text/javascript">document.write\(Tr(Out|In)\("\d+", "(\d+)", "\w*"\)\);</script>', re.S).finditer(html)
1315 self.blacklist = ([], [])
1316 for entry in entries:
1317 if entry.group(1) == "In":
1318 self.blacklist[0].append(entry.group(2))
1320 self.blacklist[1].append(entry.group(2))
1321 debug("[FritzCallFBF] _okBlacklist: %s" % repr(self.blacklist))
1323 def _errorBlacklist(self, error):
1324 debug("[FritzCallFBF] _errorBlacklist: %s" % (error))
1325 text = _("FRITZ!Box - Error getting blacklist: %s") % error.getErrorMessage()
1328 #===============================================================================
1330 # ''' hangup call on port; not used for now '''
1331 # url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
1332 # parms = urlencode({
1333 # 'id':'uiPostForm',
1334 # 'name':'uiPostForm',
1335 # 'login:command/password': config.plugins.FritzCall.password.value,
1336 # 'telcfg:settings/UseClickToDial':'1',
1337 # 'telcfg:settings/DialPort':config.plugins.FritzCall.extension.value,
1338 # 'telcfg:command/Hangup':'',
1339 # 'sid':self._md5Sid
1341 # debug("[FritzCallFBF] hangup url: '" + url + "' parms: '" + parms + "'")
1345 # 'Content-Type': "application/x-www-form-urlencoded",
1346 # 'Content-Length': str(len(parms))},
1348 #===============================================================================
1352 class FritzMenu(Screen, HelpableScreen):
1353 def __init__(self, session):
1354 fontSize = scaleV(24, 21) # indeed this is font size +2
1355 noButtons = 2 # reset, wlan
1357 if not fritzbox or not fritzbox.info:
1360 if fritzbox.info[FBF_tamActive]:
1361 noButtons += 1 # toggle mailboxes
1362 width = max(DESKTOP_WIDTH - scaleH(500, 250), noButtons*140+(noButtons+1)*10)
1363 # boxInfo 2 lines, gap, internet 2 lines, gap, dsl/wlan each 1 line, gap, buttons
1364 height = 5 + 2*fontSize + 10 + 2*fontSize + 10 + 2*fontSize + 10 + 40 + 5
1365 if fritzbox.info[FBF_tamActive] is not None:
1367 if fritzbox.info[FBF_dectActive] is not None:
1369 if fritzbox.info[FBF_faxActive] is not None:
1371 if fritzbox.info[FBF_rufumlActive] is not None:
1373 buttonsGap = (width-noButtons*140)/(noButtons+1)
1374 buttonsVPos = height-40-5
1377 if fritzbox.info[FBF_tamActive] is not None:
1379 <widget name="FBFMailbox" position="%d,%d" size="%d,%d" font="Regular;%d" />
1380 <widget name="mailbox_inactive" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1381 <widget name="mailbox_active" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1382 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
1383 <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" />
1385 40, 5+2*fontSize+10+varLinePos*fontSize+10, # position mailbox
1386 width-40-20, fontSize, # size mailbox
1388 "skin_default/buttons/button_green_off.png",
1389 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button mailbox
1390 "skin_default/buttons/button_green.png",
1391 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button mailbox
1392 noButtons*buttonsGap+(noButtons-1)*140, buttonsVPos,
1393 noButtons*buttonsGap+(noButtons-1)*140, buttonsVPos,
1399 if fritzbox.info[FBF_dectActive] is not None:
1401 <widget name="FBFDect" position="%d,%d" size="%d,%d" font="Regular;%d" />
1402 <widget name="dect_inactive" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1403 <widget name="dect_active" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1405 40, 5+2*fontSize+10+varLinePos*fontSize+10, # position dect
1406 width-40-20, fontSize, # size dect
1408 "skin_default/buttons/button_green_off.png",
1409 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button dect
1410 "skin_default/buttons/button_green.png",
1411 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button dect
1417 if fritzbox.info[FBF_faxActive] is not None:
1419 <widget name="FBFFax" position="%d,%d" size="%d,%d" font="Regular;%d" />
1420 <widget name="fax_inactive" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1421 <widget name="fax_active" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1423 40, 5+2*fontSize+10+varLinePos*fontSize+10, # position dect
1424 width-40-20, fontSize, # size dect
1426 "skin_default/buttons/button_green_off.png",
1427 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button dect
1428 "skin_default/buttons/button_green.png",
1429 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button dect
1435 if fritzbox.info[FBF_rufumlActive] is not None:
1437 <widget name="FBFRufuml" position="%d,%d" size="%d,%d" font="Regular;%d" />
1438 <widget name="rufuml_inactive" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1439 <widget name="rufuml_active" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1441 40, 5+2*fontSize+10+varLinePos*fontSize+10, # position dect
1442 width-40-20, fontSize, # size dect
1444 "skin_default/buttons/button_green_off.png",
1445 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button dect
1446 "skin_default/buttons/button_green.png",
1447 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button dect
1454 <screen name="FritzMenu" position="center,center" size="%d,%d" title="FRITZ!Box Fon Status" >
1455 <widget name="FBFInfo" position="%d,%d" size="%d,%d" font="Regular;%d" />
1456 <widget name="FBFInternet" position="%d,%d" size="%d,%d" font="Regular;%d" />
1457 <widget name="internet_inactive" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1458 <widget name="internet_active" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1459 <widget name="FBFDsl" position="%d,%d" size="%d,%d" font="Regular;%d" />
1460 <widget name="dsl_inactive" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1461 <widget name="dsl_active" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1462 <widget name="FBFWlan" position="%d,%d" size="%d,%d" font="Regular;%d" />
1463 <widget name="wlan_inactive" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1464 <widget name="wlan_active" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1469 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
1470 <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" />
1471 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
1472 <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" />
1474 width, height, # size
1475 40, 5, # position info
1476 width-2*40, 2*fontSize, # size info
1478 40, 5+2*fontSize+10, # position internet
1479 width-40, 2*fontSize, # size internet
1481 "skin_default/buttons/button_green_off.png",
1482 20, 5+2*fontSize+10+(fontSize-16)/2, # position button internet
1483 "skin_default/buttons/button_green.png",
1484 20, 5+2*fontSize+10+(fontSize-16)/2, # position button internet
1485 40, 5+2*fontSize+10+2*fontSize+10, # position dsl
1486 width-40-20, fontSize, # size dsl
1488 "skin_default/buttons/button_green_off.png",
1489 20, 5+2*fontSize+10+2*fontSize+10+(fontSize-16)/2, # position button dsl
1490 "skin_default/buttons/button_green.png",
1491 20, 5+2*fontSize+10+2*fontSize+10+(fontSize-16)/2, # position button dsl
1492 40, 5+2*fontSize+10+3*fontSize+10, # position wlan
1493 width-40-20, fontSize, # size wlan
1495 "skin_default/buttons/button_green_off.png",
1496 20, 5+2*fontSize+10+3*fontSize+10+(fontSize-16)/2, # position button wlan
1497 "skin_default/buttons/button_green.png",
1498 20, 5+2*fontSize+10+3*fontSize+10+(fontSize-16)/2, # position button wlan
1503 buttonsGap, buttonsVPos, "skin_default/buttons/red.png", buttonsGap, buttonsVPos,
1504 buttonsGap+140+buttonsGap, buttonsVPos, "skin_default/buttons/green.png", buttonsGap+140+buttonsGap, buttonsVPos,
1507 Screen.__init__(self, session)
1508 HelpableScreen.__init__(self)
1509 # TRANSLATORS: keep it short, this is a button
1510 self["key_red"] = Button(_("Reset"))
1511 # TRANSLATORS: keep it short, this is a button
1512 self["key_green"] = Button(_("Toggle WLAN"))
1513 self._mailboxActive = False
1514 if fritzbox.info[FBF_tamActive] is not None:
1515 # TRANSLATORS: keep it short, this is a button
1516 self["key_yellow"] = Button(_("Toggle Mailbox"))
1517 self["menuActions"] = ActionMap(["OkCancelActions", "ColorActions", "NumberActions", "EPGSelectActions"],
1519 "cancel": self._exit,
1522 "green": self._toggleWlan,
1523 "yellow": (lambda: self._toggleMailbox(-1)),
1524 "0": (lambda: self._toggleMailbox(0)),
1525 "1": (lambda: self._toggleMailbox(1)),
1526 "2": (lambda: self._toggleMailbox(2)),
1527 "3": (lambda: self._toggleMailbox(3)),
1528 "4": (lambda: self._toggleMailbox(4)),
1529 "info": self._getInfo,
1531 # TRANSLATORS: keep it short, this is a help text
1532 self.helpList.append((self["menuActions"], "ColorActions", [("yellow", _("Toggle all mailboxes"))]))
1533 # TRANSLATORS: keep it short, this is a help text
1534 self.helpList.append((self["menuActions"], "NumberActions", [("0", _("Toggle 1. mailbox"))]))
1535 # TRANSLATORS: keep it short, this is a help text
1536 self.helpList.append((self["menuActions"], "NumberActions", [("1", _("Toggle 2. mailbox"))]))
1537 # TRANSLATORS: keep it short, this is a help text
1538 self.helpList.append((self["menuActions"], "NumberActions", [("2", _("Toggle 3. mailbox"))]))
1539 # TRANSLATORS: keep it short, this is a help text
1540 self.helpList.append((self["menuActions"], "NumberActions", [("3", _("Toggle 4. mailbox"))]))
1541 # TRANSLATORS: keep it short, this is a help text
1542 self.helpList.append((self["menuActions"], "NumberActions", [("4", _("Toggle 5. mailbox"))]))
1543 self["FBFMailbox"] = Label(_('Mailbox'))
1544 self["mailbox_inactive"] = Pixmap()
1545 self["mailbox_active"] = Pixmap()
1546 self["mailbox_active"].hide()
1548 self["menuActions"] = ActionMap(["OkCancelActions", "ColorActions", "EPGSelectActions"],
1550 "cancel": self._exit,
1552 "green": self._toggleWlan,
1554 "info": self._getInfo,
1557 # TRANSLATORS: keep it short, this is a help text
1558 self.helpList.append((self["menuActions"], "OkCancelActions", [("cancel", _("Quit"))]))
1559 # TRANSLATORS: keep it short, this is a help text
1560 self.helpList.append((self["menuActions"], "OkCancelActions", [("ok", _("Quit"))]))
1561 # TRANSLATORS: keep it short, this is a help text
1562 self.helpList.append((self["menuActions"], "ColorActions", [("green", _("Toggle WLAN"))]))
1563 # TRANSLATORS: keep it short, this is a help text
1564 self.helpList.append((self["menuActions"], "ColorActions", [("red", _("Reset"))]))
1565 # TRANSLATORS: keep it short, this is a help text
1566 self.helpList.append((self["menuActions"], "EPGSelectActions", [("info", _("Refresh status"))]))
1568 self["FBFInfo"] = Label(_('Getting status from FRITZ!Box Fon...'))
1570 self["FBFInternet"] = Label('Internet')
1571 self["internet_inactive"] = Pixmap()
1572 self["internet_active"] = Pixmap()
1573 self["internet_active"].hide()
1575 self["FBFDsl"] = Label('DSL')
1576 self["dsl_inactive"] = Pixmap()
1577 self["dsl_inactive"].hide()
1578 self["dsl_active"] = Pixmap()
1579 self["dsl_active"].hide()
1581 self["FBFWlan"] = Label('WLAN ')
1582 self["wlan_inactive"] = Pixmap()
1583 self["wlan_inactive"].hide()
1584 self["wlan_active"] = Pixmap()
1585 self["wlan_active"].hide()
1586 self._wlanActive = False
1588 if fritzbox.info[FBF_dectActive] is not None:
1589 self["FBFDect"] = Label('DECT')
1590 self["dect_inactive"] = Pixmap()
1591 self["dect_active"] = Pixmap()
1592 self["dect_active"].hide()
1594 if fritzbox.info[FBF_faxActive] is not None:
1595 self["FBFFax"] = Label('Fax')
1596 self["fax_inactive"] = Pixmap()
1597 self["fax_active"] = Pixmap()
1598 self["fax_active"].hide()
1600 if fritzbox.info[FBF_rufumlActive] is not None:
1601 self["FBFRufuml"] = Label(_('Call redirection'))
1602 self["rufuml_inactive"] = Pixmap()
1603 self["rufuml_active"] = Pixmap()
1604 self["rufuml_active"].hide()
1606 self._timer = eTimer()
1607 self._timer.callback.append(self._getInfo)
1608 self.onShown.append(lambda: self._timer.start(5000))
1609 self.onHide.append(self._timer.stop)
1611 self.onLayoutFinish.append(self.setWindowTitle)
1613 def setWindowTitle(self):
1614 # TRANSLATORS: this is a window title.
1615 self.setTitle(_("FRITZ!Box Fon Status"))
1618 fritzbox.getInfo(self._fillMenu)
1620 def _fillMenu(self, status):
1621 (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive) = status
1622 self._wlanActive = (wlanState[0] == '1')
1623 self._mailboxActive = False
1625 if not self.has_key("FBFInfo"): # screen is closed already
1629 self["FBFInfo"].setText(boxInfo.replace(', ', '\n'))
1631 self["FBFInfo"].setText('BoxInfo ' + _('Status not available'))
1635 self["FBFInternet"].setText('Internet ' + _('IP Address:') + ' ' + ipAddress + '\n' + _('Connected since') + ' ' + upTime)
1637 self["FBFInternet"].setText('Internet ' + _('IP Address:') + ' ' + ipAddress)
1638 self["internet_inactive"].hide()
1639 self["internet_active"].show()
1641 self["internet_active"].hide()
1642 self["internet_inactive"].show()
1645 if dslState[0] == '5':
1646 self["dsl_inactive"].hide()
1647 self["dsl_active"].show()
1649 self["FBFDsl"].setText('DSL ' + dslState[1])
1651 self["dsl_active"].hide()
1652 self["dsl_inactive"].show()
1654 self["FBFDsl"].setText('DSL ' + _('Status not available'))
1655 self["dsl_active"].hide()
1656 self["dsl_inactive"].hide()
1659 if wlanState[0 ] == '1':
1660 self["wlan_inactive"].hide()
1661 self["wlan_active"].show()
1663 if wlanState[1] == '0':
1664 message += ' ' + _('not encrypted')
1666 message += ' ' + _('encrypted')
1668 if wlanState[2] == '0':
1669 message = message + ', ' + _('no device active')
1670 elif wlanState[2] == '1':
1671 message = message + ', ' + _('one device active')
1673 message = message + ', ' + wlanState[2] + ' ' + _('devices active')
1674 self["FBFWlan"].setText(message)
1676 self["wlan_active"].hide()
1677 self["wlan_inactive"].show()
1678 self["FBFWlan"].setText('WLAN')
1680 self["FBFWlan"].setText('WLAN ' + _('Status not available'))
1681 self["wlan_active"].hide()
1682 self["wlan_inactive"].hide()
1684 if fritzbox.info[FBF_tamActive]:
1685 if not tamActive or tamActive[0] == 0:
1686 self._mailboxActive = False
1687 self["mailbox_active"].hide()
1688 self["mailbox_inactive"].show()
1689 self["FBFMailbox"].setText(_('No mailbox active'))
1691 self._mailboxActive = True
1695 message = message + str(i) + ','
1696 message = message[:-1] + ')'
1697 self["mailbox_inactive"].hide()
1698 self["mailbox_active"].show()
1699 if tamActive[0] == 1:
1700 self["FBFMailbox"].setText(_('One mailbox active') + ' ' + message)
1702 self["FBFMailbox"].setText(str(tamActive[0]) + ' ' + _('mailboxes active') + ' ' + message)
1704 if fritzbox.info[FBF_dectActive] and dectActive:
1705 self["dect_inactive"].hide()
1706 self["dect_active"].show()
1708 self["FBFDect"].setText(_('No DECT phone registered'))
1711 self["FBFDect"].setText(_('One DECT phone registered'))
1713 self["FBFDect"].setText(str(dectActive) + ' ' + _('DECT phones registered'))
1715 if fritzbox.info[FBF_faxActive] and faxActive:
1716 self["fax_inactive"].hide()
1717 self["fax_active"].show()
1718 self["FBFFax"].setText(_('Software fax active'))
1720 if fritzbox.info[FBF_rufumlActive] is not None and rufumlActive is not None:
1721 if rufumlActive == 0:
1722 self["rufuml_active"].hide()
1723 self["rufuml_inactive"].show()
1724 self["FBFRufuml"].setText(_('No call redirection active'))
1726 self["rufuml_inactive"].hide()
1727 self["rufuml_active"].show()
1728 if rufumlActive == 1:
1729 self["FBFRufuml"].setText(_('One call redirection active'))
1731 self["FBFRufuml"].setText(str(rufumlActive) + ' ' + _('call redirections active'))
1734 debug("[FritzCallFBF] _fillMenu: " + traceback.format_exc())
1736 def _toggleWlan(self):
1737 if self._wlanActive:
1738 debug("[FritzMenu] toggleWlan off")
1739 fritzbox.changeWLAN('0')
1741 debug("[FritzMenu] toggleWlan off")
1742 fritzbox.changeWLAN('1')
1744 def _toggleMailbox(self, which):
1745 debug("[FritzMenu] toggleMailbox")
1746 if fritzbox.info[FBF_tamActive]:
1747 debug("[FritzMenu] toggleMailbox off")
1748 fritzbox.changeMailbox(which)
1759 class FritzDisplayCalls(Screen, HelpableScreen):
1761 def __init__(self, session, text=""): #@UnusedVariable # pylint: disable=W0613
1762 self.width = DESKTOP_WIDTH * scaleH(75, 85)/100
1763 self.height = DESKTOP_HEIGHT * 0.75
1764 dateFieldWidth = scaleH(180, 105)
1766 lengthFieldWidth = scaleH(55, 45)
1767 scrollbarWidth = scaleH(35, 35)
1768 entriesWidth = self.width -scaleH(40, 5) -5
1769 hereFieldWidth = entriesWidth -dirFieldWidth -5 -dateFieldWidth -5 -lengthFieldWidth -scrollbarWidth
1770 fieldWidth = entriesWidth -dirFieldWidth -5 -5 -scrollbarWidth
1771 fontSize = scaleV(22, 20)
1772 itemHeight = 2*fontSize+5
1773 entriesHeight = self.height -scaleV(15, 10) -5 -fontSize -5 -5 -5 -40 -5
1774 buttonGap = (self.width -4*140)/5
1775 buttonV = self.height -40
1776 debug("[FritzDisplayCalls] width: " + str(self.width))
1778 <screen name="FritzDisplayCalls" position="center,center" size="%d,%d" title="Phone calls" >
1779 <eLabel position="0,0" size="%d,2" backgroundColor="#aaaaaa" />
1780 <widget name="statusbar" position="%d,%d" size="%d,%d" font="Regular;%d" backgroundColor="#aaaaaa" transparent="1" />
1781 <eLabel position="0,%d" size="%d,2" backgroundColor="#aaaaaa" />
1782 <widget source="entries" render="Listbox" position="%d,%d" size="%d,%d" scrollbarMode="showOnDemand" transparent="1">
1783 <convert type="TemplatedMultiContent">
1785 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
1786 MultiContentEntryPixmapAlphaTest(pos = (%d,%d), size = (%d,%d), png = 2), # index 1 i direction pixmap
1787 MultiContentEntryText(pos = (%d,%d), size = (%d,%d), font=1, flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER, text = 3), # index 2 is remote name/number
1788 MultiContentEntryText(pos = (%d,%d), size = (%d,%d), font=0, flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER, text = 4), # index 3 is length of call
1789 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
1791 "fonts": [gFont("Regular", %d), gFont("Regular", %d)],
1796 <eLabel position="0,%d" size="%d,2" backgroundColor="#aaaaaa" />
1797 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
1798 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
1799 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
1800 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
1801 <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" />
1802 <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" />
1803 <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" />
1804 <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" />
1806 # scaleH(90, 75), scaleV(100, 78), # position
1807 self.width, self.height, # size
1808 self.width, # eLabel width
1809 scaleH(40, 5), scaleV(10, 5), # statusbar position
1810 self.width, fontSize+5, # statusbar size
1811 scaleV(21, 21), # statusbar font size
1812 scaleV(10, 5)+5+fontSize+5, # eLabel position vertical
1813 self.width, # eLabel width
1814 scaleH(40, 5), scaleV(10, 5)+5+fontSize+5+5, # entries position
1815 entriesWidth, entriesHeight, # entries size
1816 5+dirFieldWidth+5, fontSize+5, dateFieldWidth, fontSize, # date pos/size
1817 5, (itemHeight-dirFieldWidth)/2, dirFieldWidth, dirFieldWidth, # dir pos/size
1818 5+dirFieldWidth+5, 5, fieldWidth, fontSize, # caller pos/size
1819 2+dirFieldWidth+2+dateFieldWidth+5, fontSize+5, lengthFieldWidth, fontSize, # length pos/size
1820 2+dirFieldWidth+2+dateFieldWidth+5+lengthFieldWidth+5, fontSize+5, hereFieldWidth, fontSize, # my number pos/size
1821 fontSize-4, fontSize, # fontsize
1822 itemHeight, # itemHeight
1823 buttonV-5, # eLabel position vertical
1824 self.width, # eLabel width
1825 buttonGap, buttonV, "skin_default/buttons/red.png", # widget red
1826 2*buttonGap+140, buttonV, "skin_default/buttons/green.png", # widget green
1827 3*buttonGap+2*140, buttonV, "skin_default/buttons/yellow.png", # widget yellow
1828 4*buttonGap+3*140, buttonV, "skin_default/buttons/blue.png", # widget blue
1829 buttonGap, buttonV, scaleV(22, 21), # widget red
1830 2*buttonGap+140, buttonV, scaleV(22, 21), # widget green
1831 3*buttonGap+2*140, buttonV, scaleV(22, 21), # widget yellow
1832 4*buttonGap+3*140, buttonV, scaleV(22, 21), # widget blue
1834 # debug("[FritzDisplayCalls] skin: " + self.skin)
1835 Screen.__init__(self, session)
1836 HelpableScreen.__init__(self)
1838 # TRANSLATORS: keep it short, this is a button
1839 self["key_yellow"] = Button(_("All"))
1840 # TRANSLATORS: keep it short, this is a button
1841 self["key_red"] = Button(_("Missed"))
1842 # TRANSLATORS: keep it short, this is a button
1843 self["key_blue"] = Button(_("Incoming"))
1844 # TRANSLATORS: keep it short, this is a button
1845 self["key_green"] = Button(_("Outgoing"))
1847 self["setupActions"] = ActionMap(["OkCancelActions", "ColorActions"],
1849 "yellow": (lambda: self.display(FBF_ALL_CALLS)),
1850 "red": (lambda: self.display(FBF_MISSED_CALLS)),
1851 "blue": (lambda: self.display(FBF_IN_CALLS)),
1852 "green": (lambda: self.display(FBF_OUT_CALLS)),
1854 "ok": self.showEntry, }, - 2)
1856 # TRANSLATORS: keep it short, this is a help text
1857 self.helpList.append((self["setupActions"], "OkCancelActions", [("ok", _("Show details of entry"))]))
1858 # TRANSLATORS: keep it short, this is a help text
1859 self.helpList.append((self["setupActions"], "OkCancelActions", [("cancel", _("Quit"))]))
1860 # TRANSLATORS: keep it short, this is a help text
1861 self.helpList.append((self["setupActions"], "ColorActions", [("yellow", _("Display all calls"))]))
1862 # TRANSLATORS: keep it short, this is a help text
1863 self.helpList.append((self["setupActions"], "ColorActions", [("red", _("Display missed calls"))]))
1864 # TRANSLATORS: keep it short, this is a help text
1865 self.helpList.append((self["setupActions"], "ColorActions", [("blue", _("Display incoming calls"))]))
1866 # TRANSLATORS: keep it short, this is a help text
1867 self.helpList.append((self["setupActions"], "ColorActions", [("green", _("Display outgoing calls"))]))
1869 self["statusbar"] = Label(_("Getting calls from FRITZ!Box..."))
1871 self["entries"] = List(self.list)
1872 #=======================================================================
1873 # fontSize = scaleV(22, 18)
1874 # fontHeight = scaleV(24, 20)
1875 # self["entries"].l.setFont(0, gFont("Regular", fontSize))
1876 # self["entries"].l.setItemHeight(fontHeight)
1877 #=======================================================================
1878 debug("[FritzDisplayCalls] init: '''%s'''" % config.plugins.FritzCall.fbfCalls.value)
1880 self.onLayoutFinish.append(self.setWindowTitle)
1882 def setWindowTitle(self):
1883 # TRANSLATORS: this is a window title.
1884 self.setTitle(_("Phone calls"))
1889 def display(self, which=config.plugins.FritzCall.fbfCalls.value):
1890 debug("[FritzDisplayCalls] display")
1891 config.plugins.FritzCall.fbfCalls.value = which
1892 config.plugins.FritzCall.fbfCalls.save()
1893 fritzbox.getCalls(self, lambda x: self.gotCalls(x, which), which)
1895 def gotCalls(self, listOfCalls, which):
1896 debug("[FritzDisplayCalls] gotCalls")
1897 self.updateStatus(fbfCallsChoices[which] + " (" + str(len(listOfCalls)) + ")")
1899 directout = LoadPixmap(resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/images/callout.png"))
1900 directin = LoadPixmap(resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/images/callin.png"))
1901 directfailed = LoadPixmap(resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/images/callinfailed.png"))
1903 if direct == FBF_OUT_CALLS:
1905 elif direct == FBF_IN_CALLS:
1908 direct = directfailed
1911 # debug("[FritzDisplayCalls] gotCalls: %s" %repr(listOfCalls))
1912 self.list = [(number, date[:6] + ' ' + date[9:14], pixDir(direct), remote, length, here) for (number, date, direct, remote, length, here) in listOfCalls]
1913 self["entries"].setList(self.list)
1914 if len(self.list) > 1:
1915 self["entries"].setIndex(1)
1917 def updateStatus(self, text):
1918 if self.has_key("statusbar"):
1919 self["statusbar"].setText(_("Getting calls from FRITZ!Box...") + ' ' + text)
1921 def showEntry(self):
1922 debug("[FritzDisplayCalls] showEntry")
1923 cur = self["entries"].getCurrent()
1926 debug("[FritzDisplayCalls] showEntry %s" % (cur[0]))
1928 fullname = phonebook.search(cur[0])
1930 # we have a name for this number
1932 self.session.open(FritzOfferAction, self, number, name)
1935 self.session.open(FritzOfferAction, self, number, name)
1938 fullname = resolveNumberWithAvon(number, config.plugins.FritzCall.country.value)
1941 self.session.open(FritzOfferAction, self, number, name)
1943 self.session.open(FritzOfferAction, self, number)
1945 # we do not even have a number...
1946 self.session.open(MessageBox,
1948 type=MessageBox.TYPE_INFO)
1951 class FritzOfferAction(Screen):
1953 def __init__(self, session, parent, number, name=""):
1954 # the layout will completely be recalculated in finishLayout
1956 <screen name="FritzOfferAction" title="Do what?" >
1957 <widget name="text" size="%d,%d" font="Regular;%d" />
1958 <widget name="FacePixmap" size="%d,%d" alphatest="on" />
1959 <widget name="key_red_p" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
1960 <widget name="key_green_p" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
1961 <widget name="key_yellow_p" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
1962 <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" />
1963 <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" />
1964 <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" />
1966 DESKTOP_WIDTH, DESKTOP_HEIGHT, # set maximum size
1967 scaleH(22,21), # text
1968 DESKTOP_WIDTH, DESKTOP_HEIGHT, # set maximum size
1969 "skin_default/buttons/red.png",
1970 "skin_default/buttons/green.png",
1971 "skin_default/buttons/yellow.png",
1973 debug("[FritzOfferAction] init: %s, %s" %(number, name))
1974 Screen.__init__(self, session)
1976 # TRANSLATORS: keep it short, this is a button
1977 self["key_red"] = Button(_("Lookup"))
1978 # TRANSLATORS: keep it short, this is a button
1979 self["key_green"] = Button(_("Call"))
1980 # TRANSLATORS: keep it short, this is a button
1981 self["key_yellow"] = Button(_("Save"))
1982 # TRANSLATORS: keep it short, this is a button
1983 # self["key_blue"] = Button(_("Search"))
1985 self["FritzOfferActions"] = ActionMap(["OkCancelActions", "ColorActions"],
1987 "red": self._lookup,
1988 "green": self._call,
1989 "yellow": self._add,
1990 "cancel": self._exit,
1991 "ok": self._exit, }, - 2)
1993 self._session = session
1994 if config.plugins.FritzCall.internal.value and len(number) > 3 and number[0] == "0":
1996 self._number = number
1997 self._name = name.replace("\n", ", ")
1998 self["text"] = Label(number + "\n\n" + name.replace(", ", "\n"))
1999 self._parent = parent
2000 self._lookupState = 0
2001 self["key_red_p"] = Pixmap()
2002 self["key_green_p"] = Pixmap()
2003 self["key_yellow_p"] = Pixmap()
2004 self["FacePixmap"] = Pixmap()
2005 self.onLayoutFinish.append(self._finishLayout)
2006 self.onLayoutFinish.append(self.setWindowTitle)
2008 def setWindowTitle(self):
2009 # TRANSLATORS: this is a window title.
2010 self.setTitle(_("Do what?"))
2012 def _finishLayout(self):
2013 # pylint: disable=W0142
2014 debug("[FritzCall] FritzOfferAction/finishLayout number: %s/%s" % (self._number, self._name))
2016 faceFile = findFace(self._number, self._name)
2017 picPixmap = LoadPixmap(faceFile)
2018 if not picPixmap: # that means most probably, that the picture is not 8 bit...
2019 Notifications.AddNotification(MessageBox, _("Found picture\n\n%s\n\nBut did not load. Probably not PNG, 8-bit") %faceFile, type = MessageBox.TYPE_ERROR)
2020 picPixmap = LoadPixmap(resolveFilename(SCOPE_SKIN_IMAGE, "skin_default/icons/input_error.png"))
2021 picSize = picPixmap.size()
2022 self["FacePixmap"].instance.setPixmap(picPixmap)
2025 # recalculate window size
2026 textSize = self["text"].getSize()
2027 textSize = (textSize[0]+20, textSize[1]+20) # don't know, why, but size is too small
2028 debug("[FritzCall] FritzOfferAction/finishLayout textsize: %s/%s" % textSize)
2029 textSize = eSize(*textSize)
2030 width = max(scaleH(620, 545), noButtons*145, picSize.width() + textSize.width() + 30)
2031 height = max(picSize.height()+5, textSize.height()+5, scaleV(-1, 136)) + 5 + 40 + 5
2032 buttonsGap = (width-noButtons*140)/(noButtons+1)
2033 buttonsVPos = height-40-5
2034 wSize = (width, height)
2035 wSize = eSize(*wSize)
2037 # center the smaller vertically
2038 hGap = (width-picSize.width()-textSize.width())/3
2039 picPos = (hGap, (height-50-picSize.height())/2+5)
2040 textPos = (hGap+picSize.width()+hGap, (height-50-textSize.height())/2+5)
2043 self.instance.resize(wSize)
2045 self["text"].instance.resize(textSize)
2047 self["FacePixmap"].instance.resize(picSize)
2049 buttonPos = (buttonsGap, buttonsVPos)
2050 self["key_red_p"].instance.move(ePoint(*buttonPos))
2051 self["key_red"].instance.move(ePoint(*buttonPos))
2052 buttonPos = (buttonsGap+140+buttonsGap, buttonsVPos)
2053 self["key_green_p"].instance.move(ePoint(*buttonPos))
2054 self["key_green"].instance.move(ePoint(*buttonPos))
2055 buttonPos = (buttonsGap+140+buttonsGap+140+buttonsGap, buttonsVPos)
2056 self["key_yellow_p"].instance.move(ePoint(*buttonPos))
2057 self["key_yellow"].instance.move(ePoint(*buttonPos))
2059 self["text"].instance.move(ePoint(*textPos))
2061 self["FacePixmap"].instance.move(ePoint(*picPos))
2063 self.instance.move(ePoint((DESKTOP_WIDTH-wSize.width())/2, (DESKTOP_HEIGHT-wSize.height())/2))
2065 def _setTextAndResize(self, message):
2066 # pylint: disable=W0142
2067 self["text"].instance.resize(eSize(*(DESKTOP_WIDTH, DESKTOP_HEIGHT)))
2068 self["text"].setText(self._number + "\n\n" + message)
2069 self._finishLayout()
2072 phonebookLocation = config.plugins.FritzCall.phonebookLocation.value
2073 if self._lookupState == 0:
2074 self._lookupState = 1
2075 self._setTextAndResize(_("Reverse searching..."))
2076 ReverseLookupAndNotifier(self._number, self._lookedUp, "UTF-8", config.plugins.FritzCall.country.value)
2078 if self._lookupState == 1 and os.path.exists(os.path.join(phonebookLocation, "PhoneBook.csv")):
2079 self._setTextAndResize(_("Searching in Outlook export..."))
2080 self._lookupState = 2
2081 self._lookedUp(self._number, FritzOutlookCSV.findNumber(self._number, os.path.join(phonebookLocation, "PhoneBook.csv"))) #@UndefinedVariable
2084 self._lookupState = 2
2085 if self._lookupState == 2 and os.path.exists(os.path.join(phonebookLocation, "PhoneBook.ldif")):
2086 self._setTextAndResize(_("Searching in LDIF..."))
2087 self._lookupState = 0
2088 FritzLDIF.FindNumber(self._number, open(os.path.join(phonebookLocation, "PhoneBook.ldif")), self._lookedUp)
2091 self._lookupState = 0
2094 def _lookedUp(self, number, name):
2095 name = handleReverseLookupResult(name)
2097 if self._lookupState == 1:
2098 name = _("No result from reverse lookup")
2099 elif self._lookupState == 2:
2100 name = _("No result from Outlook export")
2102 name = _("No result from LDIF")
2104 self._number = number
2105 debug("[FritzOfferAction] lookedUp: " + str(name.replace(", ", "\n")))
2106 self._setTextAndResize(str(name.replace(", ", "\n")))
2109 debug("[FritzOfferAction] add: %s" %self._number)
2110 fritzbox.dial(self._number)
2114 debug("[FritzOfferAction] add: %s, %s" %(self._number, self._name))
2115 phonebook.FritzDisplayPhonebook(self._session).add(self._parent, self._number, self._name)
2122 class FritzCallPhonebook:
2124 debug("[FritzCallPhonebook] init")
2125 # Beware: strings in phonebook.phonebook have to be in utf-8!
2130 debug("[FritzCallPhonebook] reload")
2131 # Beware: strings in phonebook.phonebook have to be in utf-8!
2134 if not config.plugins.FritzCall.enable.value:
2137 phonebookFilename = os.path.join(config.plugins.FritzCall.phonebookLocation.value, "PhoneBook.txt")
2138 if config.plugins.FritzCall.phonebook.value and os.path.exists(phonebookFilename):
2139 debug("[FritzCallPhonebook] reload: read " + phonebookFilename)
2140 phonebookTxtCorrupt = False
2142 for line in open(phonebookFilename):
2144 # Beware: strings in phonebook.phonebook have to be in utf-8!
2145 line = line.decode("utf-8")
2146 except UnicodeDecodeError: # this is just for the case, somebody wrote latin1 chars into PhoneBook.txt
2148 line = line.decode("iso-8859-1")
2149 debug("[FritzCallPhonebook] Fallback to ISO-8859-1 in %s" % line)
2150 phonebookTxtCorrupt = True
2151 except UnicodeDecodeError:
2152 debug("[FritzCallPhonebook] Could not parse internal Phonebook Entry %s" % line)
2153 phonebookTxtCorrupt = True
2154 line = line.encode("utf-8")
2155 elems = line.split('#')
2158 self.phonebook[elems[0]] = elems[1]
2159 except ValueError: # how could this possibly happen?!?!
2160 debug("[FritzCallPhonebook] Could not parse internal Phonebook Entry %s" % line)
2161 phonebookTxtCorrupt = True
2163 debug("[FritzCallPhonebook] Could not parse internal Phonebook Entry %s" % line)
2164 phonebookTxtCorrupt = True
2166 #===============================================================
2167 # found = re.match("^(\d+)#(.*)$", line)
2170 # self.phonebook[found.group(1)] = found.group(2)
2171 # except ValueError: # how could this possibly happen?!?!
2172 # debug("[FritzCallPhonebook] Could not parse internal Phonebook Entry %s" % line)
2173 # phonebookTxtCorrupt = True
2175 # debug("[FritzCallPhonebook] Could not parse internal Phonebook Entry %s" % line)
2176 # phonebookTxtCorrupt = True
2177 #===============================================================
2179 if phonebookTxtCorrupt:
2180 # dump phonebook to PhoneBook.txt
2181 debug("[FritzCallPhonebook] dump Phonebook.txt")
2183 os.rename(phonebookFilename, phonebookFilename + ".bck")
2184 fNew = open(phonebookFilename, 'w')
2185 # Beware: strings in phonebook.phonebook are utf-8!
2186 for (number, name) in self.phonebook.iteritems():
2187 # Beware: strings in PhoneBook.txt have to be in utf-8!
2188 fNew.write(number + "#" + name.encode("utf-8"))
2190 except (IOError, OSError):
2191 debug("[FritzCallPhonebook] error renaming or writing to %s" %phonebookFilename)
2193 #===============================================================================
2195 # # read entries from Outlook export
2197 # # not reliable with coding yet
2199 # # import csv exported from Outlook 2007 with csv(Windows)
2200 # csvFilename = "/tmp/PhoneBook.csv"
2201 # if config.plugins.FritzCall.phonebook.value and os.path.exists(csvFilename):
2203 # readOutlookCSV(csvFilename, self.add)
2204 # os.rename(csvFilename, csvFilename + ".done")
2205 # except ImportError:
2206 # debug("[FritzCallPhonebook] CSV import failed" %line)
2207 #===============================================================================
2210 #===============================================================================
2212 # # read entries from LDIF
2214 # # import ldif exported from Thunderbird 2.0.0.19
2215 # ldifFilename = "/tmp/PhoneBook.ldif"
2216 # if config.plugins.FritzCall.phonebook.value and os.path.exists(ldifFilename):
2218 # parser = MyLDIF(open(ldifFilename), self.add)
2220 # os.rename(ldifFilename, ldifFilename + ".done")
2221 # except ImportError:
2222 # debug("[FritzCallPhonebook] LDIF import failed" %line)
2223 #===============================================================================
2225 if fritzbox and config.plugins.FritzCall.fritzphonebook.value:
2226 fritzbox.loadFritzBoxPhonebook()
2228 def search(self, number):
2229 # debug("[FritzCallPhonebook] Searching for %s" %number)
2231 if not self.phonebook or not number:
2234 if config.plugins.FritzCall.prefix.value:
2235 prefix = config.plugins.FritzCall.prefix.value
2236 if number[0] != '0':
2237 number = prefix + number
2238 # debug("[FritzCallPhonebook] search: added prefix: %s" %number)
2239 elif number[:len(prefix)] == prefix and self.phonebook.has_key(number[len(prefix):]):
2240 # debug("[FritzCallPhonebook] search: same prefix")
2241 name = self.phonebook[number[len(prefix):]]
2242 # debug("[FritzCallPhonebook] search: result: %s" %name)
2246 if not name and self.phonebook.has_key(number):
2247 name = self.phonebook[number]
2249 return name.replace(", ", "\n").strip()
2251 def add(self, number, name):
2254 @param number: number of entry
2255 @param name: name of entry, has to be in utf-8
2257 debug("[FritzCallPhonebook] add")
2258 name = name.replace("\n", ", ").replace('#','') # this is just for safety reasons. add should only be called with newlines converted into commas
2260 self.phonebook[number] = name
2261 if number and number != 0:
2262 if config.plugins.FritzCall.phonebook.value:
2264 name = name.strip() + "\n"
2265 string = "%s#%s" % (number, name)
2266 # Beware: strings in PhoneBook.txt have to be in utf-8!
2267 f = open(os.path.join(config.plugins.FritzCall.phonebookLocation.value, "PhoneBook.txt"), 'a')
2270 debug("[FritzCallPhonebook] added %s with %s to Phonebook.txt" % (number, name.strip()))
2276 def remove(self, number):
2277 if number in self.phonebook:
2278 debug("[FritzCallPhonebook] remove entry in phonebook")
2279 del self.phonebook[number]
2280 if config.plugins.FritzCall.phonebook.value:
2282 phonebookFilename = os.path.join(config.plugins.FritzCall.phonebookLocation.value, "PhoneBook.txt")
2283 debug("[FritzCallPhonebook] remove entry in Phonebook.txt")
2284 fOld = open(phonebookFilename, 'r')
2285 fNew = open(phonebookFilename + str(os.getpid()), 'w')
2286 line = fOld.readline()
2288 elems = line.split('#')
2289 if len(elems) == 2 and not elems[0] == number:
2291 line = fOld.readline()
2294 # os.remove(phonebookFilename)
2295 eBackgroundFileEraser.getInstance().erase(phonebookFilename)
2296 os.rename(phonebookFilename + str(os.getpid()), phonebookFilename)
2297 debug("[FritzCallPhonebook] removed %s from Phonebook.txt" % number)
2300 except (IOError, OSError):
2301 debug("[FritzCallPhonebook] error removing %s from %s" %(number, phonebookFilename))
2304 class FritzDisplayPhonebook(Screen, HelpableScreen, NumericalTextInput):
2306 def __init__(self, session):
2307 self.entriesWidth = DESKTOP_WIDTH * scaleH(75, 85)/100
2308 self.height = DESKTOP_HEIGHT * 0.75
2309 numberFieldWidth = scaleH(220, 160)
2310 fieldWidth = self.entriesWidth -5 -numberFieldWidth -10
2311 fontSize = scaleV(22, 18)
2312 fontHeight = scaleV(24, 20)
2313 buttonGap = (self.entriesWidth-4*140)/5
2314 debug("[FritzDisplayPhonebook] width: " + str(self.entriesWidth))
2316 <screen name="FritzDisplayPhonebook" position="center,center" size="%d,%d" title="Phonebook" >
2317 <eLabel position="0,0" size="%d,2" backgroundColor="#aaaaaa" />
2318 <widget source="entries" render="Listbox" position="%d,%d" size="%d,%d" scrollbarMode="showOnDemand" transparent="1">
2319 <convert type="TemplatedMultiContent">
2321 MultiContentEntryText(pos = (%d,%d), size = (%d,%d), font=0, flags = RT_HALIGN_LEFT, text = 1), # index 0 is the name, index 1 is shortname
2322 MultiContentEntryText(pos = (%d,%d), size = (%d,%d), font=0, flags = RT_HALIGN_LEFT, text = 2), # index 2 is number
2324 "fonts": [gFont("Regular", %d)],
2329 <eLabel position="0,%d" size="%d,2" backgroundColor="#aaaaaa" />
2330 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
2331 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
2332 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
2333 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
2334 <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" />
2335 <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" />
2336 <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" />
2337 <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" />
2339 # scaleH(90, 75), scaleV(100, 73), # position
2340 self.entriesWidth, self.height, # size
2341 self.entriesWidth, # eLabel width
2342 scaleH(40, 5), scaleV(20, 5), # entries position
2343 self.entriesWidth-scaleH(40, 5), self.height-scaleV(20, 5)-5-5-40, # entries size
2344 0, 0, fieldWidth, scaleH(24,20), # name pos/size
2345 fieldWidth +5, 0, numberFieldWidth, scaleH(24,20), # dir pos/size
2346 fontSize, # fontsize
2347 fontHeight, # itemHeight
2348 self.height-40-5, # eLabel position vertical
2349 self.entriesWidth, # eLabel width
2350 buttonGap, self.height-40, "skin_default/buttons/red.png", # ePixmap red
2351 2*buttonGap+140, self.height-40, "skin_default/buttons/green.png", # ePixmap green
2352 3*buttonGap+2*140, self.height-40, "skin_default/buttons/yellow.png", # ePixmap yellow
2353 4*buttonGap+3*140, self.height-40, "skin_default/buttons/blue.png", # ePixmap blue
2354 buttonGap, self.height-40, scaleV(22, 21), # widget red
2355 2*buttonGap+140, self.height-40, scaleV(22, 21), # widget green
2356 3*buttonGap+2*140, self.height-40, scaleV(22, 21), # widget yellow
2357 4*buttonGap+3*140, self.height-40, scaleV(22, 21), # widget blue
2360 # debug("[FritzDisplayCalls] skin: " + self.skin)
2361 Screen.__init__(self, session)
2362 NumericalTextInput.__init__(self)
2363 HelpableScreen.__init__(self)
2365 # TRANSLATORS: keep it short, this is a button
2366 self["key_red"] = Button(_("Delete"))
2367 # TRANSLATORS: keep it short, this is a button
2368 self["key_green"] = Button(_("New"))
2369 # TRANSLATORS: keep it short, this is a button
2370 self["key_yellow"] = Button(_("Edit"))
2371 # TRANSLATORS: keep it short, this is a button
2372 self["key_blue"] = Button(_("Search"))
2374 self["setupActions"] = ActionMap(["OkCancelActions", "ColorActions"],
2378 "yellow": self.edit,
2379 "blue": self.search,
2380 "cancel": self.exit,
2381 "ok": self.showEntry, }, - 2)
2383 # TRANSLATORS: keep it short, this is a help text
2384 self.helpList.append((self["setupActions"], "OkCancelActions", [("ok", _("Show details of entry"))]))
2385 # TRANSLATORS: keep it short, this is a help text
2386 self.helpList.append((self["setupActions"], "OkCancelActions", [("cancel", _("Quit"))]))
2387 # TRANSLATORS: keep it short, this is a help text
2388 self.helpList.append((self["setupActions"], "ColorActions", [("red", _("Delete entry"))]))
2389 # TRANSLATORS: keep it short, this is a help text
2390 self.helpList.append((self["setupActions"], "ColorActions", [("green", _("Add entry to phonebook"))]))
2391 # TRANSLATORS: keep it short, this is a help text
2392 self.helpList.append((self["setupActions"], "ColorActions", [("yellow", _("Edit selected entry"))]))
2393 # TRANSLATORS: keep it short, this is a help text
2394 self.helpList.append((self["setupActions"], "ColorActions", [("blue", _("Search (case insensitive)"))]))
2396 self["entries"] = List([])
2397 debug("[FritzCallPhonebook] displayPhonebook init")
2398 self.help_window = None
2400 self.onLayoutFinish.append(self.setWindowTitle)
2403 def setWindowTitle(self):
2404 # TRANSLATORS: this is a window title.
2405 self.setTitle(_("Phonebook"))
2407 def display(self, filterNumber=""):
2408 debug("[FritzCallPhonebook] displayPhonebook/display")
2410 # Beware: strings in phonebook.phonebook are utf-8!
2411 sortlistHelp = sorted((name.lower(), name, number) for (number, name) in phonebook.phonebook.iteritems())
2412 for (low, name, number) in sortlistHelp:
2413 if number == "01234567890":
2416 low = low.decode("utf-8")
2417 except UnicodeDecodeError: # this should definitely not happen
2419 low = low.decode("iso-8859-1")
2420 except UnicodeDecodeError:
2421 debug("[FritzCallPhonebook] displayPhonebook/display: corrupt phonebook entry for %s" % number)
2422 # self.session.open(MessageBox, _("Corrupt phonebook entry\nfor number %s\nDeleting.") %number, type = MessageBox.TYPE_ERROR)
2423 phonebook.remove(number)
2427 filterNumber = filterNumber.lower()
2428 if low.find(filterNumber) == - 1:
2430 name = name.strip().decode("utf-8")
2431 number = number.strip().decode("utf-8")
2432 comma = name.find(',')
2434 shortname = name[:comma]
2437 number = number.encode("utf-8", "replace")
2438 name = name.encode("utf-8", "replace")
2439 shortname = shortname.encode('utf-8', 'replace')
2440 self.sortlist.append((name, shortname, number))
2442 self["entries"].setList(self.sortlist)
2444 def showEntry(self):
2445 cur = self["entries"].getCurrent()
2447 debug("[FritzCallPhonebook] displayPhonebook/showEntry %s" % (repr(cur)))
2450 self.session.open(FritzOfferAction, self, number, name)
2453 cur = self["entries"].getCurrent()
2455 debug("[FritzCallPhonebook] displayPhonebook/delete %s" % (repr(cur)))
2456 self.session.openWithCallback(
2457 self.deleteConfirmed,
2459 _("Do you really want to delete entry for\n\n%(number)s\n\n%(name)s?")
2460 % { 'number':str(cur[2]), 'name':str(cur[0]).replace(", ", "\n") }
2463 self.session.open(MessageBox, _("No entry selected"), MessageBox.TYPE_INFO)
2465 def deleteConfirmed(self, ret):
2466 debug("[FritzCallPhonebook] displayPhonebook/deleteConfirmed")
2468 # if ret: delete number from sortlist, delete number from phonebook.phonebook and write it to disk
2470 cur = self["entries"].getCurrent()
2473 # delete number from sortlist, delete number from phonebook.phonebook and write it to disk
2474 debug("[FritzCallPhonebook] displayPhonebook/deleteConfirmed %s" % (repr(cur)))
2475 phonebook.remove(cur[2])
2478 # self.session.open(MessageBox, _("Not deleted."), MessageBox.TYPE_INFO)
2480 self.session.open(MessageBox, _("No entry selected"), MessageBox.TYPE_INFO)
2482 def add(self, parent=None, number="", name=""):
2483 class AddScreen(Screen, ConfigListScreen):
2484 '''ConfiglistScreen with two ConfigTexts for Name and Number'''
2486 def __init__(self, session, parent, number="", name=""):
2488 # setup screen with two ConfigText and OK and ABORT button
2491 width = max(scaleH(-1, 570), noButtons*140)
2492 height = scaleV(-1, 100) # = 5 + 126 + 40 + 5; 6 lines of text possible
2493 buttonsGap = (width-noButtons*140)/(noButtons+1)
2494 buttonsVPos = height-40-5
2496 <screen position="center,center" size="%d,%d" title="Add entry to phonebook" >
2497 <widget name="config" position="5,5" size="%d,%d" scrollbarMode="showOnDemand" />
2498 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
2499 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
2500 <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" />
2501 <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" />
2504 width - 5 - 5, height - 5 - 40 - 5,
2505 buttonsGap, buttonsVPos, "skin_default/buttons/red.png",
2506 buttonsGap+140+buttonsGap, buttonsVPos, "skin_default/buttons/green.png",
2507 buttonsGap, buttonsVPos,
2508 buttonsGap+140+buttonsGap, buttonsVPos,
2510 Screen.__init__(self, session)
2511 self.session = session
2512 self.parent = parent
2513 # TRANSLATORS: keep it short, this is a button
2514 self["key_red"] = Button(_("Cancel"))
2515 # TRANSLATORS: keep it short, this is a button
2516 self["key_green"] = Button(_("OK"))
2517 self["setupActions"] = ActionMap(["SetupActions", "ColorActions"],
2519 "cancel": self.cancel,
2526 ConfigListScreen.__init__(self, self.list, session=session)
2528 self.number = number
2529 config.plugins.FritzCall.name.value = name
2530 config.plugins.FritzCall.number.value = number
2531 self.list.append(getConfigListEntry(_("Name"), config.plugins.FritzCall.name))
2532 self.list.append(getConfigListEntry(_("Number"), config.plugins.FritzCall.number))
2533 self["config"].list = self.list
2534 self["config"].l.setList(self.list)
2535 self.onLayoutFinish.append(self.setWindowTitle)
2537 def setWindowTitle(self):
2538 # TRANSLATORS: this is a window title.
2539 self.setTitle(_("Add entry to phonebook"))
2542 # get texts from Screen
2543 # add (number,name) to sortlist and phonebook.phonebook and disk
2544 self.name = config.plugins.FritzCall.name.value
2545 self.number = config.plugins.FritzCall.number.value
2546 if not self.number or not self.name:
2547 self.session.open(MessageBox, _("Entry incomplete."), type=MessageBox.TYPE_ERROR)
2549 # add (number,name) to sortlist and phonebook.phonebook and disk
2550 # oldname = phonebook.search(self.number)
2552 # self.session.openWithCallback(
2553 # self.overwriteConfirmed,
2555 # _("Do you really want to overwrite entry for %(number)s\n\n%(name)s\n\nwith\n\n%(newname)s?")
2557 # 'number':self.number,
2559 # 'newname':self.name.replace(", ","\n")
2564 phonebook.add(self.number, self.name)
2566 self.parent.display()
2568 def overwriteConfirmed(self, ret):
2570 phonebook.remove(self.number)
2571 phonebook.add(self.number, self.name)
2572 self.parent.display()
2577 debug("[FritzCallPhonebook] displayPhonebook/add")
2580 self.session.open(AddScreen, parent, number, name)
2583 debug("[FritzCallPhonebook] displayPhonebook/edit")
2584 cur = self["entries"].getCurrent()
2586 self.session.open(MessageBox, _("No entry selected"), MessageBox.TYPE_INFO)
2588 self.add(self, cur[2], cur[0])
2591 debug("[FritzCallPhonebook] displayPhonebook/search")
2592 self.help_window = self.session.instantiateDialog(NumericalTextInputHelpDialog, self)
2593 self.help_window.show()
2594 # VirtualKeyboard instead of InputBox?
2595 self.session.openWithCallback(self.doSearch, InputBox, _("Enter Search Terms"), _("Search phonebook"))
2597 def doSearch(self, searchTerms):
2600 debug("[FritzCallPhonebook] displayPhonebook/doSearch: " + searchTerms)
2601 if self.help_window:
2602 self.session.deleteDialog(self.help_window)
2603 self.help_window = None
2604 self.display(searchTerms)
2609 phonebook = FritzCallPhonebook()
2611 class FritzCallSetup(Screen, ConfigListScreen, HelpableScreen):
2613 def __init__(self, session, args=None): #@UnusedVariable # pylint: disable=W0613
2614 self.width = scaleH(20+4*(140+90)+2*(35+40)+20, 4*140+2*35)
2616 debug("[FritzCallSetup] width: " + str(self.width))
2618 <screen name="FritzCallSetup" position="center,center" size="%d,%d" title="FritzCall Setup" >
2619 <eLabel position="0,0" size="%d,2" backgroundColor="#aaaaaa" />
2620 <widget name="consideration" position="%d,%d" halign="center" size="%d,%d" font="Regular;%d" backgroundColor="#20040404" transparent="1" />
2621 <eLabel position="0,%d" size="%d,2" backgroundColor="#aaaaaa" />
2622 <widget name="config" position="%d,%d" size="%d,%d" scrollbarMode="showOnDemand" backgroundColor="#20040404" transparent="1" />
2623 <eLabel position="0,%d" size="%d,2" backgroundColor="#aaaaaa" />
2624 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
2625 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
2626 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
2627 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
2628 <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" />
2629 <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" />
2630 <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" />
2631 <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" />
2632 <ePixmap position="%d,%d" zPosition="4" size="35,25" pixmap="%s" transparent="1" alphatest="on" />
2633 <ePixmap position="%d,%d" zPosition="4" size="35,25" pixmap="%s" transparent="1" alphatest="on" />
2635 # (DESKTOP_WIDTH-width)/2, scaleV(100, 73), # position
2636 width, scaleV(560, 430), # size
2637 width, # eLabel width
2638 scaleH(40, 20), scaleV(10, 5), # consideration position
2639 scaleH(width-80, width-40), scaleV(25, 45), # consideration size
2640 scaleV(22, 20), # consideration font size
2641 scaleV(40, 50), # eLabel position vertical
2642 width, # eLabel width
2643 scaleH(40, 5), scaleV(60, 57), # config position
2644 scaleH(width-80, width-10), scaleV(453, 328), # config size
2645 scaleV(518, 390), # eLabel position vertical
2646 width, # eLabel width
2647 scaleH(20, 0), scaleV(525, 395), "skin_default/buttons/red.png", # pixmap red
2648 scaleH(20+140+90, 140), scaleV(525, 395), "skin_default/buttons/green.png", # pixmap green
2649 scaleH(20+2*(140+90), 2*140), scaleV(525, 395), "skin_default/buttons/yellow.png", # pixmap yellow
2650 scaleH(20+3*(140+90), 3*140), scaleV(525, 395), "skin_default/buttons/blue.png", # pixmap blue
2651 scaleH(20, 0), scaleV(525, 395), scaleV(21, 21), # widget red
2652 scaleH(20+(140+90), 140), scaleV(525, 395), scaleV(21, 21), # widget green
2653 scaleH(20+2*(140+90), 2*140), scaleV(525, 395), scaleV(21, 21), # widget yellow
2654 scaleH(20+3*(140+90), 3*140), scaleV(525, 395), scaleV(21, 21), # widget blue
2655 scaleH(20+4*(140+90), 4*140), scaleV(532, 402), "skin_default/buttons/key_info.png", # button info
2656 scaleH(20+4*(140+90)+(35+40), 4*140+35), scaleV(532, 402), "skin_default/buttons/key_menu.png", # button menu
2659 Screen.__init__(self, session)
2660 HelpableScreen.__init__(self)
2661 self.session = session
2663 self["consideration"] = Label(_("You need to enable the monitoring on your FRITZ!Box by dialing #96*5*!"))
2666 # Initialize Buttons
2667 # TRANSLATORS: keep it short, this is a button
2668 self["key_red"] = Button(_("Cancel"))
2669 # TRANSLATORS: keep it short, this is a button
2670 self["key_green"] = Button(_("OK"))
2671 # TRANSLATORS: keep it short, this is a button
2672 self["key_yellow"] = Button(_("Phone calls"))
2673 # TRANSLATORS: keep it short, this is a button
2674 self["key_blue"] = Button(_("Phonebook"))
2675 # TRANSLATORS: keep it short, this is a button
2676 self["key_info"] = Button(_("About FritzCall"))
2677 # TRANSLATORS: keep it short, this is a button
2678 self["key_menu"] = Button(_("FRITZ!Box Fon Status"))
2680 self["setupActions"] = ActionMap(["ColorActions", "OkCancelActions", "MenuActions", "EPGSelectActions"],
2684 "yellow": self.displayCalls,
2685 "blue": self.displayPhonebook,
2686 "cancel": self.cancel,
2692 # TRANSLATORS: keep it short, this is a help text
2693 self.helpList.append((self["setupActions"], "ColorActions", [("red", _("quit"))]))
2694 # TRANSLATORS: keep it short, this is a help text
2695 self.helpList.append((self["setupActions"], "ColorActions", [("green", _("save and quit"))]))
2696 # TRANSLATORS: keep it short, this is a help text
2697 self.helpList.append((self["setupActions"], "ColorActions", [("yellow", _("display calls"))]))
2698 # TRANSLATORS: keep it short, this is a help text
2699 self.helpList.append((self["setupActions"], "ColorActions", [("blue", _("display phonebook"))]))
2700 # TRANSLATORS: keep it short, this is a help text
2701 self.helpList.append((self["setupActions"], "OkCancelActions", [("ok", _("save and quit"))]))
2702 # TRANSLATORS: keep it short, this is a help text
2703 self.helpList.append((self["setupActions"], "OkCancelActions", [("cancel", _("quit"))]))
2704 # TRANSLATORS: keep it short, this is a help text
2705 self.helpList.append((self["setupActions"], "MenuActions", [("menu", _("FRITZ!Box Fon Status"))]))
2706 # TRANSLATORS: keep it short, this is a help text
2707 self.helpList.append((self["setupActions"], "EPGSelectActions", [("info", _("About FritzCall"))]))
2709 ConfigListScreen.__init__(self, self.list, session=session)
2711 # get new list of locations for PhoneBook.txt
2712 self._mountedDevs = getMountedDevs()
2714 self.onLayoutFinish.append(self.setWindowTitle)
2716 def setWindowTitle(self):
2717 # TRANSLATORS: this is a window title.
2718 self.setTitle(_("FritzCall Setup") + " (" + "$Revision: 640 $"[1: - 1] + "$Date: 2011-01-15 16:17:12 +0100 (Sa, 15. Jan 2011) $"[7:23] + ")")
2721 ConfigListScreen.keyLeft(self)
2725 ConfigListScreen.keyRight(self)
2728 def createSetup(self):
2730 self.list.append(getConfigListEntry(_("Call monitoring"), config.plugins.FritzCall.enable))
2731 if config.plugins.FritzCall.enable.value:
2732 self.list.append(getConfigListEntry(_("FRITZ!Box FON address (Name or IP)"), config.plugins.FritzCall.hostname))
2734 self.list.append(getConfigListEntry(_("Show after Standby"), config.plugins.FritzCall.afterStandby))
2736 self.list.append(getConfigListEntry(_("Show only calls for specific MSN"), config.plugins.FritzCall.filter))
2737 if config.plugins.FritzCall.filter.value:
2738 self.list.append(getConfigListEntry(_("MSN to show (separated by ,)"), config.plugins.FritzCall.filtermsn))
2739 self.list.append(getConfigListEntry(_("Filter also list of calls"), config.plugins.FritzCall.filterCallList))
2740 self.list.append(getConfigListEntry(_("Mute on call"), config.plugins.FritzCall.muteOnCall))
2742 self.list.append(getConfigListEntry(_("Show Outgoing Calls"), config.plugins.FritzCall.showOutgoing))
2743 # not only for outgoing: config.plugins.FritzCall.showOutgoing.value:
2744 self.list.append(getConfigListEntry(_("Areacode to add to calls without one (if necessary)"), config.plugins.FritzCall.prefix))
2745 self.list.append(getConfigListEntry(_("Timeout for Call Notifications (seconds)"), config.plugins.FritzCall.timeout))
2746 self.list.append(getConfigListEntry(_("Reverse Lookup Caller ID (select country below)"), config.plugins.FritzCall.lookup))
2747 if config.plugins.FritzCall.lookup.value:
2748 self.list.append(getConfigListEntry(_("Country"), config.plugins.FritzCall.country))
2750 # TODO: make password unreadable?
2751 self.list.append(getConfigListEntry(_("Password Accessing FRITZ!Box"), config.plugins.FritzCall.password))
2752 self.list.append(getConfigListEntry(_("Extension number to initiate call on"), config.plugins.FritzCall.extension))
2753 self.list.append(getConfigListEntry(_("Read PhoneBook from FRITZ!Box"), config.plugins.FritzCall.fritzphonebook))
2754 if config.plugins.FritzCall.fritzphonebook.value:
2755 self.list.append(getConfigListEntry(_("Append type of number"), config.plugins.FritzCall.showType))
2756 self.list.append(getConfigListEntry(_("Append shortcut number"), config.plugins.FritzCall.showShortcut))
2757 self.list.append(getConfigListEntry(_("Append vanity name"), config.plugins.FritzCall.showVanity))
2759 self.list.append(getConfigListEntry(_("Use internal PhoneBook"), config.plugins.FritzCall.phonebook))
2760 if config.plugins.FritzCall.phonebook.value:
2761 if config.plugins.FritzCall.phonebookLocation.value in self._mountedDevs:
2762 config.plugins.FritzCall.phonebookLocation.setChoices(self._mountedDevs, config.plugins.FritzCall.phonebookLocation.value)
2764 config.plugins.FritzCall.phonebookLocation.setChoices(self._mountedDevs)
2765 path = config.plugins.FritzCall.phonebookLocation.value
2766 # check whether we can write to PhoneBook.txt
2767 if os.path.exists(os.path.join(path[0], "PhoneBook.txt")):
2768 if not os.access(os.path.join(path[0], "PhoneBook.txt"), os.W_OK):
2769 debug("[FritzCallSetup] createSetup: %s/PhoneBook.txt not writable, resetting to default" %(path[0]))
2770 config.plugins.FritzCall.phonebookLocation.setChoices(self._mountedDevs)
2771 elif not (os.path.isdir(path[0]) and os.access(path[0], os.W_OK|os.X_OK)):
2772 debug("[FritzCallSetup] createSetup: directory %s not writable, resetting to default" %(path[0]))
2773 config.plugins.FritzCall.phonebookLocation.setChoices(self._mountedDevs)
2775 self.list.append(getConfigListEntry(_("PhoneBook Location"), config.plugins.FritzCall.phonebookLocation))
2776 if config.plugins.FritzCall.lookup.value:
2777 self.list.append(getConfigListEntry(_("Automatically add new Caller to PhoneBook"), config.plugins.FritzCall.addcallers))
2779 self.list.append(getConfigListEntry(_("Strip Leading 0"), config.plugins.FritzCall.internal))
2780 # self.list.append(getConfigListEntry(_("Default display mode for FRITZ!Box calls"), config.plugins.FritzCall.fbfCalls))
2781 self.list.append(getConfigListEntry(_("Display connection infos"), config.plugins.FritzCall.connectionVerbose))
2782 self.list.append(getConfigListEntry(_("Debug"), config.plugins.FritzCall.debug))
2784 self["config"].list = self.list
2785 self["config"].l.setList(self.list)
2788 # debug("[FritzCallSetup] save"
2789 for x in self["config"].list:
2791 if config.plugins.FritzCall.phonebookLocation.isChanged():
2793 phonebook = FritzCallPhonebook()
2795 if config.plugins.FritzCall.enable.value:
2796 fritz_call.connect()
2798 fritz_call.shutdown()
2802 # debug("[FritzCallSetup] cancel"
2803 for x in self["config"].list:
2807 def displayCalls(self):
2808 if config.plugins.FritzCall.enable.value:
2810 self.session.open(FritzDisplayCalls)
2812 self.session.open(MessageBox, _("Cannot get calls from FRITZ!Box"), type=MessageBox.TYPE_INFO)
2814 self.session.open(MessageBox, _("Plugin not active"), type=MessageBox.TYPE_INFO)
2816 def displayPhonebook(self):
2818 if config.plugins.FritzCall.enable.value:
2819 self.session.open(phonebook.FritzDisplayPhonebook)
2821 self.session.open(MessageBox, _("Plugin not active"), type=MessageBox.TYPE_INFO)
2823 self.session.open(MessageBox, _("No phonebook"), type=MessageBox.TYPE_INFO)
2826 self.session.open(FritzAbout)
2829 if config.plugins.FritzCall.enable.value:
2830 if fritzbox and fritzbox.info:
2831 self.session.open(FritzMenu)
2833 self.session.open(MessageBox, _("Cannot get infos from FRITZ!Box"), type=MessageBox.TYPE_INFO)
2835 self.session.open(MessageBox, _("Plugin not active"), type=MessageBox.TYPE_INFO)
2839 class FritzCallList:
2843 def add(self, event, date, number, caller, phone):
2844 debug("[FritzCallList] add: %s %s" % (number, caller))
2845 if len(self.callList) > 10:
2846 if self.callList[0] != "Start":
2847 self.callList[0] = "Start"
2848 del self.callList[1]
2850 self.callList.append((event, number, date, caller, phone))
2853 debug("[FritzCallList] display")
2856 # Standby.inStandby.onClose.remove(self.display) object does not exist anymore...
2857 # build screen from call list
2860 if not self.callList:
2861 text = _("no calls")
2863 if self.callList[0] == "Start":
2864 text = text + _("Last 10 calls:\n")
2865 del self.callList[0]
2867 for call in self.callList:
2868 (event, number, date, caller, phone) = call
2874 # shorten the date info
2875 date = date[:6] + date[9:14]
2877 # our phone could be of the form "0123456789 (home)", then we only take "home"
2878 oBrack = phone.find('(')
2879 cBrack = phone.find(')')
2880 if oBrack != -1 and cBrack != -1:
2881 phone = phone[oBrack+1:cBrack]
2883 # should not happen, for safety reasons
2885 caller = _("UNKNOWN")
2887 # if we have an unknown number, show the number
2888 if caller == _("UNKNOWN") and number != "":
2891 # strip off the address part of the remote caller/callee, if there is any
2892 nl = caller.find('\n')
2894 caller = caller[:nl]
2895 elif caller[0] == '[' and caller[-1] == ']':
2896 # that means, we've got an unknown number with a city added from avon.dat
2897 if (len(number) + 1 + len(caller) + len(phone)) <= 40:
2898 caller = number + ' ' + caller
2902 while (len(caller) + len(phone)) > 40:
2903 if len(caller) > len(phone):
2904 caller = caller[: - 1]
2906 phone = phone[: - 1]
2908 text = text + "%s %s %s %s\n" % (date, caller, direction, phone)
2909 debug("[FritzCallList] display: '%s %s %s %s'" % (date, caller, direction, phone))
2912 Notifications.AddNotification(MessageBox, text, type=MessageBox.TYPE_INFO)
2913 # TODO please HELP: from where can I get a session?
2914 # my_global_session.open(FritzDisplayCalls, text)
2917 callList = FritzCallList()
2919 def findFace(number, name):
2920 debug("[FritzCall] findFace number/name: %s/%s" % (number, name))
2922 sep = name.find(',')
2925 sep = name.find('\n')
2931 facesDir = os.path.join(config.plugins.FritzCall.phonebookLocation.value, "FritzCallFaces")
2932 numberFile = os.path.join(facesDir, number)
2933 nameFile = os.path.join(facesDir, name)
2935 if number and os.path.exists(numberFile):
2936 facesFile = numberFile
2937 elif number and os.path.exists(numberFile + ".png"):
2938 facesFile = numberFile + ".png"
2939 elif number and os.path.exists(numberFile + ".PNG"):
2940 facesFile = numberFile + ".PNG"
2941 elif name and os.path.exists(nameFile + ".png"):
2942 facesFile = nameFile + ".png"
2943 elif name and os.path.exists(nameFile + ".PNG"):
2944 facesFile = nameFile + ".PNG"
2946 facesFile = resolveFilename(SCOPE_SKIN_IMAGE, "skin_default/icons/input_info.png")
2948 debug("[FritzCall] findFace result: %s" % (facesFile))
2951 class MessageBoxPixmap(Screen):
2952 def __init__(self, session, text, number = "", name = "", timeout = -1):
2954 <screen name="MessageBoxPixmap" position="center,center" size="600,10" title="MessageBoxPixmap">
2955 <widget name="text" position="115,8" size="520,0" font="Regular;%d" />
2956 <widget name="InfoPixmap" pixmap="%s" position="5,5" size="100,100" alphatest="on" />
2959 # scaleH(350, 60), scaleV(175, 245),
2960 scaleV(24, 22), resolveFilename(SCOPE_SKIN_IMAGE, "skin_default/icons/input_info.png")
2962 debug("[FritzCall] MessageBoxPixmap number: %s" % number)
2963 Screen.__init__(self, session)
2964 # MessageBox.__init__(self, session, text, type=MessageBox.TYPE_INFO, timeout=timeout)
2965 self["text"] = Label(text)
2966 self["InfoPixmap"] = Pixmap()
2967 self._session = session
2968 self._number = number
2970 self._timerRunning = False
2972 self._timeout = timeout
2973 self._origTitle = None
2975 self.onLayoutFinish.append(self._finishLayout)
2976 self["actions"] = ActionMap(["OkCancelActions"],
2978 "cancel": self._exit,
2979 "ok": self._exit, }, - 2)
2981 def _finishLayout(self):
2982 # pylint: disable=W0142
2983 debug("[FritzCall] MessageBoxPixmap/setInfoPixmap number: %s/%s" % (self._number, self._name))
2985 faceFile = findFace(self._number, self._name)
2986 picPixmap = LoadPixmap(faceFile)
2987 if not picPixmap: # that means most probably, that the picture is not 8 bit...
2988 Notifications.AddNotification(MessageBox, _("Found picture\n\n%s\n\nBut did not load. Probably not PNG, 8-bit") %faceFile, type = MessageBox.TYPE_ERROR)
2989 picPixmap = LoadPixmap(resolveFilename(SCOPE_SKIN_IMAGE, "skin_default/icons/input_error.png"))
2990 picSize = picPixmap.size()
2991 self["InfoPixmap"].instance.setPixmap(picPixmap)
2993 # recalculate window size
2994 textSize = self["text"].getSize()
2995 textSize = (textSize[0]+20, textSize[1]+20) # don't know, why, but size is too small
2996 textSize = eSize(*textSize)
2997 width = max(scaleH(600, 280), picSize.width() + textSize.width() + 30)
2998 height = max(scaleV(300, 250), picSize.height()+10, textSize.height()+10)
2999 wSize = (width, height)
3000 wSize = eSize(*wSize)
3002 # center the smaller vertically
3003 hGap = (width-picSize.width()-textSize.width())/3
3004 picPos = (hGap, (height-picSize.height())/2+1)
3005 textPos = (hGap+picSize.width()+hGap, (height-textSize.height())/2+1)
3008 self.instance.resize(wSize)
3010 self["text"].instance.resize(textSize)
3012 self["InfoPixmap"].instance.resize(picSize)
3014 self["text"].instance.move(ePoint(*textPos))
3016 self["InfoPixmap"].instance.move(ePoint(*picPos))
3018 self.instance.move(ePoint((DESKTOP_WIDTH-wSize.width())/2, (DESKTOP_HEIGHT-wSize.height())/2))
3020 def _initTimeout(self):
3021 if self._timeout > 0:
3022 self._timer = eTimer()
3023 self._timer.callback.append(self._timerTick)
3024 self.onExecBegin.append(self._startTimer)
3025 self._origTitle = None
3029 self.onShown.append(self.__onShown)
3030 self._timerRunning = True
3032 self._timerRunning = False
3034 def __onShown(self):
3035 self.onShown.remove(self.__onShown)
3038 def _startTimer(self):
3039 self._timer.start(1000)
3041 #===============================================================================
3042 # def stopTimer(self):
3043 # if self._timerRunning:
3045 # self.setTitle(self._origTitle)
3046 # self._timerRunning = False
3047 #===============================================================================
3049 def _timerTick(self):
3052 if self._origTitle is None:
3053 self._origTitle = self.instance.getTitle()
3054 self.setTitle(self._origTitle + " (" + str(self._timeout) + ")")
3055 if self._timeout == 0:
3057 self._timerRunning = False
3063 mutedOnConnID = None
3064 def notifyCall(event, date, number, caller, phone, connID):
3065 if Standby.inStandby is None or config.plugins.FritzCall.afterStandby.value == "each":
3067 global mutedOnConnID
3068 if config.plugins.FritzCall.muteOnCall.value and not mutedOnConnID:
3069 debug("[FritzCall] mute on connID: %s" % connID)
3070 mutedOnConnID = connID
3071 # eDVBVolumecontrol.getInstance().volumeMute() # with this, we get no mute icon...
3072 if not eDVBVolumecontrol.getInstance().isMuted():
3073 globalActionMap.actions["volumeMute"]()
3074 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 }
3076 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 }
3077 debug("[FritzCall] notifyCall:\n%s" % text)
3078 # Notifications.AddNotification(MessageBox, text, type=MessageBox.TYPE_INFO, timeout=config.plugins.FritzCall.timeout.value)
3079 Notifications.AddNotification(MessageBoxPixmap, text, number=number, name=caller, timeout=config.plugins.FritzCall.timeout.value)
3080 elif config.plugins.FritzCall.afterStandby.value == "inList":
3082 # if not yet done, register function to show call list
3084 if not standbyMode :
3086 Standby.inStandby.onHide.append(callList.display) #@UndefinedVariable
3087 # add text/timeout to call list
3088 callList.add(event, date, number, caller, phone)
3089 debug("[FritzCall] notifyCall: added to callList")
3090 else: # this is the "None" case
3091 debug("[FritzCall] notifyCall: standby and no show")
3094 # call FritzCallserAction.sh in the same dir as Phonebook.txt with the following parameters:
3095 # event: "RING" (incomning) or "CALL" (outgoing)
3096 # date of event, format: "dd.mm.yy hh.mm.ss"
3097 # telephone number which is calling/is called
3098 # caller's name and address, format Name\n Street\n ZIP City
3099 # line/number which is called/which is used for calling
3100 userActionScript = os.path.join(config.plugins.FritzCall.phonebookLocation.value, "FritzCallUserAction.sh")
3101 if os.path.exists(userActionScript) and os.access(userActionScript, os.X_OK):
3102 cmd = userActionScript + ' "' + event + '" "' + date + '" "' + number + '" "' + caller + '" "' + phone + '"'
3103 debug("[FritzCall] notifyCall: calling: %s" % cmd)
3107 #===============================================================================
3108 # We need a separate class for each invocation of reverseLookup to retain
3109 # the necessary data for the notification
3110 #===============================================================================
3113 reverselookupMtime = 0
3115 class FritzReverseLookupAndNotifier:
3116 def __init__(self, event, number, caller, phone, date, connID):
3119 Initiate a reverse lookup for the given number in the configured country
3121 @param event: CALL or RING
3122 @param number: number to be looked up
3123 @param caller: caller including name and address
3124 @param phone: Number (and name) of or own phone
3125 @param date: date of call
3127 debug("[FritzReverseLookupAndNotifier] reverse Lookup for %s!" % number)
3129 self.number = number
3130 self.caller = caller
3133 self.connID = connID
3135 if number[0] != "0":
3136 self.notifyAndReset(number, caller)
3139 ReverseLookupAndNotifier(number, self.notifyAndReset, "UTF-8", config.plugins.FritzCall.country.value)
3141 def notifyAndReset(self, number, caller):
3144 this gets called with the result of the reverse lookup
3146 @param number: number
3147 @param caller: name and address of remote. it comes in with name, address and city separated by commas
3149 debug("[FritzReverseLookupAndNotifier] got: " + caller)
3150 self.number = number
3151 #===============================================================================
3152 # if not caller and os.path.exists(config.plugins.FritzCall.phonebookLocation.value + "/PhoneBook.csv"):
3153 # caller = FritzOutlookCSV.findNumber(number, config.plugins.FritzCall.phonebookLocation.value + "/PhoneBook.csv") #@UndefinedVariable
3154 # debug("[FritzReverseLookupAndNotifier] got from Outlook csv: " + caller)
3155 #===============================================================================
3156 #===============================================================================
3157 # if not caller and os.path.exists(config.plugins.FritzCall.phonebookLocation.value + "/PhoneBook.ldif"):
3158 # caller = FritzLDIF.findNumber(number, open(config.plugins.FritzCall.phonebookLocation.value + "/PhoneBook.ldif"))
3159 # debug("[FritzReverseLookupAndNotifier] got from ldif: " + caller)
3160 #===============================================================================
3162 name = handleReverseLookupResult(caller)
3164 self.caller = name.replace(", ", "\n").replace('#','')
3165 # TODO: I don't know, why we store only for incoming calls...
3166 # if self.number != 0 and config.plugins.FritzCall.addcallers.value and self.event == "RING":
3167 if self.number != 0 and config.plugins.FritzCall.addcallers.value:
3168 debug("[FritzReverseLookupAndNotifier] add to phonebook")
3169 phonebook.add(self.number, self.caller)
3171 name = resolveNumberWithAvon(self.number, config.plugins.FritzCall.country.value)
3173 self.caller = _("UNKNOWN")
3176 notifyCall(self.event, self.date, self.number, self.caller, self.phone, self.connID)
3177 # kill that object...
3179 class FritzProtocol(LineReceiver):
3181 debug("[FritzProtocol] " + "$Revision: 640 $"[1:-1] + "$Date: 2011-01-15 16:17:12 +0100 (Sa, 15. Jan 2011) $"[7:23] + " starting")
3182 global mutedOnConnID
3183 mutedOnConnID = None
3191 def resetValues(self):
3192 debug("[FritzProtocol] resetValues")
3200 def notifyAndReset(self):
3201 notifyCall(self.event, self.date, self.number, self.caller, self.phone, self.connID)
3204 def lineReceived(self, line):
3205 debug("[FritzProtocol] lineReceived: %s" % line)
3206 #15.07.06 00:38:54;CALL;1;4;<from/our msn>;<to/extern>;
3207 #15.07.06 00:38:58;DISCONNECT;1;0;
3208 #15.07.06 00:39:22;RING;0;<from/extern>;<to/our msn>;
3209 #15.07.06 00:39:27;DISCONNECT;0;0;
3210 anEvent = line.split(';')
3211 (self.date, self.event) = anEvent[0:2]
3212 self.connID = anEvent[2]
3214 filtermsns = config.plugins.FritzCall.filtermsn.value.split(",")
3215 for i in range(len(filtermsns)):
3216 filtermsns[i] = filtermsns[i].strip()
3218 # debug("[FritzProtocol] Volcontrol dir: %s" % dir(eDVBVolumecontrol.getInstance()))
3219 # debug("[FritzCall] unmute on connID: %s?" %self.connID)
3220 global mutedOnConnID
3221 if self.event == "DISCONNECT" and config.plugins.FritzCall.muteOnCall.value and mutedOnConnID == self.connID:
3222 debug("[FritzCall] unmute on connID: %s!" % self.connID)
3223 mutedOnConnID = None
3224 # eDVBVolumecontrol.getInstance().volumeUnMute()
3225 if eDVBVolumecontrol.getInstance().isMuted():
3226 globalActionMap.actions["volumeMute"]()
3227 # not supported so far, because, taht would mean muting on EVERY connect, regardless of RING or CALL or filter active
3228 #=======================================================================
3229 # elif self.event == "CONNECT" and config.plugins.FritzCall.muteOnCall.value == "connect":
3230 # debug("[FritzCall] mute on connID: %s" % self.connID)
3231 # mutedOnConnID = self.connID
3232 # # eDVBVolumecontrol.getInstance().volumeMute() # with this, we get no mute icon...
3233 # if not eDVBVolumecontrol.getInstance().isMuted():
3234 # globalActionMap.actions["volumeMute"]()
3235 #=======================================================================
3236 elif self.event == "RING" or (self.event == "CALL" and config.plugins.FritzCall.showOutgoing.value):
3239 if self.event == "RING":
3241 if fritzbox and number in fritzbox.blacklist[0]:
3242 debug("[FritzProtocol] lineReceived phone: '''%s''' blacklisted number: '''%s'''" % (phone, number))
3246 if number in fritzbox.blacklist[1]:
3247 debug("[FritzProtocol] lineReceived phone: '''%s''' blacklisted number: '''%s'''" % (phone, number))
3250 debug("[FritzProtocol] lineReceived phone: '''%s''' number: '''%s'''" % (phone, number))
3252 if not (config.plugins.FritzCall.filter.value and phone not in filtermsns):
3253 debug("[FritzProtocol] lineReceived no filter hit")
3255 phonename = phonebook.search(phone) # do we have a name for the number of our side?
3257 self.phone = "%s (%s)" % (phone, phonename)
3261 self.phone = _("UNKNOWN")
3264 debug("[FritzProtocol] lineReceived: no number")
3265 self.number = _("number suppressed")
3266 self.caller = _("UNKNOWN")
3268 if config.plugins.FritzCall.internal.value and len(number) > 3 and number[0] == "0":
3269 debug("[FritzProtocol] lineReceived: strip leading 0")
3270 self.number = number[1:]
3272 self.number = number
3273 if self.event == "CALL" and self.number[0] != '0': # should only happen for outgoing
3274 debug("[FritzProtocol] lineReceived: add local prefix")
3275 self.number = config.plugins.FritzCall.prefix.value + self.number
3277 # strip CbC prefixes
3278 if self.event == "CALL":
3279 number = stripCbCPrefix(self.number, config.plugins.FritzCall.country.value)
3281 debug("[FritzProtocol] lineReceived phonebook.search: %s" % self.number)
3282 self.caller = phonebook.search(self.number)
3283 debug("[FritzProtocol] lineReceived phonebook.search reault: %s" % self.caller)
3285 if config.plugins.FritzCall.lookup.value:
3286 FritzReverseLookupAndNotifier(self.event, self.number, self.caller, self.phone, self.date, self.connID)
3287 return # reverselookup is supposed to handle the message itself
3289 self.caller = _("UNKNOWN")
3291 self.notifyAndReset()
3293 class FritzClientFactory(ReconnectingClientFactory):
3298 self.hangup_ok = False
3299 def startedConnecting(self, connector): #@UnusedVariable # pylint: disable=W0613
3300 if config.plugins.FritzCall.connectionVerbose.value:
3301 Notifications.AddNotification(MessageBox, _("Connecting to FRITZ!Box..."), type=MessageBox.TYPE_INFO, timeout=2)
3303 def buildProtocol(self, addr): #@UnusedVariable # pylint: disable=W0613
3304 global fritzbox, phonebook
3305 if config.plugins.FritzCall.connectionVerbose.value:
3306 Notifications.AddNotification(MessageBox, _("Connected to FRITZ!Box!"), type=MessageBox.TYPE_INFO, timeout=4)
3311 fritzbox = FritzCallFBF()
3312 phonebook = FritzCallPhonebook()
3313 return FritzProtocol()
3315 def clientConnectionLost(self, connector, reason):
3317 if not self.hangup_ok and config.plugins.FritzCall.connectionVerbose.value:
3318 Notifications.AddNotification(MessageBox, _("Connection to FRITZ!Box! lost\n (%s)\nretrying...") % reason.getErrorMessage(), type=MessageBox.TYPE_INFO, timeout=config.plugins.FritzCall.timeout.value)
3319 ReconnectingClientFactory.clientConnectionLost(self, connector, reason)
3320 # config.plugins.FritzCall.enable.value = False
3323 def clientConnectionFailed(self, connector, reason):
3325 if config.plugins.FritzCall.connectionVerbose.value:
3326 Notifications.AddNotification(MessageBox, _("Connecting to FRITZ!Box failed\n (%s)\nretrying...") % reason.getErrorMessage(), type=MessageBox.TYPE_INFO, timeout=config.plugins.FritzCall.timeout.value)
3327 ReconnectingClientFactory.clientConnectionFailed(self, connector, reason)
3328 # config.plugins.FritzCall.enable.value = False
3335 if config.plugins.FritzCall.enable.value:
3340 if config.plugins.FritzCall.enable.value:
3341 fact = FritzClientFactory()
3342 self.desc = (fact, reactor.connectTCP(config.plugins.FritzCall.hostname.value, 1012, fact)) #@UndefinedVariable # pylint: disable=E1101
3348 if self.desc is not None:
3349 self.desc[0].hangup_ok = True
3350 self.desc[0].stopTrying()
3351 self.desc[1].disconnect()
3354 def displayCalls(session, servicelist=None): #@UnusedVariable # pylint: disable=W0613
3355 if config.plugins.FritzCall.enable.value:
3357 session.open(FritzDisplayCalls)
3359 Notifications.AddNotification(MessageBox, _("Cannot get calls from FRITZ!Box"), type=MessageBox.TYPE_INFO)
3361 Notifications.AddNotification(MessageBox, _("Plugin not active"), type=MessageBox.TYPE_INFO)
3363 def displayPhonebook(session, servicelist=None): #@UnusedVariable # pylint: disable=W0613
3365 if config.plugins.FritzCall.enable.value:
3366 session.open(phonebook.FritzDisplayPhonebook)
3368 Notifications.AddNotification(MessageBox, _("Plugin not active"), type=MessageBox.TYPE_INFO)
3370 Notifications.AddNotification(MessageBox, _("No phonebook"), type=MessageBox.TYPE_INFO)
3372 def displayFBFStatus(session, servicelist=None): #@UnusedVariable # pylint: disable=W0613
3373 if config.plugins.FritzCall.enable.value:
3374 if fritzbox and fritzbox.info:
3375 session.open(FritzMenu)
3377 Notifications.AddNotification(MessageBox, _("Cannot get infos from FRITZ!Box"), type=MessageBox.TYPE_INFO)
3379 Notifications.AddNotification(MessageBox, _("Plugin not active"), type=MessageBox.TYPE_INFO)
3381 def main(session, servicelist=None):
3382 session.open(FritzCallSetup)
3386 def autostart(reason, **kwargs):
3389 # ouch, this is a hack
3390 if kwargs.has_key("session"):
3391 global my_global_session
3392 my_global_session = kwargs["session"]
3395 debug("[FRITZ!Call] - Autostart")
3397 fritz_call = FritzCall()
3399 fritz_call.shutdown()
3402 def Plugins(**kwargs): #@UnusedVariable # pylint: disable=W0613,C0103
3403 what = _("Display FRITZ!box-Fon calls on screen")
3404 what_calls = _("Phone calls")
3405 what_phonebook = _("Phonebook")
3406 what_status = _("FRITZ!Box Fon Status")
3407 return [ PluginDescriptor(name="FritzCall", description=what, where=PluginDescriptor.WHERE_PLUGINMENU, icon="plugin.png", fnc=main),
3408 PluginDescriptor(name=what_calls, description=what_calls, where=PluginDescriptor.WHERE_EXTENSIONSMENU, fnc=displayCalls),
3409 PluginDescriptor(name=what_phonebook, description=what_phonebook, where=PluginDescriptor.WHERE_EXTENSIONSMENU, fnc=displayPhonebook),
3410 PluginDescriptor(name=what_status, description=what_status, where=PluginDescriptor.WHERE_EXTENSIONSMENU, fnc=displayFBFStatus),
3411 PluginDescriptor(where=[PluginDescriptor.WHERE_SESSIONSTART, PluginDescriptor.WHERE_AUTOSTART], fnc=autostart) ]