1 # -*- coding: utf-8 -*-
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-msg=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-msg=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.hostname = ConfigText(default="fritz.box", fixed_size=False)
86 config.plugins.FritzCall.afterStandby = ConfigSelection(choices=[("none", _("show nothing")), ("inList", _("show as list")), ("each", _("show each call"))])
87 config.plugins.FritzCall.filter = ConfigEnableDisable(default=False)
88 config.plugins.FritzCall.filtermsn = ConfigText(default="", fixed_size=False)
89 config.plugins.FritzCall.filtermsn.setUseableChars('0123456789,')
90 config.plugins.FritzCall.filterCallList = ConfigEnableDisable(default=True)
91 config.plugins.FritzCall.showOutgoing = ConfigEnableDisable(default=False)
92 config.plugins.FritzCall.timeout = ConfigInteger(default=15, limits=(0, 60))
93 config.plugins.FritzCall.lookup = ConfigEnableDisable(default=False)
94 config.plugins.FritzCall.internal = ConfigEnableDisable(default=False)
95 config.plugins.FritzCall.fritzphonebook = ConfigEnableDisable(default=False)
96 config.plugins.FritzCall.phonebook = ConfigEnableDisable(default=False)
97 config.plugins.FritzCall.addcallers = ConfigEnableDisable(default=False)
98 config.plugins.FritzCall.enable = ConfigEnableDisable(default=False)
99 config.plugins.FritzCall.password = ConfigPassword(default="", fixed_size=False)
100 config.plugins.FritzCall.extension = ConfigText(default='1', fixed_size=False)
101 config.plugins.FritzCall.extension.setUseableChars('0123456789')
102 config.plugins.FritzCall.showType = ConfigEnableDisable(default=True)
103 config.plugins.FritzCall.showShortcut = ConfigEnableDisable(default=False)
104 config.plugins.FritzCall.showVanity = ConfigEnableDisable(default=False)
105 config.plugins.FritzCall.prefix = ConfigText(default="", fixed_size=False)
106 config.plugins.FritzCall.prefix.setUseableChars('0123456789')
107 config.plugins.FritzCall.connectionVerbose = ConfigEnableDisable(default=True)
110 def getMountedDevs():
111 def handleMountpoint(loc):
112 # debug("[FritzCall] handleMountpoint: %s" %repr(loc))
116 #=======================================================================
117 # if os.path.exists(os.path.join(mp, "PhoneBook.txt")):
118 # if os.access(os.path.join(mp, "PhoneBook.txt"), os.W_OK):
124 # desc = loc[1] + desc
125 #=======================================================================
127 return (mp, desc + " (" + mp + ")")
129 mountedDevs = [(resolveFilename(SCOPE_CONFIG), _("Flash")),
130 (resolveFilename(SCOPE_MEDIA, "cf"), _("Compact Flash")),
131 (resolveFilename(SCOPE_MEDIA, "usb"), _("USB Device"))]
132 mountedDevs += map(lambda p: (p.mountpoint, (_(p.description) if p.description else "")), harddiskmanager.getMountedPartitions(True))
133 mediaDir = resolveFilename(SCOPE_MEDIA)
134 for p in os.listdir(mediaDir):
135 if os.path.join(mediaDir, p) not in [path[0] for path in mountedDevs]:
136 mountedDevs.append((os.path.join(mediaDir, p), _("Media directory")))
137 debug("[FritzCall] getMountedDevs1: %s" %repr(mountedDevs))
138 mountedDevs = filter(lambda path: os.path.isdir(path[0]) and os.access(path[0], os.W_OK|os.X_OK), mountedDevs)
139 # put this after the write/executable check, that is far too slow...
140 netDir = resolveFilename(SCOPE_MEDIA, "net")
141 if os.path.isdir(netDir):
142 mountedDevs += map(lambda p: (os.path.join(netDir, p), _("Network mount")), os.listdir(netDir))
143 mountedDevs = map(handleMountpoint, mountedDevs)
145 config.plugins.FritzCall.phonebookLocation = ConfigSelection(choices=getMountedDevs())
148 ("0049", _("Germany")),
149 ("0031", _("The Netherlands")),
150 ("0033", _("France")),
151 ("0039", _("Italy")),
152 ("0041", _("Switzerland")),
153 ("0043", _("Austria"))
155 config.plugins.FritzCall.country = ConfigSelection(choices=countryCodes)
159 FBF_MISSED_CALLS = "2"
161 fbfCallsChoices = {FBF_ALL_CALLS: _("All calls"),
162 FBF_IN_CALLS: _("Incoming calls"),
163 FBF_MISSED_CALLS: _("Missed calls"),
164 FBF_OUT_CALLS: _("Outgoing calls")
166 config.plugins.FritzCall.fbfCalls = ConfigSelection(choices=fbfCallsChoices)
168 config.plugins.FritzCall.name = ConfigText(default="", fixed_size=False)
169 config.plugins.FritzCall.number = ConfigText(default="", fixed_size=False)
170 config.plugins.FritzCall.number.setUseableChars('0123456789')
178 avonFileName = resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/avon.dat")
179 if os.path.exists(avonFileName):
180 for line in open(avonFileName):
181 line = line.decode("iso-8859-1").encode('utf-8')
184 parts = line.split(':')
186 avon[parts[0].replace('-','').replace('*','').replace('/','')] = parts[1]
188 def resolveNumberWithAvon(number, countrycode):
189 if not number or number[0] != '0':
192 countrycode = countrycode.replace('00','+')
193 if number[:2] == '00':
194 normNumber = '+' + number[2:]
195 elif number[:1] == '0':
196 normNumber = countrycode + number[1:]
197 else: # this should can not happen, but safety first
200 # debug('normNumer: ' + normNumber)
201 for i in reversed(range(min(10, len(number)))):
202 if avon.has_key(normNumber[:i]):
203 return '[' + avon[normNumber[:i]].strip() + ']'
206 def handleReverseLookupResult(name):
207 found = re.match("NA: ([^;]*);VN: ([^;]*);STR: ([^;]*);HNR: ([^;]*);PLZ: ([^;]*);ORT: ([^;]*)", name)
209 ( name, firstname, street, streetno, zipcode, city ) = (found.group(1),
217 name += ' ' + firstname
218 if street or streetno or zipcode or city:
223 name += ' ' + streetno
224 if (street or streetno) and (zipcode or city):
227 name += zipcode + ' ' + city
234 from xml.dom.minidom import parse
237 callbycallFileName = resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/callbycall_world.xml")
238 if os.path.exists(callbycallFileName):
239 dom = parse(callbycallFileName)
240 for top in dom.getElementsByTagName("callbycalls"):
241 for cbc in top.getElementsByTagName("country"):
242 code = cbc.getAttribute("code").replace("+","00")
243 cbcInfos[code] = cbc.getElementsByTagName("callbycall")
245 debug("[FritzCall] initCbC: callbycallFileName does not exist?!?!")
247 def stripCbCPrefix(number, countrycode):
248 if number and number[:2] != "00" and cbcInfos.has_key(countrycode):
249 for cbc in cbcInfos[countrycode]:
250 if len(cbc.getElementsByTagName("length"))<1 or len(cbc.getElementsByTagName("prefix"))<1:
251 debug("[FritzCall] stripCbCPrefix: entries for " + countrycode + " %s invalid")
253 length = int(cbc.getElementsByTagName("length")[0].childNodes[0].data)
254 prefix = cbc.getElementsByTagName("prefix")[0].childNodes[0].data
255 # if re.match('^'+prefix, number):
256 if number[:len(prefix)] == prefix:
257 return number[length:]
260 class FritzAbout(Screen):
262 def __init__(self, session):
263 textFieldWidth = scaleV(350, 250)
264 width = 5 + 150 + 20 + textFieldWidth + 5 + 175 + 5
265 height = 5 + 175 + 5 + 25 + 5
267 <screen name="FritzAbout" position="center,center" size="%d,%d" title="About FritzCall" >
268 <widget name="text" position="175,%d" size="%d,%d" font="Regular;%d" />
269 <ePixmap position="5,37" size="150,110" pixmap="%s" transparent="1" alphatest="blend" />
270 <ePixmap position="%d,5" size="175,175" pixmap="%s" transparent="1" alphatest="blend" />
271 <widget name="url" position="20,185" size="%d,25" font="Regular;%d" />
273 width, height, # size
274 (height-scaleV(150,130)) / 2, # text vertical position
276 scaleV(150,130), # text height
277 scaleV(24,21), # text font size
278 resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/images/fritz.png"), # 150x110
279 5 + 150 + 5 + textFieldWidth + 5, # qr code horizontal offset
280 resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/images/website.png"), # 175x175
281 width-40, # url width
282 scaleV(24,21) # url font size
284 Screen.__init__(self, session)
285 self["aboutActions"] = ActionMap(["OkCancelActions"],
290 self["text"] = Label(
291 "FritzCall Plugin" + "\n\n" +
292 "$Author$"[1:-2] + "\n" +
293 "$Revision$"[1:-2] + "\n" +
294 "$Date$"[1:23] + "\n"
296 self["url"] = Label("http://wiki.blue-panel.com/index.php/FritzCall")
297 self.onLayoutFinish.append(self.setWindowTitle)
299 def setWindowTitle(self):
300 # TRANSLATORS: this is a window title.
301 self.setTitle(_("About FritzCall"))
318 debug("[FritzCallFBF] __init__")
319 self._callScreen = None
320 self._md5LoginTimestamp = None
321 self._md5Sid = '0000000000000000'
322 self._callTimestamp = 0
324 self._callType = config.plugins.FritzCall.fbfCalls.value
325 self._phoneBookID = '0'
326 self.info = None # (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive)
328 self.blacklist = ([], [])
331 def _notify(self, text):
332 debug("[FritzCallFBF] notify: " + text)
333 self._md5LoginTimestamp = None
335 debug("[FritzCallFBF] notify: try to close callScreen")
336 self._callScreen.close()
337 self._callScreen = None
338 Notifications.AddNotification(MessageBox, text, type=MessageBox.TYPE_ERROR, timeout=config.plugins.FritzCall.timeout.value)
340 def _login(self, callback=None):
341 debug("[FritzCallFBF] _login")
343 self._callScreen.updateStatus(_("login"))
344 if self._md5LoginTimestamp and ((time.time() - self._md5LoginTimestamp) < float(9.5*60)) and self._md5Sid != '0000000000000000': # new login after 9.5 minutes inactivity
345 debug("[FritzCallFBF] _login: renew timestamp: " + time.ctime(self._md5LoginTimestamp) + " time: " + time.ctime())
346 self._md5LoginTimestamp = time.time()
349 debug("[FritzCallFBF] _login: not logged in or outdated login")
350 # http://fritz.box/cgi-bin/webcm?getpage=../html/login_sid.xml
351 parms = urlencode({'getpage':'../html/login_sid.xml'})
352 url = "http://%s/cgi-bin/webcm" % (config.plugins.FritzCall.hostname.value)
353 debug("[FritzCallFBF] _login: '" + url + "' parms: '" + parms + "'")
356 headers={'Content-Type': "application/x-www-form-urlencoded", 'Content-Length': str(len(parms))
357 }, postdata=parms).addCallback(lambda x: self._md5Login(callback,x)).addErrback(lambda x:self._oldLogin(callback,x))
359 def _oldLogin(self, callback, error):
360 debug("[FritzCallFBF] _oldLogin: " + repr(error))
361 self._md5LoginTimestamp = None
362 if config.plugins.FritzCall.password.value != "":
363 parms = "login:command/password=%s" % (config.plugins.FritzCall.password.value)
364 url = "http://%s/cgi-bin/webcm" % (config.plugins.FritzCall.hostname.value)
365 debug("[FritzCallFBF] _oldLogin: '" + url + "' parms: '" + parms + "'")
368 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
369 headers={'Content-Type': "application/x-www-form-urlencoded", 'Content-Length': str(len(parms))
370 }, postdata=parms).addCallback(self._gotPageLogin).addCallback(callback).addErrback(self._errorLogin)
372 debug("[FritzCallFBF] _oldLogin: no password, calling " + repr(callback))
375 def _md5Login(self, callback, sidXml):
376 def buildResponse(challenge, text):
377 debug("[FritzCallFBF] _md5Login7buildResponse: challenge: " + challenge + ' text: ' + text)
378 text = (challenge + '-' + text).decode('utf-8','ignore').encode('utf-16-le')
379 for i in range(len(text)):
380 if ord(text[i]) > 255:
384 debug("[FritzCallFBF] md5Login/buildResponse: " + md5.hexdigest())
385 return challenge + '-' + md5.hexdigest()
387 debug("[FritzCallFBF] _md5Login")
388 found = re.match('.*<SID>([^<]*)</SID>', sidXml, re.S)
390 self._md5Sid = found.group(1)
391 debug("[FritzCallFBF] _md5Login: SID "+ self._md5Sid)
393 debug("[FritzCallFBF] _md5Login: no sid! That must be an old firmware.")
394 self._oldLogin(callback, 'No error')
397 debug("[FritzCallFBF] _md5Login: renew timestamp: " + time.ctime(self._md5LoginTimestamp) + " time: " + time.ctime())
398 self._md5LoginTimestamp = time.time()
399 if sidXml.find('<iswriteaccess>0</iswriteaccess>') != -1:
400 debug("[FritzCallFBF] _md5Login: logging in")
401 found = re.match('.*<Challenge>([^<]*)</Challenge>', sidXml, re.S)
403 challenge = found.group(1)
404 debug("[FritzCallFBF] _md5Login: challenge " + challenge)
407 debug("[FritzCallFBF] _md5Login: login necessary and no challenge! That is terribly wrong.")
409 'getpage':'../html/de/menus/menu2.html', # 'var:pagename':'home', 'var:menu':'home',
410 'login:command/response': buildResponse(challenge, config.plugins.FritzCall.password.value),
412 url = "http://%s/cgi-bin/webcm" % (config.plugins.FritzCall.hostname.value)
413 debug("[FritzCallFBF] _md5Login: '" + url + "' parms: '" + parms + "'")
416 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
417 headers={'Content-Type': "application/x-www-form-urlencoded", 'Content-Length': str(len(parms))
418 }, postdata=parms).addCallback(self._gotPageLogin).addCallback(callback).addErrback(self._errorLogin)
419 elif callback: # we assume value 1 here, no login necessary
420 debug("[FritzCallFBF] _md5Login: no login necessary")
423 def _gotPageLogin(self, html):
425 self._callScreen.updateStatus(_("login verification"))
426 debug("[FritzCallFBF] _gotPageLogin: verify login")
427 start = html.find('<p class="errorMessage">FEHLER: ')
429 start = start + len('<p class="errorMessage">FEHLER: ')
430 text = _("FRITZ!Box - Error logging in: %s") + html[start, html.find('</p>', start)]
434 self._callScreen.updateStatus(_("login ok"))
436 found = re.match('.*<input type="hidden" name="sid" value="([^\"]*)"', html, re.S)
438 self._md5Sid = found.group(1)
439 debug("[FritzCallFBF] _gotPageLogin: found sid: " + self._md5Sid)
441 def _errorLogin(self, error):
443 debug("[FritzCallFBF] _errorLogin: %s" % (error))
444 text = _("FRITZ!Box - Error logging in: %s\nDisabling plugin.") % error.getErrorMessage()
445 # config.plugins.FritzCall.enable.value = False
450 if self._md5LoginTimestamp:
451 self._md5LoginTimestamp = None
453 'getpage':'../html/de/menus/menu2.html', # 'var:pagename':'home', 'var:menu':'home',
454 'login:command/logout':'bye bye Fritz'
456 url = "http://%s/cgi-bin/webcm" % (config.plugins.FritzCall.hostname.value)
457 debug("[FritzCallFBF] logout: '" + url + "' parms: '" + parms + "'")
460 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
461 headers={'Content-Type': "application/x-www-form-urlencoded", 'Content-Length': str(len(parms))
462 }, postdata=parms).addErrback(self._errorLogout)
464 def _errorLogout(self, error):
465 debug("[FritzCallFBF] _errorLogout: %s" % (error))
466 text = _("FRITZ!Box - Error logging out: %s") % error.getErrorMessage()
469 def loadFritzBoxPhonebook(self):
470 debug("[FritzCallFBF] loadFritzBoxPhonebook")
471 if config.plugins.FritzCall.fritzphonebook.value:
472 self._phoneBookID = '0'
473 debug("[FritzCallFBF] loadFritzBoxPhonebook: logging in")
474 self._login(self._loadFritzBoxPhonebook)
476 def _loadFritzBoxPhonebook(self, html):
478 #===================================================================
479 # found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)
481 # self._errorLoad('Login: ' + found.group(1))
483 #===================================================================
484 start = html.find('<p class="errorMessage">FEHLER: ')
486 start = start + len('<p class="errorMessage">FEHLER: ')
487 self._errorLoad('Login: ' + html[start, html.find('</p>', start)])
490 'getpage':'../html/de/menus/menu2.html',
492 'var:pagename':'fonbuch',
495 'telcfg:settings/Phonebook/Books/Select':self._phoneBookID, # this selects always the first phonbook
497 url = "http://%s/cgi-bin/webcm" % (config.plugins.FritzCall.hostname.value)
498 debug("[FritzCallFBF] _loadFritzBoxPhonebook: '" + url + "' parms: '" + parms + "'")
501 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
502 headers={'Content-Type': "application/x-www-form-urlencoded", 'Content-Length': str(len(parms))
503 }, postdata=parms).addCallback(self._parseFritzBoxPhonebook).addErrback(self._errorLoad)
505 def _parseFritzBoxPhonebook(self, html):
506 debug("[FritzCallFBF] _parseFritzBoxPhonebook")
508 # first, let us get the charset
509 found = re.match('.*<meta http-equiv=content-type content="text/html; charset=([^"]*)">', html, re.S)
511 charset = found.group(1)
512 debug("[FritzCallFBF] _parseFritzBoxPhonebook: found charset: " + charset)
513 html = html2unicode(html.decode(charset), charset).encode('utf-8') # this looks silly, but has to be
514 else: # this is kind of emergency conversion...
516 debug("[FritzCallFBF] _parseFritzBoxPhonebook: try charset utf-8")
518 html = html2unicode(html.decode('utf-8'), 'utf-8').encode('utf-8') # this looks silly, but has to be
519 except UnicodeDecodeError:
520 debug("[FritzCallFBF] _parseFritzBoxPhonebook: try charset iso-8859-1")
521 charset = 'iso-8859-1'
522 html = html2unicode(html.decode('iso-8859-1'), 'iso-8859-1').encode('utf-8') # this looks silly, but has to be
524 # if re.search('document.write\(TrFon1\(\)', html):
525 if html.find('document.write(TrFon1()') != -1:
526 #===============================================================================
527 # 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)
528 # 7170 (FW 29.04.70) 22.03.2009
529 # 7141 (FW 40.04.68) 22.03.2009
530 # We expect one line with TrFonName followed by several lines with
531 # TrFonNr(Type,Number,Shortcut,Vanity), which all belong to the name in TrFonName.
532 #===============================================================================
533 debug("[FritzCallFBF] _parseFritzBoxPhonebook: discovered newer firmware")
534 found = re.match('.*<input type="hidden" name="telcfg:settings/Phonebook/Books/Name(\d+)" value="[Dd]reambox" id="uiPostPhonebookName\d+" disabled>', html, re.S)
536 phoneBookID = found.group(1)
537 debug("[FritzCallFBF] _parseFritzBoxPhonebook: found dreambox phonebook with id: " + phoneBookID)
538 if self._phoneBookID != phoneBookID:
539 self._phoneBookID = phoneBookID
540 debug("[FritzCallFBF] _parseFritzBoxPhonebook: reload phonebook")
541 self._loadFritzBoxPhonebook(self._phoneBookID) # reload with dreambox phonebook
544 entrymask = re.compile('(TrFonName\("[^"]+", "[^"]+", "[^"]*"(?:, "[^"]*")?\);.*?)document.write\(TrFon1\(\)', re.S)
545 entries = entrymask.finditer(html)
546 for entry in entries:
547 # TrFonName (id, name, category)
548 # TODO: replace re.match?
549 found = re.match('TrFonName\("[^"]*", "([^"]+)", "[^"]*"(?:, "[^"]*")?\);', entry.group(1))
551 debug("[FritzCallFBF] _parseFritzBoxPhonebook: name: %s" %found.group(1))
552 name = found.group(1).replace(',','').strip()
554 debug("[FritzCallFBF] _parseFritzBoxPhonebook: could not find name")
556 # TrFonNr (type, rufnr, code, vanity)
557 detailmask = re.compile('TrFonNr\("([^"]*)", "([^"]*)", "([^"]*)", "([^"]*)"\);', re.S)
558 details = detailmask.finditer(entry.group(1))
559 for found in details:
560 thisnumber = found.group(2).strip()
562 debug("[FritzCallFBF] Ignoring entry with empty number for '''%s'''" % (name))
566 callType = found.group(1)
567 if config.plugins.FritzCall.showType.value:
568 if callType == "mobile":
569 thisname = thisname + " (" + _("mobile") + ")"
570 elif callType == "home":
571 thisname = thisname + " (" + _("home") + ")"
572 elif callType == "work":
573 thisname = thisname + " (" + _("work") + ")"
575 if config.plugins.FritzCall.showShortcut.value and found.group(3):
576 thisname = thisname + ", " + _("Shortcut") + ": " + found.group(3)
577 if config.plugins.FritzCall.showVanity.value and found.group(4):
578 thisname = thisname + ", " + _("Vanity") + ": " + found.group(4)
580 debug("[FritzCallFBF] Adding '''%s''' with '''%s''' from FRITZ!Box Phonebook!" % (thisname.strip(), thisnumber))
581 # Beware: strings in phonebook.phonebook have to be in utf-8!
582 phonebook.phonebook[thisnumber] = thisname
584 # elif re.search('document.write\(TrFon\(', html):
585 elif html.find('document.write(TrFon(') != -1:
586 #===============================================================================
587 # Old Style: 7050 (FW 14.04.33)
588 # We expect one line with TrFon(No,Name,Number,Shortcut,Vanity)
589 # Encoding should be plain Ascii...
590 #===============================================================================
591 entrymask = re.compile('TrFon\("[^"]*", "([^"]*)", "([^"]*)", "([^"]*)", "([^"]*)"\)', re.S)
592 entries = entrymask.finditer(html)
593 for found in entries:
594 name = found.group(1).strip().replace(',','')
595 # debug("[FritzCallFBF] pos: %s name: %s" %(found.group(0),name))
596 thisnumber = found.group(2).strip()
597 if config.plugins.FritzCall.showShortcut.value and found.group(3):
598 name = name + ", " + _("Shortcut") + ": " + found.group(3)
599 if config.plugins.FritzCall.showVanity.value and found.group(4):
600 name = name + ", " + _("Vanity") + ": " + found.group(4)
602 # name = name.encode('utf-8')
603 debug("[FritzCallFBF] Adding '''%s''' with '''%s''' from FRITZ!Box Phonebook!" % (name, thisnumber))
604 # Beware: strings in phonebook.phonebook have to be in utf-8!
605 phonebook.phonebook[thisnumber] = name
607 debug("[FritzCallFBF] ignoring empty number for %s" % name)
609 elif self._md5Sid == '0000000000000000': # retry, it could be a race condition
610 debug("[FritzCallFBF] _parseFritzBoxPhonebook: retry loading phonebook")
611 self.loadFritzBoxPhonebook()
613 self._notify(_("Could not parse FRITZ!Box Phonebook entry"))
615 def _errorLoad(self, error):
616 debug("[FritzCallFBF] _errorLoad: %s" % (error))
617 text = _("FRITZ!Box - Could not load phonebook: %s") % error.getErrorMessage()
620 def getCalls(self, callScreen, callback, callType):
622 # call sequence must be:
624 # - getPage -> _gotPageLogin
625 # - loginCallback (_getCalls)
626 # - getPage -> _getCalls1
627 debug("[FritzCallFBF] getCalls")
628 self._callScreen = callScreen
629 self._callType = callType
630 if (time.time() - self._callTimestamp) > 180:
631 debug("[FritzCallFBF] getCalls: outdated data, login and get new ones: " + time.ctime(self._callTimestamp) + " time: " + time.ctime())
632 self._callTimestamp = time.time()
633 self._login(lambda x:self._getCalls(callback, x))
634 elif not self._callList:
635 debug("[FritzCallFBF] getCalls: time is ok, but no callList")
636 self._getCalls1(callback)
638 debug("[FritzCallFBF] getCalls: time is ok, callList is ok")
639 self._gotPageCalls(callback)
641 def _getCalls(self, callback, html):
643 #===================================================================
644 # found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)
646 # self._errorCalls('Login: ' + found.group(1))
648 #===================================================================
649 start = html.find('<p class="errorMessage">FEHLER: ')
651 start = start + len('<p class="errorMessage">FEHLER: ')
652 self._errorCalls('Login: ' + html[start, html.find('</p>', start)])
655 # we need this to fill Anrufliste.csv
656 # http://repeater1/cgi-bin/webcm?getpage=../html/de/menus/menu2.html&var:lang=de&var:menu=fon&var:pagename=foncalls
658 debug("[FritzCallFBF] _getCalls")
660 #===================================================================
661 # found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)
663 # text = _("FRITZ!Box - Error logging in: %s") + found.group(1)
666 #===================================================================
667 start = html.find('<p class="errorMessage">FEHLER: ')
669 start = start + len('<p class="errorMessage">FEHLER: ')
670 self._notify(_("FRITZ!Box - Error logging in: %s") + html[start, html.find('</p>', start)])
674 self._callScreen.updateStatus(_("preparing"))
675 parms = urlencode({'getpage':'../html/de/menus/menu2.html', 'var:lang':'de', 'var:pagename':'foncalls', 'var:menu':'fon', 'sid':self._md5Sid})
676 url = "http://%s/cgi-bin/webcm?%s" % (config.plugins.FritzCall.hostname.value, parms)
677 getPage(url).addCallback(lambda x:self._getCalls1(callback)).addErrback(self._errorCalls) #@UnusedVariable # pylint: disable-msg=W0613
679 def _getCalls1(self, callback):
681 # finally we should have successfully lgged in and filled the csv
683 debug("[FritzCallFBF] _getCalls1")
685 self._callScreen.updateStatus(_("finishing"))
686 parms = urlencode({'getpage':'../html/de/FRITZ!Box_Anrufliste.csv', 'sid':self._md5Sid})
687 url = "http://%s/cgi-bin/webcm?%s" % (config.plugins.FritzCall.hostname.value, parms)
688 getPage(url).addCallback(lambda x:self._gotPageCalls(callback, x)).addErrback(self._errorCalls)
690 def _gotPageCalls(self, callback, csv=""):
691 def resolveNumber(number):
693 if config.plugins.FritzCall.internal.value and len(number) > 3 and number[0] == "0":
696 number = stripCbCPrefix(number, config.plugins.FritzCall.country.value)
697 if config.plugins.FritzCall.prefix.value and number and number[0] != '0': # should only happen for outgoing
698 number = config.plugins.FritzCall.prefix.value + number
699 name = phonebook.search(number)
701 #===========================================================
702 # found = re.match('(.*?)\n.*', name)
704 # name = found.group(1)
705 #===========================================================
706 end = name.find('\n')
711 name = resolveNumberWithAvon(number, config.plugins.FritzCall.country.value)
713 number = number + ' ' + name
715 number = _("UNKNOWN")
716 # if len(number) > 20: number = number[:20]
720 debug("[FritzCallFBF] _gotPageCalls: got csv, setting callList")
722 self._callScreen.updateStatus(_("done"))
723 # check for error: wrong password or password not set... TODO
724 # found = re.search('Melden Sie sich mit dem Kennwort der FRITZ!Box an', csv)
725 if csv.find('Melden Sie sich mit dem Kennwort der FRITZ!Box an') != -1:
726 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.")
727 # self.session.open(MessageBox, text, MessageBox.TYPE_ERROR, timeout=config.plugins.FritzCall.timeout.value)
731 csv = csv.decode('iso-8859-1', 'replace').encode('utf-8', 'replace')
732 lines = csv.splitlines()
733 self._callList = lines
735 debug("[FritzCallFBF] _gotPageCalls: got no csv, but have callList")
737 self._callScreen.updateStatus(_("done, using last list"))
738 lines = self._callList
740 debug("[FritzCallFBF] _gotPageCalls: got no csv, no callList, laving")
744 if config.plugins.FritzCall.filter.value and config.plugins.FritzCall.filterCallList.value:
745 filtermsns = map(lambda x: x.strip(), config.plugins.FritzCall.filtermsn.value.split(","))
746 debug("[FritzCallFBF] _gotPageCalls: filtermsns %s" % (repr(filtermsns)))
748 # Typ;e;Rufnummer;Nebenstelle;Eigene Rufnummer;Dauer
749 elems = line.split(';')
750 # found = re.match("^(" + self._callType + ");([^;]*);([^;]*);([^;]*);([^;]*);([^;]*);([^;]*)", line)
751 if len(elems) != 7: # this happens, if someone puts a ';' in the name in the FBF phonebook
752 debug("[FritzCallFBF] _gotPageCalls: len != 7: %s" % (line))
753 if len(elems) == 7 and (self._callType == '.' or elems[0] == self._callType):
754 # debug("[FritzCallFBF] _gotPageCalls: elems %s" % (elems))
758 remote = resolveNumber(elems[3])
759 if not remote and direct != FBF_OUT_CALLS and elems[2]:
761 #===============================================================
762 # found1 = re.match('Internet: (.*)', found.group(6))
764 # here = found1.group(1)
766 # here = found.group(6)
767 #===============================================================
769 start = here.find('Internet: ')
771 start += len('Internet: ')
775 if 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)
782 number = stripCbCPrefix(elems[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))
787 # debug("[FritzCallFBF] _gotPageCalls result:\n" + text
790 # debug("[FritzCallFBF] _gotPageCalls call callback with\n" + text
792 self._callScreen = None
794 def _errorCalls(self, error):
795 debug("[FritzCallFBF] _errorCalls: %s" % (error))
796 text = _("FRITZ!Box - Could not load calls: %s") % error.getErrorMessage()
799 def dial(self, number):
800 ''' initiate a call to number '''
801 self._login(lambda x: self._dial(number, x))
803 def _dial(self, number, html):
805 #===================================================================
806 # found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)
808 # self._errorDial('Login: ' + found.group(1))
810 #===================================================================
811 start = html.find('<p class="errorMessage">FEHLER: ')
813 start = start + len('<p class="errorMessage">FEHLER: ')
814 self._errorDial('Login: ' + html[start, html.find('</p>', start)])
816 url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
818 'getpage':'../html/de/menus/menu2.html',
819 'var:pagename':'fonbuch',
821 'telcfg:settings/UseClickToDial':'1',
822 'telcfg:settings/DialPort':config.plugins.FritzCall.extension.value,
823 'telcfg:command/Dial':number,
826 debug("[FritzCallFBF] dial url: '" + url + "' parms: '" + parms + "'")
829 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
831 'Content-Type': "application/x-www-form-urlencoded",
832 'Content-Length': str(len(parms))},
833 postdata=parms).addCallback(self._okDial).addErrback(self._errorDial)
835 def _okDial(self, html): #@UnusedVariable # pylint: disable-msg=W0613
836 debug("[FritzCallFBF] okDial")
838 def _errorDial(self, error):
839 debug("[FritzCallFBF] errorDial: $s" % error)
840 text = _("FRITZ!Box - Dialling failed: %s") % error.getErrorMessage()
843 def changeWLAN(self, statusWLAN):
844 ''' get status info from FBF '''
845 debug("[FritzCallFBF] changeWLAN start")
846 if not statusWLAN or (statusWLAN != '1' and statusWLAN != '0'):
848 self._login(lambda x: self._changeWLAN(statusWLAN, x))
850 def _changeWLAN(self, statusWLAN, html):
852 #===================================================================
853 # found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)
855 # self._errorChangeWLAN('Login: ' + found.group(1))
857 #===================================================================
858 start = html.find('<p class="errorMessage">FEHLER: ')
860 start = start + len('<p class="errorMessage">FEHLER: ')
861 self._errorChangeWLAN('Login: ' + html[start, html.find('</p>', start)])
863 url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
865 'getpage':'../html/de/menus/menu2.html',
867 'var:pagename':'wlan',
869 'wlan:settings/ap_enabled':str(statusWLAN),
872 debug("[FritzCallFBF] changeWLAN url: '" + url + "' parms: '" + parms + "'")
875 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
877 'Content-Type': "application/x-www-form-urlencoded",
878 'Content-Length': str(len(parms))},
879 postdata=parms).addCallback(self._okChangeWLAN).addErrback(self._errorChangeWLAN)
881 def _okChangeWLAN(self, html): #@UnusedVariable # pylint: disable-msg=W0613
882 debug("[FritzCallFBF] _okChangeWLAN")
884 def _errorChangeWLAN(self, error):
885 debug("[FritzCallFBF] _errorChangeWLAN: $s" % error)
886 text = _("FRITZ!Box - Failed changing WLAN: %s") % error.getErrorMessage()
889 def changeMailbox(self, whichMailbox):
890 ''' switch mailbox on/off '''
891 debug("[FritzCallFBF] changeMailbox start: " + str(whichMailbox))
892 self._login(lambda x: self._changeMailbox(whichMailbox, x))
894 def _changeMailbox(self, whichMailbox, html):
896 #===================================================================
897 # found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)
899 # self._errorChangeMailbox('Login: ' + found.group(1))
901 #===================================================================
902 start = html.find('<p class="errorMessage">FEHLER: ')
904 start = start + len('<p class="errorMessage">FEHLER: ')
905 self._errorChangeMailbox('Login: ' + html[start, html.find('</p>', start)])
907 debug("[FritzCallFBF] _changeMailbox")
908 url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
909 if whichMailbox == -1:
911 if self.info[FBF_tamActive][i+1]:
916 'tam:settings/TAM'+str(i)+'/Active':state,
919 debug("[FritzCallFBF] changeMailbox url: '" + url + "' parms: '" + parms + "'")
922 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
924 'Content-Type': "application/x-www-form-urlencoded",
925 'Content-Length': str(len(parms))},
926 postdata=parms).addCallback(self._okChangeMailbox).addErrback(self._errorChangeMailbox)
927 elif whichMailbox > 4:
928 debug("[FritzCallFBF] changeMailbox invalid mailbox number")
930 if self.info[FBF_tamActive][whichMailbox+1]:
935 'tam:settings/TAM'+str(whichMailbox)+'/Active':state,
938 debug("[FritzCallFBF] changeMailbox url: '" + url + "' parms: '" + parms + "'")
941 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
943 'Content-Type': "application/x-www-form-urlencoded",
944 'Content-Length': str(len(parms))},
945 postdata=parms).addCallback(self._okChangeMailbox).addErrback(self._errorChangeMailbox)
947 def _okChangeMailbox(self, html): #@UnusedVariable # pylint: disable-msg=W0613
948 debug("[FritzCallFBF] _okChangeMailbox")
950 def _errorChangeMailbox(self, error):
951 debug("[FritzCallFBF] _errorChangeMailbox: $s" % error)
952 text = _("FRITZ!Box - Failed changing Mailbox: %s") % error.getErrorMessage()
955 def getInfo(self, callback):
956 ''' get status info from FBF '''
957 debug("[FritzCallFBF] getInfo")
958 self._login(lambda x:self._getInfo(callback, x))
960 def _getInfo(self, callback, html):
961 # http://192.168.178.1/cgi-bin/webcm?getpage=../html/de/menus/menu2.html&var:lang=de&var:pagename=home&var:menu=home
962 debug("[FritzCallFBF] _getInfo: verify login")
964 #===================================================================
965 # found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)
967 # self._errorGetInfo('Login: ' + found.group(1))
969 #===================================================================
970 start = html.find('<p class="errorMessage">FEHLER: ')
972 start = start + len('<p class="errorMessage">FEHLER: ')
973 self._errorGetInfo('Login: ' + html[start, html.find('</p>', start)])
976 url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
978 'getpage':'../html/de/menus/menu2.html',
980 'var:pagename':'home',
984 debug("[FritzCallFBF] _getInfo url: '" + url + "' parms: '" + parms + "'")
987 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
989 'Content-Type': "application/x-www-form-urlencoded",
990 'Content-Length': str(len(parms))},
991 postdata=parms).addCallback(lambda x:self._okGetInfo(callback,x)).addErrback(self._errorGetInfo)
993 def _okGetInfo(self, callback, html):
996 (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive) = self.info
998 (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive) = (None, None, None, None, None, None, None, None, None)
1000 debug("[FritzCallFBF] _okGetInfo/readinfo")
1001 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)
1003 boxInfo = found.group(1)+ ', ' + found.group(2)
1004 boxInfo = boxInfo.replace(' ',' ')
1005 # debug("[FritzCallFBF] _okGetInfo Boxinfo: " + boxInfo)
1007 found = re.match('.*<p class="ac">([^<]*)</p>', html, re.S)
1009 # debug("[FritzCallFBF] _okGetInfo Boxinfo: " + found.group(1))
1010 boxInfo = found.group(1)
1012 if html.find('home_coninf.txt') != -1:
1013 url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
1015 'getpage':'../html/de/home/home_coninf.txt',
1018 # debug("[FritzCallFBF] get coninfo: url: '" + url + "' parms: '" + parms + "'")
1021 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
1023 'Content-Type': "application/x-www-form-urlencoded",
1024 'Content-Length': str(len(parms))},
1025 postdata=parms).addCallback(lambda x:self._okSetConInfo(callback,x)).addErrback(self._errorGetInfo)
1027 found = re.match('.*if \(isNaN\(jetzt\)\)\s*return "";\s*var str = "([^"]*)";', html, re.S)
1029 # debug("[FritzCallFBF] _okGetInfo Uptime: " + found.group(1))
1030 upTime = found.group(1)
1032 found = re.match('.*str = g_pppSeit \+"([^<]*)<br>"\+mldIpAdr;', html, re.S)
1034 # debug("[FritzCallFBF] _okGetInfo Uptime: " + found.group(1))
1035 upTime = found.group(1)
1037 found = re.match(".*IpAdrDisplay\('([.\d]+)'\)", html, re.S)
1039 # debug("[FritzCallFBF] _okGetInfo IpAdrDisplay: " + found.group(1))
1040 ipAddress = found.group(1)
1042 if html.find('g_tamActive') != -1:
1043 entries = re.compile('if \("(\d)" == "1"\) {\s*g_tamActive \+= 1;\s*}', re.S).finditer(html)
1044 tamActive = [0, False, False, False, False, False]
1046 for entry in entries:
1047 state = entry.group(1)
1052 # debug("[FritzCallFBF] _okGetInfo tamActive: " + str(tamActive))
1054 if html.find('home_dect.txt') != -1:
1055 url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
1057 'getpage':'../html/de/home/home_dect.txt',
1060 # debug("[FritzCallFBF] get coninfo: url: '" + url + "' parms: '" + parms + "'")
1063 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
1065 'Content-Type': "application/x-www-form-urlencoded",
1066 'Content-Length': str(len(parms))},
1067 postdata=parms).addCallback(lambda x:self._okSetDect(callback,x)).addErrback(self._errorGetInfo)
1069 if html.find('countDect2') != -1:
1070 entries = re.compile('if \("1" == "1"\) countDect2\+\+;', re.S).findall(html)
1071 dectActive = len(entries)
1072 # debug("[FritzCallFBF] _okGetInfo dectActive: " + str(dectActive))
1074 found = re.match('.*var g_intFaxActive = "0";\s*if \("1" != ""\) {\s*g_intFaxActive = "1";\s*}\s*', html, re.S)
1077 # debug("[FritzCallFBF] _okGetInfo faxActive")
1079 if html.find('cntRufumleitung') != -1:
1080 entries = re.compile('mode = "1";\s*ziel = "[^"]+";\s*if \(mode == "1" \|\| ziel != ""\)\s*{\s*g_RufumleitungAktiv = true;', re.S).findall(html)
1081 rufumlActive = len(entries)
1082 entries = re.compile('if \("([^"]*)"=="([^"]*)"\) isAllIncoming\+\+;', re.S).finditer(html)
1084 for entry in entries:
1085 # debug("[FritzCallFBF] _okGetInfo rufumlActive add isAllIncoming")
1086 if entry.group(1) == entry.group(2):
1088 if isAllIncoming == 2 and rufumlActive > 0:
1090 # debug("[FritzCallFBF] _okGetInfo rufumlActive: " + str(rufumlActive))
1092 # /cgi-bin/webcm?getpage=../html/de/home/home_dsl.txt
1093 # { "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": "" }
1094 if html.find('home_dsl.txt') != -1:
1095 url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
1097 'getpage':'../html/de/home/home_dsl.txt',
1100 # debug("[FritzCallFBF] get dsl state: url: '" + url + "' parms: '" + parms + "'")
1103 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
1105 'Content-Type': "application/x-www-form-urlencoded",
1106 'Content-Length': str(len(parms))},
1107 postdata=parms).addCallback(lambda x:self._okSetDslState(callback,x)).addErrback(self._errorGetInfo)
1109 found = re.match('.*function DslStateDisplay \(state\){\s*var state = "(\d+)";', html, re.S)
1111 # debug("[FritzCallFBF] _okGetInfo DslState: " + found.group(1))
1112 dslState = [ found.group(1), None ] # state, speed
1113 found = re.match('.*function DslStateDisplay \(state\){\s*var state = "\d+";.*?if \("3130" != "0"\) str = "([^"]*)";', html, re.S)
1115 # debug("[FritzCallFBF] _okGetInfo DslSpeed: " + found.group(1).strip())
1116 dslState[1] = found.group(1).strip()
1118 # /cgi-bin/webcm?getpage=../html/de/home/home_wlan.txt
1119 # { "ap_enabled": "1", "active_stations": "0", "encryption": "4", "wireless_stickandsurf_enabled": "0", "is_macfilter_active": "0", "wmm_enabled": "1", "wlan_state": [ "end" ] }
1120 if html.find('home_wlan.txt') != -1:
1121 url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
1123 'getpage':'../html/de/home/home_wlan.txt',
1126 # debug("[FritzCallFBF] get wlan state: url: '" + url + "' parms: '" + parms + "'")
1129 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
1131 'Content-Type': "application/x-www-form-urlencoded",
1132 'Content-Length': str(len(parms))},
1133 postdata=parms).addCallback(lambda x:self._okSetWlanState(callback,x)).addErrback(self._errorGetInfo)
1135 found = re.match('.*function WlanStateLed \(state\){.*?return StateLed\("(\d+)"\);\s*}', html, re.S)
1137 # debug("[FritzCallFBF] _okGetInfo WlanState: " + found.group(1))
1138 wlanState = [ found.group(1), 0, 0 ] # state, encryption, number of devices
1139 found = re.match('.*var (?:g_)?encryption = "(\d+)";', html, re.S)
1141 # debug("[FritzCallFBF] _okGetInfo WlanEncrypt: " + found.group(1))
1142 wlanState[1] = found.group(1)
1144 return (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive)
1146 debug("[FritzCallFBF] _okGetInfo")
1147 info = readInfo(html)
1148 debug("[FritzCallFBF] _okGetInfo info: " + str(info))
1153 def _okSetDect(self, callback, html):
1154 # debug("[FritzCallFBF] _okSetDect: " + html)
1155 # found = re.match('.*"connection_status":"(\d+)".*"connection_ip":"([.\d]+)".*"connection_detail":"([^"]+)".*"connection_uptime":"([^"]+)"', html, re.S)
1156 if html.find('"dect_enabled": "1"') != -1:
1157 # debug("[FritzCallFBF] _okSetDect: dect_enabled")
1158 found = re.match('.*"dect_device_list":.*\[([^\]]*)\]', html, re.S)
1160 # debug("[FritzCallFBF] _okSetDect: dect_device_list: %s" %(found.group(1)))
1161 entries = re.compile('"1"', re.S).findall(found.group(1))
1162 dectActive = len(entries)
1163 (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dummy, faxActive, rufumlActive) = self.info
1164 self.info = (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive)
1165 debug("[FritzCallFBF] _okSetDect info: " + str(self.info))
1169 def _okSetConInfo(self, callback, html):
1170 # debug("[FritzCallFBF] _okSetConInfo: " + html)
1171 # found = re.match('.*"connection_status":"(\d+)".*"connection_ip":"([.\d]+)".*"connection_detail":"([^"]+)".*"connection_uptime":"([^"]+)"', html, re.S)
1172 found = re.match('.*"connection_ip": "([.\d]+)".*"connection_uptime": "([^"]+)"', html, re.S)
1174 # debug("[FritzCallFBF] _okSetConInfo: connection_ip: %s upTime: %s" %( found.group(1), found.group(2)))
1175 ipAddress = found.group(1)
1176 upTime = found.group(2)
1177 (boxInfo, dummy, dummy, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive) = self.info
1178 self.info = (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive)
1179 debug("[FritzCallFBF] _okSetWlanState info: " + str(self.info))
1181 found = re.match('.*_ip": "([.\d]+)".*"connection_uptime": "([^"]+)"', html, re.S)
1183 # debug("[FritzCallFBF] _okSetConInfo: _ip: %s upTime: %s" %( found.group(1), found.group(2)))
1184 ipAddress = found.group(1)
1185 upTime = found.group(2)
1186 (boxInfo, dummy, dummy, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive) = self.info
1187 self.info = (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive)
1188 debug("[FritzCallFBF] _okSetWlanState info: " + str(self.info))
1192 def _okSetWlanState(self, callback, html):
1193 # debug("[FritzCallFBF] _okSetWlanState: " + html)
1194 found = re.match('.*"ap_enabled": "(\d+)"', html, re.S)
1196 # debug("[FritzCallFBF] _okSetWlanState: ap_enabled: " + found.group(1))
1197 wlanState = [ found.group(1), None, None ]
1198 found = re.match('.*"encryption": "(\d+)"', html, re.S)
1200 # debug("[FritzCallFBF] _okSetWlanState: encryption: " + found.group(1))
1201 wlanState[1] = found.group(1)
1202 found = re.match('.*"active_stations": "(\d+)"', html, re.S)
1204 # debug("[FritzCallFBF] _okSetWlanState: active_stations: " + found.group(1))
1205 wlanState[2] = found.group(1)
1206 (boxInfo, upTime, ipAddress, dummy, dslState, tamActive, dectActive, faxActive, rufumlActive) = self.info
1207 self.info = (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive)
1208 debug("[FritzCallFBF] _okSetWlanState info: " + str(self.info))
1212 def _okSetDslState(self, callback, html):
1213 # debug("[FritzCallFBF] _okSetDslState: " + html)
1214 found = re.match('.*"dsl_carrier_state": "(\d+)"', html, re.S)
1216 # debug("[FritzCallFBF] _okSetDslState: dsl_carrier_state: " + found.group(1))
1217 dslState = [ found.group(1), None ]
1218 found = re.match('.*"dsl_ds_nrate": "(\d+)"', html, re.S)
1220 # debug("[FritzCallFBF] _okSetDslState: dsl_ds_nrate: " + found.group(1))
1221 dslState[1] = found.group(1)
1222 found = re.match('.*"dsl_us_nrate": "(\d+)"', html, re.S)
1224 # debug("[FritzCallFBF] _okSetDslState: dsl_us_nrate: " + found.group(1))
1225 dslState[1] = dslState[1] + '/' + found.group(1)
1226 (boxInfo, upTime, ipAddress, wlanState, dummy, tamActive, dectActive, faxActive, rufumlActive) = self.info
1227 self.info = (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive)
1228 debug("[FritzCallFBF] _okSetDslState info: " + str(self.info))
1232 def _errorGetInfo(self, error):
1233 debug("[FritzCallFBF] _errorGetInfo: %s" % (error))
1234 text = _("FRITZ!Box - Error getting status: %s") % error.getErrorMessage()
1236 # linkP = open("/tmp/FritzCall_errorGetInfo.htm", "w")
1237 # linkP.write(error)
1241 self._login(self._reset)
1243 def _reset(self, html):
1244 # 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
1246 #===================================================================
1247 # found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)
1249 # self._errorReset('Login: ' + found.group(1))
1251 #===================================================================
1252 start = html.find('<p class="errorMessage">FEHLER: ')
1254 start = start + len('<p class="errorMessage">FEHLER: ')
1255 self._errorReset('Login: ' + html[start, html.find('</p>', start)])
1257 if self._callScreen:
1258 self._callScreen.close()
1259 url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
1261 'getpage':'../html/reboot.html',
1263 'var:pagename':'reset',
1264 'var:menu':'system',
1265 'logic:command/reboot':'../gateway/commands/saveconfig.html',
1268 debug("[FritzCallFBF] _reset url: '" + url + "' parms: '" + parms + "'")
1271 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
1273 'Content-Type': "application/x-www-form-urlencoded",
1274 'Content-Length': str(len(parms))},
1277 def _okReset(self, html): #@UnusedVariable # pylint: disable-msg=W0613
1278 debug("[FritzCallFBF] _okReset")
1280 def _errorReset(self, error):
1281 debug("[FritzCallFBF] _errorReset: %s" % (error))
1282 text = _("FRITZ!Box - Error resetting: %s") % error.getErrorMessage()
1285 def readBlacklist(self):
1286 self._login(self._readBlacklist)
1288 def _readBlacklist(self, html):
1290 #===================================================================
1291 # found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)
1293 # self._errorBlacklist('Login: ' + found.group(1))
1295 #===================================================================
1296 start = html.find('<p class="errorMessage">FEHLER: ')
1298 start = start + len('<p class="errorMessage">FEHLER: ')
1299 self._errorBlacklist('Login: ' + html[start, html.find('</p>', start)])
1301 # http://fritz.box/cgi-bin/webcm?getpage=../html/de/menus/menu2.html&var:lang=de&var:menu=fon&var:pagename=sperre
1302 url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
1304 'getpage':'../html/de/menus/menu2.html',
1306 'var:pagename':'sperre',
1310 debug("[FritzCallFBF] _readBlacklist url: '" + url + "' parms: '" + parms + "'")
1313 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
1315 'Content-Type': "application/x-www-form-urlencoded",
1316 'Content-Length': str(len(parms))},
1317 postdata=parms).addCallback(self._okBlacklist).addErrback(self._errorBlacklist)
1319 def _okBlacklist(self, html):
1320 debug("[FritzCallFBF] _okBlacklist")
1321 entries = re.compile('<script type="text/javascript">document.write\(Tr(Out|In)\("\d+", "(\d+)", "\w*"\)\);</script>', re.S).finditer(html)
1322 self.blacklist = ([], [])
1323 for entry in entries:
1324 if entry.group(1) == "In":
1325 self.blacklist[0].append(entry.group(2))
1327 self.blacklist[1].append(entry.group(2))
1328 debug("[FritzCallFBF] _okBlacklist: %s" % repr(self.blacklist))
1330 def _errorBlacklist(self, error):
1331 debug("[FritzCallFBF] _errorBlacklist: %s" % (error))
1332 text = _("FRITZ!Box - Error getting blacklist: %s") % error.getErrorMessage()
1335 #===============================================================================
1337 # ''' hangup call on port; not used for now '''
1338 # url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
1339 # parms = urlencode({
1340 # 'id':'uiPostForm',
1341 # 'name':'uiPostForm',
1342 # 'login:command/password': config.plugins.FritzCall.password.value,
1343 # 'telcfg:settings/UseClickToDial':'1',
1344 # 'telcfg:settings/DialPort':config.plugins.FritzCall.extension.value,
1345 # 'telcfg:command/Hangup':'',
1346 # 'sid':self._md5Sid
1348 # debug("[FritzCallFBF] hangup url: '" + url + "' parms: '" + parms + "'")
1352 # 'Content-Type': "application/x-www-form-urlencoded",
1353 # 'Content-Length': str(len(parms))},
1355 #===============================================================================
1359 class FritzMenu(Screen, HelpableScreen):
1360 def __init__(self, session):
1361 fontSize = scaleV(24, 21) # indeed this is font size +2
1362 noButtons = 2 # reset, wlan
1364 if not fritzbox or not fritzbox.info:
1367 if fritzbox.info[FBF_tamActive]:
1368 noButtons += 1 # toggle mailboxes
1369 width = max(DESKTOP_WIDTH - scaleH(500, 250), noButtons*140+(noButtons+1)*10)
1370 # boxInfo 2 lines, gap, internet 2 lines, gap, dsl/wlan each 1 line, gap, buttons
1371 height = 5 + 2*fontSize + 10 + 2*fontSize + 10 + 2*fontSize + 10 + 40 + 5
1372 if fritzbox.info[FBF_tamActive] is not None:
1374 if fritzbox.info[FBF_dectActive] is not None:
1376 if fritzbox.info[FBF_faxActive] is not None:
1378 if fritzbox.info[FBF_rufumlActive] is not None:
1380 buttonsGap = (width-noButtons*140)/(noButtons+1)
1381 buttonsVPos = height-40-5
1384 if fritzbox.info[FBF_tamActive] is not None:
1386 <widget name="FBFMailbox" position="%d,%d" size="%d,%d" font="Regular;%d" />
1387 <widget name="mailbox_inactive" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1388 <widget name="mailbox_active" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1389 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
1390 <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" />
1392 40, 5+2*fontSize+10+varLinePos*fontSize+10, # position mailbox
1393 width-40-20, fontSize, # size mailbox
1395 "skin_default/buttons/button_green_off.png",
1396 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button mailbox
1397 "skin_default/buttons/button_green.png",
1398 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button mailbox
1399 noButtons*buttonsGap+(noButtons-1)*140, buttonsVPos,
1400 noButtons*buttonsGap+(noButtons-1)*140, buttonsVPos,
1406 if fritzbox.info[FBF_dectActive] is not None:
1408 <widget name="FBFDect" position="%d,%d" size="%d,%d" font="Regular;%d" />
1409 <widget name="dect_inactive" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1410 <widget name="dect_active" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1412 40, 5+2*fontSize+10+varLinePos*fontSize+10, # position dect
1413 width-40-20, fontSize, # size dect
1415 "skin_default/buttons/button_green_off.png",
1416 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button dect
1417 "skin_default/buttons/button_green.png",
1418 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button dect
1424 if fritzbox.info[FBF_faxActive] is not None:
1426 <widget name="FBFFax" position="%d,%d" size="%d,%d" font="Regular;%d" />
1427 <widget name="fax_inactive" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1428 <widget name="fax_active" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1430 40, 5+2*fontSize+10+varLinePos*fontSize+10, # position dect
1431 width-40-20, fontSize, # size dect
1433 "skin_default/buttons/button_green_off.png",
1434 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button dect
1435 "skin_default/buttons/button_green.png",
1436 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button dect
1442 if fritzbox.info[FBF_rufumlActive] is not None:
1444 <widget name="FBFRufuml" position="%d,%d" size="%d,%d" font="Regular;%d" />
1445 <widget name="rufuml_inactive" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1446 <widget name="rufuml_active" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1448 40, 5+2*fontSize+10+varLinePos*fontSize+10, # position dect
1449 width-40-20, fontSize, # size dect
1451 "skin_default/buttons/button_green_off.png",
1452 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button dect
1453 "skin_default/buttons/button_green.png",
1454 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button dect
1461 <screen name="FritzMenu" position="center,center" size="%d,%d" title="FRITZ!Box Fon Status" >
1462 <widget name="FBFInfo" position="%d,%d" size="%d,%d" font="Regular;%d" />
1463 <widget name="FBFInternet" position="%d,%d" size="%d,%d" font="Regular;%d" />
1464 <widget name="internet_inactive" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1465 <widget name="internet_active" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1466 <widget name="FBFDsl" position="%d,%d" size="%d,%d" font="Regular;%d" />
1467 <widget name="dsl_inactive" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1468 <widget name="dsl_active" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1469 <widget name="FBFWlan" position="%d,%d" size="%d,%d" font="Regular;%d" />
1470 <widget name="wlan_inactive" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1471 <widget name="wlan_active" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1476 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
1477 <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" />
1478 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
1479 <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" />
1481 width, height, # size
1482 40, 5, # position info
1483 width-2*40, 2*fontSize, # size info
1485 40, 5+2*fontSize+10, # position internet
1486 width-40, 2*fontSize, # size internet
1488 "skin_default/buttons/button_green_off.png",
1489 20, 5+2*fontSize+10+(fontSize-16)/2, # position button internet
1490 "skin_default/buttons/button_green.png",
1491 20, 5+2*fontSize+10+(fontSize-16)/2, # position button internet
1492 40, 5+2*fontSize+10+2*fontSize+10, # position dsl
1493 width-40-20, fontSize, # size dsl
1495 "skin_default/buttons/button_green_off.png",
1496 20, 5+2*fontSize+10+2*fontSize+10+(fontSize-16)/2, # position button dsl
1497 "skin_default/buttons/button_green.png",
1498 20, 5+2*fontSize+10+2*fontSize+10+(fontSize-16)/2, # position button dsl
1499 40, 5+2*fontSize+10+3*fontSize+10, # position wlan
1500 width-40-20, fontSize, # size wlan
1502 "skin_default/buttons/button_green_off.png",
1503 20, 5+2*fontSize+10+3*fontSize+10+(fontSize-16)/2, # position button wlan
1504 "skin_default/buttons/button_green.png",
1505 20, 5+2*fontSize+10+3*fontSize+10+(fontSize-16)/2, # position button wlan
1510 buttonsGap, buttonsVPos, "skin_default/buttons/red.png", buttonsGap, buttonsVPos,
1511 buttonsGap+140+buttonsGap, buttonsVPos, "skin_default/buttons/green.png", buttonsGap+140+buttonsGap, buttonsVPos,
1514 Screen.__init__(self, session)
1515 HelpableScreen.__init__(self)
1516 # TRANSLATORS: keep it short, this is a button
1517 self["key_red"] = Button(_("Reset"))
1518 # TRANSLATORS: keep it short, this is a button
1519 self["key_green"] = Button(_("Toggle WLAN"))
1520 self._mailboxActive = False
1521 if fritzbox.info[FBF_tamActive] is not None:
1522 # TRANSLATORS: keep it short, this is a button
1523 self["key_yellow"] = Button(_("Toggle Mailbox"))
1524 self["menuActions"] = ActionMap(["OkCancelActions", "ColorActions", "NumberActions", "EPGSelectActions"],
1526 "cancel": self._exit,
1529 "green": self._toggleWlan,
1530 "yellow": (lambda: self._toggleMailbox(-1)),
1531 "0": (lambda: self._toggleMailbox(0)),
1532 "1": (lambda: self._toggleMailbox(1)),
1533 "2": (lambda: self._toggleMailbox(2)),
1534 "3": (lambda: self._toggleMailbox(3)),
1535 "4": (lambda: self._toggleMailbox(4)),
1536 "info": self._getInfo,
1538 # TRANSLATORS: keep it short, this is a help text
1539 self.helpList.append((self["menuActions"], "ColorActions", [("yellow", _("Toggle all mailboxes"))]))
1540 # TRANSLATORS: keep it short, this is a help text
1541 self.helpList.append((self["menuActions"], "NumberActions", [("0", _("Toggle 1. mailbox"))]))
1542 # TRANSLATORS: keep it short, this is a help text
1543 self.helpList.append((self["menuActions"], "NumberActions", [("1", _("Toggle 2. mailbox"))]))
1544 # TRANSLATORS: keep it short, this is a help text
1545 self.helpList.append((self["menuActions"], "NumberActions", [("2", _("Toggle 3. mailbox"))]))
1546 # TRANSLATORS: keep it short, this is a help text
1547 self.helpList.append((self["menuActions"], "NumberActions", [("3", _("Toggle 4. mailbox"))]))
1548 # TRANSLATORS: keep it short, this is a help text
1549 self.helpList.append((self["menuActions"], "NumberActions", [("4", _("Toggle 5. mailbox"))]))
1550 self["FBFMailbox"] = Label(_('Mailbox'))
1551 self["mailbox_inactive"] = Pixmap()
1552 self["mailbox_active"] = Pixmap()
1553 self["mailbox_active"].hide()
1555 self["menuActions"] = ActionMap(["OkCancelActions", "ColorActions", "EPGSelectActions"],
1557 "cancel": self._exit,
1559 "green": self._toggleWlan,
1561 "info": self._getInfo,
1564 # TRANSLATORS: keep it short, this is a help text
1565 self.helpList.append((self["menuActions"], "OkCancelActions", [("cancel", _("Quit"))]))
1566 # TRANSLATORS: keep it short, this is a help text
1567 self.helpList.append((self["menuActions"], "OkCancelActions", [("ok", _("Quit"))]))
1568 # TRANSLATORS: keep it short, this is a help text
1569 self.helpList.append((self["menuActions"], "ColorActions", [("green", _("Toggle WLAN"))]))
1570 # TRANSLATORS: keep it short, this is a help text
1571 self.helpList.append((self["menuActions"], "ColorActions", [("red", _("Reset"))]))
1572 # TRANSLATORS: keep it short, this is a help text
1573 self.helpList.append((self["menuActions"], "EPGSelectActions", [("info", _("Refresh status"))]))
1575 self["FBFInfo"] = Label(_('Getting status from FRITZ!Box Fon...'))
1577 self["FBFInternet"] = Label('Internet')
1578 self["internet_inactive"] = Pixmap()
1579 self["internet_active"] = Pixmap()
1580 self["internet_active"].hide()
1582 self["FBFDsl"] = Label('DSL')
1583 self["dsl_inactive"] = Pixmap()
1584 self["dsl_inactive"].hide()
1585 self["dsl_active"] = Pixmap()
1586 self["dsl_active"].hide()
1588 self["FBFWlan"] = Label('WLAN ')
1589 self["wlan_inactive"] = Pixmap()
1590 self["wlan_inactive"].hide()
1591 self["wlan_active"] = Pixmap()
1592 self["wlan_active"].hide()
1593 self._wlanActive = False
1595 if fritzbox.info[FBF_dectActive] is not None:
1596 self["FBFDect"] = Label('DECT')
1597 self["dect_inactive"] = Pixmap()
1598 self["dect_active"] = Pixmap()
1599 self["dect_active"].hide()
1601 if fritzbox.info[FBF_faxActive] is not None:
1602 self["FBFFax"] = Label('Fax')
1603 self["fax_inactive"] = Pixmap()
1604 self["fax_active"] = Pixmap()
1605 self["fax_active"].hide()
1607 if fritzbox.info[FBF_rufumlActive] is not None:
1608 self["FBFRufuml"] = Label(_('Call redirection'))
1609 self["rufuml_inactive"] = Pixmap()
1610 self["rufuml_active"] = Pixmap()
1611 self["rufuml_active"].hide()
1613 self._timer = eTimer()
1614 self._timer.callback.append(self._getInfo)
1615 self.onShown.append(lambda: self._timer.start(5000))
1616 self.onHide.append(self._timer.stop)
1618 self.onLayoutFinish.append(self.setWindowTitle)
1620 def setWindowTitle(self):
1621 # TRANSLATORS: this is a window title.
1622 self.setTitle(_("FRITZ!Box Fon Status"))
1625 fritzbox.getInfo(self._fillMenu)
1627 def _fillMenu(self, status):
1628 (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive) = status
1629 self._wlanActive = (wlanState[0] == '1')
1630 self._mailboxActive = False
1632 if not self.has_key("FBFInfo"): # screen is closed already
1636 self["FBFInfo"].setText(boxInfo.replace(', ', '\n'))
1638 self["FBFInfo"].setText('BoxInfo ' + _('Status not available'))
1642 self["FBFInternet"].setText('Internet ' + _('IP Address:') + ' ' + ipAddress + '\n' + _('Connected since') + ' ' + upTime)
1644 self["FBFInternet"].setText('Internet ' + _('IP Address:') + ' ' + ipAddress)
1645 self["internet_inactive"].hide()
1646 self["internet_active"].show()
1648 self["internet_active"].hide()
1649 self["internet_inactive"].show()
1652 if dslState[0] == '5':
1653 self["dsl_inactive"].hide()
1654 self["dsl_active"].show()
1656 self["FBFDsl"].setText('DSL ' + dslState[1])
1658 self["dsl_active"].hide()
1659 self["dsl_inactive"].show()
1661 self["FBFDsl"].setText('DSL ' + _('Status not available'))
1662 self["dsl_active"].hide()
1663 self["dsl_inactive"].hide()
1666 if wlanState[0 ] == '1':
1667 self["wlan_inactive"].hide()
1668 self["wlan_active"].show()
1670 if wlanState[1] == '0':
1671 message += ' ' + _('not encrypted')
1673 message += ' ' + _('encrypted')
1675 if wlanState[2] == '0':
1676 message = message + ', ' + _('no device active')
1677 elif wlanState[2] == '1':
1678 message = message + ', ' + _('one device active')
1680 message = message + ', ' + wlanState[2] + ' ' + _('devices active')
1681 self["FBFWlan"].setText(message)
1683 self["wlan_active"].hide()
1684 self["wlan_inactive"].show()
1685 self["FBFWlan"].setText('WLAN')
1687 self["FBFWlan"].setText('WLAN ' + _('Status not available'))
1688 self["wlan_active"].hide()
1689 self["wlan_inactive"].hide()
1691 if fritzbox.info[FBF_tamActive]:
1692 if not tamActive or tamActive[0] == 0:
1693 self._mailboxActive = False
1694 self["mailbox_active"].hide()
1695 self["mailbox_inactive"].show()
1696 self["FBFMailbox"].setText(_('No mailbox active'))
1698 self._mailboxActive = True
1702 message = message + str(i) + ','
1703 message = message[:-1] + ')'
1704 self["mailbox_inactive"].hide()
1705 self["mailbox_active"].show()
1706 if tamActive[0] == 1:
1707 self["FBFMailbox"].setText(_('One mailbox active') + ' ' + message)
1709 self["FBFMailbox"].setText(str(tamActive[0]) + ' ' + _('mailboxes active') + ' ' + message)
1711 if fritzbox.info[FBF_dectActive] and dectActive:
1712 self["dect_inactive"].hide()
1713 self["dect_active"].show()
1715 self["FBFDect"].setText(_('No DECT phone registered'))
1718 self["FBFDect"].setText(_('One DECT phone registered'))
1720 self["FBFDect"].setText(str(dectActive) + ' ' + _('DECT phones registered'))
1722 if fritzbox.info[FBF_faxActive] and faxActive:
1723 self["fax_inactive"].hide()
1724 self["fax_active"].show()
1725 self["FBFFax"].setText(_('Software fax active'))
1727 if fritzbox.info[FBF_rufumlActive] is not None and rufumlActive is not None:
1728 if rufumlActive == 0:
1729 self["rufuml_active"].hide()
1730 self["rufuml_inactive"].show()
1731 self["FBFRufuml"].setText(_('No call redirection active'))
1733 self["rufuml_inactive"].hide()
1734 self["rufuml_active"].show()
1735 if rufumlActive == 1:
1736 self["FBFRufuml"].setText(_('One call redirection active'))
1738 self["FBFRufuml"].setText(str(rufumlActive) + ' ' + _('call redirections active'))
1741 debug("[FritzCallFBF] _fillMenu: " + traceback.format_exc())
1743 def _toggleWlan(self):
1744 if self._wlanActive:
1745 debug("[FritzMenu] toggleWlan off")
1746 fritzbox.changeWLAN('0')
1748 debug("[FritzMenu] toggleWlan off")
1749 fritzbox.changeWLAN('1')
1751 def _toggleMailbox(self, which):
1752 debug("[FritzMenu] toggleMailbox")
1753 if fritzbox.info[FBF_tamActive]:
1754 debug("[FritzMenu] toggleMailbox off")
1755 fritzbox.changeMailbox(which)
1766 class FritzDisplayCalls(Screen, HelpableScreen):
1768 def __init__(self, session, text=""): #@UnusedVariable # pylint: disable-msg=W0613
1769 self.width = DESKTOP_WIDTH * scaleH(75, 85)/100
1770 self.height = DESKTOP_HEIGHT * 0.75
1771 dateFieldWidth = scaleH(180, 105)
1773 lengthFieldWidth = scaleH(55, 45)
1774 scrollbarWidth = scaleH(35, 35)
1775 entriesWidth = self.width -scaleH(40, 5) -5
1776 hereFieldWidth = entriesWidth -dirFieldWidth -5 -dateFieldWidth -5 -lengthFieldWidth -scrollbarWidth
1777 fieldWidth = entriesWidth -dirFieldWidth -5 -5 -scrollbarWidth
1778 fontSize = scaleV(22, 20)
1779 itemHeight = 2*fontSize+5
1780 entriesHeight = self.height -scaleV(15, 10) -5 -fontSize -5 -5 -5 -40 -5
1781 buttonGap = (self.width -4*140)/5
1782 buttonV = self.height -40
1783 debug("[FritzDisplayCalls] width: " + str(self.width))
1785 <screen name="FritzDisplayCalls" position="center,center" size="%d,%d" title="Phone calls" >
1786 <eLabel position="0,0" size="%d,2" backgroundColor="#aaaaaa" />
1787 <widget name="statusbar" position="%d,%d" size="%d,%d" font="Regular;%d" backgroundColor="#aaaaaa" transparent="1" />
1788 <eLabel position="0,%d" size="%d,2" backgroundColor="#aaaaaa" />
1789 <widget source="entries" render="Listbox" position="%d,%d" size="%d,%d" scrollbarMode="showOnDemand" transparent="1">
1790 <convert type="TemplatedMultiContent">
1792 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
1793 MultiContentEntryPixmapAlphaTest(pos = (%d,%d), size = (%d,%d), png = 2), # index 1 i direction pixmap
1794 MultiContentEntryText(pos = (%d,%d), size = (%d,%d), font=1, flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER, text = 3), # index 2 is remote name/number
1795 MultiContentEntryText(pos = (%d,%d), size = (%d,%d), font=0, flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER, text = 4), # index 3 is length of call
1796 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
1798 "fonts": [gFont("Regular", %d), gFont("Regular", %d)],
1803 <eLabel position="0,%d" size="%d,2" backgroundColor="#aaaaaa" />
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 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
1808 <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" />
1809 <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" />
1810 <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" />
1811 <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" />
1813 # scaleH(90, 75), scaleV(100, 78), # position
1814 self.width, self.height, # size
1815 self.width, # eLabel width
1816 scaleH(40, 5), scaleV(10, 5), # statusbar position
1817 self.width, fontSize+5, # statusbar size
1818 scaleV(21, 21), # statusbar font size
1819 scaleV(10, 5)+5+fontSize+5, # eLabel position vertical
1820 self.width, # eLabel width
1821 scaleH(40, 5), scaleV(10, 5)+5+fontSize+5+5, # entries position
1822 entriesWidth, entriesHeight, # entries size
1823 5+dirFieldWidth+5, fontSize+5, dateFieldWidth, fontSize, # date pos/size
1824 5, (itemHeight-dirFieldWidth)/2, dirFieldWidth, dirFieldWidth, # dir pos/size
1825 5+dirFieldWidth+5, 5, fieldWidth, fontSize, # caller pos/size
1826 2+dirFieldWidth+2+dateFieldWidth+5, fontSize+5, lengthFieldWidth, fontSize, # length pos/size
1827 2+dirFieldWidth+2+dateFieldWidth+5+lengthFieldWidth+5, fontSize+5, hereFieldWidth, fontSize, # my number pos/size
1828 fontSize-4, fontSize, # fontsize
1829 itemHeight, # itemHeight
1830 buttonV-5, # eLabel position vertical
1831 self.width, # eLabel width
1832 buttonGap, buttonV, "skin_default/buttons/red.png", # widget red
1833 2*buttonGap+140, buttonV, "skin_default/buttons/green.png", # widget green
1834 3*buttonGap+2*140, buttonV, "skin_default/buttons/yellow.png", # widget yellow
1835 4*buttonGap+3*140, buttonV, "skin_default/buttons/blue.png", # widget blue
1836 buttonGap, buttonV, scaleV(22, 21), # widget red
1837 2*buttonGap+140, buttonV, scaleV(22, 21), # widget green
1838 3*buttonGap+2*140, buttonV, scaleV(22, 21), # widget yellow
1839 4*buttonGap+3*140, buttonV, scaleV(22, 21), # widget blue
1841 # debug("[FritzDisplayCalls] skin: " + self.skin)
1842 Screen.__init__(self, session)
1843 HelpableScreen.__init__(self)
1845 # TRANSLATORS: keep it short, this is a button
1846 self["key_yellow"] = Button(_("All"))
1847 # TRANSLATORS: keep it short, this is a button
1848 self["key_red"] = Button(_("Missed"))
1849 # TRANSLATORS: keep it short, this is a button
1850 self["key_blue"] = Button(_("Incoming"))
1851 # TRANSLATORS: keep it short, this is a button
1852 self["key_green"] = Button(_("Outgoing"))
1854 self["setupActions"] = ActionMap(["OkCancelActions", "ColorActions"],
1856 "yellow": (lambda: self.display(FBF_ALL_CALLS)),
1857 "red": (lambda: self.display(FBF_MISSED_CALLS)),
1858 "blue": (lambda: self.display(FBF_IN_CALLS)),
1859 "green": (lambda: self.display(FBF_OUT_CALLS)),
1861 "ok": self.showEntry, }, - 2)
1863 # TRANSLATORS: keep it short, this is a help text
1864 self.helpList.append((self["setupActions"], "OkCancelActions", [("ok", _("Show details of entry"))]))
1865 # TRANSLATORS: keep it short, this is a help text
1866 self.helpList.append((self["setupActions"], "OkCancelActions", [("cancel", _("Quit"))]))
1867 # TRANSLATORS: keep it short, this is a help text
1868 self.helpList.append((self["setupActions"], "ColorActions", [("yellow", _("Display all calls"))]))
1869 # TRANSLATORS: keep it short, this is a help text
1870 self.helpList.append((self["setupActions"], "ColorActions", [("red", _("Display missed calls"))]))
1871 # TRANSLATORS: keep it short, this is a help text
1872 self.helpList.append((self["setupActions"], "ColorActions", [("blue", _("Display incoming calls"))]))
1873 # TRANSLATORS: keep it short, this is a help text
1874 self.helpList.append((self["setupActions"], "ColorActions", [("green", _("Display outgoing calls"))]))
1876 self["statusbar"] = Label(_("Getting calls from FRITZ!Box..."))
1878 self["entries"] = List(self.list)
1879 #=======================================================================
1880 # fontSize = scaleV(22, 18)
1881 # fontHeight = scaleV(24, 20)
1882 # self["entries"].l.setFont(0, gFont("Regular", fontSize))
1883 # self["entries"].l.setItemHeight(fontHeight)
1884 #=======================================================================
1885 debug("[FritzDisplayCalls] init: '''%s'''" % config.plugins.FritzCall.fbfCalls.value)
1887 self.onLayoutFinish.append(self.setWindowTitle)
1889 def setWindowTitle(self):
1890 # TRANSLATORS: this is a window title.
1891 self.setTitle(_("Phone calls"))
1896 def display(self, which=config.plugins.FritzCall.fbfCalls.value):
1897 debug("[FritzDisplayCalls] display")
1898 config.plugins.FritzCall.fbfCalls.value = which
1899 config.plugins.FritzCall.fbfCalls.save()
1900 fritzbox.getCalls(self, lambda x: self.gotCalls(x, which), which)
1902 def gotCalls(self, listOfCalls, which):
1903 debug("[FritzDisplayCalls] gotCalls")
1904 self.updateStatus(fbfCallsChoices[which] + " (" + str(len(listOfCalls)) + ")")
1906 directout = LoadPixmap(resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/images/callout.png"))
1907 directin = LoadPixmap(resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/images/callin.png"))
1908 directfailed = LoadPixmap(resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/images/callinfailed.png"))
1910 if direct == FBF_OUT_CALLS:
1912 elif direct == FBF_IN_CALLS:
1915 direct = directfailed
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)
1921 def updateStatus(self, text):
1922 if self.has_key("statusbar"):
1923 self["statusbar"].setText(_("Getting calls from FRITZ!Box...") + ' ' + text)
1925 def showEntry(self):
1926 debug("[FritzDisplayCalls] showEntry")
1927 cur = self["entries"].getCurrent()
1930 debug("[FritzDisplayCalls] showEntry %s" % (cur[0]))
1932 fullname = phonebook.search(cur[0])
1934 # we have a name for this number
1936 self.session.open(FritzOfferAction, self, number, name)
1939 fullname = resolveNumberWithAvon(number, config.plugins.FritzCall.country.value)
1942 self.session.open(FritzOfferAction, self, number, name)
1944 self.session.open(FritzOfferAction, self, number)
1946 # we do not even have a number...
1947 self.session.open(MessageBox,
1949 type=MessageBox.TYPE_INFO)
1952 class FritzOfferAction(Screen):
1954 def __init__(self, session, parent, number, name=""):
1955 # the layout will completely be recalculated in finishLayout
1957 <screen name="FritzOfferAction" title="Do what?" >
1958 <widget name="text" size="%d,%d" font="Regular;%d" />
1959 <widget name="FacePixmap" size="%d,%d" alphatest="on" />
1960 <widget name="key_red_p" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
1961 <widget name="key_green_p" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
1962 <widget name="key_yellow_p" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
1963 <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" />
1964 <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" />
1965 <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" />
1967 DESKTOP_WIDTH, DESKTOP_HEIGHT, # set maximum size
1968 scaleH(22,21), # text
1969 DESKTOP_WIDTH, DESKTOP_HEIGHT, # set maximum size
1970 "skin_default/buttons/red.png",
1971 "skin_default/buttons/green.png",
1972 "skin_default/buttons/yellow.png",
1974 debug("[FritzOfferAction] init: %s, %s" %(number, name))
1975 Screen.__init__(self, session)
1977 # TRANSLATORS: keep it short, this is a button
1978 self["key_red"] = Button(_("Lookup"))
1979 # TRANSLATORS: keep it short, this is a button
1980 self["key_green"] = Button(_("Call"))
1981 # TRANSLATORS: keep it short, this is a button
1982 self["key_yellow"] = Button(_("Save"))
1983 # TRANSLATORS: keep it short, this is a button
1984 # self["key_blue"] = Button(_("Search"))
1986 self["FritzOfferActions"] = ActionMap(["OkCancelActions", "ColorActions"],
1988 "red": self._lookup,
1989 "green": self._call,
1990 "yellow": self._add,
1991 "cancel": self._exit,
1992 "ok": self._exit, }, - 2)
1994 self._session = session
1995 self._number = number
1996 self._name = name.replace("\n", ", ")
1997 self["text"] = Label(number + "\n\n" + name.replace(", ", "\n"))
1998 self._parent = parent
1999 self._lookupState = 0
2000 self["key_red_p"] = Pixmap()
2001 self["key_green_p"] = Pixmap()
2002 self["key_yellow_p"] = Pixmap()
2003 self["FacePixmap"] = Pixmap()
2004 self.onLayoutFinish.append(self._finishLayout)
2005 self.onLayoutFinish.append(self.setWindowTitle)
2007 def setWindowTitle(self):
2008 # TRANSLATORS: this is a window title.
2009 self.setTitle(_("Do what?"))
2011 def _finishLayout(self):
2012 # pylint: disable-msg=W0142
2013 debug("[FritzCall] FritzOfferAction/finishLayout number: %s/%s" % (self._number, self._name))
2015 faceFile = findFace(self._number, self._name)
2016 picPixmap = LoadPixmap(faceFile)
2017 if not picPixmap: # that means most probably, that the picture is not 8 bit...
2018 Notifications.AddNotification(MessageBox, _("Found picture\n\n%s\n\nBut did not load. Probably not PNG, 8-bit") %faceFile, type = MessageBox.TYPE_ERROR)
2019 picPixmap = LoadPixmap(resolveFilename(SCOPE_SKIN_IMAGE, "skin_default/icons/input_error.png"))
2020 picSize = picPixmap.size()
2021 self["FacePixmap"].instance.setPixmap(picPixmap)
2024 # recalculate window size
2025 textSize = self["text"].getSize()
2026 textSize = (textSize[0]+20, textSize[1]+20) # don't know, why, but size is too small
2027 debug("[FritzCall] FritzOfferAction/finishLayout textsize: %s/%s" % textSize)
2028 textSize = eSize(*textSize)
2029 width = max(scaleH(620, 545), noButtons*145, picSize.width() + textSize.width() + 30)
2030 height = max(picSize.height()+5, textSize.height()+5, scaleV(-1, 136)) + 5 + 40 + 5
2031 buttonsGap = (width-noButtons*140)/(noButtons+1)
2032 buttonsVPos = height-40-5
2033 wSize = (width, height)
2034 wSize = eSize(*wSize)
2036 # center the smaller vertically
2037 hGap = (width-picSize.width()-textSize.width())/3
2038 picPos = (hGap, (height-50-picSize.height())/2+5)
2039 textPos = (hGap+picSize.width()+hGap, (height-50-textSize.height())/2+5)
2042 self.instance.resize(wSize)
2044 self["text"].instance.resize(textSize)
2046 self["FacePixmap"].instance.resize(picSize)
2048 buttonPos = (buttonsGap, buttonsVPos)
2049 self["key_red_p"].instance.move(ePoint(*buttonPos))
2050 self["key_red"].instance.move(ePoint(*buttonPos))
2051 buttonPos = (buttonsGap+140+buttonsGap, buttonsVPos)
2052 self["key_green_p"].instance.move(ePoint(*buttonPos))
2053 self["key_green"].instance.move(ePoint(*buttonPos))
2054 buttonPos = (buttonsGap+140+buttonsGap+140+buttonsGap, buttonsVPos)
2055 self["key_yellow_p"].instance.move(ePoint(*buttonPos))
2056 self["key_yellow"].instance.move(ePoint(*buttonPos))
2058 self["text"].instance.move(ePoint(*textPos))
2060 self["FacePixmap"].instance.move(ePoint(*picPos))
2062 self.instance.move(ePoint((DESKTOP_WIDTH-wSize.width())/2, (DESKTOP_HEIGHT-wSize.height())/2))
2064 def _setTextAndResize(self, message):
2065 # pylint: disable-msg=W0142
2066 self["text"].instance.resize(eSize(*(DESKTOP_WIDTH, DESKTOP_HEIGHT)))
2067 self["text"].setText(self._number + "\n\n" + message)
2068 self._finishLayout()
2071 phonebookLocation = config.plugins.FritzCall.phonebookLocation.value
2072 if self._lookupState == 0:
2073 self._lookupState = 1
2074 self._setTextAndResize(_("Reverse searching..."))
2075 ReverseLookupAndNotifier(self._number, self._lookedUp, "UTF-8", config.plugins.FritzCall.country.value)
2077 if self._lookupState == 1 and os.path.exists(os.path.join(phonebookLocation, "PhoneBook.csv")):
2078 self._setTextAndResize(_("Searching in Outlook export..."))
2079 self._lookupState = 2
2080 self._lookedUp(self._number, FritzOutlookCSV.findNumber(self._number, os.path.join(phonebookLocation, "PhoneBook.csv"))) #@UndefinedVariable
2083 self._lookupState = 2
2084 if self._lookupState == 2 and os.path.exists(os.path.join(phonebookLocation, "PhoneBook.ldif")):
2085 self._setTextAndResize(_("Searching in LDIF..."))
2086 self._lookupState = 0
2087 FritzLDIF.FindNumber(self._number, open(os.path.join(phonebookLocation, "PhoneBook.ldif")), self._lookedUp)
2090 self._lookupState = 0
2093 def _lookedUp(self, number, name):
2094 name = handleReverseLookupResult(name)
2096 if self._lookupState == 1:
2097 name = _("No result from reverse lookup")
2098 elif self._lookupState == 2:
2099 name = _("No result from Outlook export")
2101 name = _("No result from LDIF")
2103 self._number = number
2104 debug("[FritzOfferAction] lookedUp: " + str(name.replace(", ", "\n")))
2105 self._setTextAndResize(str(name.replace(", ", "\n")))
2108 debug("[FritzOfferAction] add: %s" %self._number)
2109 fritzbox.dial(self._number)
2113 debug("[FritzOfferAction] add: %s, %s" %(self._number, self._name))
2114 phonebook.FritzDisplayPhonebook(self._session).add(self._parent, self._number, self._name)
2121 class FritzCallPhonebook:
2123 debug("[FritzCallPhonebook] init")
2124 # Beware: strings in phonebook.phonebook have to be in utf-8!
2129 debug("[FritzCallPhonebook] reload")
2130 # Beware: strings in phonebook.phonebook have to be in utf-8!
2133 if not config.plugins.FritzCall.enable.value:
2136 phonebookFilename = os.path.join(config.plugins.FritzCall.phonebookLocation.value, "PhoneBook.txt")
2137 if config.plugins.FritzCall.phonebook.value and os.path.exists(phonebookFilename):
2138 debug("[FritzCallPhonebook] reload: read " + phonebookFilename)
2139 phonebookTxtCorrupt = False
2141 for line in open(phonebookFilename):
2143 # Beware: strings in phonebook.phonebook have to be in utf-8!
2144 line = line.decode("utf-8")
2145 except UnicodeDecodeError: # this is just for the case, somebody wrote latin1 chars into PhoneBook.txt
2147 line = line.decode("iso-8859-1")
2148 debug("[FritzCallPhonebook] Fallback to ISO-8859-1 in %s" % line)
2149 phonebookTxtCorrupt = True
2150 except UnicodeDecodeError:
2151 debug("[FritzCallPhonebook] Could not parse internal Phonebook Entry %s" % line)
2152 phonebookTxtCorrupt = True
2153 line = line.encode("utf-8")
2154 elems = line.split('#')
2157 self.phonebook[elems[0]] = elems[1]
2158 except ValueError: # how could this possibly happen?!?!
2159 debug("[FritzCallPhonebook] Could not parse internal Phonebook Entry %s" % line)
2160 phonebookTxtCorrupt = True
2162 debug("[FritzCallPhonebook] Could not parse internal Phonebook Entry %s" % line)
2163 phonebookTxtCorrupt = True
2165 #===============================================================
2166 # found = re.match("^(\d+)#(.*)$", line)
2169 # self.phonebook[found.group(1)] = found.group(2)
2170 # except ValueError: # how could this possibly happen?!?!
2171 # debug("[FritzCallPhonebook] Could not parse internal Phonebook Entry %s" % line)
2172 # phonebookTxtCorrupt = True
2174 # debug("[FritzCallPhonebook] Could not parse internal Phonebook Entry %s" % line)
2175 # phonebookTxtCorrupt = True
2176 #===============================================================
2178 if phonebookTxtCorrupt:
2179 # dump phonebook to PhoneBook.txt
2180 debug("[FritzCallPhonebook] dump Phonebook.txt")
2182 os.rename(phonebookFilename, phonebookFilename + ".bck")
2183 fNew = open(phonebookFilename, 'w')
2184 # Beware: strings in phonebook.phonebook are utf-8!
2185 for (number, name) in self.phonebook.iteritems():
2186 # Beware: strings in PhoneBook.txt have to be in utf-8!
2187 fNew.write(number + "#" + name.encode("utf-8"))
2189 except (IOError, OSError):
2190 debug("[FritzCallPhonebook] error renaming or writing to %s" %phonebookFilename)
2192 #===============================================================================
2194 # # read entries from Outlook export
2196 # # not reliable with coding yet
2198 # # import csv exported from Outlook 2007 with csv(Windows)
2199 # csvFilename = "/tmp/PhoneBook.csv"
2200 # if config.plugins.FritzCall.phonebook.value and os.path.exists(csvFilename):
2202 # readOutlookCSV(csvFilename, self.add)
2203 # os.rename(csvFilename, csvFilename + ".done")
2204 # except ImportError:
2205 # debug("[FritzCallPhonebook] CSV import failed" %line)
2206 #===============================================================================
2209 #===============================================================================
2211 # # read entries from LDIF
2213 # # import ldif exported from Thunderbird 2.0.0.19
2214 # ldifFilename = "/tmp/PhoneBook.ldif"
2215 # if config.plugins.FritzCall.phonebook.value and os.path.exists(ldifFilename):
2217 # parser = MyLDIF(open(ldifFilename), self.add)
2219 # os.rename(ldifFilename, ldifFilename + ".done")
2220 # except ImportError:
2221 # debug("[FritzCallPhonebook] LDIF import failed" %line)
2222 #===============================================================================
2224 if fritzbox and config.plugins.FritzCall.fritzphonebook.value:
2225 fritzbox.loadFritzBoxPhonebook()
2227 def search(self, number):
2228 # debug("[FritzCallPhonebook] Searching for %s" %number)
2230 if not self.phonebook or not number:
2233 if config.plugins.FritzCall.prefix.value:
2234 prefix = config.plugins.FritzCall.prefix.value
2235 if number[0] != '0':
2236 number = prefix + number
2237 # debug("[FritzCallPhonebook] search: added prefix: %s" %number)
2238 elif number[:len(prefix)] == prefix and self.phonebook.has_key(number[len(prefix):]):
2239 # debug("[FritzCallPhonebook] search: same prefix")
2240 name = self.phonebook[number[len(prefix):]]
2241 # debug("[FritzCallPhonebook] search: result: %s" %name)
2245 if not name and self.phonebook.has_key(number):
2246 name = self.phonebook[number]
2248 return name.replace(", ", "\n").strip()
2250 def add(self, number, name):
2253 @param number: number of entry
2254 @param name: name of entry, has to be in utf-8
2256 debug("[FritzCallPhonebook] add")
2257 name = name.replace("\n", ", ").replace('#','') # this is just for safety reasons. add should only be called with newlines converted into commas
2259 self.phonebook[number] = name
2260 if number and number != 0:
2261 if config.plugins.FritzCall.phonebook.value:
2263 name = name.strip() + "\n"
2264 string = "%s#%s" % (number, name)
2265 # Beware: strings in PhoneBook.txt have to be in utf-8!
2266 f = open(os.path.join(config.plugins.FritzCall.phonebookLocation.value, "PhoneBook.txt"), 'a')
2269 debug("[FritzCallPhonebook] added %s with %s to Phonebook.txt" % (number, name.strip()))
2275 def remove(self, number):
2276 if number in self.phonebook:
2277 debug("[FritzCallPhonebook] remove entry in phonebook")
2278 del self.phonebook[number]
2279 if config.plugins.FritzCall.phonebook.value:
2281 phonebookFilename = os.path.join(config.plugins.FritzCall.phonebookLocation.value, "PhoneBook.txt")
2282 debug("[FritzCallPhonebook] remove entry in Phonebook.txt")
2283 fOld = open(phonebookFilename, 'r')
2284 fNew = open(phonebookFilename + str(os.getpid()), 'w')
2285 line = fOld.readline()
2287 elems = line.split('#')
2288 if len(elems) == 2 and not elems[0] == number:
2290 line = fOld.readline()
2293 # os.remove(phonebookFilename)
2294 eBackgroundFileEraser.getInstance().erase(phonebookFilename)
2295 os.rename(phonebookFilename + str(os.getpid()), phonebookFilename)
2296 debug("[FritzCallPhonebook] removed %s from Phonebook.txt" % number)
2299 except (IOError, OSError):
2300 debug("[FritzCallPhonebook] error removing %s from %s" %(number, phonebookFilename))
2303 class FritzDisplayPhonebook(Screen, HelpableScreen, NumericalTextInput):
2305 def __init__(self, session):
2306 self.entriesWidth = DESKTOP_WIDTH * scaleH(75, 85)/100
2307 self.height = DESKTOP_HEIGHT * 0.75
2308 numberFieldWidth = scaleH(190, 150)
2309 fieldWidth = self.entriesWidth -5 -numberFieldWidth -10
2310 fontSize = scaleV(22, 18)
2311 fontHeight = scaleV(24, 20)
2312 debug("[FritzDisplayPhonebook] width: " + str(self.width))
2314 <screen name="FritzDisplayPhonebook" position="center,center" size="%d,%d" title="Phonebook" >
2315 <eLabel position="0,0" size="%d,2" backgroundColor="#aaaaaa" />
2316 <widget source="entries" render="Listbox" position="%d,%d" size="%d,%d" scrollbarMode="showOnDemand" transparent="1">
2317 <convert type="TemplatedMultiContent">
2319 MultiContentEntryText(pos = (%d,%d), size = (%d,%d), font=0, flags = RT_HALIGN_LEFT, text = 1), # index 0 is the name, index 1 is shortname
2320 MultiContentEntryText(pos = (%d,%d), size = (%d,%d), font=0, flags = RT_HALIGN_LEFT, text = 2), # index 2 is number
2322 "fonts": [gFont("Regular", %d)],
2327 <eLabel position="0,%d" size="%d,2" backgroundColor="#aaaaaa" />
2328 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
2329 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
2330 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
2331 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
2332 <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" />
2333 <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" />
2334 <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" />
2335 <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" />
2337 # scaleH(90, 75), scaleV(100, 73), # position
2338 scaleH(1100, 570), scaleV(560, 430), # size
2339 scaleH(1100, 570), # eLabel width
2340 scaleH(40, 5), scaleV(20, 5), # entries position
2341 self.entriesWidth, scaleV(488, 380), # entries size
2342 0, 0, fieldWidth, scaleH(24,20), # name pos/size
2343 fieldWidth +5, 0, numberFieldWidth, scaleH(24,20), # dir pos/size
2344 fontSize, # fontsize
2345 fontHeight, # itemHeight
2346 scaleV(518, 390), # eLabel position vertical
2347 scaleH(1100, 570), # eLabel width
2348 scaleH(20, 5), scaleV(525, 395), "skin_default/buttons/red.png", # ePixmap red
2349 scaleH(290, 145), scaleV(525, 395), "skin_default/buttons/green.png", # ePixmap green
2350 scaleH(560, 285), scaleV(525, 395), "skin_default/buttons/yellow.png", # ePixmap yellow
2351 scaleH(830, 425), scaleV(525, 395), "skin_default/buttons/blue.png", # ePixmap blue
2352 scaleH(20, 5), scaleV(525, 395), scaleV(22, 21), # widget red
2353 scaleH(290, 145), scaleV(525, 395), scaleV(22, 21), # widget green
2354 scaleH(560, 285), scaleV(525, 395), scaleV(22, 21), # widget yellow
2355 scaleH(830, 425), scaleV(525, 395), scaleV(22, 21), # widget blue
2358 # debug("[FritzDisplayCalls] skin: " + self.skin)
2359 Screen.__init__(self, session)
2360 NumericalTextInput.__init__(self)
2361 HelpableScreen.__init__(self)
2363 # TRANSLATORS: keep it short, this is a button
2364 self["key_red"] = Button(_("Delete"))
2365 # TRANSLATORS: keep it short, this is a button
2366 self["key_green"] = Button(_("New"))
2367 # TRANSLATORS: keep it short, this is a button
2368 self["key_yellow"] = Button(_("Edit"))
2369 # TRANSLATORS: keep it short, this is a button
2370 self["key_blue"] = Button(_("Search"))
2372 self["setupActions"] = ActionMap(["OkCancelActions", "ColorActions"],
2376 "yellow": self.edit,
2377 "blue": self.search,
2378 "cancel": self.exit,
2379 "ok": self.showEntry, }, - 2)
2381 # TRANSLATORS: keep it short, this is a help text
2382 self.helpList.append((self["setupActions"], "OkCancelActions", [("ok", _("Show details of entry"))]))
2383 # TRANSLATORS: keep it short, this is a help text
2384 self.helpList.append((self["setupActions"], "OkCancelActions", [("cancel", _("Quit"))]))
2385 # TRANSLATORS: keep it short, this is a help text
2386 self.helpList.append((self["setupActions"], "ColorActions", [("red", _("Delete entry"))]))
2387 # TRANSLATORS: keep it short, this is a help text
2388 self.helpList.append((self["setupActions"], "ColorActions", [("green", _("Add entry to phonebook"))]))
2389 # TRANSLATORS: keep it short, this is a help text
2390 self.helpList.append((self["setupActions"], "ColorActions", [("yellow", _("Edit selected entry"))]))
2391 # TRANSLATORS: keep it short, this is a help text
2392 self.helpList.append((self["setupActions"], "ColorActions", [("blue", _("Search (case insensitive)"))]))
2394 self["entries"] = List([])
2395 debug("[FritzCallPhonebook] displayPhonebook init")
2396 self.help_window = None
2398 self.onLayoutFinish.append(self.setWindowTitle)
2401 def setWindowTitle(self):
2402 # TRANSLATORS: this is a window title.
2403 self.setTitle(_("Phonebook"))
2405 def display(self, filterNumber=""):
2406 debug("[FritzCallPhonebook] displayPhonebook/display")
2408 # Beware: strings in phonebook.phonebook are utf-8!
2409 sortlistHelp = sorted((name.lower(), name, number) for (number, name) in phonebook.phonebook.iteritems())
2410 for (low, name, number) in sortlistHelp:
2411 if number == "01234567890":
2414 low = low.decode("utf-8")
2415 except UnicodeDecodeError: # this should definitely not happen
2417 low = low.decode("iso-8859-1")
2418 except UnicodeDecodeError:
2419 debug("[FritzCallPhonebook] displayPhonebook/display: corrupt phonebook entry for %s" % number)
2420 # self.session.open(MessageBox, _("Corrupt phonebook entry\nfor number %s\nDeleting.") %number, type = MessageBox.TYPE_ERROR)
2421 phonebook.remove(number)
2425 filterNumber = filterNumber.lower()
2426 if low.find(filterNumber) == - 1:
2428 name = name.strip().decode("utf-8")
2429 number = number.strip().decode("utf-8")
2430 comma = name.find(',')
2432 shortname = name[:comma]
2435 number = number.encode("utf-8", "replace")
2436 name = name.encode("utf-8", "replace")
2437 shortname = shortname.encode('utf-8', 'replace')
2438 self.sortlist.append((name, shortname, number))