1 # -*- coding: utf-8 -*-
5 $Date: 2011-07-03 16:23:41 +0200 (So, 03 Jul 2011) $
6 $Id: plugin.py 650 2011-07-03 14:23:41Z 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)
109 config.plugins.FritzCall.ignoreUnknown = ConfigEnableDisable(default=False)
112 def getMountedDevs():
113 def handleMountpoint(loc):
114 # debug("[FritzCall] handleMountpoint: %s" %repr(loc))
118 #=======================================================================
119 # if os.path.exists(os.path.join(mp, "PhoneBook.txt")):
120 # if os.access(os.path.join(mp, "PhoneBook.txt"), os.W_OK):
126 # desc = loc[1] + desc
127 #=======================================================================
129 return (mp, desc + " (" + mp + ")")
131 mountedDevs = [(resolveFilename(SCOPE_CONFIG), _("Flash")),
132 (resolveFilename(SCOPE_MEDIA, "cf"), _("Compact Flash")),
133 (resolveFilename(SCOPE_MEDIA, "usb"), _("USB Device"))]
134 mountedDevs += map(lambda p: (p.mountpoint, (_(p.description) if p.description else "")), harddiskmanager.getMountedPartitions(True))
135 mediaDir = resolveFilename(SCOPE_MEDIA)
136 for p in os.listdir(mediaDir):
137 if os.path.join(mediaDir, p) not in [path[0] for path in mountedDevs]:
138 mountedDevs.append((os.path.join(mediaDir, p), _("Media directory")))
139 debug("[FritzCall] getMountedDevs1: %s" %repr(mountedDevs))
140 mountedDevs = filter(lambda path: os.path.isdir(path[0]) and os.access(path[0], os.W_OK|os.X_OK), mountedDevs)
141 # put this after the write/executable check, that is far too slow...
142 netDir = resolveFilename(SCOPE_MEDIA, "net")
143 if os.path.isdir(netDir):
144 mountedDevs += map(lambda p: (os.path.join(netDir, p), _("Network mount")), os.listdir(netDir))
145 mountedDevs = map(handleMountpoint, mountedDevs)
147 config.plugins.FritzCall.phonebookLocation = ConfigSelection(choices=getMountedDevs())
150 ("0049", _("Germany")),
151 ("0031", _("The Netherlands")),
152 ("0033", _("France")),
153 ("0039", _("Italy")),
154 ("0041", _("Switzerland")),
155 ("0043", _("Austria"))
157 config.plugins.FritzCall.country = ConfigSelection(choices=countryCodes)
161 FBF_MISSED_CALLS = "2"
163 fbfCallsChoices = {FBF_ALL_CALLS: _("All calls"),
164 FBF_IN_CALLS: _("Incoming calls"),
165 FBF_MISSED_CALLS: _("Missed calls"),
166 FBF_OUT_CALLS: _("Outgoing calls")
168 config.plugins.FritzCall.fbfCalls = ConfigSelection(choices=fbfCallsChoices)
170 config.plugins.FritzCall.name = ConfigText(default="", fixed_size=False)
171 config.plugins.FritzCall.number = ConfigText(default="", fixed_size=False)
172 config.plugins.FritzCall.number.setUseableChars('0123456789')
180 avonFileName = resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/avon.dat")
181 if os.path.exists(avonFileName):
182 for line in open(avonFileName):
183 line = line.decode("iso-8859-1").encode('utf-8')
186 parts = line.split(':')
188 avon[parts[0].replace('-','').replace('*','').replace('/','')] = parts[1]
190 def resolveNumberWithAvon(number, countrycode):
191 if not number or number[0] != '0':
194 countrycode = countrycode.replace('00','+')
195 if number[:2] == '00':
196 normNumber = '+' + number[2:]
197 elif number[:1] == '0':
198 normNumber = countrycode + number[1:]
199 else: # this should can not happen, but safety first
202 # debug('normNumer: ' + normNumber)
203 for i in reversed(range(min(10, len(number)))):
204 if avon.has_key(normNumber[:i]):
205 return '[' + avon[normNumber[:i]].strip() + ']'
208 def handleReverseLookupResult(name):
209 found = re.match("NA: ([^;]*);VN: ([^;]*);STR: ([^;]*);HNR: ([^;]*);PLZ: ([^;]*);ORT: ([^;]*)", name)
211 ( name, firstname, street, streetno, zipcode, city ) = (found.group(1),
219 name += ' ' + firstname
220 if street or streetno or zipcode or city:
225 name += ' ' + streetno
226 if (street or streetno) and (zipcode or city):
229 name += zipcode + ' ' + city
236 from xml.dom.minidom import parse
239 callbycallFileName = resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/callbycall_world.xml")
240 if os.path.exists(callbycallFileName):
241 dom = parse(callbycallFileName)
242 for top in dom.getElementsByTagName("callbycalls"):
243 for cbc in top.getElementsByTagName("country"):
244 code = cbc.getAttribute("code").replace("+","00")
245 cbcInfos[code] = cbc.getElementsByTagName("callbycall")
247 debug("[FritzCall] initCbC: callbycallFileName does not exist?!?!")
249 def stripCbCPrefix(number, countrycode):
250 if number and number[:2] != "00" and cbcInfos.has_key(countrycode):
251 for cbc in cbcInfos[countrycode]:
252 if len(cbc.getElementsByTagName("length"))<1 or len(cbc.getElementsByTagName("prefix"))<1:
253 debug("[FritzCall] stripCbCPrefix: entries for " + countrycode + " %s invalid")
255 length = int(cbc.getElementsByTagName("length")[0].childNodes[0].data)
256 prefix = cbc.getElementsByTagName("prefix")[0].childNodes[0].data
257 # if re.match('^'+prefix, number):
258 if number[:len(prefix)] == prefix:
259 return number[length:]
262 class FritzAbout(Screen):
264 def __init__(self, session):
265 textFieldWidth = scaleV(350, 250)
266 width = 5 + 150 + 20 + textFieldWidth + 5 + 175 + 5
267 height = 5 + 175 + 5 + 25 + 5
269 <screen name="FritzAbout" position="center,center" size="%d,%d" title="About FritzCall" >
270 <widget name="text" position="175,%d" size="%d,%d" font="Regular;%d" />
271 <ePixmap position="5,37" size="150,110" pixmap="%s" transparent="1" alphatest="blend" />
272 <ePixmap position="%d,5" size="175,175" pixmap="%s" transparent="1" alphatest="blend" />
273 <widget name="url" position="20,185" size="%d,25" font="Regular;%d" />
275 width, height, # size
276 (height-scaleV(150,130)) / 2, # text vertical position
278 scaleV(150,130), # text height
279 scaleV(24,21), # text font size
280 resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/images/fritz.png"), # 150x110
281 5 + 150 + 5 + textFieldWidth + 5, # qr code horizontal offset
282 resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/images/website.png"), # 175x175
283 width-40, # url width
284 scaleV(24,21) # url font size
286 Screen.__init__(self, session)
287 self["aboutActions"] = ActionMap(["OkCancelActions"],
292 self["text"] = Label(
293 "FritzCall Plugin" + "\n\n" +
294 "$Author: michael $"[1:-2] + "\n" +
295 "$Revision: 650 $"[1:-2] + "\n" +
296 "$Date: 2011-07-03 16:23:41 +0200 (So, 03 Jul 2011) $"[1:23] + "\n"
298 self["url"] = Label("http://wiki.blue-panel.com/index.php/FritzCall")
299 self.onLayoutFinish.append(self.setWindowTitle)
301 def setWindowTitle(self):
302 # TRANSLATORS: this is a window title.
303 self.setTitle(_("About FritzCall"))
320 debug("[FritzCallFBF] __init__")
321 self._callScreen = None
322 self._md5LoginTimestamp = None
323 self._md5Sid = '0000000000000000'
324 self._callTimestamp = 0
326 self._callType = config.plugins.FritzCall.fbfCalls.value
327 self._phoneBookID = '0'
328 self.info = None # (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive)
330 self.blacklist = ([], [])
333 def _notify(self, text):
334 debug("[FritzCallFBF] notify: " + text)
335 self._md5LoginTimestamp = None
337 debug("[FritzCallFBF] notify: try to close callScreen")
338 self._callScreen.close()
339 self._callScreen = None
340 Notifications.AddNotification(MessageBox, text, type=MessageBox.TYPE_ERROR, timeout=config.plugins.FritzCall.timeout.value)
342 def _login(self, callback=None):
343 debug("[FritzCallFBF] _login")
345 self._callScreen.updateStatus(_("login"))
346 if self._md5LoginTimestamp and ((time.time() - self._md5LoginTimestamp) < float(9.5*60)) and self._md5Sid != '0000000000000000': # new login after 9.5 minutes inactivity
347 debug("[FritzCallFBF] _login: renew timestamp: " + time.ctime(self._md5LoginTimestamp) + " time: " + time.ctime())
348 self._md5LoginTimestamp = time.time()
351 debug("[FritzCallFBF] _login: not logged in or outdated login")
352 # http://fritz.box/cgi-bin/webcm?getpage=../html/login_sid.xml
353 parms = urlencode({'getpage':'../html/login_sid.xml'})
354 url = "http://%s/cgi-bin/webcm" % (config.plugins.FritzCall.hostname.value)
355 debug("[FritzCallFBF] _login: '" + url + "' parms: '" + parms + "'")
358 headers={'Content-Type': "application/x-www-form-urlencoded", 'Content-Length': str(len(parms))
359 }, postdata=parms).addCallback(lambda x: self._md5Login(callback,x)).addErrback(lambda x:self._oldLogin(callback,x))
361 def _oldLogin(self, callback, error):
362 debug("[FritzCallFBF] _oldLogin: " + repr(error))
363 self._md5LoginTimestamp = None
364 if config.plugins.FritzCall.password.value != "":
365 parms = "login:command/password=%s" % (config.plugins.FritzCall.password.value)
366 url = "http://%s/cgi-bin/webcm" % (config.plugins.FritzCall.hostname.value)
367 debug("[FritzCallFBF] _oldLogin: '" + url + "' parms: '" + parms + "'")
370 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
371 headers={'Content-Type': "application/x-www-form-urlencoded", 'Content-Length': str(len(parms))
372 }, postdata=parms).addCallback(self._gotPageLogin).addCallback(callback).addErrback(self._errorLogin)
374 debug("[FritzCallFBF] _oldLogin: no password, calling " + repr(callback))
377 def _md5Login(self, callback, sidXml):
378 def buildResponse(challenge, text):
379 debug("[FritzCallFBF] _md5Login7buildResponse: challenge: " + challenge + ' text: ' + text)
380 text = (challenge + '-' + text).decode('utf-8','ignore').encode('utf-16-le')
381 for i in range(len(text)):
382 if ord(text[i]) > 255:
386 debug("[FritzCallFBF] md5Login/buildResponse: " + md5.hexdigest())
387 return challenge + '-' + md5.hexdigest()
389 debug("[FritzCallFBF] _md5Login")
390 found = re.match('.*<SID>([^<]*)</SID>', sidXml, re.S)
392 self._md5Sid = found.group(1)
393 debug("[FritzCallFBF] _md5Login: SID "+ self._md5Sid)
395 debug("[FritzCallFBF] _md5Login: no sid! That must be an old firmware.")
396 self._oldLogin(callback, 'No error')
399 debug("[FritzCallFBF] _md5Login: renew timestamp: " + time.ctime(self._md5LoginTimestamp) + " time: " + time.ctime())
400 self._md5LoginTimestamp = time.time()
401 if sidXml.find('<iswriteaccess>0</iswriteaccess>') != -1:
402 debug("[FritzCallFBF] _md5Login: logging in")
403 found = re.match('.*<Challenge>([^<]*)</Challenge>', sidXml, re.S)
405 challenge = found.group(1)
406 debug("[FritzCallFBF] _md5Login: challenge " + challenge)
409 debug("[FritzCallFBF] _md5Login: login necessary and no challenge! That is terribly wrong.")
411 'getpage':'../html/de/menus/menu2.html', # 'var:pagename':'home', 'var:menu':'home',
412 'login:command/response': buildResponse(challenge, config.plugins.FritzCall.password.value),
414 url = "http://%s/cgi-bin/webcm" % (config.plugins.FritzCall.hostname.value)
415 debug("[FritzCallFBF] _md5Login: '" + url + "' parms: '" + parms + "'")
418 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
419 headers={'Content-Type': "application/x-www-form-urlencoded", 'Content-Length': str(len(parms))
420 }, postdata=parms).addCallback(self._gotPageLogin).addCallback(callback).addErrback(self._errorLogin)
421 elif callback: # we assume value 1 here, no login necessary
422 debug("[FritzCallFBF] _md5Login: no login necessary")
425 def _gotPageLogin(self, html):
427 self._callScreen.updateStatus(_("login verification"))
428 debug("[FritzCallFBF] _gotPageLogin: verify login")
429 start = html.find('<p class="errorMessage">FEHLER: ')
431 start = start + len('<p class="errorMessage">FEHLER: ')
432 text = _("FRITZ!Box - Error logging in\n\n") + html[start : html.find('</p>', start)]
436 self._callScreen.updateStatus(_("login ok"))
438 found = re.match('.*<input type="hidden" name="sid" value="([^\"]*)"', html, re.S)
440 self._md5Sid = found.group(1)
441 debug("[FritzCallFBF] _gotPageLogin: found sid: " + self._md5Sid)
443 def _errorLogin(self, error):
445 debug("[FritzCallFBF] _errorLogin: %s" % (error))
446 text = _("FRITZ!Box - Error logging in: %s\nDisabling plugin.") % error.getErrorMessage()
447 # config.plugins.FritzCall.enable.value = False
452 if self._md5LoginTimestamp:
453 self._md5LoginTimestamp = None
455 'getpage':'../html/de/menus/menu2.html', # 'var:pagename':'home', 'var:menu':'home',
456 'login:command/logout':'bye bye Fritz'
458 url = "http://%s/cgi-bin/webcm" % (config.plugins.FritzCall.hostname.value)
459 debug("[FritzCallFBF] logout: '" + url + "' parms: '" + parms + "'")
462 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
463 headers={'Content-Type': "application/x-www-form-urlencoded", 'Content-Length': str(len(parms))
464 }, postdata=parms).addErrback(self._errorLogout)
466 def _errorLogout(self, error):
467 debug("[FritzCallFBF] _errorLogout: %s" % (error))
468 text = _("FRITZ!Box - Error logging out: %s") % error.getErrorMessage()
471 def loadFritzBoxPhonebook(self):
472 debug("[FritzCallFBF] loadFritzBoxPhonebook")
473 if config.plugins.FritzCall.fritzphonebook.value:
474 self._phoneBookID = '0'
475 debug("[FritzCallFBF] loadFritzBoxPhonebook: logging in")
476 self._login(self._loadFritzBoxPhonebook)
478 def _loadFritzBoxPhonebook(self, html):
480 #===================================================================
481 # found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)
483 # self._errorLoad('Login: ' + found.group(1))
485 #===================================================================
486 start = html.find('<p class="errorMessage">FEHLER: ')
488 start = start + len('<p class="errorMessage">FEHLER: ')
489 self._errorLoad('Login: ' + html[start, html.find('</p>', start)])
492 'getpage':'../html/de/menus/menu2.html',
494 'var:pagename':'fonbuch',
497 'telcfg:settings/Phonebook/Books/Select':self._phoneBookID, # this selects always the first phonbook
499 url = "http://%s/cgi-bin/webcm" % (config.plugins.FritzCall.hostname.value)
500 debug("[FritzCallFBF] _loadFritzBoxPhonebook: '" + url + "' parms: '" + parms + "'")
503 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
504 headers={'Content-Type': "application/x-www-form-urlencoded", 'Content-Length': str(len(parms))
505 }, postdata=parms).addCallback(self._parseFritzBoxPhonebook).addErrback(self._errorLoad)
507 def _parseFritzBoxPhonebook(self, html):
508 debug("[FritzCallFBF] _parseFritzBoxPhonebook")
510 # first, let us get the charset
511 found = re.match('.*<meta http-equiv=content-type content="text/html; charset=([^"]*)">', html, re.S)
513 charset = found.group(1)
514 debug("[FritzCallFBF] _parseFritzBoxPhonebook: found charset: " + charset)
515 html = html2unicode(html.replace(chr(0xf6),'').decode(charset)).encode('utf-8')
516 else: # this is kind of emergency conversion...
518 debug("[FritzCallFBF] _parseFritzBoxPhonebook: try charset utf-8")
520 html = html2unicode(html.decode('utf-8')).encode('utf-8') # this looks silly, but has to be
521 except UnicodeDecodeError:
522 debug("[FritzCallFBF] _parseFritzBoxPhonebook: try charset iso-8859-1")
523 charset = 'iso-8859-1'
524 html = html2unicode(html.decode('iso-8859-1')).encode('utf-8') # this looks silly, but has to be
526 # if re.search('document.write\(TrFon1\(\)', html):
527 if html.find('document.write(TrFon1()') != -1:
528 #===============================================================================
529 # 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)
530 # 7170 (FW 29.04.70) 22.03.2009
531 # 7141 (FW 40.04.68) 22.03.2009
532 # We expect one line with
533 # TrFonName(Entry umber, Name, ???, Path to picture)
534 # followed by several lines with
535 # TrFonNr(Type,Number,Shortcut,Vanity), which all belong to the name in TrFonName.
537 # Photo could be fetched with http://192.168.0.1/lua/photo.lua?photo=<Path to picture[7:]&sid=????
538 #===============================================================================
539 debug("[FritzCallFBF] _parseFritzBoxPhonebook: discovered newer firmware")
540 found = re.match('.*<input type="hidden" name="telcfg:settings/Phonebook/Books/Name(\d+)" value="[Dd]reambox" id="uiPostPhonebookName\d+" disabled>', html, re.S)
542 phoneBookID = found.group(1)
543 debug("[FritzCallFBF] _parseFritzBoxPhonebook: found dreambox phonebook with id: " + phoneBookID)
544 if self._phoneBookID != phoneBookID:
545 self._phoneBookID = phoneBookID
546 debug("[FritzCallFBF] _parseFritzBoxPhonebook: reload phonebook")
547 self._loadFritzBoxPhonebook(self._phoneBookID) # reload with dreambox phonebook
550 entrymask = re.compile('(TrFonName\("[^"]+", "[^"]+", "[^"]*"(?:, "[^"]*")?\);.*?)document.write\(TrFon1\(\)', re.S)
551 entries = entrymask.finditer(html)
552 for entry in entries:
553 # TrFonName (id, name, category)
554 # TODO: replace re.match?
555 found = re.match('TrFonName\("[^"]*", "([^"]+)", "[^"]*"(?:, "[^"]*")?\);', entry.group(1))
557 debug("[FritzCallFBF] _parseFritzBoxPhonebook: name: %s" %found.group(1))
558 name = found.group(1).replace(',','').strip()
560 debug("[FritzCallFBF] _parseFritzBoxPhonebook: could not find name")
562 # TrFonNr (type, rufnr, code, vanity)
563 detailmask = re.compile('TrFonNr\("([^"]*)", "([^"]*)", "([^"]*)", "([^"]*)"\);', re.S)
564 details = detailmask.finditer(entry.group(1))
565 for found in details:
566 thisnumber = found.group(2).strip()
568 debug("[FritzCallFBF] Ignoring entry with empty number for '''%s'''" % (name))
572 callType = found.group(1)
573 if config.plugins.FritzCall.showType.value:
574 if callType == "mobile":
575 thisname = thisname + " (" + _("mobile") + ")"
576 elif callType == "home":
577 thisname = thisname + " (" + _("home") + ")"
578 elif callType == "work":
579 thisname = thisname + " (" + _("work") + ")"
581 if config.plugins.FritzCall.showShortcut.value and found.group(3):
582 thisname = thisname + ", " + _("Shortcut") + ": " + found.group(3)
583 if config.plugins.FritzCall.showVanity.value and found.group(4):
584 thisname = thisname + ", " + _("Vanity") + ": " + found.group(4)
586 debug("[FritzCallFBF] Adding '''%s''' with '''%s''' from FRITZ!Box Phonebook!" % (thisname.strip(), thisnumber))
587 # Beware: strings in phonebook.phonebook have to be in utf-8!
588 phonebook.phonebook[thisnumber] = thisname
590 # elif re.search('document.write\(TrFon\(', html):
591 elif html.find('document.write(TrFon(') != -1:
592 #===============================================================================
593 # Old Style: 7050 (FW 14.04.33)
594 # We expect one line with TrFon(No,Name,Number,Shortcut,Vanity)
595 # Encoding should be plain Ascii...
596 #===============================================================================
597 entrymask = re.compile('TrFon\("[^"]*", "([^"]*)", "([^"]*)", "([^"]*)", "([^"]*)"\)', re.S)
598 entries = entrymask.finditer(html)
599 for found in entries:
600 name = found.group(1).strip().replace(',','')
601 # debug("[FritzCallFBF] pos: %s name: %s" %(found.group(0),name))
602 thisnumber = found.group(2).strip()
603 if config.plugins.FritzCall.showShortcut.value and found.group(3):
604 name = name + ", " + _("Shortcut") + ": " + found.group(3)
605 if config.plugins.FritzCall.showVanity.value and found.group(4):
606 name = name + ", " + _("Vanity") + ": " + found.group(4)
608 # name = name.encode('utf-8')
609 debug("[FritzCallFBF] Adding '''%s''' with '''%s''' from FRITZ!Box Phonebook!" % (name, thisnumber))
610 # Beware: strings in phonebook.phonebook have to be in utf-8!
611 phonebook.phonebook[thisnumber] = name
613 debug("[FritzCallFBF] ignoring empty number for %s" % name)
615 elif self._md5Sid == '0000000000000000': # retry, it could be a race condition
616 debug("[FritzCallFBF] _parseFritzBoxPhonebook: retry loading phonebook")
617 self.loadFritzBoxPhonebook()
619 self._notify(_("Could not parse FRITZ!Box Phonebook entry"))
621 def _errorLoad(self, error):
622 debug("[FritzCallFBF] _errorLoad: %s" % (error))
623 text = _("FRITZ!Box - Could not load phonebook: %s") % error.getErrorMessage()
626 def getCalls(self, callScreen, callback, callType):
628 # call sequence must be:
630 # - getPage -> _gotPageLogin
631 # - loginCallback (_getCalls)
632 # - getPage -> _getCalls1
633 debug("[FritzCallFBF] getCalls")
634 self._callScreen = callScreen
635 self._callType = callType
636 if (time.time() - self._callTimestamp) > 180:
637 debug("[FritzCallFBF] getCalls: outdated data, login and get new ones: " + time.ctime(self._callTimestamp) + " time: " + time.ctime())
638 self._callTimestamp = time.time()
639 self._login(lambda x:self._getCalls(callback, x))
640 elif not self._callList:
641 debug("[FritzCallFBF] getCalls: time is ok, but no callList")
642 self._getCalls1(callback)
644 debug("[FritzCallFBF] getCalls: time is ok, callList is ok")
645 self._gotPageCalls(callback)
647 def _getCalls(self, callback, html):
649 #===================================================================
650 # found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)
652 # self._errorCalls('Login: ' + found.group(1))
654 #===================================================================
655 start = html.find('<p class="errorMessage">FEHLER: ')
657 start = start + len('<p class="errorMessage">FEHLER: ')
658 self._errorCalls('Login: ' + html[start, html.find('</p>', start)])
661 # we need this to fill Anrufliste.csv
662 # http://repeater1/cgi-bin/webcm?getpage=../html/de/menus/menu2.html&var:lang=de&var:menu=fon&var:pagename=foncalls
664 debug("[FritzCallFBF] _getCalls")
666 #===================================================================
667 # found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)
669 # text = _("FRITZ!Box - Error logging in: %s") + found.group(1)
672 #===================================================================
673 start = html.find('<p class="errorMessage">FEHLER: ')
675 start = start + len('<p class="errorMessage">FEHLER: ')
676 self._notify(_("FRITZ!Box - Error logging in: %s") + html[start, html.find('</p>', start)])
680 self._callScreen.updateStatus(_("preparing"))
681 parms = urlencode({'getpage':'../html/de/menus/menu2.html', 'var:lang':'de', 'var:pagename':'foncalls', 'var:menu':'fon', 'sid':self._md5Sid})
682 url = "http://%s/cgi-bin/webcm?%s" % (config.plugins.FritzCall.hostname.value, parms)
683 getPage(url).addCallback(lambda x:self._getCalls1(callback)).addErrback(self._errorCalls) #@UnusedVariable # pylint: disable=W0613
685 def _getCalls1(self, callback):
687 # finally we should have successfully lgged in and filled the csv
689 debug("[FritzCallFBF] _getCalls1")
691 self._callScreen.updateStatus(_("finishing"))
692 parms = urlencode({'getpage':'../html/de/FRITZ!Box_Anrufliste.csv', 'sid':self._md5Sid})
693 url = "http://%s/cgi-bin/webcm?%s" % (config.plugins.FritzCall.hostname.value, parms)
694 getPage(url).addCallback(lambda x:self._gotPageCalls(callback, x)).addErrback(self._errorCalls)
696 def _gotPageCalls(self, callback, csv=""):
697 def resolveNumber(number, default=None):
699 if config.plugins.FritzCall.internal.value and len(number) > 3 and number[0] == "0":
702 number = stripCbCPrefix(number, config.plugins.FritzCall.country.value)
703 if config.plugins.FritzCall.prefix.value and number and number[0] != '0': # should only happen for outgoing
704 number = config.plugins.FritzCall.prefix.value + number
705 name = phonebook.search(number)
707 #===========================================================
708 # found = re.match('(.*?)\n.*', name)
710 # name = found.group(1)
711 #===========================================================
712 end = name.find('\n')
719 name = resolveNumberWithAvon(number, config.plugins.FritzCall.country.value)
721 number = number + ' ' + name
723 number = _("UNKNOWN")
724 # if len(number) > 20: number = number[:20]
728 debug("[FritzCallFBF] _gotPageCalls: got csv, setting callList")
730 self._callScreen.updateStatus(_("done"))
731 if csv.find('Melden Sie sich mit dem Kennwort der FRITZ!Box an') != -1:
732 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.")
733 # self.session.open(MessageBox, text, MessageBox.TYPE_ERROR, timeout=config.plugins.FritzCall.timeout.value)
737 csv = csv.decode('iso-8859-1', 'replace').encode('utf-8', 'replace')
738 lines = csv.splitlines()
739 self._callList = lines
741 debug("[FritzCallFBF] _gotPageCalls: got no csv, but have callList")
743 self._callScreen.updateStatus(_("done, using last list"))
744 lines = self._callList
746 debug("[FritzCallFBF] _gotPageCalls: got no csv, no callList, laving")
750 if config.plugins.FritzCall.filter.value and config.plugins.FritzCall.filterCallList.value:
751 filtermsns = map(lambda x: x.strip(), config.plugins.FritzCall.filtermsn.value.split(","))
752 debug("[FritzCallFBF] _gotPageCalls: filtermsns %s" % (repr(filtermsns)))
754 # Typ;Datum;Name;Rufnummer;Nebenstelle;Eigene Rufnummer;Dauer
755 # 0 ;1 ;2 ;3 ;4 ;5 ;6
756 lines = map(lambda line: line.split(';'), lines)
757 lines = filter(lambda line: (len(line)==7 and (line[0]=="Typ" or self._callType == '.' or line[0] == self._callType)), lines)
760 # debug("[FritzCallFBF] _gotPageCalls: line %s" % (line))
764 if config.plugins.FritzCall.phonebook.value and line[2]:
765 remote = resolveNumber(line[3], line[2] + " (FBF)")
767 remote = resolveNumber(line[3], line[2])
769 start = here.find('Internet: ')
771 start += len('Internet: ')
775 if direct != "Typ" and config.plugins.FritzCall.filter.value and config.plugins.FritzCall.filterCallList.value:
776 # debug("[FritzCallFBF] _gotPageCalls: check %s" % (here))
777 if here not in filtermsns:
778 # debug("[FritzCallFBF] _gotPageCalls: skip %s" % (here))
780 here = resolveNumber(here, line[4])
782 number = stripCbCPrefix(line[3], config.plugins.FritzCall.country.value)
783 if config.plugins.FritzCall.prefix.value and number and number[0] != '0': # should only happen for outgoing
784 number = config.plugins.FritzCall.prefix.value + number
785 callListL.append((number, date, direct, remote, length, here))
788 # debug("[FritzCallFBF] _gotPageCalls call callback with\n" + text
790 self._callScreen = None
792 def _errorCalls(self, error):
793 debug("[FritzCallFBF] _errorCalls: %s" % (error))
794 text = _("FRITZ!Box - Could not load calls: %s") % error.getErrorMessage()
797 def dial(self, number):
798 ''' initiate a call to number '''
799 self._login(lambda x: self._dial(number, x))
801 def _dial(self, number, html):
803 #===================================================================
804 # found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)
806 # self._errorDial('Login: ' + found.group(1))
808 #===================================================================
809 start = html.find('<p class="errorMessage">FEHLER: ')
811 start = start + len('<p class="errorMessage">FEHLER: ')
812 self._errorDial('Login: ' + html[start, html.find('</p>', start)])
814 url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
816 'getpage':'../html/de/menus/menu2.html',
817 'var:pagename':'fonbuch',
819 'telcfg:settings/UseClickToDial':'1',
820 'telcfg:settings/DialPort':config.plugins.FritzCall.extension.value,
821 'telcfg:command/Dial':number,
824 debug("[FritzCallFBF] dial url: '" + url + "' parms: '" + parms + "'")
827 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
829 'Content-Type': "application/x-www-form-urlencoded",
830 'Content-Length': str(len(parms))},
831 postdata=parms).addCallback(self._okDial).addErrback(self._errorDial)
833 def _okDial(self, html): #@UnusedVariable # pylint: disable=W0613
834 debug("[FritzCallFBF] okDial")
836 def _errorDial(self, error):
837 debug("[FritzCallFBF] errorDial: $s" % error)
838 text = _("FRITZ!Box - Dialling failed: %s") % error.getErrorMessage()
841 def changeWLAN(self, statusWLAN):
842 ''' get status info from FBF '''
843 debug("[FritzCallFBF] changeWLAN start")
844 if not statusWLAN or (statusWLAN != '1' and statusWLAN != '0'):
846 self._login(lambda x: self._changeWLAN(statusWLAN, x))
848 def _changeWLAN(self, statusWLAN, html):
850 #===================================================================
851 # found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)
853 # self._errorChangeWLAN('Login: ' + found.group(1))
855 #===================================================================
856 start = html.find('<p class="errorMessage">FEHLER: ')
858 start = start + len('<p class="errorMessage">FEHLER: ')
859 self._errorChangeWLAN('Login: ' + html[start, html.find('</p>', start)])
861 url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
863 'getpage':'../html/de/menus/menu2.html',
865 'var:pagename':'wlan',
867 'wlan:settings/ap_enabled':str(statusWLAN),
870 debug("[FritzCallFBF] changeWLAN url: '" + url + "' parms: '" + parms + "'")
873 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
875 'Content-Type': "application/x-www-form-urlencoded",
876 'Content-Length': str(len(parms))},
877 postdata=parms).addCallback(self._okChangeWLAN).addErrback(self._errorChangeWLAN)
879 def _okChangeWLAN(self, html): #@UnusedVariable # pylint: disable=W0613
880 debug("[FritzCallFBF] _okChangeWLAN")
882 def _errorChangeWLAN(self, error):
883 debug("[FritzCallFBF] _errorChangeWLAN: $s" % error)
884 text = _("FRITZ!Box - Failed changing WLAN: %s") % error.getErrorMessage()
887 def changeMailbox(self, whichMailbox):
888 ''' switch mailbox on/off '''
889 debug("[FritzCallFBF] changeMailbox start: " + str(whichMailbox))
890 self._login(lambda x: self._changeMailbox(whichMailbox, x))
892 def _changeMailbox(self, whichMailbox, html):
894 #===================================================================
895 # found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)
897 # self._errorChangeMailbox('Login: ' + found.group(1))
899 #===================================================================
900 start = html.find('<p class="errorMessage">FEHLER: ')
902 start = start + len('<p class="errorMessage">FEHLER: ')
903 self._errorChangeMailbox('Login: ' + html[start, html.find('</p>', start)])
905 debug("[FritzCallFBF] _changeMailbox")
906 url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
907 if whichMailbox == -1:
909 if self.info[FBF_tamActive][i+1]:
914 'tam:settings/TAM'+str(i)+'/Active':state,
917 debug("[FritzCallFBF] changeMailbox url: '" + url + "' parms: '" + parms + "'")
920 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
922 'Content-Type': "application/x-www-form-urlencoded",
923 'Content-Length': str(len(parms))},
924 postdata=parms).addCallback(self._okChangeMailbox).addErrback(self._errorChangeMailbox)
925 elif whichMailbox > 4:
926 debug("[FritzCallFBF] changeMailbox invalid mailbox number")
928 if self.info[FBF_tamActive][whichMailbox+1]:
933 'tam:settings/TAM'+str(whichMailbox)+'/Active':state,
936 debug("[FritzCallFBF] changeMailbox url: '" + url + "' parms: '" + parms + "'")
939 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
941 'Content-Type': "application/x-www-form-urlencoded",
942 'Content-Length': str(len(parms))},
943 postdata=parms).addCallback(self._okChangeMailbox).addErrback(self._errorChangeMailbox)
945 def _okChangeMailbox(self, html): #@UnusedVariable # pylint: disable=W0613
946 debug("[FritzCallFBF] _okChangeMailbox")
948 def _errorChangeMailbox(self, error):
949 debug("[FritzCallFBF] _errorChangeMailbox: $s" % error)
950 text = _("FRITZ!Box - Failed changing Mailbox: %s") % error.getErrorMessage()
953 def getInfo(self, callback):
954 ''' get status info from FBF '''
955 debug("[FritzCallFBF] getInfo")
956 self._login(lambda x:self._getInfo(callback, x))
958 def _getInfo(self, callback, html):
959 # http://192.168.178.1/cgi-bin/webcm?getpage=../html/de/menus/menu2.html&var:lang=de&var:pagename=home&var:menu=home
960 debug("[FritzCallFBF] _getInfo: verify login")
962 #===================================================================
963 # found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)
965 # self._errorGetInfo('Login: ' + found.group(1))
967 #===================================================================
968 start = html.find('<p class="errorMessage">FEHLER: ')
970 start = start + len('<p class="errorMessage">FEHLER: ')
971 self._errorGetInfo('Login: ' + html[start, html.find('</p>', start)])
974 url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
976 'getpage':'../html/de/menus/menu2.html',
978 'var:pagename':'home',
982 debug("[FritzCallFBF] _getInfo url: '" + url + "' parms: '" + parms + "'")
985 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
987 'Content-Type': "application/x-www-form-urlencoded",
988 'Content-Length': str(len(parms))},
989 postdata=parms).addCallback(lambda x:self._okGetInfo(callback,x)).addErrback(self._errorGetInfo)
991 def _okGetInfo(self, callback, html):
994 (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive) = self.info
996 (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive) = (None, None, None, None, None, None, None, None, None)
998 debug("[FritzCallFBF] _okGetInfo/readinfo")
999 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)
1001 boxInfo = found.group(1)+ ', ' + found.group(2)
1002 boxInfo = boxInfo.replace(' ',' ')
1003 # debug("[FritzCallFBF] _okGetInfo Boxinfo: " + boxInfo)
1005 found = re.match('.*<p class="ac">([^<]*)</p>', html, re.S)
1007 # debug("[FritzCallFBF] _okGetInfo Boxinfo: " + found.group(1))
1008 boxInfo = found.group(1)
1010 if html.find('home_coninf.txt') != -1:
1011 url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
1013 'getpage':'../html/de/home/home_coninf.txt',
1016 # debug("[FritzCallFBF] get coninfo: url: '" + url + "' parms: '" + parms + "'")
1019 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
1021 'Content-Type': "application/x-www-form-urlencoded",
1022 'Content-Length': str(len(parms))},
1023 postdata=parms).addCallback(lambda x:self._okSetConInfo(callback,x)).addErrback(self._errorGetInfo)
1025 found = re.match('.*if \(isNaN\(jetzt\)\)\s*return "";\s*var str = "([^"]*)";', html, re.S)
1027 # debug("[FritzCallFBF] _okGetInfo Uptime: " + found.group(1))
1028 upTime = found.group(1)
1030 found = re.match('.*str = g_pppSeit \+"([^<]*)<br>"\+mldIpAdr;', html, re.S)
1032 # debug("[FritzCallFBF] _okGetInfo Uptime: " + found.group(1))
1033 upTime = found.group(1)
1035 found = re.match(".*IpAdrDisplay\('([.\d]+)'\)", html, re.S)
1037 # debug("[FritzCallFBF] _okGetInfo IpAdrDisplay: " + found.group(1))
1038 ipAddress = found.group(1)
1040 if html.find('g_tamActive') != -1:
1041 entries = re.compile('if \("(\d)" == "1"\) {\s*g_tamActive \+= 1;\s*}', re.S).finditer(html)
1042 tamActive = [0, False, False, False, False, False]
1044 for entry in entries:
1045 state = entry.group(1)
1050 # debug("[FritzCallFBF] _okGetInfo tamActive: " + str(tamActive))
1052 if html.find('home_dect.txt') != -1:
1053 url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
1055 'getpage':'../html/de/home/home_dect.txt',
1058 # debug("[FritzCallFBF] get coninfo: url: '" + url + "' parms: '" + parms + "'")
1061 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
1063 'Content-Type': "application/x-www-form-urlencoded",
1064 'Content-Length': str(len(parms))},
1065 postdata=parms).addCallback(lambda x:self._okSetDect(callback,x)).addErrback(self._errorGetInfo)
1067 if html.find('countDect2') != -1:
1068 entries = re.compile('if \("1" == "1"\) countDect2\+\+;', re.S).findall(html)
1069 dectActive = len(entries)
1070 # debug("[FritzCallFBF] _okGetInfo dectActive: " + str(dectActive))
1072 found = re.match('.*var g_intFaxActive = "0";\s*if \("1" != ""\) {\s*g_intFaxActive = "1";\s*}\s*', html, re.S)
1075 # debug("[FritzCallFBF] _okGetInfo faxActive")
1077 if html.find('cntRufumleitung') != -1:
1078 entries = re.compile('mode = "1";\s*ziel = "[^"]+";\s*if \(mode == "1" \|\| ziel != ""\)\s*{\s*g_RufumleitungAktiv = true;', re.S).findall(html)
1079 rufumlActive = len(entries)
1080 entries = re.compile('if \("([^"]*)"=="([^"]*)"\) isAllIncoming\+\+;', re.S).finditer(html)
1082 for entry in entries:
1083 # debug("[FritzCallFBF] _okGetInfo rufumlActive add isAllIncoming")
1084 if entry.group(1) == entry.group(2):
1086 if isAllIncoming == 2 and rufumlActive > 0:
1088 # debug("[FritzCallFBF] _okGetInfo rufumlActive: " + str(rufumlActive))
1090 # /cgi-bin/webcm?getpage=../html/de/home/home_dsl.txt
1091 # { "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": "" }
1092 if html.find('home_dsl.txt') != -1:
1093 url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
1095 'getpage':'../html/de/home/home_dsl.txt',
1098 # debug("[FritzCallFBF] get dsl state: url: '" + url + "' parms: '" + parms + "'")
1101 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
1103 'Content-Type': "application/x-www-form-urlencoded",
1104 'Content-Length': str(len(parms))},
1105 postdata=parms).addCallback(lambda x:self._okSetDslState(callback,x)).addErrback(self._errorGetInfo)
1107 found = re.match('.*function DslStateDisplay \(state\){\s*var state = "(\d+)";', html, re.S)
1109 # debug("[FritzCallFBF] _okGetInfo DslState: " + found.group(1))
1110 dslState = [ found.group(1), None ] # state, speed
1111 found = re.match('.*function DslStateDisplay \(state\){\s*var state = "\d+";.*?if \("3130" != "0"\) str = "([^"]*)";', html, re.S)
1113 # debug("[FritzCallFBF] _okGetInfo DslSpeed: " + found.group(1).strip())
1114 dslState[1] = found.group(1).strip()
1116 # /cgi-bin/webcm?getpage=../html/de/home/home_wlan.txt
1117 # { "ap_enabled": "1", "active_stations": "0", "encryption": "4", "wireless_stickandsurf_enabled": "0", "is_macfilter_active": "0", "wmm_enabled": "1", "wlan_state": [ "end" ] }
1118 if html.find('home_wlan.txt') != -1:
1119 url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
1121 'getpage':'../html/de/home/home_wlan.txt',
1124 # debug("[FritzCallFBF] get wlan state: url: '" + url + "' parms: '" + parms + "'")
1127 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
1129 'Content-Type': "application/x-www-form-urlencoded",
1130 'Content-Length': str(len(parms))},
1131 postdata=parms).addCallback(lambda x:self._okSetWlanState(callback,x)).addErrback(self._errorGetInfo)
1133 found = re.match('.*function WlanStateLed \(state\){.*?return StateLed\("(\d+)"\);\s*}', html, re.S)
1135 # debug("[FritzCallFBF] _okGetInfo WlanState: " + found.group(1))
1136 wlanState = [ found.group(1), 0, 0 ] # state, encryption, number of devices
1137 found = re.match('.*var (?:g_)?encryption = "(\d+)";', html, re.S)
1139 # debug("[FritzCallFBF] _okGetInfo WlanEncrypt: " + found.group(1))
1140 wlanState[1] = found.group(1)
1142 return (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive)
1144 debug("[FritzCallFBF] _okGetInfo")
1145 info = readInfo(html)
1146 debug("[FritzCallFBF] _okGetInfo info: " + str(info))
1151 def _okSetDect(self, callback, html):
1152 # debug("[FritzCallFBF] _okSetDect: " + html)
1153 # found = re.match('.*"connection_status":"(\d+)".*"connection_ip":"([.\d]+)".*"connection_detail":"([^"]+)".*"connection_uptime":"([^"]+)"', html, re.S)
1154 if html.find('"dect_enabled": "1"') != -1:
1155 # debug("[FritzCallFBF] _okSetDect: dect_enabled")
1156 found = re.match('.*"dect_device_list":.*\[([^\]]*)\]', html, re.S)
1158 # debug("[FritzCallFBF] _okSetDect: dect_device_list: %s" %(found.group(1)))
1159 entries = re.compile('"1"', re.S).findall(found.group(1))
1160 dectActive = len(entries)
1161 (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dummy, faxActive, rufumlActive) = self.info
1162 self.info = (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive)
1163 debug("[FritzCallFBF] _okSetDect info: " + str(self.info))
1167 def _okSetConInfo(self, callback, html):
1168 # debug("[FritzCallFBF] _okSetConInfo: " + html)
1169 # found = re.match('.*"connection_status":"(\d+)".*"connection_ip":"([.\d]+)".*"connection_detail":"([^"]+)".*"connection_uptime":"([^"]+)"', html, re.S)
1170 found = re.match('.*"connection_ip": "([.\d]+)".*"connection_uptime": "([^"]+)"', html, re.S)
1172 # debug("[FritzCallFBF] _okSetConInfo: connection_ip: %s upTime: %s" %( found.group(1), found.group(2)))
1173 ipAddress = found.group(1)
1174 upTime = found.group(2)
1175 (boxInfo, dummy, dummy, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive) = self.info
1176 self.info = (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive)
1177 debug("[FritzCallFBF] _okSetWlanState info: " + str(self.info))
1179 found = re.match('.*_ip": "([.\d]+)".*"connection_uptime": "([^"]+)"', html, re.S)
1181 # debug("[FritzCallFBF] _okSetConInfo: _ip: %s upTime: %s" %( found.group(1), found.group(2)))
1182 ipAddress = found.group(1)
1183 upTime = found.group(2)
1184 (boxInfo, dummy, dummy, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive) = self.info
1185 self.info = (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive)
1186 debug("[FritzCallFBF] _okSetWlanState info: " + str(self.info))
1190 def _okSetWlanState(self, callback, html):
1191 # debug("[FritzCallFBF] _okSetWlanState: " + html)
1192 found = re.match('.*"ap_enabled": "(\d+)"', html, re.S)
1194 # debug("[FritzCallFBF] _okSetWlanState: ap_enabled: " + found.group(1))
1195 wlanState = [ found.group(1), None, None ]
1196 found = re.match('.*"encryption": "(\d+)"', html, re.S)
1198 # debug("[FritzCallFBF] _okSetWlanState: encryption: " + found.group(1))
1199 wlanState[1] = found.group(1)
1200 found = re.match('.*"active_stations": "(\d+)"', html, re.S)
1202 # debug("[FritzCallFBF] _okSetWlanState: active_stations: " + found.group(1))
1203 wlanState[2] = found.group(1)
1204 (boxInfo, upTime, ipAddress, dummy, dslState, tamActive, dectActive, faxActive, rufumlActive) = self.info
1205 self.info = (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive)
1206 debug("[FritzCallFBF] _okSetWlanState info: " + str(self.info))
1210 def _okSetDslState(self, callback, html):
1211 # debug("[FritzCallFBF] _okSetDslState: " + html)
1212 found = re.match('.*"dsl_carrier_state": "(\d+)"', html, re.S)
1214 # debug("[FritzCallFBF] _okSetDslState: dsl_carrier_state: " + found.group(1))
1215 dslState = [ found.group(1), None ]
1216 found = re.match('.*"dsl_ds_nrate": "(\d+)"', html, re.S)
1218 # debug("[FritzCallFBF] _okSetDslState: dsl_ds_nrate: " + found.group(1))
1219 dslState[1] = found.group(1)
1220 found = re.match('.*"dsl_us_nrate": "(\d+)"', html, re.S)
1222 # debug("[FritzCallFBF] _okSetDslState: dsl_us_nrate: " + found.group(1))
1223 dslState[1] = dslState[1] + '/' + found.group(1)
1224 (boxInfo, upTime, ipAddress, wlanState, dummy, tamActive, dectActive, faxActive, rufumlActive) = self.info
1225 self.info = (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive)
1226 debug("[FritzCallFBF] _okSetDslState info: " + str(self.info))
1230 def _errorGetInfo(self, error):
1231 debug("[FritzCallFBF] _errorGetInfo: %s" % (error))
1232 text = _("FRITZ!Box - Error getting status: %s") % error.getErrorMessage()
1234 # linkP = open("/tmp/FritzCall_errorGetInfo.htm", "w")
1235 # linkP.write(error)
1239 self._login(self._reset)
1241 def _reset(self, html):
1242 # 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
1244 #===================================================================
1245 # found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)
1247 # self._errorReset('Login: ' + found.group(1))
1249 #===================================================================
1250 start = html.find('<p class="errorMessage">FEHLER: ')
1252 start = start + len('<p class="errorMessage">FEHLER: ')
1253 self._errorReset('Login: ' + html[start, html.find('</p>', start)])
1255 if self._callScreen:
1256 self._callScreen.close()
1257 url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
1259 'getpage':'../html/reboot.html',
1261 'var:pagename':'reset',
1262 'var:menu':'system',
1263 'logic:command/reboot':'../gateway/commands/saveconfig.html',
1266 debug("[FritzCallFBF] _reset url: '" + url + "' parms: '" + parms + "'")
1269 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
1271 'Content-Type': "application/x-www-form-urlencoded",
1272 'Content-Length': str(len(parms))},
1275 def _okReset(self, html): #@UnusedVariable # pylint: disable=W0613
1276 debug("[FritzCallFBF] _okReset")
1278 def _errorReset(self, error):
1279 debug("[FritzCallFBF] _errorReset: %s" % (error))
1280 text = _("FRITZ!Box - Error resetting: %s") % error.getErrorMessage()
1283 def readBlacklist(self):
1284 self._login(self._readBlacklist)
1286 def _readBlacklist(self, html):
1288 #===================================================================
1289 # found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)
1291 # self._errorBlacklist('Login: ' + found.group(1))
1293 #===================================================================
1294 start = html.find('<p class="errorMessage">FEHLER: ')
1296 start = start + len('<p class="errorMessage">FEHLER: ')
1297 self._errorBlacklist('Login: ' + html[start, html.find('</p>', start)])
1299 # http://fritz.box/cgi-bin/webcm?getpage=../html/de/menus/menu2.html&var:lang=de&var:menu=fon&var:pagename=sperre
1300 url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
1302 'getpage':'../html/de/menus/menu2.html',
1304 'var:pagename':'sperre',
1308 debug("[FritzCallFBF] _readBlacklist url: '" + url + "' parms: '" + parms + "'")
1311 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
1313 'Content-Type': "application/x-www-form-urlencoded",
1314 'Content-Length': str(len(parms))},
1315 postdata=parms).addCallback(self._okBlacklist).addErrback(self._errorBlacklist)
1317 def _okBlacklist(self, html):
1318 debug("[FritzCallFBF] _okBlacklist")
1319 entries = re.compile('<script type="text/javascript">document.write\(Tr(Out|In)\("\d+", "(\d+)", "\w*"\)\);</script>', re.S).finditer(html)
1320 self.blacklist = ([], [])
1321 for entry in entries:
1322 if entry.group(1) == "In":
1323 self.blacklist[0].append(entry.group(2))
1325 self.blacklist[1].append(entry.group(2))
1326 debug("[FritzCallFBF] _okBlacklist: %s" % repr(self.blacklist))
1328 def _errorBlacklist(self, error):
1329 debug("[FritzCallFBF] _errorBlacklist: %s" % (error))
1330 text = _("FRITZ!Box - Error getting blacklist: %s") % error.getErrorMessage()
1333 #===============================================================================
1335 # ''' hangup call on port; not used for now '''
1336 # url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
1337 # parms = urlencode({
1338 # 'id':'uiPostForm',
1339 # 'name':'uiPostForm',
1340 # 'login:command/password': config.plugins.FritzCall.password.value,
1341 # 'telcfg:settings/UseClickToDial':'1',
1342 # 'telcfg:settings/DialPort':config.plugins.FritzCall.extension.value,
1343 # 'telcfg:command/Hangup':'',
1344 # 'sid':self._md5Sid
1346 # debug("[FritzCallFBF] hangup url: '" + url + "' parms: '" + parms + "'")
1350 # 'Content-Type': "application/x-www-form-urlencoded",
1351 # 'Content-Length': str(len(parms))},
1353 #===============================================================================
1357 class FritzMenu(Screen, HelpableScreen):
1358 def __init__(self, session):
1359 fontSize = scaleV(24, 21) # indeed this is font size +2
1360 noButtons = 2 # reset, wlan
1362 if not fritzbox or not fritzbox.info:
1365 if fritzbox.info[FBF_tamActive]:
1366 noButtons += 1 # toggle mailboxes
1367 width = max(DESKTOP_WIDTH - scaleH(500, 250), noButtons*140+(noButtons+1)*10)
1368 # boxInfo 2 lines, gap, internet 2 lines, gap, dsl/wlan each 1 line, gap, buttons
1369 height = 5 + 2*fontSize + 10 + 2*fontSize + 10 + 2*fontSize + 10 + 40 + 5
1370 if fritzbox.info[FBF_tamActive] is not None:
1372 if fritzbox.info[FBF_dectActive] is not None:
1374 if fritzbox.info[FBF_faxActive] is not None:
1376 if fritzbox.info[FBF_rufumlActive] is not None:
1378 buttonsGap = (width-noButtons*140)/(noButtons+1)
1379 buttonsVPos = height-40-5
1382 if fritzbox.info[FBF_tamActive] is not None:
1384 <widget name="FBFMailbox" position="%d,%d" size="%d,%d" font="Regular;%d" />
1385 <widget name="mailbox_inactive" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1386 <widget name="mailbox_active" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1387 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
1388 <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" />
1390 40, 5+2*fontSize+10+varLinePos*fontSize+10, # position mailbox
1391 width-40-20, fontSize, # size mailbox
1393 "skin_default/buttons/button_green_off.png",
1394 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button mailbox
1395 "skin_default/buttons/button_green.png",
1396 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button mailbox
1397 noButtons*buttonsGap+(noButtons-1)*140, buttonsVPos,
1398 noButtons*buttonsGap+(noButtons-1)*140, buttonsVPos,
1404 if fritzbox.info[FBF_dectActive] is not None:
1406 <widget name="FBFDect" position="%d,%d" size="%d,%d" font="Regular;%d" />
1407 <widget name="dect_inactive" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1408 <widget name="dect_active" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1410 40, 5+2*fontSize+10+varLinePos*fontSize+10, # position dect
1411 width-40-20, fontSize, # size dect
1413 "skin_default/buttons/button_green_off.png",
1414 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button dect
1415 "skin_default/buttons/button_green.png",
1416 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button dect
1422 if fritzbox.info[FBF_faxActive] is not None:
1424 <widget name="FBFFax" position="%d,%d" size="%d,%d" font="Regular;%d" />
1425 <widget name="fax_inactive" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1426 <widget name="fax_active" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1428 40, 5+2*fontSize+10+varLinePos*fontSize+10, # position dect
1429 width-40-20, fontSize, # size dect
1431 "skin_default/buttons/button_green_off.png",
1432 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button dect
1433 "skin_default/buttons/button_green.png",
1434 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button dect
1440 if fritzbox.info[FBF_rufumlActive] is not None:
1442 <widget name="FBFRufuml" position="%d,%d" size="%d,%d" font="Regular;%d" />
1443 <widget name="rufuml_inactive" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1444 <widget name="rufuml_active" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1446 40, 5+2*fontSize+10+varLinePos*fontSize+10, # position dect
1447 width-40-20, fontSize, # size dect
1449 "skin_default/buttons/button_green_off.png",
1450 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button dect
1451 "skin_default/buttons/button_green.png",
1452 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button dect
1459 <screen name="FritzMenu" position="center,center" size="%d,%d" title="FRITZ!Box Fon Status" >
1460 <widget name="FBFInfo" position="%d,%d" size="%d,%d" font="Regular;%d" />
1461 <widget name="FBFInternet" position="%d,%d" size="%d,%d" font="Regular;%d" />
1462 <widget name="internet_inactive" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1463 <widget name="internet_active" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1464 <widget name="FBFDsl" position="%d,%d" size="%d,%d" font="Regular;%d" />
1465 <widget name="dsl_inactive" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1466 <widget name="dsl_active" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1467 <widget name="FBFWlan" position="%d,%d" size="%d,%d" font="Regular;%d" />
1468 <widget name="wlan_inactive" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1469 <widget name="wlan_active" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1474 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
1475 <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" />
1476 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
1477 <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" />
1479 width, height, # size
1480 40, 5, # position info
1481 width-2*40, 2*fontSize, # size info
1483 40, 5+2*fontSize+10, # position internet
1484 width-40, 2*fontSize, # size internet
1486 "skin_default/buttons/button_green_off.png",
1487 20, 5+2*fontSize+10+(fontSize-16)/2, # position button internet
1488 "skin_default/buttons/button_green.png",
1489 20, 5+2*fontSize+10+(fontSize-16)/2, # position button internet
1490 40, 5+2*fontSize+10+2*fontSize+10, # position dsl
1491 width-40-20, fontSize, # size dsl
1493 "skin_default/buttons/button_green_off.png",
1494 20, 5+2*fontSize+10+2*fontSize+10+(fontSize-16)/2, # position button dsl
1495 "skin_default/buttons/button_green.png",
1496 20, 5+2*fontSize+10+2*fontSize+10+(fontSize-16)/2, # position button dsl
1497 40, 5+2*fontSize+10+3*fontSize+10, # position wlan
1498 width-40-20, fontSize, # size wlan
1500 "skin_default/buttons/button_green_off.png",
1501 20, 5+2*fontSize+10+3*fontSize+10+(fontSize-16)/2, # position button wlan
1502 "skin_default/buttons/button_green.png",
1503 20, 5+2*fontSize+10+3*fontSize+10+(fontSize-16)/2, # position button wlan
1508 buttonsGap, buttonsVPos, "skin_default/buttons/red.png", buttonsGap, buttonsVPos,
1509 buttonsGap+140+buttonsGap, buttonsVPos, "skin_default/buttons/green.png", buttonsGap+140+buttonsGap, buttonsVPos,
1512 Screen.__init__(self, session)
1513 HelpableScreen.__init__(self)
1514 # TRANSLATORS: keep it short, this is a button
1515 self["key_red"] = Button(_("Reset"))
1516 # TRANSLATORS: keep it short, this is a button
1517 self["key_green"] = Button(_("Toggle WLAN"))
1518 self._mailboxActive = False
1519 if fritzbox.info[FBF_tamActive] is not None:
1520 # TRANSLATORS: keep it short, this is a button
1521 self["key_yellow"] = Button(_("Toggle Mailbox"))
1522 self["menuActions"] = ActionMap(["OkCancelActions", "ColorActions", "NumberActions", "EPGSelectActions"],
1524 "cancel": self._exit,
1527 "green": self._toggleWlan,
1528 "yellow": (lambda: self._toggleMailbox(-1)),
1529 "0": (lambda: self._toggleMailbox(0)),
1530 "1": (lambda: self._toggleMailbox(1)),
1531 "2": (lambda: self._toggleMailbox(2)),
1532 "3": (lambda: self._toggleMailbox(3)),
1533 "4": (lambda: self._toggleMailbox(4)),
1534 "info": self._getInfo,
1536 # TRANSLATORS: keep it short, this is a help text
1537 self.helpList.append((self["menuActions"], "ColorActions", [("yellow", _("Toggle all mailboxes"))]))
1538 # TRANSLATORS: keep it short, this is a help text
1539 self.helpList.append((self["menuActions"], "NumberActions", [("0", _("Toggle 1. mailbox"))]))
1540 # TRANSLATORS: keep it short, this is a help text
1541 self.helpList.append((self["menuActions"], "NumberActions", [("1", _("Toggle 2. mailbox"))]))
1542 # TRANSLATORS: keep it short, this is a help text
1543 self.helpList.append((self["menuActions"], "NumberActions", [("2", _("Toggle 3. mailbox"))]))
1544 # TRANSLATORS: keep it short, this is a help text
1545 self.helpList.append((self["menuActions"], "NumberActions", [("3", _("Toggle 4. mailbox"))]))
1546 # TRANSLATORS: keep it short, this is a help text
1547 self.helpList.append((self["menuActions"], "NumberActions", [("4", _("Toggle 5. mailbox"))]))
1548 self["FBFMailbox"] = Label(_('Mailbox'))
1549 self["mailbox_inactive"] = Pixmap()
1550 self["mailbox_active"] = Pixmap()
1551 self["mailbox_active"].hide()
1553 self["menuActions"] = ActionMap(["OkCancelActions", "ColorActions", "EPGSelectActions"],
1555 "cancel": self._exit,
1557 "green": self._toggleWlan,
1559 "info": self._getInfo,
1562 # TRANSLATORS: keep it short, this is a help text
1563 self.helpList.append((self["menuActions"], "OkCancelActions", [("cancel", _("Quit"))]))
1564 # TRANSLATORS: keep it short, this is a help text
1565 self.helpList.append((self["menuActions"], "OkCancelActions", [("ok", _("Quit"))]))
1566 # TRANSLATORS: keep it short, this is a help text
1567 self.helpList.append((self["menuActions"], "ColorActions", [("green", _("Toggle WLAN"))]))
1568 # TRANSLATORS: keep it short, this is a help text
1569 self.helpList.append((self["menuActions"], "ColorActions", [("red", _("Reset"))]))
1570 # TRANSLATORS: keep it short, this is a help text
1571 self.helpList.append((self["menuActions"], "EPGSelectActions", [("info", _("Refresh status"))]))
1573 self["FBFInfo"] = Label(_('Getting status from FRITZ!Box Fon...'))
1575 self["FBFInternet"] = Label('Internet')
1576 self["internet_inactive"] = Pixmap()
1577 self["internet_active"] = Pixmap()
1578 self["internet_active"].hide()
1580 self["FBFDsl"] = Label('DSL')
1581 self["dsl_inactive"] = Pixmap()
1582 self["dsl_inactive"].hide()
1583 self["dsl_active"] = Pixmap()
1584 self["dsl_active"].hide()
1586 self["FBFWlan"] = Label('WLAN ')
1587 self["wlan_inactive"] = Pixmap()
1588 self["wlan_inactive"].hide()
1589 self["wlan_active"] = Pixmap()
1590 self["wlan_active"].hide()
1591 self._wlanActive = False
1593 if fritzbox.info[FBF_dectActive] is not None:
1594 self["FBFDect"] = Label('DECT')
1595 self["dect_inactive"] = Pixmap()
1596 self["dect_active"] = Pixmap()
1597 self["dect_active"].hide()
1599 if fritzbox.info[FBF_faxActive] is not None:
1600 self["FBFFax"] = Label('Fax')
1601 self["fax_inactive"] = Pixmap()
1602 self["fax_active"] = Pixmap()
1603 self["fax_active"].hide()
1605 if fritzbox.info[FBF_rufumlActive] is not None:
1606 self["FBFRufuml"] = Label(_('Call redirection'))
1607 self["rufuml_inactive"] = Pixmap()
1608 self["rufuml_active"] = Pixmap()
1609 self["rufuml_active"].hide()
1611 self._timer = eTimer()
1612 self._timer.callback.append(self._getInfo)
1613 self.onShown.append(lambda: self._timer.start(5000))
1614 self.onHide.append(self._timer.stop)
1616 self.onLayoutFinish.append(self.setWindowTitle)
1618 def setWindowTitle(self):
1619 # TRANSLATORS: this is a window title.
1620 self.setTitle(_("FRITZ!Box Fon Status"))
1624 fritzbox.getInfo(self._fillMenu)
1626 def _fillMenu(self, status):
1627 (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive) = status
1628 self._wlanActive = (wlanState[0] == '1')
1629 self._mailboxActive = False
1631 if not self.has_key("FBFInfo"): # screen is closed already
1635 self["FBFInfo"].setText(boxInfo.replace(', ', '\n'))
1637 self["FBFInfo"].setText('BoxInfo ' + _('Status not available'))
1641 self["FBFInternet"].setText('Internet ' + _('IP Address:') + ' ' + ipAddress + '\n' + _('Connected since') + ' ' + upTime)
1643 self["FBFInternet"].setText('Internet ' + _('IP Address:') + ' ' + ipAddress)
1644 self["internet_inactive"].hide()
1645 self["internet_active"].show()
1647 self["internet_active"].hide()
1648 self["internet_inactive"].show()
1651 if dslState[0] == '5':
1652 self["dsl_inactive"].hide()
1653 self["dsl_active"].show()
1655 self["FBFDsl"].setText('DSL ' + dslState[1])
1657 self["dsl_active"].hide()
1658 self["dsl_inactive"].show()
1660 self["FBFDsl"].setText('DSL ' + _('Status not available'))
1661 self["dsl_active"].hide()
1662 self["dsl_inactive"].hide()
1665 if wlanState[0 ] == '1':
1666 self["wlan_inactive"].hide()
1667 self["wlan_active"].show()
1669 if wlanState[1] == '0':
1670 message += ' ' + _('not encrypted')
1672 message += ' ' + _('encrypted')
1674 if wlanState[2] == '0':
1675 message = message + ', ' + _('no device active')
1676 elif wlanState[2] == '1':
1677 message = message + ', ' + _('one device active')
1679 message = message + ', ' + wlanState[2] + ' ' + _('devices active')
1680 self["FBFWlan"].setText(message)
1682 self["wlan_active"].hide()
1683 self["wlan_inactive"].show()
1684 self["FBFWlan"].setText('WLAN')
1686 self["FBFWlan"].setText('WLAN ' + _('Status not available'))
1687 self["wlan_active"].hide()
1688 self["wlan_inactive"].hide()
1690 if fritzbox.info[FBF_tamActive]:
1691 if not tamActive or tamActive[0] == 0:
1692 self._mailboxActive = False
1693 self["mailbox_active"].hide()
1694 self["mailbox_inactive"].show()
1695 self["FBFMailbox"].setText(_('No mailbox active'))
1697 self._mailboxActive = True
1701 message = message + str(i) + ','
1702 message = message[:-1] + ')'
1703 self["mailbox_inactive"].hide()
1704 self["mailbox_active"].show()
1705 if tamActive[0] == 1:
1706 self["FBFMailbox"].setText(_('One mailbox active') + ' ' + message)
1708 self["FBFMailbox"].setText(str(tamActive[0]) + ' ' + _('mailboxes active') + ' ' + message)
1710 if fritzbox.info[FBF_dectActive] and dectActive:
1711 self["dect_inactive"].hide()
1712 self["dect_active"].show()
1714 self["FBFDect"].setText(_('No DECT phone registered'))
1717 self["FBFDect"].setText(_('One DECT phone registered'))
1719 self["FBFDect"].setText(str(dectActive) + ' ' + _('DECT phones registered'))
1721 if fritzbox.info[FBF_faxActive] and faxActive:
1722 self["fax_inactive"].hide()
1723 self["fax_active"].show()
1724 self["FBFFax"].setText(_('Software fax active'))
1726 if fritzbox.info[FBF_rufumlActive] is not None and rufumlActive is not None:
1727 if rufumlActive == 0:
1728 self["rufuml_active"].hide()
1729 self["rufuml_inactive"].show()
1730 self["FBFRufuml"].setText(_('No call redirection active'))
1732 self["rufuml_inactive"].hide()
1733 self["rufuml_active"].show()
1734 if rufumlActive == 1:
1735 self["FBFRufuml"].setText(_('One call redirection active'))
1737 self["FBFRufuml"].setText(str(rufumlActive) + ' ' + _('call redirections active'))
1740 debug("[FritzCallFBF] _fillMenu: " + traceback.format_exc())
1742 def _toggleWlan(self):
1743 if self._wlanActive:
1744 debug("[FritzMenu] toggleWlan off")
1745 fritzbox.changeWLAN('0')
1747 debug("[FritzMenu] toggleWlan off")
1748 fritzbox.changeWLAN('1')
1750 def _toggleMailbox(self, which):
1751 debug("[FritzMenu] toggleMailbox")
1752 if fritzbox.info[FBF_tamActive]:
1753 debug("[FritzMenu] toggleMailbox off")
1754 fritzbox.changeMailbox(which)
1765 class FritzDisplayCalls(Screen, HelpableScreen):
1767 def __init__(self, session, text=""): #@UnusedVariable # pylint: disable=W0613
1768 self.width = DESKTOP_WIDTH * scaleH(75, 85)/100
1769 self.height = DESKTOP_HEIGHT * 0.75
1770 dateFieldWidth = scaleH(180, 105)
1772 lengthFieldWidth = scaleH(55, 45)
1773 scrollbarWidth = scaleH(35, 35)
1774 entriesWidth = self.width -scaleH(40, 5) -5
1775 hereFieldWidth = entriesWidth -dirFieldWidth -5 -dateFieldWidth -5 -lengthFieldWidth -scrollbarWidth
1776 fieldWidth = entriesWidth -dirFieldWidth -5 -5 -scrollbarWidth
1777 fontSize = scaleV(22, 20)
1778 itemHeight = 2*fontSize+5
1779 entriesHeight = self.height -scaleV(15, 10) -5 -fontSize -5 -5 -5 -40 -5
1780 buttonGap = (self.width -4*140)/5
1781 buttonV = self.height -40
1782 debug("[FritzDisplayCalls] width: " + str(self.width))
1784 <screen name="FritzDisplayCalls" position="center,center" size="%d,%d" title="Phone calls" >
1785 <eLabel position="0,0" size="%d,2" backgroundColor="#aaaaaa" />
1786 <widget name="statusbar" position="%d,%d" size="%d,%d" font="Regular;%d" backgroundColor="#aaaaaa" transparent="1" />
1787 <eLabel position="0,%d" size="%d,2" backgroundColor="#aaaaaa" />
1788 <widget source="entries" render="Listbox" position="%d,%d" size="%d,%d" scrollbarMode="showOnDemand" transparent="1">
1789 <convert type="TemplatedMultiContent">
1791 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
1792 MultiContentEntryPixmapAlphaTest(pos = (%d,%d), size = (%d,%d), png = 2), # index 1 i direction pixmap
1793 MultiContentEntryText(pos = (%d,%d), size = (%d,%d), font=1, flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER, text = 3), # index 2 is remote name/number
1794 MultiContentEntryText(pos = (%d,%d), size = (%d,%d), font=0, flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER, text = 4), # index 3 is length of call
1795 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
1797 "fonts": [gFont("Regular", %d), gFont("Regular", %d)],
1802 <eLabel position="0,%d" size="%d,2" backgroundColor="#aaaaaa" />
1803 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
1804 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
1805 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
1806 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
1807 <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" />
1808 <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" />
1809 <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" />
1810 <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" />
1812 # scaleH(90, 75), scaleV(100, 78), # position
1813 self.width, self.height, # size
1814 self.width, # eLabel width
1815 scaleH(40, 5), scaleV(10, 5), # statusbar position
1816 self.width, fontSize+5, # statusbar size
1817 scaleV(21, 21), # statusbar font size
1818 scaleV(10, 5)+5+fontSize+5, # eLabel position vertical
1819 self.width, # eLabel width
1820 scaleH(40, 5), scaleV(10, 5)+5+fontSize+5+5, # entries position
1821 entriesWidth, entriesHeight, # entries size
1822 5+dirFieldWidth+5, fontSize+5, dateFieldWidth, fontSize, # date pos/size
1823 5, (itemHeight-dirFieldWidth)/2, dirFieldWidth, dirFieldWidth, # dir pos/size
1824 5+dirFieldWidth+5, 5, fieldWidth, fontSize, # caller pos/size
1825 2+dirFieldWidth+2+dateFieldWidth+5, fontSize+5, lengthFieldWidth, fontSize, # length pos/size
1826 2+dirFieldWidth+2+dateFieldWidth+5+lengthFieldWidth+5, fontSize+5, hereFieldWidth, fontSize, # my number pos/size
1827 fontSize-4, fontSize, # fontsize
1828 itemHeight, # itemHeight
1829 buttonV-5, # eLabel position vertical
1830 self.width, # eLabel width
1831 buttonGap, buttonV, "skin_default/buttons/red.png", # widget red
1832 2*buttonGap+140, buttonV, "skin_default/buttons/green.png", # widget green
1833 3*buttonGap+2*140, buttonV, "skin_default/buttons/yellow.png", # widget yellow
1834 4*buttonGap+3*140, buttonV, "skin_default/buttons/blue.png", # widget blue
1835 buttonGap, buttonV, scaleV(22, 21), # widget red
1836 2*buttonGap+140, buttonV, scaleV(22, 21), # widget green
1837 3*buttonGap+2*140, buttonV, scaleV(22, 21), # widget yellow
1838 4*buttonGap+3*140, buttonV, scaleV(22, 21), # widget blue
1840 # debug("[FritzDisplayCalls] skin: " + self.skin)
1841 Screen.__init__(self, session)
1842 HelpableScreen.__init__(self)
1844 # TRANSLATORS: keep it short, this is a button
1845 self["key_yellow"] = Button(_("All"))
1846 # TRANSLATORS: keep it short, this is a button
1847 self["key_red"] = Button(_("Missed"))
1848 # TRANSLATORS: keep it short, this is a button
1849 self["key_blue"] = Button(_("Incoming"))
1850 # TRANSLATORS: keep it short, this is a button
1851 self["key_green"] = Button(_("Outgoing"))
1853 self["setupActions"] = ActionMap(["OkCancelActions", "ColorActions"],
1855 "yellow": (lambda: self.display(FBF_ALL_CALLS)),
1856 "red": (lambda: self.display(FBF_MISSED_CALLS)),
1857 "blue": (lambda: self.display(FBF_IN_CALLS)),
1858 "green": (lambda: self.display(FBF_OUT_CALLS)),
1860 "ok": self.showEntry, }, - 2)
1862 # TRANSLATORS: keep it short, this is a help text
1863 self.helpList.append((self["setupActions"], "OkCancelActions", [("ok", _("Show details of entry"))]))
1864 # TRANSLATORS: keep it short, this is a help text
1865 self.helpList.append((self["setupActions"], "OkCancelActions", [("cancel", _("Quit"))]))
1866 # TRANSLATORS: keep it short, this is a help text
1867 self.helpList.append((self["setupActions"], "ColorActions", [("yellow", _("Display all calls"))]))
1868 # TRANSLATORS: keep it short, this is a help text
1869 self.helpList.append((self["setupActions"], "ColorActions", [("red", _("Display missed calls"))]))
1870 # TRANSLATORS: keep it short, this is a help text
1871 self.helpList.append((self["setupActions"], "ColorActions", [("blue", _("Display incoming calls"))]))
1872 # TRANSLATORS: keep it short, this is a help text
1873 self.helpList.append((self["setupActions"], "ColorActions", [("green", _("Display outgoing calls"))]))
1875 self["statusbar"] = Label(_("Getting calls from FRITZ!Box..."))
1877 self["entries"] = List(self.list)
1878 #=======================================================================
1879 # fontSize = scaleV(22, 18)
1880 # fontHeight = scaleV(24, 20)
1881 # self["entries"].l.setFont(0, gFont("Regular", fontSize))
1882 # self["entries"].l.setItemHeight(fontHeight)
1883 #=======================================================================
1884 debug("[FritzDisplayCalls] init: '''%s'''" % config.plugins.FritzCall.fbfCalls.value)
1886 self.onLayoutFinish.append(self.setWindowTitle)
1888 def setWindowTitle(self):
1889 # TRANSLATORS: this is a window title.
1890 self.setTitle(_("Phone calls"))
1895 def display(self, which=config.plugins.FritzCall.fbfCalls.value):
1896 debug("[FritzDisplayCalls] display")
1897 config.plugins.FritzCall.fbfCalls.value = which
1898 config.plugins.FritzCall.fbfCalls.save()
1899 fritzbox.getCalls(self, lambda x: self.gotCalls(x, which), which)
1901 def gotCalls(self, listOfCalls, which):
1902 debug("[FritzDisplayCalls] gotCalls")
1903 self.updateStatus(fbfCallsChoices[which] + " (" + str(len(listOfCalls)) + ")")
1905 directout = LoadPixmap(resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/images/callout.png"))
1906 directin = LoadPixmap(resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/images/callin.png"))
1907 directfailed = LoadPixmap(resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/images/callinfailed.png"))
1909 if direct == FBF_OUT_CALLS:
1911 elif direct == FBF_IN_CALLS:
1914 direct = directfailed
1917 # debug("[FritzDisplayCalls] gotCalls: %s" %repr(listOfCalls))
1918 self.list = [(number, date[:6] + ' ' + date[9:14], pixDir(direct), remote, length, here) for (number, date, direct, remote, length, here) in listOfCalls]
1919 self["entries"].setList(self.list)
1920 if len(self.list) > 1:
1921 self["entries"].setIndex(1)
1923 def updateStatus(self, text):
1924 if self.has_key("statusbar"):
1925 self["statusbar"].setText(_("Getting calls from FRITZ!Box...") + ' ' + text)
1927 def showEntry(self):
1928 debug("[FritzDisplayCalls] showEntry")
1929 cur = self["entries"].getCurrent()
1932 debug("[FritzDisplayCalls] showEntry %s" % (cur[0]))
1934 fullname = phonebook.search(cur[0])
1936 # we have a name for this number
1938 self.session.open(FritzOfferAction, self, number, name)
1941 self.session.open(FritzOfferAction, self, number, name)
1944 fullname = resolveNumberWithAvon(number, config.plugins.FritzCall.country.value)
1947 self.session.open(FritzOfferAction, self, number, name)
1949 self.session.open(FritzOfferAction, self, number)
1951 # we do not even have a number...
1952 self.session.open(MessageBox,
1954 type=MessageBox.TYPE_INFO)
1957 class FritzOfferAction(Screen):
1959 def __init__(self, session, parent, number, name=""):
1960 # the layout will completely be recalculated in finishLayout
1962 <screen name="FritzOfferAction" title="Do what?" >
1963 <widget name="text" size="%d,%d" font="Regular;%d" />
1964 <widget name="FacePixmap" size="%d,%d" alphatest="on" />
1965 <widget name="key_red_p" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
1966 <widget name="key_green_p" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
1967 <widget name="key_yellow_p" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
1968 <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" />
1969 <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" />
1970 <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" />
1972 DESKTOP_WIDTH, DESKTOP_HEIGHT, # set maximum size
1973 scaleH(22,21), # text
1974 DESKTOP_WIDTH, DESKTOP_HEIGHT, # set maximum size
1975 "skin_default/buttons/red.png",
1976 "skin_default/buttons/green.png",
1977 "skin_default/buttons/yellow.png",
1979 debug("[FritzOfferAction] init: %s, %s" %(number, name))
1980 Screen.__init__(self, session)
1982 # TRANSLATORS: keep it short, this is a button
1983 self["key_red"] = Button(_("Lookup"))
1984 # TRANSLATORS: keep it short, this is a button
1985 self["key_green"] = Button(_("Call"))
1986 # TRANSLATORS: keep it short, this is a button
1987 self["key_yellow"] = Button(_("Save"))
1988 # TRANSLATORS: keep it short, this is a button
1989 # self["key_blue"] = Button(_("Search"))
1991 self["FritzOfferActions"] = ActionMap(["OkCancelActions", "ColorActions"],
1993 "red": self._lookup,
1994 "green": self._call,
1995 "yellow": self._add,
1996 "cancel": self._exit,
1997 "ok": self._exit, }, - 2)
1999 self._session = session
2000 if config.plugins.FritzCall.internal.value and len(number) > 3 and number[0] == "0":
2002 self._number = number
2003 self._name = name.replace("\n", ", ")
2004 self["text"] = Label(number + "\n\n" + name.replace(", ", "\n"))
2005 self._parent = parent
2006 self._lookupState = 0
2007 self["key_red_p"] = Pixmap()
2008 self["key_green_p"] = Pixmap()
2009 self["key_yellow_p"] = Pixmap()
2010 self["FacePixmap"] = Pixmap()
2011 self.onLayoutFinish.append(self._finishLayout)
2012 self.onLayoutFinish.append(self.setWindowTitle)
2014 def setWindowTitle(self):
2015 # TRANSLATORS: this is a window title.
2016 self.setTitle(_("Do what?"))
2018 def _finishLayout(self):
2019 # pylint: disable=W0142
2020 debug("[FritzCall] FritzOfferAction/finishLayout number: %s/%s" % (self._number, self._name))
2022 faceFile = findFace(self._number, self._name)
2023 picPixmap = LoadPixmap(faceFile)
2024 if not picPixmap: # that means most probably, that the picture is not 8 bit...
2025 Notifications.AddNotification(MessageBox, _("Found picture\n\n%s\n\nBut did not load. Probably not PNG, 8-bit") %faceFile, type = MessageBox.TYPE_ERROR)
2026 picPixmap = LoadPixmap(resolveFilename(SCOPE_SKIN_IMAGE, "skin_default/icons/input_error.png"))
2027 picSize = picPixmap.size()
2028 self["FacePixmap"].instance.setPixmap(picPixmap)
2031 # recalculate window size
2032 textSize = self["text"].getSize()
2033 textSize = (textSize[0]+20, textSize[1]+20) # don't know, why, but size is too small
2034 debug("[FritzCall] FritzOfferAction/finishLayout textsize: %s/%s" % textSize)
2035 textSize = eSize(*textSize)
2036 width = max(scaleH(620, 545), noButtons*145, picSize.width() + textSize.width() + 30)
2037 height = max(picSize.height()+5, textSize.height()+5, scaleV(-1, 136)) + 5 + 40 + 5
2038 buttonsGap = (width-noButtons*140)/(noButtons+1)
2039 buttonsVPos = height-40-5
2040 wSize = (width, height)
2041 wSize = eSize(*wSize)
2043 # center the smaller vertically
2044 hGap = (width-picSize.width()-textSize.width())/3
2045 picPos = (hGap, (height-50-picSize.height())/2+5)
2046 textPos = (hGap+picSize.width()+hGap, (height-50-textSize.height())/2+5)
2049 self.instance.resize(wSize)
2051 self["text"].instance.resize(textSize)
2053 self["FacePixmap"].instance.resize(picSize)
2055 buttonPos = (buttonsGap, buttonsVPos)
2056 self["key_red_p"].instance.move(ePoint(*buttonPos))
2057 self["key_red"].instance.move(ePoint(*buttonPos))
2058 buttonPos = (buttonsGap+140+buttonsGap, buttonsVPos)
2059 self["key_green_p"].instance.move(ePoint(*buttonPos))
2060 self["key_green"].instance.move(ePoint(*buttonPos))
2061 buttonPos = (buttonsGap+140+buttonsGap+140+buttonsGap, buttonsVPos)
2062 self["key_yellow_p"].instance.move(ePoint(*buttonPos))
2063 self["key_yellow"].instance.move(ePoint(*buttonPos))
2065 self["text"].instance.move(ePoint(*textPos))
2067 self["FacePixmap"].instance.move(ePoint(*picPos))
2069 self.instance.move(ePoint((DESKTOP_WIDTH-wSize.width())/2, (DESKTOP_HEIGHT-wSize.height())/2))
2071 def _setTextAndResize(self, message):
2072 # pylint: disable=W0142
2073 self["text"].instance.resize(eSize(*(DESKTOP_WIDTH, DESKTOP_HEIGHT)))
2074 self["text"].setText(self._number + "\n\n" + message)
2075 self._finishLayout()
2078 phonebookLocation = config.plugins.FritzCall.phonebookLocation.value
2079 if self._lookupState == 0:
2080 self._lookupState = 1
2081 self._setTextAndResize(_("Reverse searching..."))
2082 ReverseLookupAndNotifier(self._number, self._lookedUp, "UTF-8", config.plugins.FritzCall.country.value)
2084 if self._lookupState == 1 and os.path.exists(os.path.join(phonebookLocation, "PhoneBook.csv")):
2085 self._setTextAndResize(_("Searching in Outlook export..."))
2086 self._lookupState = 2
2087 self._lookedUp(self._number, FritzOutlookCSV.findNumber(self._number, os.path.join(phonebookLocation, "PhoneBook.csv"))) #@UndefinedVariable
2090 self._lookupState = 2
2091 if self._lookupState == 2 and os.path.exists(os.path.join(phonebookLocation, "PhoneBook.ldif")):
2092 self._setTextAndResize(_("Searching in LDIF..."))
2093 self._lookupState = 0
2094 FritzLDIF.FindNumber(self._number, open(os.path.join(phonebookLocation, "PhoneBook.ldif")), self._lookedUp)
2097 self._lookupState = 0
2100 def _lookedUp(self, number, name):
2101 name = handleReverseLookupResult(name)
2103 if self._lookupState == 1:
2104 name = _("No result from reverse lookup")
2105 elif self._lookupState == 2:
2106 name = _("No result from Outlook export")
2108 name = _("No result from LDIF")
2110 self._number = number
2111 debug("[FritzOfferAction] lookedUp: " + str(name.replace(", ", "\n")))
2112 self._setTextAndResize(str(name.replace(", ", "\n")))
2115 debug("[FritzOfferAction] add: %s" %self._number)
2116 fritzbox.dial(self._number)
2120 debug("[FritzOfferAction] add: %s, %s" %(self._number, self._name))
2121 phonebook.FritzDisplayPhonebook(self._session).add(self._parent, self._number, self._name)
2128 class FritzCallPhonebook:
2130 debug("[FritzCallPhonebook] init")
2131 # Beware: strings in phonebook.phonebook have to be in utf-8!
2136 debug("[FritzCallPhonebook] reload")
2137 # Beware: strings in phonebook.phonebook have to be in utf-8!
2140 if not config.plugins.FritzCall.enable.value:
2143 phonebookFilename = os.path.join(config.plugins.FritzCall.phonebookLocation.value, "PhoneBook.txt")
2144 if config.plugins.FritzCall.phonebook.value and os.path.exists(phonebookFilename):
2145 debug("[FritzCallPhonebook] reload: read " + phonebookFilename)
2146 phonebookTxtCorrupt = False
2148 for line in open(phonebookFilename):
2150 # Beware: strings in phonebook.phonebook have to be in utf-8!
2151 line = line.decode("utf-8")
2152 except UnicodeDecodeError: # this is just for the case, somebody wrote latin1 chars into PhoneBook.txt
2154 line = line.decode("iso-8859-1")
2155 debug("[FritzCallPhonebook] Fallback to ISO-8859-1 in %s" % line)
2156 phonebookTxtCorrupt = True
2157 except UnicodeDecodeError:
2158 debug("[FritzCallPhonebook] Could not parse internal Phonebook Entry %s" % line)
2159 phonebookTxtCorrupt = True
2160 line = line.encode("utf-8")
2161 elems = line.split('#')
2164 self.phonebook[elems[0]] = elems[1]
2165 except ValueError: # how could this possibly happen?!?!
2166 debug("[FritzCallPhonebook] Could not parse internal Phonebook Entry %s" % line)
2167 phonebookTxtCorrupt = True
2169 debug("[FritzCallPhonebook] Could not parse internal Phonebook Entry %s" % line)
2170 phonebookTxtCorrupt = True
2172 #===============================================================
2173 # found = re.match("^(\d+)#(.*)$", line)
2176 # self.phonebook[found.group(1)] = found.group(2)
2177 # except ValueError: # how could this possibly happen?!?!
2178 # debug("[FritzCallPhonebook] Could not parse internal Phonebook Entry %s" % line)
2179 # phonebookTxtCorrupt = True
2181 # debug("[FritzCallPhonebook] Could not parse internal Phonebook Entry %s" % line)
2182 # phonebookTxtCorrupt = True
2183 #===============================================================
2185 if phonebookTxtCorrupt:
2186 # dump phonebook to PhoneBook.txt
2187 debug("[FritzCallPhonebook] dump Phonebook.txt")
2189 os.rename(phonebookFilename, phonebookFilename + ".bck")
2190 fNew = open(phonebookFilename, 'w')
2191 # Beware: strings in phonebook.phonebook are utf-8!
2192 for (number, name) in self.phonebook.iteritems():
2193 # Beware: strings in PhoneBook.txt have to be in utf-8!
2194 fNew.write(number + "#" + name.encode("utf-8"))
2196 except (IOError, OSError):
2197 debug("[FritzCallPhonebook] error renaming or writing to %s" %phonebookFilename)
2199 #===============================================================================
2201 # # read entries from Outlook export
2203 # # not reliable with coding yet
2205 # # import csv exported from Outlook 2007 with csv(Windows)
2206 # csvFilename = "/tmp/PhoneBook.csv"
2207 # if config.plugins.FritzCall.phonebook.value and os.path.exists(csvFilename):
2209 # readOutlookCSV(csvFilename, self.add)
2210 # os.rename(csvFilename, csvFilename + ".done")
2211 # except ImportError:
2212 # debug("[FritzCallPhonebook] CSV import failed" %line)
2213 #===============================================================================
2216 #===============================================================================
2218 # # read entries from LDIF
2220 # # import ldif exported from Thunderbird 2.0.0.19
2221 # ldifFilename = "/tmp/PhoneBook.ldif"
2222 # if config.plugins.FritzCall.phonebook.value and os.path.exists(ldifFilename):
2224 # parser = MyLDIF(open(ldifFilename), self.add)
2226 # os.rename(ldifFilename, ldifFilename + ".done")
2227 # except ImportError:
2228 # debug("[FritzCallPhonebook] LDIF import failed" %line)
2229 #===============================================================================
2231 if fritzbox and config.plugins.FritzCall.fritzphonebook.value:
2232 fritzbox.loadFritzBoxPhonebook()
2234 def search(self, number):
2235 # debug("[FritzCallPhonebook] Searching for %s" %number)
2237 if not self.phonebook or not number:
2240 if config.plugins.FritzCall.prefix.value:
2241 prefix = config.plugins.FritzCall.prefix.value
2242 if number[0] != '0':
2243 number = prefix + number
2244 # debug("[FritzCallPhonebook] search: added prefix: %s" %number)
2245 elif number[:len(prefix)] == prefix and self.phonebook.has_key(number[len(prefix):]):
2246 # debug("[FritzCallPhonebook] search: same prefix")
2247 name = self.phonebook[number[len(prefix):]]
2248 # debug("[FritzCallPhonebook] search: result: %s" %name)
2252 if not name and self.phonebook.has_key(number):
2253 name = self.phonebook[number]
2255 return name.replace(", ", "\n").strip()
2257 def add(self, number, name):
2260 @param number: number of entry
2261 @param name: name of entry, has to be in utf-8
2263 debug("[FritzCallPhonebook] add")
2264 name = name.replace("\n", ", ").replace('#','') # this is just for safety reasons. add should only be called with newlines converted into commas
2266 self.phonebook[number] = name
2267 if number and number != 0:
2268 if config.plugins.FritzCall.phonebook.value:
2270 name = name.strip() + "\n"
2271 string = "%s#%s" % (number, name)
2272 # Beware: strings in PhoneBook.txt have to be in utf-8!
2273 f = open(os.path.join(config.plugins.FritzCall.phonebookLocation.value, "PhoneBook.txt"), 'a')
2276 debug("[FritzCallPhonebook] added %s with %s to Phonebook.txt" % (number, name.strip()))
2282 def remove(self, number):
2283 if number in self.phonebook:
2284 debug("[FritzCallPhonebook] remove entry in phonebook")
2285 del self.phonebook[number]
2286 if config.plugins.FritzCall.phonebook.value:
2288 phonebookFilename = os.path.join(config.plugins.FritzCall.phonebookLocation.value, "PhoneBook.txt")
2289 debug("[FritzCallPhonebook] remove entry in Phonebook.txt")
2290 fOld = open(phonebookFilename, 'r')
2291 fNew = open(phonebookFilename + str(os.getpid()), 'w')
2292 line = fOld.readline()
2294 elems = line.split('#')
2295 if len(elems) == 2 and not elems[0] == number:
2297 line = fOld.readline()
2300 # os.remove(phonebookFilename)
2301 eBackgroundFileEraser.getInstance().erase(phonebookFilename)
2302 os.rename(phonebookFilename + str(os.getpid()), phonebookFilename)
2303 debug("[FritzCallPhonebook] removed %s from Phonebook.txt" % number)
2306 except (IOError, OSError):
2307 debug("[FritzCallPhonebook] error removing %s from %s" %(number, phonebookFilename))
2310 class FritzDisplayPhonebook(Screen, HelpableScreen, NumericalTextInput):
2312 def __init__(self, session):
2313 self.entriesWidth = DESKTOP_WIDTH * scaleH(75, 85)/100
2314 self.height = DESKTOP_HEIGHT * 0.75
2315 numberFieldWidth = scaleH(220, 160)
2316 fieldWidth = self.entriesWidth -5 -numberFieldWidth -10
2317 fontSize = scaleV(22, 18)
2318 fontHeight = scaleV(24, 20)
2319 buttonGap = (self.entriesWidth-4*140)/5
2320 debug("[FritzDisplayPhonebook] width: " + str(self.entriesWidth))
2322 <screen name="FritzDisplayPhonebook" position="center,center" size="%d,%d" title="Phonebook" >
2323 <eLabel position="0,0" size="%d,2" backgroundColor="#aaaaaa" />
2324 <widget source="entries" render="Listbox" position="%d,%d" size="%d,%d" scrollbarMode="showOnDemand" transparent="1">
2325 <convert type="TemplatedMultiContent">
2327 MultiContentEntryText(pos = (%d,%d), size = (%d,%d), font=0, flags = RT_HALIGN_LEFT, text = 1), # index 0 is the name, index 1 is shortname
2328 MultiContentEntryText(pos = (%d,%d), size = (%d,%d), font=0, flags = RT_HALIGN_LEFT, text = 2), # index 2 is number
2330 "fonts": [gFont("Regular", %d)],
2335 <eLabel position="0,%d" size="%d,2" backgroundColor="#aaaaaa" />
2336 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
2337 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
2338 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
2339 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
2340 <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" />
2341 <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" />
2342 <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" />
2343 <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" />
2345 # scaleH(90, 75), scaleV(100, 73), # position
2346 self.entriesWidth, self.height, # size
2347 self.entriesWidth, # eLabel width
2348 scaleH(40, 5), scaleV(20, 5), # entries position
2349 self.entriesWidth-scaleH(40, 5), self.height-scaleV(20, 5)-5-5-40, # entries size
2350 0, 0, fieldWidth, scaleH(24,20), # name pos/size
2351 fieldWidth +5, 0, numberFieldWidth, scaleH(24,20), # dir pos/size
2352 fontSize, # fontsize
2353 fontHeight, # itemHeight
2354 self.height-40-5, # eLabel position vertical
2355 self.entriesWidth, # eLabel width
2356 buttonGap, self.height-40, "skin_default/buttons/red.png", # ePixmap red
2357 2*buttonGap+140, self.height-40, "skin_default/buttons/green.png", # ePixmap green
2358 3*buttonGap+2*140, self.height-40, "skin_default/buttons/yellow.png", # ePixmap yellow
2359 4*buttonGap+3*140, self.height-40, "skin_default/buttons/blue.png", # ePixmap blue
2360 buttonGap, self.height-40, scaleV(22, 21), # widget red
2361 2*buttonGap+140, self.height-40, scaleV(22, 21), # widget green
2362 3*buttonGap+2*140, self.height-40, scaleV(22, 21), # widget yellow
2363 4*buttonGap+3*140, self.height-40, scaleV(22, 21), # widget blue
2366 # debug("[FritzDisplayCalls] skin: " + self.skin)
2367 Screen.__init__(self, session)
2368 NumericalTextInput.__init__(self)
2369 HelpableScreen.__init__(self)
2371 # TRANSLATORS: keep it short, this is a button
2372 self["key_red"] = Button(_("Delete"))
2373 # TRANSLATORS: keep it short, this is a button
2374 self["key_green"] = Button(_("New"))
2375 # TRANSLATORS: keep it short, this is a button
2376 self["key_yellow"] = Button(_("Edit"))
2377 # TRANSLATORS: keep it short, this is a button
2378 self["key_blue"] = Button(_("Search"))
2380 self["setupActions"] = ActionMap(["OkCancelActions", "ColorActions"],
2384 "yellow": self.edit,
2385 "blue": self.search,
2386 "cancel": self.exit,
2387 "ok": self.showEntry, }, - 2)
2389 # TRANSLATORS: keep it short, this is a help text
2390 self.helpList.append((self["setupActions"], "OkCancelActions", [("ok", _("Show details of entry"))]))
2391 # TRANSLATORS: keep it short, this is a help text
2392 self.helpList.append((self["setupActions"], "OkCancelActions", [("cancel", _("Quit"))]))
2393 # TRANSLATORS: keep it short, this is a help text
2394 self.helpList.append((self["setupActions"], "ColorActions", [("red", _("Delete entry"))]))
2395 # TRANSLATORS: keep it short, this is a help text
2396 self.helpList.append((self["setupActions"], "ColorActions", [("green", _("Add entry to phonebook"))]))
2397 # TRANSLATORS: keep it short, this is a help text
2398 self.helpList.append((self["setupActions"], "ColorActions", [("yellow", _("Edit selected entry"))]))
2399 # TRANSLATORS: keep it short, this is a help text
2400 self.helpList.append((self["setupActions"], "ColorActions", [("blue", _("Search (case insensitive)"))]))
2402 self["entries"] = List([])
2403 debug("[FritzCallPhonebook] displayPhonebook init")
2404 self.help_window = None
2406 self.onLayoutFinish.append(self.setWindowTitle)
2409 def setWindowTitle(self):
2410 # TRANSLATORS: this is a window title.
2411 self.setTitle(_("Phonebook"))
2413 def display(self, filterNumber=""):
2414 debug("[FritzCallPhonebook] displayPhonebook/display")
2416 # Beware: strings in phonebook.phonebook are utf-8!
2417 sortlistHelp = sorted((name.lower(), name, number) for (number, name) in phonebook.phonebook.iteritems())
2418 for (low, name, number) in sortlistHelp:
2419 if number == "01234567890":
2422 low = low.decode("utf-8")
2423 except UnicodeDecodeError: # this should definitely not happen
2425 low = low.decode("iso-8859-1")
2426 except UnicodeDecodeError:
2427 debug("[FritzCallPhonebook] displayPhonebook/display: corrupt phonebook entry for %s" % number)
2428 # self.session.open(MessageBox, _("Corrupt phonebook entry\nfor number %s\nDeleting.") %number, type = MessageBox.TYPE_ERROR)
2429 phonebook.remove(number)
2433 filterNumber = filterNumber.lower()
2434 if low.find(filterNumber) == - 1:
2436 name = name.strip().decode("utf-8")
2437 number = number.strip().decode("utf-8")
2438 comma = name.find(',')
2440 shortname = name[:comma]
2443 number = number.encode("utf-8", "replace")