-# -*- coding: utf-8 -*-\r
-'''\r
-$Author$\r
-$Revision$\r
-$Date$\r
-$Id$\r
-'''\r
-from Screens.Screen import Screen\r
-from Screens.MessageBox import MessageBox\r
-from Screens.NumericalTextInputHelpDialog import NumericalTextInputHelpDialog\r
-from Screens.InputBox import InputBox\r
-from Screens import Standby\r
-from Screens.HelpMenu import HelpableScreen\r
-\r
-from enigma import eTimer, eSize, ePoint #@UnresolvedImport # pylint: disable-msg=E0611\r
-from enigma import eDVBVolumecontrol\r
-from enigma import eBackgroundFileEraser\r
-#BgFileEraser = eBackgroundFileEraser.getInstance()\r
-#BgFileEraser.erase("blabla.txt")\r
-\r
-from Components.ActionMap import ActionMap\r
-from Components.Label import Label\r
-from Components.Button import Button\r
-from Components.Pixmap import Pixmap\r
-from Components.Sources.List import List\r
-from Components.config import config, ConfigSubsection, ConfigSelection, ConfigEnableDisable, getConfigListEntry, ConfigText, ConfigInteger\r
-from Components.ConfigList import ConfigListScreen\r
-from Components.Harddisk import harddiskmanager\r
-try:\r
- from Components.config import ConfigPassword\r
-except ImportError:\r
- ConfigPassword = ConfigText\r
-\r
-from Plugins.Plugin import PluginDescriptor\r
-from Tools import Notifications\r
-from Tools.NumericalTextInput import NumericalTextInput\r
-from Tools.Directories import resolveFilename, SCOPE_PLUGINS, SCOPE_SKIN_IMAGE, SCOPE_CONFIG, SCOPE_MEDIA\r
-from Tools.LoadPixmap import LoadPixmap\r
-from GlobalActions import globalActionMap # for muting\r
-\r
-from twisted.internet import reactor #@UnresolvedImport\r
-from twisted.internet.protocol import ReconnectingClientFactory #@UnresolvedImport\r
-from twisted.protocols.basic import LineReceiver #@UnresolvedImport\r
-from twisted.web.client import getPage #@UnresolvedImport\r
-\r
-from urllib import urlencode \r
-import re, time, os, hashlib, traceback\r
-\r
-from nrzuname import ReverseLookupAndNotifier, html2unicode\r
-import FritzOutlookCSV, FritzLDIF\r
-from . import _, initDebug, debug #@UnresolvedImport # pylint: disable-msg=E0611,F0401\r
-\r
-from enigma import getDesktop\r
-DESKTOP_WIDTH = getDesktop(0).size().width()\r
-DESKTOP_HEIGHT = getDesktop(0).size().height()\r
-\r
-#\r
-# this is pure magic.\r
-# It returns the first value, if HD (1280x720),\r
-# the second if SD (720x576),\r
-# else something scaled accordingly\r
-# if one of the parameters is -1, scale proportionally\r
-#\r
-def scaleH(y2, y1):\r
- if y2 == -1:\r
- y2 = y1*1280/720\r
- elif y1 == -1:\r
- y1 = y2*720/1280\r
- return scale(y2, y1, 1280, 720, DESKTOP_WIDTH)\r
-def scaleV(y2, y1):\r
- if y2 == -1:\r
- y2 = y1*720/576\r
- elif y1 == -1:\r
- y1 = y2*576/720\r
- return scale(y2, y1, 720, 576, DESKTOP_HEIGHT)\r
-def scale(y2, y1, x2, x1, x):\r
- return (y2 - y1) * (x - x1) / (x2 - x1) + y1\r
-\r
-my_global_session = None\r
-\r
-config.plugins.FritzCall = ConfigSubsection()\r
-config.plugins.FritzCall.debug = ConfigEnableDisable(default=False)\r
-#config.plugins.FritzCall.muteOnCall = ConfigSelection(choices=[(None, _("no")), ("ring", _("on ring")), ("connect", _("on connect"))])\r
-config.plugins.FritzCall.muteOnCall = ConfigSelection(choices=[(None, _("no")), ("ring", _("on ring"))])\r
-config.plugins.FritzCall.hostname = ConfigText(default="fritz.box", fixed_size=False)\r
-config.plugins.FritzCall.afterStandby = ConfigSelection(choices=[("none", _("show nothing")), ("inList", _("show as list")), ("each", _("show each call"))])\r
-config.plugins.FritzCall.filter = ConfigEnableDisable(default=False)\r
-config.plugins.FritzCall.filtermsn = ConfigText(default="", fixed_size=False)\r
-config.plugins.FritzCall.filtermsn.setUseableChars('0123456789,')\r
-config.plugins.FritzCall.filterCallList = ConfigEnableDisable(default=True)\r
-config.plugins.FritzCall.showOutgoing = ConfigEnableDisable(default=False)\r
-config.plugins.FritzCall.timeout = ConfigInteger(default=15, limits=(0, 60))\r
-config.plugins.FritzCall.lookup = ConfigEnableDisable(default=False)\r
-config.plugins.FritzCall.internal = ConfigEnableDisable(default=False)\r
-config.plugins.FritzCall.fritzphonebook = ConfigEnableDisable(default=False)\r
-config.plugins.FritzCall.phonebook = ConfigEnableDisable(default=False)\r
-config.plugins.FritzCall.addcallers = ConfigEnableDisable(default=False)\r
-config.plugins.FritzCall.enable = ConfigEnableDisable(default=False)\r
-config.plugins.FritzCall.password = ConfigPassword(default="", fixed_size=False)\r
-config.plugins.FritzCall.extension = ConfigText(default='1', fixed_size=False)\r
-config.plugins.FritzCall.extension.setUseableChars('0123456789')\r
-config.plugins.FritzCall.showType = ConfigEnableDisable(default=True)\r
-config.plugins.FritzCall.showShortcut = ConfigEnableDisable(default=False)\r
-config.plugins.FritzCall.showVanity = ConfigEnableDisable(default=False)\r
-config.plugins.FritzCall.prefix = ConfigText(default="", fixed_size=False)\r
-config.plugins.FritzCall.prefix.setUseableChars('0123456789')\r
-config.plugins.FritzCall.connectionVerbose = ConfigEnableDisable(default=True)\r
-\r
-\r
-def getMountedDevs():\r
- def handleMountpoint(loc):\r
- # debug("[FritzCall] handleMountpoint: %s" %repr(loc))\r
- mp = loc[0]\r
- while mp[-1] == '/':\r
- mp = mp[:-1]\r
- #=======================================================================\r
- # if os.path.exists(os.path.join(mp, "PhoneBook.txt")):\r
- # if os.access(os.path.join(mp, "PhoneBook.txt"), os.W_OK):\r
- # desc = ' *'\r
- # else:\r
- # desc = ' -'\r
- # else:\r
- # desc = ''\r
- # desc = loc[1] + desc\r
- #=======================================================================\r
- desc = loc[1]\r
- return (mp, desc + " (" + mp + ")")\r
-\r
- mountedDevs = [(resolveFilename(SCOPE_CONFIG), _("Flash")),\r
- (resolveFilename(SCOPE_MEDIA, "cf"), _("Compact Flash")),\r
- (resolveFilename(SCOPE_MEDIA, "usb"), _("USB Device"))]\r
- mountedDevs += map(lambda p: (p.mountpoint, (_(p.description) if p.description else "")), harddiskmanager.getMountedPartitions(True))\r
- mediaDir = resolveFilename(SCOPE_MEDIA)\r
- for p in os.listdir(mediaDir):\r
- if os.path.join(mediaDir, p) not in [path[0] for path in mountedDevs]:\r
- mountedDevs.append((os.path.join(mediaDir, p), _("Media directory")))\r
- debug("[FritzCall] getMountedDevs1: %s" %repr(mountedDevs))\r
- mountedDevs = filter(lambda path: os.path.isdir(path[0]) and os.access(path[0], os.W_OK|os.X_OK), mountedDevs)\r
- # put this after the write/executable check, that is far too slow...\r
- netDir = resolveFilename(SCOPE_MEDIA, "net")\r
- if os.path.isdir(netDir):\r
- mountedDevs += map(lambda p: (os.path.join(netDir, p), _("Network mount")), os.listdir(netDir))\r
- mountedDevs = map(handleMountpoint, mountedDevs)\r
- return mountedDevs\r
-config.plugins.FritzCall.phonebookLocation = ConfigSelection(choices=getMountedDevs())\r
-\r
-countryCodes = [\r
- ("0049", _("Germany")),\r
- ("0031", _("The Netherlands")),\r
- ("0033", _("France")),\r
- ("0039", _("Italy")),\r
- ("0041", _("Switzerland")),\r
- ("0043", _("Austria"))\r
- ]\r
-config.plugins.FritzCall.country = ConfigSelection(choices=countryCodes)\r
-\r
-FBF_ALL_CALLS = "."\r
-FBF_IN_CALLS = "1"\r
-FBF_MISSED_CALLS = "2"\r
-FBF_OUT_CALLS = "3"\r
-fbfCallsChoices = {FBF_ALL_CALLS: _("All calls"),\r
- FBF_IN_CALLS: _("Incoming calls"),\r
- FBF_MISSED_CALLS: _("Missed calls"),\r
- FBF_OUT_CALLS: _("Outgoing calls")\r
- }\r
-config.plugins.FritzCall.fbfCalls = ConfigSelection(choices=fbfCallsChoices)\r
-\r
-config.plugins.FritzCall.name = ConfigText(default="", fixed_size=False)\r
-config.plugins.FritzCall.number = ConfigText(default="", fixed_size=False)\r
-config.plugins.FritzCall.number.setUseableChars('0123456789')\r
-\r
-phonebook = None\r
-fritzbox = None\r
-\r
-avon = {}\r
-\r
-def initAvon():\r
- avonFileName = resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/avon.dat")\r
- if os.path.exists(avonFileName):\r
- for line in open(avonFileName):\r
- line = line.decode("iso-8859-1").encode('utf-8')\r
- if line[0] == '#':\r
- continue\r
- parts = line.split(':')\r
- if len(parts) == 2:\r
- avon[parts[0].replace('-','').replace('*','').replace('/','')] = parts[1]\r
-\r
-def resolveNumberWithAvon(number, countrycode):\r
- if not number or number[0] != '0':\r
- return ""\r
- \r
- countrycode = countrycode.replace('00','+')\r
- if number[:2] == '00':\r
- normNumber = '+' + number[2:]\r
- elif number[:1] == '0':\r
- normNumber = countrycode + number[1:]\r
- else: # this should can not happen, but safety first\r
- return ""\r
- \r
- # debug('normNumer: ' + normNumber)\r
- for i in reversed(range(min(10, len(number)))):\r
- if avon.has_key(normNumber[:i]):\r
- return '[' + avon[normNumber[:i]].strip() + ']'\r
- return ""\r
-\r
-def handleReverseLookupResult(name):\r
- found = re.match("NA: ([^;]*);VN: ([^;]*);STR: ([^;]*);HNR: ([^;]*);PLZ: ([^;]*);ORT: ([^;]*)", name)\r
- if found:\r
- ( name, firstname, street, streetno, zipcode, city ) = (found.group(1),\r
- found.group(2),\r
- found.group(3),\r
- found.group(4),\r
- found.group(5),\r
- found.group(6)\r
- )\r
- if firstname:\r
- name += ' ' + firstname\r
- if street or streetno or zipcode or city:\r
- name += ', '\r
- if street:\r
- name += street\r
- if streetno:\r
- name += ' ' + streetno\r
- if (street or streetno) and (zipcode or city):\r
- name += ', '\r
- if zipcode and city:\r
- name += zipcode + ' ' + city\r
- elif zipcode:\r
- name += zipcode\r
- elif city:\r
- name += city\r
- return name\r
-\r
-from xml.dom.minidom import parse\r
-cbcInfos = {}\r
-def initCbC():\r
- callbycallFileName = resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/callbycall_world.xml")\r
- if os.path.exists(callbycallFileName):\r
- dom = parse(callbycallFileName)\r
- for top in dom.getElementsByTagName("callbycalls"):\r
- for cbc in top.getElementsByTagName("country"):\r
- code = cbc.getAttribute("code").replace("+","00")\r
- cbcInfos[code] = cbc.getElementsByTagName("callbycall")\r
- else:\r
- debug("[FritzCall] initCbC: callbycallFileName does not exist?!?!")\r
-\r
-def stripCbCPrefix(number, countrycode):\r
- if number and number[:2] != "00" and cbcInfos.has_key(countrycode):\r
- for cbc in cbcInfos[countrycode]:\r
- if len(cbc.getElementsByTagName("length"))<1 or len(cbc.getElementsByTagName("prefix"))<1:\r
- debug("[FritzCall] stripCbCPrefix: entries for " + countrycode + " %s invalid")\r
- return number\r
- length = int(cbc.getElementsByTagName("length")[0].childNodes[0].data)\r
- prefix = cbc.getElementsByTagName("prefix")[0].childNodes[0].data\r
- # if re.match('^'+prefix, number):\r
- if number[:len(prefix)] == prefix:\r
- return number[length:]\r
- return number\r
-\r
-class FritzAbout(Screen):\r
-\r
- def __init__(self, session):\r
- textFieldWidth = scaleV(350, 250)\r
- width = 5 + 150 + 20 + textFieldWidth + 5 + 175 + 5\r
- height = 5 + 175 + 5 + 25 + 5\r
- self.skin = """\r
- <screen name="FritzAbout" position="center,center" size="%d,%d" title="About FritzCall" >\r
- <widget name="text" position="175,%d" size="%d,%d" font="Regular;%d" />\r
- <ePixmap position="5,37" size="150,110" pixmap="%s" transparent="1" alphatest="blend" />\r
- <ePixmap position="%d,5" size="175,175" pixmap="%s" transparent="1" alphatest="blend" />\r
- <widget name="url" position="20,185" size="%d,25" font="Regular;%d" />\r
- </screen>""" % (\r
- width, height, # size\r
- (height-scaleV(150,130)) / 2, # text vertical position\r
- textFieldWidth,\r
- scaleV(150,130), # text height\r
- scaleV(24,21), # text font size\r
- resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/images/fritz.png"), # 150x110\r
- 5 + 150 + 5 + textFieldWidth + 5, # qr code horizontal offset\r
- resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/images/website.png"), # 175x175\r
- width-40, # url width\r
- scaleV(24,21) # url font size\r
- )\r
- Screen.__init__(self, session)\r
- self["aboutActions"] = ActionMap(["OkCancelActions"],\r
- {\r
- "cancel": self.exit,\r
- "ok": self.exit,\r
- }, -2)\r
- self["text"] = Label(\r
- "FritzCall Plugin" + "\n\n" +\r
- "$Author$"[1:-2] + "\n" +\r
- "$Revision$"[1:-2] + "\n" + \r
- "$Date$"[1:23] + "\n"\r
- )\r
- self["url"] = Label("http://wiki.blue-panel.com/index.php/FritzCall")\r
- self.onLayoutFinish.append(self.setWindowTitle)\r
-\r
- def setWindowTitle(self):\r
- # TRANSLATORS: this is a window title.\r
- self.setTitle(_("About FritzCall"))\r
-\r
- def exit(self):\r
- self.close()\r
-\r
-FBF_boxInfo = 0\r
-FBF_upTime = 1\r
-FBF_ipAddress = 2\r
-FBF_wlanState = 3\r
-FBF_dslState = 4\r
-FBF_tamActive = 5\r
-FBF_dectActive = 6\r
-FBF_faxActive = 7\r
-FBF_rufumlActive = 8\r
-\r
-class FritzCallFBF:\r
- def __init__(self):\r
- debug("[FritzCallFBF] __init__")\r
- self._callScreen = None\r
- self._md5LoginTimestamp = None\r
- self._md5Sid = '0000000000000000'\r
- self._callTimestamp = 0\r
- self._callList = []\r
- self._callType = config.plugins.FritzCall.fbfCalls.value\r
- self._phoneBookID = '0'\r
- self.info = None # (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive)\r
- self.getInfo(None)\r
- self.blacklist = ([], [])\r
- self.readBlacklist()\r
-\r
- def _notify(self, text):\r
- debug("[FritzCallFBF] notify: " + text)\r
- self._md5LoginTimestamp = None\r
- if self._callScreen:\r
- debug("[FritzCallFBF] notify: try to close callScreen")\r
- self._callScreen.close()\r
- self._callScreen = None\r
- Notifications.AddNotification(MessageBox, text, type=MessageBox.TYPE_ERROR, timeout=config.plugins.FritzCall.timeout.value)\r
- \r
- def _login(self, callback=None):\r
- debug("[FritzCallFBF] _login")\r
- if self._callScreen:\r
- self._callScreen.updateStatus(_("login"))\r
- if self._md5LoginTimestamp and ((time.time() - self._md5LoginTimestamp) < float(9.5*60)) and self._md5Sid != '0000000000000000': # new login after 9.5 minutes inactivity \r
- debug("[FritzCallFBF] _login: renew timestamp: " + time.ctime(self._md5LoginTimestamp) + " time: " + time.ctime())\r
- self._md5LoginTimestamp = time.time()\r
- callback(None)\r
- else:\r
- debug("[FritzCallFBF] _login: not logged in or outdated login")\r
- # http://fritz.box/cgi-bin/webcm?getpage=../html/login_sid.xml\r
- parms = urlencode({'getpage':'../html/login_sid.xml'})\r
- url = "http://%s/cgi-bin/webcm" % (config.plugins.FritzCall.hostname.value)\r
- debug("[FritzCallFBF] _login: '" + url + "' parms: '" + parms + "'")\r
- getPage(url,\r
- method="POST",\r
- headers={'Content-Type': "application/x-www-form-urlencoded", 'Content-Length': str(len(parms))\r
- }, postdata=parms).addCallback(lambda x: self._md5Login(callback,x)).addErrback(lambda x:self._oldLogin(callback,x))\r
-\r
- def _oldLogin(self, callback, error): \r
- debug("[FritzCallFBF] _oldLogin: " + repr(error))\r
- self._md5LoginTimestamp = None\r
- if config.plugins.FritzCall.password.value != "":\r
- parms = "login:command/password=%s" % (config.plugins.FritzCall.password.value)\r
- url = "http://%s/cgi-bin/webcm" % (config.plugins.FritzCall.hostname.value)\r
- debug("[FritzCallFBF] _oldLogin: '" + url + "' parms: '" + parms + "'")\r
- getPage(url,\r
- method="POST",\r
- agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",\r
- headers={'Content-Type': "application/x-www-form-urlencoded", 'Content-Length': str(len(parms))\r
- }, postdata=parms).addCallback(self._gotPageLogin).addCallback(callback).addErrback(self._errorLogin)\r
- elif callback:\r
- debug("[FritzCallFBF] _oldLogin: no password, calling " + repr(callback))\r
- callback(None)\r
-\r
- def _md5Login(self, callback, sidXml):\r
- def buildResponse(challenge, text):\r
- debug("[FritzCallFBF] _md5Login7buildResponse: challenge: " + challenge + ' text: ' + text)\r
- text = (challenge + '-' + text).decode('utf-8','ignore').encode('utf-16-le')\r
- for i in range(len(text)):\r
- if ord(text[i]) > 255:\r
- text[i] = '.'\r
- md5 = hashlib.md5()\r
- md5.update(text)\r
- debug("[FritzCallFBF] md5Login/buildResponse: " + md5.hexdigest())\r
- return challenge + '-' + md5.hexdigest()\r
-\r
- debug("[FritzCallFBF] _md5Login")\r
- found = re.match('.*<SID>([^<]*)</SID>', sidXml, re.S)\r
- if found:\r
- self._md5Sid = found.group(1)\r
- debug("[FritzCallFBF] _md5Login: SID "+ self._md5Sid)\r
- else:\r
- debug("[FritzCallFBF] _md5Login: no sid! That must be an old firmware.")\r
- self._oldLogin(callback, 'No error')\r
- return\r
-\r
- debug("[FritzCallFBF] _md5Login: renew timestamp: " + time.ctime(self._md5LoginTimestamp) + " time: " + time.ctime())\r
- self._md5LoginTimestamp = time.time()\r
- if sidXml.find('<iswriteaccess>0</iswriteaccess>') != -1:\r
- debug("[FritzCallFBF] _md5Login: logging in")\r
- found = re.match('.*<Challenge>([^<]*)</Challenge>', sidXml, re.S)\r
- if found:\r
- challenge = found.group(1)\r
- debug("[FritzCallFBF] _md5Login: challenge " + challenge)\r
- else:\r
- challenge = None\r
- debug("[FritzCallFBF] _md5Login: login necessary and no challenge! That is terribly wrong.")\r
- parms = urlencode({\r
- 'getpage':'../html/de/menus/menu2.html', # 'var:pagename':'home', 'var:menu':'home', \r
- 'login:command/response': buildResponse(challenge, config.plugins.FritzCall.password.value),\r
- })\r
- url = "http://%s/cgi-bin/webcm" % (config.plugins.FritzCall.hostname.value)\r
- debug("[FritzCallFBF] _md5Login: '" + url + "' parms: '" + parms + "'")\r
- getPage(url,\r
- method="POST",\r
- agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",\r
- headers={'Content-Type': "application/x-www-form-urlencoded", 'Content-Length': str(len(parms))\r
- }, postdata=parms).addCallback(self._gotPageLogin).addCallback(callback).addErrback(self._errorLogin)\r
- elif callback: # we assume value 1 here, no login necessary\r
- debug("[FritzCallFBF] _md5Login: no login necessary")\r
- callback(None)\r
-\r
- def _gotPageLogin(self, html):\r
- if self._callScreen:\r
- self._callScreen.updateStatus(_("login verification"))\r
- debug("[FritzCallFBF] _gotPageLogin: verify login")\r
- start = html.find('<p class="errorMessage">FEHLER: ')\r
- if start != -1:\r
- start = start + len('<p class="errorMessage">FEHLER: ')\r
- text = _("FRITZ!Box - Error logging in: %s") + html[start, html.find('</p>', start)]\r
- self._notify(text)\r
- else:\r
- if self._callScreen:\r
- self._callScreen.updateStatus(_("login ok"))\r
-\r
- found = re.match('.*<input type="hidden" name="sid" value="([^\"]*)"', html, re.S)\r
- if found:\r
- self._md5Sid = found.group(1)\r
- debug("[FritzCallFBF] _gotPageLogin: found sid: " + self._md5Sid)\r
-\r
- def _errorLogin(self, error):\r
- global fritzbox\r
- debug("[FritzCallFBF] _errorLogin: %s" % (error))\r
- text = _("FRITZ!Box - Error logging in: %s\nDisabling plugin.") % error.getErrorMessage()\r
- # config.plugins.FritzCall.enable.value = False\r
- fritzbox = None\r
- self._notify(text)\r
-\r
- def _logout(self):\r
- if self._md5LoginTimestamp:\r
- self._md5LoginTimestamp = None\r
- parms = urlencode({\r
- 'getpage':'../html/de/menus/menu2.html', # 'var:pagename':'home', 'var:menu':'home', \r
- 'login:command/logout':'bye bye Fritz'\r
- })\r
- url = "http://%s/cgi-bin/webcm" % (config.plugins.FritzCall.hostname.value)\r
- debug("[FritzCallFBF] logout: '" + url + "' parms: '" + parms + "'")\r
- getPage(url,\r
- method="POST",\r
- agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",\r
- headers={'Content-Type': "application/x-www-form-urlencoded", 'Content-Length': str(len(parms))\r
- }, postdata=parms).addErrback(self._errorLogout)\r
-\r
- def _errorLogout(self, error):\r
- debug("[FritzCallFBF] _errorLogout: %s" % (error))\r
- text = _("FRITZ!Box - Error logging out: %s") % error.getErrorMessage()\r
- self._notify(text)\r
-\r
- def loadFritzBoxPhonebook(self):\r
- debug("[FritzCallFBF] loadFritzBoxPhonebook")\r
- if config.plugins.FritzCall.fritzphonebook.value:\r
- self._phoneBookID = '0'\r
- debug("[FritzCallFBF] loadFritzBoxPhonebook: logging in")\r
- self._login(self._loadFritzBoxPhonebook)\r
-\r
- def _loadFritzBoxPhonebook(self, html):\r
- if html:\r
- #===================================================================\r
- # found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)\r
- # if found:\r
- # self._errorLoad('Login: ' + found.group(1))\r
- # return\r
- #===================================================================\r
- start = html.find('<p class="errorMessage">FEHLER: ')\r
- if start != -1:\r
- start = start + len('<p class="errorMessage">FEHLER: ')\r
- self._errorLoad('Login: ' + html[start, html.find('</p>', start)])\r
- return\r
- parms = urlencode({\r
- 'getpage':'../html/de/menus/menu2.html',\r
- 'var:lang':'de',\r
- 'var:pagename':'fonbuch',\r
- 'var:menu':'fon',\r
- 'sid':self._md5Sid,\r
- 'telcfg:settings/Phonebook/Books/Select':self._phoneBookID, # this selects always the first phonbook\r
- })\r
- url = "http://%s/cgi-bin/webcm" % (config.plugins.FritzCall.hostname.value)\r
- debug("[FritzCallFBF] _loadFritzBoxPhonebook: '" + url + "' parms: '" + parms + "'")\r
- getPage(url,\r
- method="POST",\r
- agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",\r
- headers={'Content-Type': "application/x-www-form-urlencoded", 'Content-Length': str(len(parms))\r
- }, postdata=parms).addCallback(self._parseFritzBoxPhonebook).addErrback(self._errorLoad)\r
-\r
- def _parseFritzBoxPhonebook(self, html):\r
- debug("[FritzCallFBF] _parseFritzBoxPhonebook")\r
-\r
- # first, let us get the charset\r
- found = re.match('.*<meta http-equiv=content-type content="text/html; charset=([^"]*)">', html, re.S)\r
- if found:\r
- charset = found.group(1)\r
- debug("[FritzCallFBF] _parseFritzBoxPhonebook: found charset: " + charset)\r
- html = html2unicode(html.decode(charset), charset).encode('utf-8') # this looks silly, but has to be\r
- else: # this is kind of emergency conversion...\r
- try:\r
- debug("[FritzCallFBF] _parseFritzBoxPhonebook: try charset utf-8")\r
- charset = 'utf-8'\r
- html = html2unicode(html.decode('utf-8'), 'utf-8').encode('utf-8') # this looks silly, but has to be\r
- except UnicodeDecodeError:\r
- debug("[FritzCallFBF] _parseFritzBoxPhonebook: try charset iso-8859-1")\r
- charset = 'iso-8859-1'\r
- html = html2unicode(html.decode('iso-8859-1'), 'iso-8859-1').encode('utf-8') # this looks silly, but has to be\r
-\r
- # if re.search('document.write\(TrFon1\(\)', html):\r
- if html.find('document.write(TrFon1()') != -1:\r
- #===============================================================================\r
- # 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)\r
- # 7170 (FW 29.04.70) 22.03.2009\r
- # 7141 (FW 40.04.68) 22.03.2009\r
- # We expect one line with TrFonName followed by several lines with\r
- # TrFonNr(Type,Number,Shortcut,Vanity), which all belong to the name in TrFonName.\r
- #===============================================================================\r
- debug("[FritzCallFBF] _parseFritzBoxPhonebook: discovered newer firmware")\r
- found = re.match('.*<input type="hidden" name="telcfg:settings/Phonebook/Books/Name(\d+)" value="[Dd]reambox" id="uiPostPhonebookName\d+" disabled>', html, re.S)\r
- if found:\r
- phoneBookID = found.group(1)\r
- debug("[FritzCallFBF] _parseFritzBoxPhonebook: found dreambox phonebook with id: " + phoneBookID)\r
- if self._phoneBookID != phoneBookID:\r
- self._phoneBookID = phoneBookID\r
- debug("[FritzCallFBF] _parseFritzBoxPhonebook: reload phonebook")\r
- self._loadFritzBoxPhonebook(self._phoneBookID) # reload with dreambox phonebook\r
- return\r
-\r
- entrymask = re.compile('(TrFonName\("[^"]+", "[^"]+", "[^"]*"(?:, "[^"]*")?\);.*?)document.write\(TrFon1\(\)', re.S)\r
- entries = entrymask.finditer(html)\r
- for entry in entries:\r
- # TrFonName (id, name, category)\r
- # TODO: replace re.match?\r
- found = re.match('TrFonName\("[^"]*", "([^"]+)", "[^"]*"(?:, "[^"]*")?\);', entry.group(1))\r
- if found:\r
- debug("[FritzCallFBF] _parseFritzBoxPhonebook: name: %s" %found.group(1))\r
- name = found.group(1).replace(',','').strip()\r
- else:\r
- debug("[FritzCallFBF] _parseFritzBoxPhonebook: could not find name")\r
- continue\r
- # TrFonNr (type, rufnr, code, vanity)\r
- detailmask = re.compile('TrFonNr\("([^"]*)", "([^"]*)", "([^"]*)", "([^"]*)"\);', re.S)\r
- details = detailmask.finditer(entry.group(1))\r
- for found in details:\r
- thisnumber = found.group(2).strip()\r
- if not thisnumber:\r
- debug("[FritzCallFBF] Ignoring entry with empty number for '''%s'''" % (name))\r
- continue\r
- else:\r
- thisname = name\r
- callType = found.group(1)\r
- if config.plugins.FritzCall.showType.value:\r
- if callType == "mobile":\r
- thisname = thisname + " (" + _("mobile") + ")"\r
- elif callType == "home":\r
- thisname = thisname + " (" + _("home") + ")"\r
- elif callType == "work":\r
- thisname = thisname + " (" + _("work") + ")"\r
-\r
- if config.plugins.FritzCall.showShortcut.value and found.group(3):\r
- thisname = thisname + ", " + _("Shortcut") + ": " + found.group(3)\r
- if config.plugins.FritzCall.showVanity.value and found.group(4):\r
- thisname = thisname + ", " + _("Vanity") + ": " + found.group(4)\r
-\r
- debug("[FritzCallFBF] Adding '''%s''' with '''%s''' from FRITZ!Box Phonebook!" % (thisname.strip(), thisnumber))\r
- # Beware: strings in phonebook.phonebook have to be in utf-8!\r
- phonebook.phonebook[thisnumber] = thisname\r
-\r
- # elif re.search('document.write\(TrFon\(', html):\r
- elif html.find('document.write(TrFon(') != -1:\r
- #===============================================================================\r
- # Old Style: 7050 (FW 14.04.33)\r
- # We expect one line with TrFon(No,Name,Number,Shortcut,Vanity)\r
- # Encoding should be plain Ascii...\r
- #=============================================================================== \r
- entrymask = re.compile('TrFon\("[^"]*", "([^"]*)", "([^"]*)", "([^"]*)", "([^"]*)"\)', re.S)\r
- entries = entrymask.finditer(html)\r
- for found in entries:\r
- name = found.group(1).strip().replace(',','')\r
- # debug("[FritzCallFBF] pos: %s name: %s" %(found.group(0),name))\r
- thisnumber = found.group(2).strip()\r
- if config.plugins.FritzCall.showShortcut.value and found.group(3):\r
- name = name + ", " + _("Shortcut") + ": " + found.group(3)\r
- if config.plugins.FritzCall.showVanity.value and found.group(4):\r
- name = name + ", " + _("Vanity") + ": " + found.group(4)\r
- if thisnumber:\r
- # name = name.encode('utf-8')\r
- debug("[FritzCallFBF] Adding '''%s''' with '''%s''' from FRITZ!Box Phonebook!" % (name, thisnumber))\r
- # Beware: strings in phonebook.phonebook have to be in utf-8!\r
- phonebook.phonebook[thisnumber] = name\r
- else:\r
- debug("[FritzCallFBF] ignoring empty number for %s" % name)\r
- continue\r
- elif self._md5Sid == '0000000000000000': # retry, it could be a race condition\r
- debug("[FritzCallFBF] _parseFritzBoxPhonebook: retry loading phonebook")\r
- self.loadFritzBoxPhonebook()\r
- else:\r
- self._notify(_("Could not parse FRITZ!Box Phonebook entry"))\r
-\r
- def _errorLoad(self, error):\r
- debug("[FritzCallFBF] _errorLoad: %s" % (error))\r
- text = _("FRITZ!Box - Could not load phonebook: %s") % error.getErrorMessage()\r
- self._notify(text)\r
-\r
- def getCalls(self, callScreen, callback, callType):\r
- #\r
- # call sequence must be:\r
- # - login\r
- # - getPage -> _gotPageLogin\r
- # - loginCallback (_getCalls)\r
- # - getPage -> _getCalls1\r
- debug("[FritzCallFBF] getCalls")\r
- self._callScreen = callScreen\r
- self._callType = callType\r
- if (time.time() - self._callTimestamp) > 180: \r
- debug("[FritzCallFBF] getCalls: outdated data, login and get new ones: " + time.ctime(self._callTimestamp) + " time: " + time.ctime())\r
- self._callTimestamp = time.time()\r
- self._login(lambda x:self._getCalls(callback, x))\r
- elif not self._callList:\r
- debug("[FritzCallFBF] getCalls: time is ok, but no callList")\r
- self._getCalls1(callback)\r
- else:\r
- debug("[FritzCallFBF] getCalls: time is ok, callList is ok")\r
- self._gotPageCalls(callback)\r
-\r
- def _getCalls(self, callback, html):\r
- if html:\r
- #===================================================================\r
- # found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)\r
- # if found:\r
- # self._errorCalls('Login: ' + found.group(1))\r
- # return\r
- #===================================================================\r
- start = html.find('<p class="errorMessage">FEHLER: ')\r
- if start != -1:\r
- start = start + len('<p class="errorMessage">FEHLER: ')\r
- self._errorCalls('Login: ' + html[start, html.find('</p>', start)])\r
- return\r
- #\r
- # we need this to fill Anrufliste.csv\r
- # http://repeater1/cgi-bin/webcm?getpage=../html/de/menus/menu2.html&var:lang=de&var:menu=fon&var:pagename=foncalls\r
- #\r
- debug("[FritzCallFBF] _getCalls")\r
- if html:\r
- #===================================================================\r
- # found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)\r
- # if found:\r
- # text = _("FRITZ!Box - Error logging in: %s") + found.group(1)\r
- # self._notify(text)\r
- # return\r
- #===================================================================\r
- start = html.find('<p class="errorMessage">FEHLER: ')\r
- if start != -1:\r
- start = start + len('<p class="errorMessage">FEHLER: ')\r
- self._notify(_("FRITZ!Box - Error logging in: %s") + html[start, html.find('</p>', start)])\r
- return\r
-\r
- if self._callScreen:\r
- self._callScreen.updateStatus(_("preparing"))\r
- parms = urlencode({'getpage':'../html/de/menus/menu2.html', 'var:lang':'de', 'var:pagename':'foncalls', 'var:menu':'fon', 'sid':self._md5Sid})\r
- url = "http://%s/cgi-bin/webcm?%s" % (config.plugins.FritzCall.hostname.value, parms)\r
- getPage(url).addCallback(lambda x:self._getCalls1(callback)).addErrback(self._errorCalls) #@UnusedVariable # pylint: disable-msg=W0613\r
-\r
- def _getCalls1(self, callback):\r
- #\r
- # finally we should have successfully lgged in and filled the csv\r
- #\r
- debug("[FritzCallFBF] _getCalls1")\r
- if self._callScreen:\r
- self._callScreen.updateStatus(_("finishing"))\r
- parms = urlencode({'getpage':'../html/de/FRITZ!Box_Anrufliste.csv', 'sid':self._md5Sid})\r
- url = "http://%s/cgi-bin/webcm?%s" % (config.plugins.FritzCall.hostname.value, parms)\r
- getPage(url).addCallback(lambda x:self._gotPageCalls(callback, x)).addErrback(self._errorCalls)\r
-\r
- def _gotPageCalls(self, callback, csv=""):\r
- def resolveNumber(number):\r
- if number.isdigit():\r
- if config.plugins.FritzCall.internal.value and len(number) > 3 and number[0] == "0":\r
- number = number[1:]\r
- # strip CbC prefix\r
- number = stripCbCPrefix(number, config.plugins.FritzCall.country.value)\r
- if config.plugins.FritzCall.prefix.value and number and number[0] != '0': # should only happen for outgoing\r
- number = config.plugins.FritzCall.prefix.value + number\r
- name = phonebook.search(number)\r
- if name:\r
- #===========================================================\r
- # found = re.match('(.*?)\n.*', name)\r
- # if found:\r
- # name = found.group(1)\r
- #===========================================================\r
- end = name.find('\n')\r
- if end != -1:\r
- name = name[:end]\r
- number = name\r
- else:\r
- name = resolveNumberWithAvon(number, config.plugins.FritzCall.country.value)\r
- if name:\r
- number = number + ' ' + name\r
- elif number == "":\r
- number = _("UNKNOWN")\r
- # if len(number) > 20: number = number[:20]\r
- return number\r
-\r
- if csv:\r
- debug("[FritzCallFBF] _gotPageCalls: got csv, setting callList")\r
- if self._callScreen:\r
- self._callScreen.updateStatus(_("done"))\r
- # check for error: wrong password or password not set... TODO\r
- # found = re.search('Melden Sie sich mit dem Kennwort der FRITZ!Box an', csv)\r
- if csv.find('Melden Sie sich mit dem Kennwort der FRITZ!Box an') != -1:\r
- 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.")\r
- # self.session.open(MessageBox, text, MessageBox.TYPE_ERROR, timeout=config.plugins.FritzCall.timeout.value)\r
- self._notify(text)\r
- return\r
-\r
- csv = csv.decode('iso-8859-1', 'replace').encode('utf-8', 'replace')\r
- lines = csv.splitlines()\r
- self._callList = lines\r
- elif self._callList:\r
- debug("[FritzCallFBF] _gotPageCalls: got no csv, but have callList")\r
- if self._callScreen:\r
- self._callScreen.updateStatus(_("done, using last list"))\r
- lines = self._callList\r
- else:\r
- debug("[FritzCallFBF] _gotPageCalls: got no csv, no callList, laving")\r
- return\r
- \r
- callListL = []\r
- if config.plugins.FritzCall.filter.value and config.plugins.FritzCall.filterCallList.value:\r
- filtermsns = map(lambda x: x.strip(), config.plugins.FritzCall.filtermsn.value.split(","))\r
- debug("[FritzCallFBF] _gotPageCalls: filtermsns %s" % (repr(filtermsns)))\r
- for line in lines:\r
- # Typ;e;Rufnummer;Nebenstelle;Eigene Rufnummer;Dauer\r
- elems = line.split(';')\r
- # found = re.match("^(" + self._callType + ");([^;]*);([^;]*);([^;]*);([^;]*);([^;]*);([^;]*)", line)\r
- if len(elems) != 7: # this happens, if someone puts a ';' in the name in the FBF phonebook\r
- debug("[FritzCallFBF] _gotPageCalls: len != 7: %s" % (line))\r
- if len(elems) == 7 and (self._callType == '.' or elems[0] == self._callType):\r
- # debug("[FritzCallFBF] _gotPageCalls: elems %s" % (elems))\r
- direct = elems[0]\r
- date = elems[1]\r
- length = elems[6]\r
- remote = resolveNumber(elems[3])\r
- if not remote and direct != FBF_OUT_CALLS and elems[2]:\r
- remote = elems[2]\r
- #===============================================================\r
- # found1 = re.match('Internet: (.*)', found.group(6))\r
- # if found1:\r
- # here = found1.group(1)\r
- # else:\r
- # here = found.group(6)\r
- #===============================================================\r
- here = elems[5]\r
- start = here.find('Internet: ')\r
- if start != -1:\r
- start += len('Internet: ')\r
- here = here[start:]\r
- else:\r
- here = elems[5]\r
- if config.plugins.FritzCall.filter.value and config.plugins.FritzCall.filterCallList.value:\r
- # debug("[FritzCallFBF] _gotPageCalls: check %s" % (here))\r
- if here not in filtermsns:\r
- # debug("[FritzCallFBF] _gotPageCalls: skip %s" % (here))\r
- continue\r
- here = resolveNumber(here)\r
-\r
- number = stripCbCPrefix(elems[3], config.plugins.FritzCall.country.value)\r
- if config.plugins.FritzCall.prefix.value and number and number[0] != '0': # should only happen for outgoing\r
- number = config.plugins.FritzCall.prefix.value + number\r
- callListL.append((number, date, direct, remote, length, here))\r
-\r
- # debug("[FritzCallFBF] _gotPageCalls result:\n" + text\r
-\r
- if callback:\r
- # debug("[FritzCallFBF] _gotPageCalls call callback with\n" + text\r
- callback(callListL)\r
- self._callScreen = None\r
-\r
- def _errorCalls(self, error):\r
- debug("[FritzCallFBF] _errorCalls: %s" % (error))\r
- text = _("FRITZ!Box - Could not load calls: %s") % error.getErrorMessage()\r
- self._notify(text)\r
-\r
- def dial(self, number):\r
- ''' initiate a call to number '''\r
- self._login(lambda x: self._dial(number, x))\r
- \r
- def _dial(self, number, html):\r
- if html:\r
- #===================================================================\r
- # found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)\r
- # if found:\r
- # self._errorDial('Login: ' + found.group(1))\r
- # return\r
- #===================================================================\r
- start = html.find('<p class="errorMessage">FEHLER: ')\r
- if start != -1:\r
- start = start + len('<p class="errorMessage">FEHLER: ')\r
- self._errorDial('Login: ' + html[start, html.find('</p>', start)])\r
- return\r
- url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value\r
- parms = urlencode({\r
- 'getpage':'../html/de/menus/menu2.html',\r
- 'var:pagename':'fonbuch',\r
- 'var:menu':'home',\r
- 'telcfg:settings/UseClickToDial':'1',\r
- 'telcfg:settings/DialPort':config.plugins.FritzCall.extension.value,\r
- 'telcfg:command/Dial':number,\r
- 'sid':self._md5Sid\r
- })\r
- debug("[FritzCallFBF] dial url: '" + url + "' parms: '" + parms + "'")\r
- getPage(url,\r
- method="POST",\r
- agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",\r
- headers={\r
- 'Content-Type': "application/x-www-form-urlencoded",\r
- 'Content-Length': str(len(parms))},\r
- postdata=parms).addCallback(self._okDial).addErrback(self._errorDial)\r
-\r
- def _okDial(self, html): #@UnusedVariable # pylint: disable-msg=W0613\r
- debug("[FritzCallFBF] okDial")\r
-\r
- def _errorDial(self, error):\r
- debug("[FritzCallFBF] errorDial: $s" % error)\r
- text = _("FRITZ!Box - Dialling failed: %s") % error.getErrorMessage()\r
- self._notify(text)\r
-\r
- def changeWLAN(self, statusWLAN):\r
- ''' get status info from FBF '''\r
- debug("[FritzCallFBF] changeWLAN start")\r
- if not statusWLAN or (statusWLAN != '1' and statusWLAN != '0'):\r
- return\r
- self._login(lambda x: self._changeWLAN(statusWLAN, x))\r
- \r
- def _changeWLAN(self, statusWLAN, html):\r
- if html:\r
- #===================================================================\r
- # found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)\r
- # if found:\r
- # self._errorChangeWLAN('Login: ' + found.group(1))\r
- # return\r
- #===================================================================\r
- start = html.find('<p class="errorMessage">FEHLER: ')\r
- if start != -1:\r
- start = start + len('<p class="errorMessage">FEHLER: ')\r
- self._errorChangeWLAN('Login: ' + html[start, html.find('</p>', start)])\r
- return\r
- url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value\r
- parms = urlencode({\r
- 'getpage':'../html/de/menus/menu2.html',\r
- 'var:lang':'de',\r
- 'var:pagename':'wlan',\r
- 'var:menu':'wlan',\r
- 'wlan:settings/ap_enabled':str(statusWLAN),\r
- 'sid':self._md5Sid\r
- })\r
- debug("[FritzCallFBF] changeWLAN url: '" + url + "' parms: '" + parms + "'")\r
- getPage(url,\r
- method="POST",\r
- agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",\r
- headers={\r
- 'Content-Type': "application/x-www-form-urlencoded",\r
- 'Content-Length': str(len(parms))},\r
- postdata=parms).addCallback(self._okChangeWLAN).addErrback(self._errorChangeWLAN)\r
-\r
- def _okChangeWLAN(self, html): #@UnusedVariable # pylint: disable-msg=W0613\r
- debug("[FritzCallFBF] _okChangeWLAN")\r
-\r
- def _errorChangeWLAN(self, error):\r
- debug("[FritzCallFBF] _errorChangeWLAN: $s" % error)\r
- text = _("FRITZ!Box - Failed changing WLAN: %s") % error.getErrorMessage()\r
- self._notify(text)\r
-\r
- def changeMailbox(self, whichMailbox):\r
- ''' switch mailbox on/off '''\r
- debug("[FritzCallFBF] changeMailbox start: " + str(whichMailbox))\r
- self._login(lambda x: self._changeMailbox(whichMailbox, x))\r
-\r
- def _changeMailbox(self, whichMailbox, html):\r
- if html:\r
- #===================================================================\r
- # found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)\r
- # if found:\r
- # self._errorChangeMailbox('Login: ' + found.group(1))\r
- # return\r
- #===================================================================\r
- start = html.find('<p class="errorMessage">FEHLER: ')\r
- if start != -1:\r
- start = start + len('<p class="errorMessage">FEHLER: ')\r
- self._errorChangeMailbox('Login: ' + html[start, html.find('</p>', start)])\r
- return\r
- debug("[FritzCallFBF] _changeMailbox")\r
- url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value\r
- if whichMailbox == -1:\r
- for i in range(5):\r
- if self.info[FBF_tamActive][i+1]:\r
- state = '0'\r
- else:\r
- state = '1'\r
- parms = urlencode({\r
- 'tam:settings/TAM'+str(i)+'/Active':state,\r
- 'sid':self._md5Sid\r
- })\r
- debug("[FritzCallFBF] changeMailbox url: '" + url + "' parms: '" + parms + "'")\r
- getPage(url,\r
- method="POST",\r
- agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",\r
- headers={\r
- 'Content-Type': "application/x-www-form-urlencoded",\r
- 'Content-Length': str(len(parms))},\r
- postdata=parms).addCallback(self._okChangeMailbox).addErrback(self._errorChangeMailbox)\r
- elif whichMailbox > 4:\r
- debug("[FritzCallFBF] changeMailbox invalid mailbox number")\r
- else:\r
- if self.info[FBF_tamActive][whichMailbox+1]:\r
- state = '0'\r
- else:\r
- state = '1'\r
- parms = urlencode({\r
- 'tam:settings/TAM'+str(whichMailbox)+'/Active':state,\r
- 'sid':self._md5Sid\r
- })\r
- debug("[FritzCallFBF] changeMailbox url: '" + url + "' parms: '" + parms + "'")\r
- getPage(url,\r
- method="POST",\r
- agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",\r
- headers={\r
- 'Content-Type': "application/x-www-form-urlencoded",\r
- 'Content-Length': str(len(parms))},\r
- postdata=parms).addCallback(self._okChangeMailbox).addErrback(self._errorChangeMailbox)\r
-\r
- def _okChangeMailbox(self, html): #@UnusedVariable # pylint: disable-msg=W0613\r
- debug("[FritzCallFBF] _okChangeMailbox")\r
-\r
- def _errorChangeMailbox(self, error):\r
- debug("[FritzCallFBF] _errorChangeMailbox: $s" % error)\r
- text = _("FRITZ!Box - Failed changing Mailbox: %s") % error.getErrorMessage()\r
- self._notify(text)\r
-\r
- def getInfo(self, callback):\r
- ''' get status info from FBF '''\r
- debug("[FritzCallFBF] getInfo")\r
- self._login(lambda x:self._getInfo(callback, x))\r
- \r
- def _getInfo(self, callback, html):\r
- # http://192.168.178.1/cgi-bin/webcm?getpage=../html/de/menus/menu2.html&var:lang=de&var:pagename=home&var:menu=home\r
- debug("[FritzCallFBF] _getInfo: verify login")\r
- if html:\r
- #===================================================================\r
- # found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)\r
- # if found:\r
- # self._errorGetInfo('Login: ' + found.group(1))\r
- # return\r
- #===================================================================\r
- start = html.find('<p class="errorMessage">FEHLER: ')\r
- if start != -1:\r
- start = start + len('<p class="errorMessage">FEHLER: ')\r
- self._errorGetInfo('Login: ' + html[start, html.find('</p>', start)])\r
- return\r
-\r
- url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value\r
- parms = urlencode({\r
- 'getpage':'../html/de/menus/menu2.html',\r
- 'var:lang':'de',\r
- 'var:pagename':'home',\r
- 'var:menu':'home',\r
- 'sid':self._md5Sid\r
- })\r
- debug("[FritzCallFBF] _getInfo url: '" + url + "' parms: '" + parms + "'")\r
- getPage(url,\r
- method="POST",\r
- agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",\r
- headers={\r
- 'Content-Type': "application/x-www-form-urlencoded",\r
- 'Content-Length': str(len(parms))},\r
- postdata=parms).addCallback(lambda x:self._okGetInfo(callback,x)).addErrback(self._errorGetInfo)\r
-\r
- def _okGetInfo(self, callback, html):\r
- def readInfo(html):\r
- if self.info:\r
- (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive) = self.info\r
- else:\r
- (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive) = (None, None, None, None, None, None, None, None, None)\r
-\r
- debug("[FritzCallFBF] _okGetInfo/readinfo")\r
- 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)\r
- if found:\r
- boxInfo = found.group(1)+ ', ' + found.group(2)\r
- boxInfo = boxInfo.replace(' ',' ')\r
- # debug("[FritzCallFBF] _okGetInfo Boxinfo: " + boxInfo)\r
- else:\r
- found = re.match('.*<p class="ac">([^<]*)</p>', html, re.S)\r
- if found:\r
- # debug("[FritzCallFBF] _okGetInfo Boxinfo: " + found.group(1))\r
- boxInfo = found.group(1)\r
-\r
- if html.find('home_coninf.txt') != -1:\r
- url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value\r
- parms = urlencode({\r
- 'getpage':'../html/de/home/home_coninf.txt',\r
- 'sid':self._md5Sid\r
- })\r
- # debug("[FritzCallFBF] get coninfo: url: '" + url + "' parms: '" + parms + "'")\r
- getPage(url,\r
- method="POST",\r
- agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",\r
- headers={\r
- 'Content-Type': "application/x-www-form-urlencoded",\r
- 'Content-Length': str(len(parms))},\r
- postdata=parms).addCallback(lambda x:self._okSetConInfo(callback,x)).addErrback(self._errorGetInfo)\r
- else:\r
- found = re.match('.*if \(isNaN\(jetzt\)\)\s*return "";\s*var str = "([^"]*)";', html, re.S)\r
- if found:\r
- # debug("[FritzCallFBF] _okGetInfo Uptime: " + found.group(1))\r
- upTime = found.group(1)\r
- else:\r
- found = re.match('.*str = g_pppSeit \+"([^<]*)<br>"\+mldIpAdr;', html, re.S)\r
- if found:\r
- # debug("[FritzCallFBF] _okGetInfo Uptime: " + found.group(1))\r
- upTime = found.group(1)\r
- \r
- found = re.match(".*IpAdrDisplay\('([.\d]+)'\)", html, re.S)\r
- if found:\r
- # debug("[FritzCallFBF] _okGetInfo IpAdrDisplay: " + found.group(1))\r
- ipAddress = found.group(1)\r
-\r
- if html.find('g_tamActive') != -1:\r
- entries = re.compile('if \("(\d)" == "1"\) {\s*g_tamActive \+= 1;\s*}', re.S).finditer(html)\r
- tamActive = [0, False, False, False, False, False]\r
- i = 1\r
- for entry in entries:\r
- state = entry.group(1)\r
- if state == '1':\r
- tamActive[0] += 1\r
- tamActive[i] = True\r
- i += 1\r
- # debug("[FritzCallFBF] _okGetInfo tamActive: " + str(tamActive))\r
- \r
- if html.find('home_dect.txt') != -1:\r
- url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value\r
- parms = urlencode({\r
- 'getpage':'../html/de/home/home_dect.txt',\r
- 'sid':self._md5Sid\r
- })\r
- # debug("[FritzCallFBF] get coninfo: url: '" + url + "' parms: '" + parms + "'")\r
- getPage(url,\r
- method="POST",\r
- agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",\r
- headers={\r
- 'Content-Type': "application/x-www-form-urlencoded",\r
- 'Content-Length': str(len(parms))},\r
- postdata=parms).addCallback(lambda x:self._okSetDect(callback,x)).addErrback(self._errorGetInfo)\r
- else:\r
- if html.find('countDect2') != -1:\r
- entries = re.compile('if \("1" == "1"\) countDect2\+\+;', re.S).findall(html)\r
- dectActive = len(entries)\r
- # debug("[FritzCallFBF] _okGetInfo dectActive: " + str(dectActive))\r
-\r
- found = re.match('.*var g_intFaxActive = "0";\s*if \("1" != ""\) {\s*g_intFaxActive = "1";\s*}\s*', html, re.S)\r
- if found:\r
- faxActive = True\r
- # debug("[FritzCallFBF] _okGetInfo faxActive")\r
-\r
- if html.find('cntRufumleitung') != -1:\r
- entries = re.compile('mode = "1";\s*ziel = "[^"]+";\s*if \(mode == "1" \|\| ziel != ""\)\s*{\s*g_RufumleitungAktiv = true;', re.S).findall(html)\r
- rufumlActive = len(entries)\r
- entries = re.compile('if \("([^"]*)"=="([^"]*)"\) isAllIncoming\+\+;', re.S).finditer(html)\r
- isAllIncoming = 0\r
- for entry in entries:\r
- # debug("[FritzCallFBF] _okGetInfo rufumlActive add isAllIncoming")\r
- if entry.group(1) == entry.group(2):\r
- isAllIncoming += 1\r
- if isAllIncoming == 2 and rufumlActive > 0:\r
- rufumlActive -= 1\r
- # debug("[FritzCallFBF] _okGetInfo rufumlActive: " + str(rufumlActive))\r
-\r
- # /cgi-bin/webcm?getpage=../html/de/home/home_dsl.txt\r
- # { "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": "" } \r
- if html.find('home_dsl.txt') != -1:\r
- url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value\r
- parms = urlencode({\r
- 'getpage':'../html/de/home/home_dsl.txt',\r
- 'sid':self._md5Sid\r
- })\r
- # debug("[FritzCallFBF] get dsl state: url: '" + url + "' parms: '" + parms + "'")\r
- getPage(url,\r
- method="POST",\r
- agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",\r
- headers={\r
- 'Content-Type': "application/x-www-form-urlencoded",\r
- 'Content-Length': str(len(parms))},\r
- postdata=parms).addCallback(lambda x:self._okSetDslState(callback,x)).addErrback(self._errorGetInfo)\r
- else:\r
- found = re.match('.*function DslStateDisplay \(state\){\s*var state = "(\d+)";', html, re.S)\r
- if found:\r
- # debug("[FritzCallFBF] _okGetInfo DslState: " + found.group(1))\r
- dslState = [ found.group(1), None ] # state, speed\r
- found = re.match('.*function DslStateDisplay \(state\){\s*var state = "\d+";.*?if \("3130" != "0"\) str = "([^"]*)";', html, re.S)\r
- if found:\r
- # debug("[FritzCallFBF] _okGetInfo DslSpeed: " + found.group(1).strip())\r
- dslState[1] = found.group(1).strip()\r
- \r
- # /cgi-bin/webcm?getpage=../html/de/home/home_wlan.txt\r
- # { "ap_enabled": "1", "active_stations": "0", "encryption": "4", "wireless_stickandsurf_enabled": "0", "is_macfilter_active": "0", "wmm_enabled": "1", "wlan_state": [ "end" ] }\r
- if html.find('home_wlan.txt') != -1:\r
- url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value\r
- parms = urlencode({\r
- 'getpage':'../html/de/home/home_wlan.txt',\r
- 'sid':self._md5Sid\r
- })\r
- # debug("[FritzCallFBF] get wlan state: url: '" + url + "' parms: '" + parms + "'")\r
- getPage(url,\r
- method="POST",\r
- agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",\r
- headers={\r
- 'Content-Type': "application/x-www-form-urlencoded",\r
- 'Content-Length': str(len(parms))},\r
- postdata=parms).addCallback(lambda x:self._okSetWlanState(callback,x)).addErrback(self._errorGetInfo)\r
- else:\r
- found = re.match('.*function WlanStateLed \(state\){.*?return StateLed\("(\d+)"\);\s*}', html, re.S)\r
- if found:\r
- # debug("[FritzCallFBF] _okGetInfo WlanState: " + found.group(1))\r
- wlanState = [ found.group(1), 0, 0 ] # state, encryption, number of devices\r
- found = re.match('.*var (?:g_)?encryption = "(\d+)";', html, re.S)\r
- if found:\r
- # debug("[FritzCallFBF] _okGetInfo WlanEncrypt: " + found.group(1))\r
- wlanState[1] = found.group(1)\r
-\r
- return (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive)\r
-\r
- debug("[FritzCallFBF] _okGetInfo")\r
- info = readInfo(html)\r
- debug("[FritzCallFBF] _okGetInfo info: " + str(info))\r
- self.info = info\r
- if callback:\r
- callback(info)\r
-\r
- def _okSetDect(self, callback, html):\r
- # debug("[FritzCallFBF] _okSetDect: " + html)\r
- # found = re.match('.*"connection_status":"(\d+)".*"connection_ip":"([.\d]+)".*"connection_detail":"([^"]+)".*"connection_uptime":"([^"]+)"', html, re.S)\r
- if html.find('"dect_enabled": "1"') != -1:\r
- # debug("[FritzCallFBF] _okSetDect: dect_enabled")\r
- found = re.match('.*"dect_device_list":.*\[([^\]]*)\]', html, re.S)\r
- if found:\r
- # debug("[FritzCallFBF] _okSetDect: dect_device_list: %s" %(found.group(1)))\r
- entries = re.compile('"1"', re.S).findall(found.group(1))\r
- dectActive = len(entries)\r
- (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dummy, faxActive, rufumlActive) = self.info\r
- self.info = (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive)\r
- debug("[FritzCallFBF] _okSetDect info: " + str(self.info))\r
- if callback:\r
- callback(self.info)\r
-\r
- def _okSetConInfo(self, callback, html):\r
- # debug("[FritzCallFBF] _okSetConInfo: " + html)\r
- # found = re.match('.*"connection_status":"(\d+)".*"connection_ip":"([.\d]+)".*"connection_detail":"([^"]+)".*"connection_uptime":"([^"]+)"', html, re.S)\r
- found = re.match('.*"connection_ip": "([.\d]+)".*"connection_uptime": "([^"]+)"', html, re.S)\r
- if found:\r
- # debug("[FritzCallFBF] _okSetConInfo: connection_ip: %s upTime: %s" %( found.group(1), found.group(2)))\r
- ipAddress = found.group(1)\r
- upTime = found.group(2)\r
- (boxInfo, dummy, dummy, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive) = self.info\r
- self.info = (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive)\r
- debug("[FritzCallFBF] _okSetWlanState info: " + str(self.info))\r
- else:\r
- found = re.match('.*_ip": "([.\d]+)".*"connection_uptime": "([^"]+)"', html, re.S)\r
- if found:\r
- # debug("[FritzCallFBF] _okSetConInfo: _ip: %s upTime: %s" %( found.group(1), found.group(2)))\r
- ipAddress = found.group(1)\r
- upTime = found.group(2)\r
- (boxInfo, dummy, dummy, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive) = self.info\r
- self.info = (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive)\r
- debug("[FritzCallFBF] _okSetWlanState info: " + str(self.info))\r
- if callback:\r
- callback(self.info)\r
-\r
- def _okSetWlanState(self, callback, html):\r
- # debug("[FritzCallFBF] _okSetWlanState: " + html)\r
- found = re.match('.*"ap_enabled": "(\d+)"', html, re.S)\r
- if found:\r
- # debug("[FritzCallFBF] _okSetWlanState: ap_enabled: " + found.group(1))\r
- wlanState = [ found.group(1), None, None ]\r
- found = re.match('.*"encryption": "(\d+)"', html, re.S)\r
- if found:\r
- # debug("[FritzCallFBF] _okSetWlanState: encryption: " + found.group(1))\r
- wlanState[1] = found.group(1)\r
- found = re.match('.*"active_stations": "(\d+)"', html, re.S)\r
- if found:\r
- # debug("[FritzCallFBF] _okSetWlanState: active_stations: " + found.group(1))\r
- wlanState[2] = found.group(1)\r
- (boxInfo, upTime, ipAddress, dummy, dslState, tamActive, dectActive, faxActive, rufumlActive) = self.info\r
- self.info = (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive)\r
- debug("[FritzCallFBF] _okSetWlanState info: " + str(self.info))\r
- if callback:\r
- callback(self.info)\r
-\r
- def _okSetDslState(self, callback, html):\r
- # debug("[FritzCallFBF] _okSetDslState: " + html)\r
- found = re.match('.*"dsl_carrier_state": "(\d+)"', html, re.S)\r
- if found:\r
- # debug("[FritzCallFBF] _okSetDslState: dsl_carrier_state: " + found.group(1))\r
- dslState = [ found.group(1), None ]\r
- found = re.match('.*"dsl_ds_nrate": "(\d+)"', html, re.S)\r
- if found:\r
- # debug("[FritzCallFBF] _okSetDslState: dsl_ds_nrate: " + found.group(1))\r
- dslState[1] = found.group(1)\r
- found = re.match('.*"dsl_us_nrate": "(\d+)"', html, re.S)\r
- if found:\r
- # debug("[FritzCallFBF] _okSetDslState: dsl_us_nrate: " + found.group(1))\r
- dslState[1] = dslState[1] + '/' + found.group(1)\r
- (boxInfo, upTime, ipAddress, wlanState, dummy, tamActive, dectActive, faxActive, rufumlActive) = self.info\r
- self.info = (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive)\r
- debug("[FritzCallFBF] _okSetDslState info: " + str(self.info))\r
- if callback:\r
- callback(self.info)\r
-\r
- def _errorGetInfo(self, error):\r
- debug("[FritzCallFBF] _errorGetInfo: %s" % (error))\r
- text = _("FRITZ!Box - Error getting status: %s") % error.getErrorMessage()\r
- self._notify(text)\r
- # linkP = open("/tmp/FritzCall_errorGetInfo.htm", "w")\r
- # linkP.write(error)\r
- # linkP.close()\r
-\r
- def reset(self):\r
- self._login(self._reset)\r
-\r
- def _reset(self, html):\r
- # 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\r
- if html:\r
- #===================================================================\r
- # found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)\r
- # if found:\r
- # self._errorReset('Login: ' + found.group(1))\r
- # return\r
- #===================================================================\r
- start = html.find('<p class="errorMessage">FEHLER: ')\r
- if start != -1:\r
- start = start + len('<p class="errorMessage">FEHLER: ')\r
- self._errorReset('Login: ' + html[start, html.find('</p>', start)])\r
- return\r
- if self._callScreen:\r
- self._callScreen.close()\r
- url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value\r
- parms = urlencode({\r
- 'getpage':'../html/reboot.html',\r
- 'var:lang':'de',\r
- 'var:pagename':'reset',\r
- 'var:menu':'system',\r
- 'logic:command/reboot':'../gateway/commands/saveconfig.html',\r
- 'sid':self._md5Sid\r
- })\r
- debug("[FritzCallFBF] _reset url: '" + url + "' parms: '" + parms + "'")\r
- getPage(url,\r
- method="POST",\r
- agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",\r
- headers={\r
- 'Content-Type': "application/x-www-form-urlencoded",\r
- 'Content-Length': str(len(parms))},\r
- postdata=parms)\r
-\r
- def _okReset(self, html): #@UnusedVariable # pylint: disable-msg=W0613\r
- debug("[FritzCallFBF] _okReset")\r
-\r
- def _errorReset(self, error):\r
- debug("[FritzCallFBF] _errorReset: %s" % (error))\r
- text = _("FRITZ!Box - Error resetting: %s") % error.getErrorMessage()\r
- self._notify(text)\r
-\r
- def readBlacklist(self):\r
- self._login(self._readBlacklist)\r
- \r
- def _readBlacklist(self, html):\r
- if html:\r
- #===================================================================\r
- # found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)\r
- # if found:\r
- # self._errorBlacklist('Login: ' + found.group(1))\r
- # return\r
- #===================================================================\r
- start = html.find('<p class="errorMessage">FEHLER: ')\r
- if start != -1:\r
- start = start + len('<p class="errorMessage">FEHLER: ')\r
- self._errorBlacklist('Login: ' + html[start, html.find('</p>', start)])\r
- return\r
- # http://fritz.box/cgi-bin/webcm?getpage=../html/de/menus/menu2.html&var:lang=de&var:menu=fon&var:pagename=sperre\r
- url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value\r
- parms = urlencode({\r
- 'getpage':'../html/de/menus/menu2.html',\r
- 'var:lang':'de',\r
- 'var:pagename':'sperre',\r
- 'var:menu':'fon',\r
- 'sid':self._md5Sid\r
- })\r
- debug("[FritzCallFBF] _readBlacklist url: '" + url + "' parms: '" + parms + "'")\r
- getPage(url,\r
- method="POST",\r
- agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",\r
- headers={\r
- 'Content-Type': "application/x-www-form-urlencoded",\r
- 'Content-Length': str(len(parms))},\r
- postdata=parms).addCallback(self._okBlacklist).addErrback(self._errorBlacklist)\r
-\r
- def _okBlacklist(self, html):\r
- debug("[FritzCallFBF] _okBlacklist")\r
- entries = re.compile('<script type="text/javascript">document.write\(Tr(Out|In)\("\d+", "(\d+)", "\w*"\)\);</script>', re.S).finditer(html)\r
- self.blacklist = ([], [])\r
- for entry in entries:\r
- if entry.group(1) == "In":\r
- self.blacklist[0].append(entry.group(2))\r
- else:\r
- self.blacklist[1].append(entry.group(2))\r
- debug("[FritzCallFBF] _okBlacklist: %s" % repr(self.blacklist))\r
-\r
- def _errorBlacklist(self, error):\r
- debug("[FritzCallFBF] _errorBlacklist: %s" % (error))\r
- text = _("FRITZ!Box - Error getting blacklist: %s") % error.getErrorMessage()\r
- self._notify(text)\r
-\r
-#===============================================================================\r
-# def hangup(self):\r
-# ''' hangup call on port; not used for now '''\r
-# url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value\r
-# parms = urlencode({\r
-# 'id':'uiPostForm',\r
-# 'name':'uiPostForm',\r
-# 'login:command/password': config.plugins.FritzCall.password.value,\r
-# 'telcfg:settings/UseClickToDial':'1',\r
-# 'telcfg:settings/DialPort':config.plugins.FritzCall.extension.value,\r
-# 'telcfg:command/Hangup':'',\r
-# 'sid':self._md5Sid\r
-# })\r
-# debug("[FritzCallFBF] hangup url: '" + url + "' parms: '" + parms + "'")\r
-# getPage(url,\r
-# method="POST",\r
-# headers={\r
-# 'Content-Type': "application/x-www-form-urlencoded",\r
-# 'Content-Length': str(len(parms))},\r
-# postdata=parms)\r
-#===============================================================================\r
-\r
-fritzbox = None\r
-\r
-class FritzMenu(Screen, HelpableScreen):\r
- def __init__(self, session):\r
- fontSize = scaleV(24, 21) # indeed this is font size +2\r
- noButtons = 2 # reset, wlan\r
-\r
- if not fritzbox or not fritzbox.info:\r
- return\r
-\r
- if fritzbox.info[FBF_tamActive]:\r
- noButtons += 1 # toggle mailboxes\r
- width = max(DESKTOP_WIDTH - scaleH(500, 250), noButtons*140+(noButtons+1)*10)\r
- # boxInfo 2 lines, gap, internet 2 lines, gap, dsl/wlan each 1 line, gap, buttons\r
- height = 5 + 2*fontSize + 10 + 2*fontSize + 10 + 2*fontSize + 10 + 40 + 5\r
- if fritzbox.info[FBF_tamActive] is not None:\r
- height += fontSize\r
- if fritzbox.info[FBF_dectActive] is not None:\r
- height += fontSize\r
- if fritzbox.info[FBF_faxActive] is not None:\r
- height += fontSize\r
- if fritzbox.info[FBF_rufumlActive] is not None:\r
- height += fontSize\r
- buttonsGap = (width-noButtons*140)/(noButtons+1)\r
- buttonsVPos = height-40-5\r
-\r
- varLinePos = 4\r
- if fritzbox.info[FBF_tamActive] is not None:\r
- mailboxLine = """\r
- <widget name="FBFMailbox" position="%d,%d" size="%d,%d" font="Regular;%d" />\r
- <widget name="mailbox_inactive" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>\r
- <widget name="mailbox_active" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>\r
- <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />\r
- <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" />\r
- """ % (\r
- 40, 5+2*fontSize+10+varLinePos*fontSize+10, # position mailbox\r
- width-40-20, fontSize, # size mailbox\r
- fontSize-2,\r
- "skin_default/buttons/button_green_off.png",\r
- 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button mailbox\r
- "skin_default/buttons/button_green.png",\r
- 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button mailbox\r
- noButtons*buttonsGap+(noButtons-1)*140, buttonsVPos,\r
- noButtons*buttonsGap+(noButtons-1)*140, buttonsVPos,\r
- )\r
- varLinePos += 1\r
- else:\r
- mailboxLine = ""\r
-\r
- if fritzbox.info[FBF_dectActive] is not None:\r
- dectLine = """\r
- <widget name="FBFDect" position="%d,%d" size="%d,%d" font="Regular;%d" />\r
- <widget name="dect_inactive" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>\r
- <widget name="dect_active" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>\r
- """ % (\r
- 40, 5+2*fontSize+10+varLinePos*fontSize+10, # position dect\r
- width-40-20, fontSize, # size dect\r
- fontSize-2,\r
- "skin_default/buttons/button_green_off.png",\r
- 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button dect\r
- "skin_default/buttons/button_green.png",\r
- 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button dect\r
- )\r
- varLinePos += 1\r
- else:\r
- dectLine = ""\r
-\r
- if fritzbox.info[FBF_faxActive] is not None:\r
- faxLine = """\r
- <widget name="FBFFax" position="%d,%d" size="%d,%d" font="Regular;%d" />\r
- <widget name="fax_inactive" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>\r
- <widget name="fax_active" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>\r
- """ % (\r
- 40, 5+2*fontSize+10+varLinePos*fontSize+10, # position dect\r
- width-40-20, fontSize, # size dect\r
- fontSize-2,\r
- "skin_default/buttons/button_green_off.png",\r
- 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button dect\r
- "skin_default/buttons/button_green.png",\r
- 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button dect\r
- )\r
- varLinePos += 1\r
- else:\r
- faxLine = ""\r
-\r
- if fritzbox.info[FBF_rufumlActive] is not None:\r
- rufumlLine = """\r
- <widget name="FBFRufuml" position="%d,%d" size="%d,%d" font="Regular;%d" />\r
- <widget name="rufuml_inactive" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>\r
- <widget name="rufuml_active" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>\r
- """ % (\r
- 40, 5+2*fontSize+10+varLinePos*fontSize+10, # position dect\r
- width-40-20, fontSize, # size dect\r
- fontSize-2,\r
- "skin_default/buttons/button_green_off.png",\r
- 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button dect\r
- "skin_default/buttons/button_green.png",\r
- 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button dect\r
- )\r
- varLinePos += 1\r
- else:\r
- rufumlLine = ""\r
- \r
- self.skin = """\r
- <screen name="FritzMenu" position="center,center" size="%d,%d" title="FRITZ!Box Fon Status" >\r
- <widget name="FBFInfo" position="%d,%d" size="%d,%d" font="Regular;%d" />\r
- <widget name="FBFInternet" position="%d,%d" size="%d,%d" font="Regular;%d" />\r
- <widget name="internet_inactive" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>\r
- <widget name="internet_active" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>\r
- <widget name="FBFDsl" position="%d,%d" size="%d,%d" font="Regular;%d" />\r
- <widget name="dsl_inactive" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>\r
- <widget name="dsl_active" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>\r
- <widget name="FBFWlan" position="%d,%d" size="%d,%d" font="Regular;%d" />\r
- <widget name="wlan_inactive" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>\r
- <widget name="wlan_active" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>\r
- %s\r
- %s\r
- %s\r
- %s\r
- <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />\r
- <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" />\r
- <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />\r
- <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" />\r
- </screen>""" % (\r
- width, height, # size\r
- 40, 5, # position info\r
- width-2*40, 2*fontSize, # size info\r
- fontSize-2,\r
- 40, 5+2*fontSize+10, # position internet\r
- width-40, 2*fontSize, # size internet\r
- fontSize-2,\r
- "skin_default/buttons/button_green_off.png",\r
- 20, 5+2*fontSize+10+(fontSize-16)/2, # position button internet\r
- "skin_default/buttons/button_green.png",\r
- 20, 5+2*fontSize+10+(fontSize-16)/2, # position button internet\r
- 40, 5+2*fontSize+10+2*fontSize+10, # position dsl\r
- width-40-20, fontSize, # size dsl\r
- fontSize-2,\r
- "skin_default/buttons/button_green_off.png",\r
- 20, 5+2*fontSize+10+2*fontSize+10+(fontSize-16)/2, # position button dsl\r
- "skin_default/buttons/button_green.png",\r
- 20, 5+2*fontSize+10+2*fontSize+10+(fontSize-16)/2, # position button dsl\r
- 40, 5+2*fontSize+10+3*fontSize+10, # position wlan\r
- width-40-20, fontSize, # size wlan\r
- fontSize-2,\r
- "skin_default/buttons/button_green_off.png",\r
- 20, 5+2*fontSize+10+3*fontSize+10+(fontSize-16)/2, # position button wlan\r
- "skin_default/buttons/button_green.png",\r
- 20, 5+2*fontSize+10+3*fontSize+10+(fontSize-16)/2, # position button wlan\r
- mailboxLine,\r
- dectLine,\r
- faxLine,\r
- rufumlLine,\r
- buttonsGap, buttonsVPos, "skin_default/buttons/red.png", buttonsGap, buttonsVPos,\r
- buttonsGap+140+buttonsGap, buttonsVPos, "skin_default/buttons/green.png", buttonsGap+140+buttonsGap, buttonsVPos,\r
- )\r
-\r
- Screen.__init__(self, session)\r
- HelpableScreen.__init__(self)\r
- # TRANSLATORS: keep it short, this is a button\r
- self["key_red"] = Button(_("Reset"))\r
- # TRANSLATORS: keep it short, this is a button\r
- self["key_green"] = Button(_("Toggle WLAN"))\r
- self._mailboxActive = False\r
- if fritzbox.info[FBF_tamActive] is not None:\r
- # TRANSLATORS: keep it short, this is a button\r
- self["key_yellow"] = Button(_("Toggle Mailbox"))\r
- self["menuActions"] = ActionMap(["OkCancelActions", "ColorActions", "NumberActions", "EPGSelectActions"],\r
- {\r
- "cancel": self._exit,\r
- "ok": self._exit,\r
- "red": self._reset,\r
- "green": self._toggleWlan,\r
- "yellow": (lambda: self._toggleMailbox(-1)),\r
- "0": (lambda: self._toggleMailbox(0)),\r
- "1": (lambda: self._toggleMailbox(1)),\r
- "2": (lambda: self._toggleMailbox(2)),\r
- "3": (lambda: self._toggleMailbox(3)),\r
- "4": (lambda: self._toggleMailbox(4)),\r
- "info": self._getInfo,\r
- }, -2)\r
- # TRANSLATORS: keep it short, this is a help text\r
- self.helpList.append((self["menuActions"], "ColorActions", [("yellow", _("Toggle all mailboxes"))]))\r
- # TRANSLATORS: keep it short, this is a help text\r
- self.helpList.append((self["menuActions"], "NumberActions", [("0", _("Toggle 1. mailbox"))]))\r
- # TRANSLATORS: keep it short, this is a help text\r
- self.helpList.append((self["menuActions"], "NumberActions", [("1", _("Toggle 2. mailbox"))]))\r
- # TRANSLATORS: keep it short, this is a help text\r
- self.helpList.append((self["menuActions"], "NumberActions", [("2", _("Toggle 3. mailbox"))]))\r
- # TRANSLATORS: keep it short, this is a help text\r
- self.helpList.append((self["menuActions"], "NumberActions", [("3", _("Toggle 4. mailbox"))]))\r
- # TRANSLATORS: keep it short, this is a help text\r
- self.helpList.append((self["menuActions"], "NumberActions", [("4", _("Toggle 5. mailbox"))]))\r
- self["FBFMailbox"] = Label(_('Mailbox'))\r
- self["mailbox_inactive"] = Pixmap()\r
- self["mailbox_active"] = Pixmap()\r
- self["mailbox_active"].hide()\r
- else:\r
- self["menuActions"] = ActionMap(["OkCancelActions", "ColorActions", "EPGSelectActions"],\r
- {\r
- "cancel": self._exit,\r
- "ok": self._exit,\r
- "green": self._toggleWlan,\r
- "red": self._reset,\r
- "info": self._getInfo,\r
- }, -2)\r
-\r
- # TRANSLATORS: keep it short, this is a help text\r
- self.helpList.append((self["menuActions"], "OkCancelActions", [("cancel", _("Quit"))]))\r
- # TRANSLATORS: keep it short, this is a help text\r
- self.helpList.append((self["menuActions"], "OkCancelActions", [("ok", _("Quit"))]))\r
- # TRANSLATORS: keep it short, this is a help text\r
- self.helpList.append((self["menuActions"], "ColorActions", [("green", _("Toggle WLAN"))]))\r
- # TRANSLATORS: keep it short, this is a help text\r
- self.helpList.append((self["menuActions"], "ColorActions", [("red", _("Reset"))]))\r
- # TRANSLATORS: keep it short, this is a help text\r
- self.helpList.append((self["menuActions"], "EPGSelectActions", [("info", _("Refresh status"))]))\r
-\r
- self["FBFInfo"] = Label(_('Getting status from FRITZ!Box Fon...'))\r
-\r
- self["FBFInternet"] = Label('Internet')\r
- self["internet_inactive"] = Pixmap()\r
- self["internet_active"] = Pixmap()\r
- self["internet_active"].hide()\r
-\r
- self["FBFDsl"] = Label('DSL')\r
- self["dsl_inactive"] = Pixmap()\r
- self["dsl_inactive"].hide()\r
- self["dsl_active"] = Pixmap()\r
- self["dsl_active"].hide()\r
-\r
- self["FBFWlan"] = Label('WLAN ')\r
- self["wlan_inactive"] = Pixmap()\r
- self["wlan_inactive"].hide()\r
- self["wlan_active"] = Pixmap()\r
- self["wlan_active"].hide()\r
- self._wlanActive = False\r
-\r
- if fritzbox.info[FBF_dectActive] is not None: \r
- self["FBFDect"] = Label('DECT')\r
- self["dect_inactive"] = Pixmap()\r
- self["dect_active"] = Pixmap()\r
- self["dect_active"].hide()\r
-\r
- if fritzbox.info[FBF_faxActive] is not None: \r
- self["FBFFax"] = Label('Fax')\r
- self["fax_inactive"] = Pixmap()\r
- self["fax_active"] = Pixmap()\r
- self["fax_active"].hide()\r
-\r
- if fritzbox.info[FBF_rufumlActive] is not None: \r
- self["FBFRufuml"] = Label(_('Call redirection'))\r
- self["rufuml_inactive"] = Pixmap()\r
- self["rufuml_active"] = Pixmap()\r
- self["rufuml_active"].hide()\r
-\r
- self._timer = eTimer()\r
- self._timer.callback.append(self._getInfo)\r
- self.onShown.append(lambda: self._timer.start(5000))\r
- self.onHide.append(self._timer.stop)\r
- self._getInfo()\r
- self.onLayoutFinish.append(self.setWindowTitle)\r
-\r
- def setWindowTitle(self):\r
- # TRANSLATORS: this is a window title.\r
- self.setTitle(_("FRITZ!Box Fon Status"))\r
-\r
- def _getInfo(self):\r
- fritzbox.getInfo(self._fillMenu)\r
-\r
- def _fillMenu(self, status):\r
- (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive) = status\r
- self._wlanActive = (wlanState[0] == '1')\r
- self._mailboxActive = False\r
- try:\r
- if not self.has_key("FBFInfo"): # screen is closed already\r
- return\r
-\r
- if boxInfo:\r
- self["FBFInfo"].setText(boxInfo.replace(', ', '\n'))\r
- else:\r
- self["FBFInfo"].setText('BoxInfo ' + _('Status not available'))\r
-\r
- if ipAddress:\r
- if upTime:\r
- self["FBFInternet"].setText('Internet ' + _('IP Address:') + ' ' + ipAddress + '\n' + _('Connected since') + ' ' + upTime)\r
- else:\r
- self["FBFInternet"].setText('Internet ' + _('IP Address:') + ' ' + ipAddress)\r
- self["internet_inactive"].hide()\r
- self["internet_active"].show()\r
- else:\r
- self["internet_active"].hide()\r
- self["internet_inactive"].show()\r
-\r
- if dslState:\r
- if dslState[0] == '5':\r
- self["dsl_inactive"].hide()\r
- self["dsl_active"].show()\r
- if dslState[1]:\r
- self["FBFDsl"].setText('DSL ' + dslState[1])\r
- else:\r
- self["dsl_active"].hide()\r
- self["dsl_inactive"].show()\r
- else:\r
- self["FBFDsl"].setText('DSL ' + _('Status not available'))\r
- self["dsl_active"].hide()\r
- self["dsl_inactive"].hide()\r
-\r
- if wlanState:\r
- if wlanState[0 ] == '1':\r
- self["wlan_inactive"].hide()\r
- self["wlan_active"].show()\r
- message = 'WLAN'\r
- if wlanState[1] == '0':\r
- message += ' ' + _('not encrypted')\r
- else:\r
- message += ' ' + _('encrypted')\r
- if wlanState[2]:\r
- if wlanState[2] == '0':\r
- message = message + ', ' + _('no device active')\r
- elif wlanState[2] == '1':\r
- message = message + ', ' + _('one device active')\r
- else:\r
- message = message + ', ' + wlanState[2] + ' ' + _('devices active')\r
- self["FBFWlan"].setText(message)\r
- else:\r
- self["wlan_active"].hide()\r
- self["wlan_inactive"].show()\r
- self["FBFWlan"].setText('WLAN')\r
- else:\r
- self["FBFWlan"].setText('WLAN ' + _('Status not available'))\r
- self["wlan_active"].hide()\r
- self["wlan_inactive"].hide()\r
-\r
- if fritzbox.info[FBF_tamActive]:\r
- if not tamActive or tamActive[0] == 0:\r
- self._mailboxActive = False\r
- self["mailbox_active"].hide()\r
- self["mailbox_inactive"].show()\r
- self["FBFMailbox"].setText(_('No mailbox active'))\r
- else:\r
- self._mailboxActive = True\r
- message = '('\r
- for i in range(5):\r
- if tamActive[i+1]:\r
- message = message + str(i) + ','\r
- message = message[:-1] + ')'\r
- self["mailbox_inactive"].hide()\r
- self["mailbox_active"].show()\r
- if tamActive[0] == 1:\r
- self["FBFMailbox"].setText(_('One mailbox active') + ' ' + message)\r
- else:\r
- self["FBFMailbox"].setText(str(tamActive[0]) + ' ' + _('mailboxes active') + ' ' + message)\r
- \r
- if fritzbox.info[FBF_dectActive] and dectActive:\r
- self["dect_inactive"].hide()\r
- self["dect_active"].show()\r
- if dectActive == 0:\r
- self["FBFDect"].setText(_('No DECT phone registered'))\r
- else:\r
- if dectActive == 1:\r
- self["FBFDect"].setText(_('One DECT phone registered'))\r
- else:\r
- self["FBFDect"].setText(str(dectActive) + ' ' + _('DECT phones registered'))\r
-\r
- if fritzbox.info[FBF_faxActive] and faxActive:\r
- self["fax_inactive"].hide()\r
- self["fax_active"].show()\r
- self["FBFFax"].setText(_('Software fax active'))\r
-\r
- if fritzbox.info[FBF_rufumlActive] is not None and rufumlActive is not None:\r
- if rufumlActive == 0:\r
- self["rufuml_active"].hide()\r
- self["rufuml_inactive"].show()\r
- self["FBFRufuml"].setText(_('No call redirection active'))\r
- else:\r
- self["rufuml_inactive"].hide()\r
- self["rufuml_active"].show()\r
- if rufumlActive == 1:\r
- self["FBFRufuml"].setText(_('One call redirection active'))\r
- else:\r
- self["FBFRufuml"].setText(str(rufumlActive) + ' ' + _('call redirections active'))\r
-\r
- except KeyError:\r
- debug("[FritzCallFBF] _fillMenu: " + traceback.format_exc())\r
-\r
- def _toggleWlan(self):\r
- if self._wlanActive:\r
- debug("[FritzMenu] toggleWlan off")\r
- fritzbox.changeWLAN('0')\r
- else:\r
- debug("[FritzMenu] toggleWlan off")\r
- fritzbox.changeWLAN('1')\r
-\r
- def _toggleMailbox(self, which):\r
- debug("[FritzMenu] toggleMailbox")\r
- if fritzbox.info[FBF_tamActive]:\r
- debug("[FritzMenu] toggleMailbox off")\r
- fritzbox.changeMailbox(which)\r
-\r
- def _reset(self):\r
- fritzbox.reset()\r
- self._exit()\r
-\r
- def _exit(self):\r
- self._timer.stop()\r
- self.close()\r
-\r
-\r
-class FritzDisplayCalls(Screen, HelpableScreen):\r
-\r
- def __init__(self, session, text=""): #@UnusedVariable # pylint: disable-msg=W0613\r
- self.width = DESKTOP_WIDTH * scaleH(75, 90)/100\r
- self.height = DESKTOP_HEIGHT * 0.75\r
- dateFieldWidth = scaleH(180, 105)\r
- dirFieldWidth = 16\r
- lengthFieldWidth = scaleH(55, 45)\r
- scrollbarWidth = scaleH(35, 35)\r
- entriesWidth = self.width -scaleH(40, 5) -5\r
- hereFieldWidth = entriesWidth -dirFieldWidth -5 -dateFieldWidth -5 -lengthFieldWidth -scrollbarWidth\r
- fieldWidth = entriesWidth -dirFieldWidth -5 -5 -scrollbarWidth\r
- fontSize = scaleV(22, 20)\r
- itemHeight = 2*fontSize+5\r
- entriesHeight = self.height -scaleV(15, 10) -5 -fontSize -5 -5 -5 -40 -5\r
- buttonGap = (self.width -4*140)/5\r
- buttonV = self.height -40\r
- debug("[FritzDisplayCalls] width: " + str(self.width))\r
- self.skin = """\r
- <screen name="FritzDisplayCalls" position="center,center" size="%d,%d" title="Phone calls" >\r
- <eLabel position="0,0" size="%d,2" backgroundColor="#aaaaaa" />\r
- <widget name="statusbar" position="%d,%d" size="%d,%d" font="Regular;%d" backgroundColor="#aaaaaa" transparent="1" />\r
- <eLabel position="0,%d" size="%d,2" backgroundColor="#aaaaaa" />\r
- <widget source="entries" render="Listbox" position="%d,%d" size="%d,%d" scrollbarMode="showOnDemand" transparent="1">\r
- <convert type="TemplatedMultiContent">\r
- {"template": [\r
- 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\r
- MultiContentEntryPixmapAlphaTest(pos = (%d,%d), size = (%d,%d), png = 2), # index 1 i direction pixmap\r
- MultiContentEntryText(pos = (%d,%d), size = (%d,%d), font=1, flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER, text = 3), # index 2 is remote name/number\r
- MultiContentEntryText(pos = (%d,%d), size = (%d,%d), font=0, flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER, text = 4), # index 3 is length of call\r
- 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\r
- ],\r
- "fonts": [gFont("Regular", %d), gFont("Regular", %d)],\r
- "itemHeight": %d\r
- }\r
- </convert>\r
- </widget>\r
- <eLabel position="0,%d" size="%d,2" backgroundColor="#aaaaaa" />\r
- <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />\r
- <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />\r
- <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />\r
- <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />\r
- <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" />\r
- <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" />\r
- <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" />\r
- <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" />\r
- </screen>""" % (\r
- # scaleH(90, 75), scaleV(100, 78), # position \r
- self.width, self.height, # size\r
- self.width, # eLabel width\r
- scaleH(40, 5), scaleV(10, 5), # statusbar position\r
- self.width, fontSize+5, # statusbar size\r
- scaleV(21, 21), # statusbar font size\r
- scaleV(10, 5)+5+fontSize+5, # eLabel position vertical\r
- self.width, # eLabel width\r
- scaleH(40, 5), scaleV(10, 5)+5+fontSize+5+5, # entries position\r
- entriesWidth, entriesHeight, # entries size\r
- 5+dirFieldWidth+5, fontSize+5, dateFieldWidth, fontSize, # date pos/size\r
- 5, (itemHeight-dirFieldWidth)/2, dirFieldWidth, dirFieldWidth, # dir pos/size\r
- 5+dirFieldWidth+5, 5, fieldWidth, fontSize, # caller pos/size\r
- 2+dirFieldWidth+2+dateFieldWidth+5, fontSize+5, lengthFieldWidth, fontSize, # length pos/size\r
- 2+dirFieldWidth+2+dateFieldWidth+5+lengthFieldWidth+5, fontSize+5, hereFieldWidth, fontSize, # my number pos/size\r
- fontSize-4, fontSize, # fontsize\r
- itemHeight, # itemHeight\r
- buttonV-5, # eLabel position vertical\r
- self.width, # eLabel width\r
- buttonGap, buttonV, "skin_default/buttons/red.png", # widget red\r
- 2*buttonGap+140, buttonV, "skin_default/buttons/green.png", # widget green\r
- 3*buttonGap+2*140, buttonV, "skin_default/buttons/yellow.png", # widget yellow\r
- 4*buttonGap+3*140, buttonV, "skin_default/buttons/blue.png", # widget blue\r
- buttonGap, buttonV, scaleV(22, 21), # widget red\r
- 2*buttonGap+140, buttonV, scaleV(22, 21), # widget green\r
- 3*buttonGap+2*140, buttonV, scaleV(22, 21), # widget yellow\r
- 4*buttonGap+3*140, buttonV, scaleV(22, 21), # widget blue\r
- )\r
- # debug("[FritzDisplayCalls] skin: " + self.skin)\r
- Screen.__init__(self, session)\r
- HelpableScreen.__init__(self)\r
-\r
- # TRANSLATORS: keep it short, this is a button\r
- self["key_yellow"] = Button(_("All"))\r
- # TRANSLATORS: keep it short, this is a button\r
- self["key_red"] = Button(_("Missed"))\r
- # TRANSLATORS: keep it short, this is a button\r
- self["key_blue"] = Button(_("Incoming"))\r
- # TRANSLATORS: keep it short, this is a button\r
- self["key_green"] = Button(_("Outgoing"))\r
-\r
- self["setupActions"] = ActionMap(["OkCancelActions", "ColorActions"],\r
- {\r
- "yellow": (lambda: self.display(FBF_ALL_CALLS)),\r
- "red": (lambda: self.display(FBF_MISSED_CALLS)),\r
- "blue": (lambda: self.display(FBF_IN_CALLS)),\r
- "green": (lambda: self.display(FBF_OUT_CALLS)),\r
- "cancel": self.ok,\r
- "ok": self.showEntry, }, - 2)\r
-\r
- # TRANSLATORS: keep it short, this is a help text\r
- self.helpList.append((self["setupActions"], "OkCancelActions", [("ok", _("Show details of entry"))]))\r
- # TRANSLATORS: keep it short, this is a help text\r
- self.helpList.append((self["setupActions"], "OkCancelActions", [("cancel", _("Quit"))]))\r
- # TRANSLATORS: keep it short, this is a help text\r
- self.helpList.append((self["setupActions"], "ColorActions", [("yellow", _("Display all calls"))]))\r
- # TRANSLATORS: keep it short, this is a help text\r
- self.helpList.append((self["setupActions"], "ColorActions", [("red", _("Display missed calls"))]))\r
- # TRANSLATORS: keep it short, this is a help text\r
- self.helpList.append((self["setupActions"], "ColorActions", [("blue", _("Display incoming calls"))]))\r
- # TRANSLATORS: keep it short, this is a help text\r
- self.helpList.append((self["setupActions"], "ColorActions", [("green", _("Display outgoing calls"))]))\r
-\r
- self["statusbar"] = Label(_("Getting calls from FRITZ!Box..."))\r
- self.list = []\r
- self["entries"] = List(self.list)\r
- #=======================================================================\r
- # fontSize = scaleV(22, 18)\r
- # fontHeight = scaleV(24, 20)\r
- # self["entries"].l.setFont(0, gFont("Regular", fontSize))\r
- # self["entries"].l.setItemHeight(fontHeight)\r
- #=======================================================================\r
- debug("[FritzDisplayCalls] init: '''%s'''" % config.plugins.FritzCall.fbfCalls.value)\r
- self.display()\r
- self.onLayoutFinish.append(self.setWindowTitle)\r
-\r
- def setWindowTitle(self):\r
- # TRANSLATORS: this is a window title.\r
- self.setTitle(_("Phone calls"))\r
-\r
- def ok(self):\r
- self.close()\r
-\r
- def display(self, which=config.plugins.FritzCall.fbfCalls.value):\r
- debug("[FritzDisplayCalls] display")\r
- config.plugins.FritzCall.fbfCalls.value = which\r
- config.plugins.FritzCall.fbfCalls.save()\r
- fritzbox.getCalls(self, lambda x: self.gotCalls(x, which), which)\r
-\r
- def gotCalls(self, listOfCalls, which):\r
- debug("[FritzDisplayCalls] gotCalls")\r
- self.updateStatus(fbfCallsChoices[which] + " (" + str(len(listOfCalls)) + ")")\r
-\r
- directout = LoadPixmap(resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/images/callout.png"))\r
- directin = LoadPixmap(resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/images/callin.png"))\r
- directfailed = LoadPixmap(resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/images/callinfailed.png"))\r
- def pixDir(direct):\r
- if direct == FBF_OUT_CALLS:\r
- direct = directout\r
- elif direct == FBF_IN_CALLS:\r
- direct = directin\r
- else:\r
- direct = directfailed\r
- return direct\r
-\r
- self.list = [(number, date[:6] + ' ' + date[9:14], pixDir(direct), remote, length, here) for (number, date, direct, remote, length, here) in listOfCalls]\r
- self["entries"].setList(self.list)\r
-\r
- def updateStatus(self, text):\r
- if self.has_key("statusbar"):\r
- self["statusbar"].setText(_("Getting calls from FRITZ!Box...") + ' ' + text)\r
-\r
- def showEntry(self):\r
- debug("[FritzDisplayCalls] showEntry")\r
- cur = self["entries"].getCurrent()\r
- if cur:\r
- if cur[0]:\r
- debug("[FritzDisplayCalls] showEntry %s" % (cur[0]))\r
- number = cur[0]\r
- fullname = phonebook.search(cur[0])\r
- if fullname:\r
- # we have a name for this number\r
- name = fullname\r
- self.session.open(FritzOfferAction, self, number, name)\r
- else:\r
- # we don't\r
- fullname = resolveNumberWithAvon(number, config.plugins.FritzCall.country.value)\r
- if fullname:\r
- name = fullname\r
- self.session.open(FritzOfferAction, self, number, name)\r
- else:\r
- self.session.open(FritzOfferAction, self, number)\r
- else:\r
- # we do not even have a number...\r
- self.session.open(MessageBox,\r
- _("UNKNOWN"),\r
- type=MessageBox.TYPE_INFO)\r
-\r
-\r
-class FritzOfferAction(Screen):\r
-\r
- def __init__(self, session, parent, number, name=""):\r
- # the layout will completely be recalculated in finishLayout\r
- self.skin = """\r
- <screen name="FritzOfferAction" title="Do what?" >\r
- <widget name="text" size="%d,%d" font="Regular;%d" />\r
- <widget name="FacePixmap" size="%d,%d" alphatest="on" />\r
- <widget name="key_red_p" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />\r
- <widget name="key_green_p" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />\r
- <widget name="key_yellow_p" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />\r
- <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" />\r
- <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" />\r
- <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" />\r
- </screen>""" % (\r
- DESKTOP_WIDTH, DESKTOP_HEIGHT, # set maximum size\r
- scaleH(22,21), # text\r
- DESKTOP_WIDTH, DESKTOP_HEIGHT, # set maximum size\r
- "skin_default/buttons/red.png",\r
- "skin_default/buttons/green.png",\r
- "skin_default/buttons/yellow.png",\r
- ) \r
- debug("[FritzOfferAction] init: %s, %s" %(number, name))\r
- Screen.__init__(self, session)\r
- \r
- # TRANSLATORS: keep it short, this is a button\r
- self["key_red"] = Button(_("Lookup"))\r
- # TRANSLATORS: keep it short, this is a button\r
- self["key_green"] = Button(_("Call"))\r
- # TRANSLATORS: keep it short, this is a button\r
- self["key_yellow"] = Button(_("Save"))\r
- # TRANSLATORS: keep it short, this is a button\r
- # self["key_blue"] = Button(_("Search"))\r
-\r
- self["FritzOfferActions"] = ActionMap(["OkCancelActions", "ColorActions"],\r
- {\r
- "red": self._lookup,\r
- "green": self._call,\r
- "yellow": self._add,\r
- "cancel": self._exit,\r
- "ok": self._exit, }, - 2)\r
-\r
- self._session = session\r
- self._number = number\r
- self._name = name.replace("\n", ", ")\r
- self["text"] = Label(number + "\n\n" + name.replace(", ", "\n"))\r
- self._parent = parent\r
- self._lookupState = 0\r
- self["key_red_p"] = Pixmap()\r
- self["key_green_p"] = Pixmap()\r
- self["key_yellow_p"] = Pixmap()\r
- self["FacePixmap"] = Pixmap()\r
- self.onLayoutFinish.append(self._finishLayout)\r
- self.onLayoutFinish.append(self.setWindowTitle)\r
-\r
- def setWindowTitle(self):\r
- # TRANSLATORS: this is a window title.\r
- self.setTitle(_("Do what?"))\r
-\r
- def _finishLayout(self):\r
- # pylint: disable-msg=W0142\r
- debug("[FritzCall] FritzOfferAction/finishLayout number: %s/%s" % (self._number, self._name))\r
-\r
- faceFile = findFace(self._number, self._name)\r
- picPixmap = LoadPixmap(faceFile)\r
- if not picPixmap: # that means most probably, that the picture is not 8 bit...\r
- Notifications.AddNotification(MessageBox, _("Found picture\n\n%s\n\nBut did not load. Probably not PNG, 8-bit") %faceFile, type = MessageBox.TYPE_ERROR)\r
- picPixmap = LoadPixmap(resolveFilename(SCOPE_SKIN_IMAGE, "skin_default/icons/input_error.png"))\r
- picSize = picPixmap.size()\r
- self["FacePixmap"].instance.setPixmap(picPixmap)\r
-\r
- noButtons = 3\r
- # recalculate window size\r
- textSize = self["text"].getSize()\r
- textSize = (textSize[0]+20, textSize[1]+20) # don't know, why, but size is too small\r
- debug("[FritzCall] FritzOfferAction/finishLayout textsize: %s/%s" % textSize)\r
- textSize = eSize(*textSize)\r
- width = max(scaleH(620, 545), noButtons*145, picSize.width() + textSize.width() + 30)\r
- height = max(picSize.height()+5, textSize.height()+5, scaleV(-1, 136)) + 5 + 40 + 5\r
- buttonsGap = (width-noButtons*140)/(noButtons+1)\r
- buttonsVPos = height-40-5\r
- wSize = (width, height)\r
- wSize = eSize(*wSize)\r
-\r
- # center the smaller vertically\r
- hGap = (width-picSize.width()-textSize.width())/3\r
- picPos = (hGap, (height-50-picSize.height())/2+5)\r
- textPos = (hGap+picSize.width()+hGap, (height-50-textSize.height())/2+5)\r
-\r
- # resize screen\r
- self.instance.resize(wSize)\r
- # resize text\r
- self["text"].instance.resize(textSize)\r
- # resize pixmap\r
- self["FacePixmap"].instance.resize(picSize)\r
- # move buttons\r
- buttonPos = (buttonsGap, buttonsVPos)\r
- self["key_red_p"].instance.move(ePoint(*buttonPos))\r
- self["key_red"].instance.move(ePoint(*buttonPos))\r
- buttonPos = (buttonsGap+140+buttonsGap, buttonsVPos)\r
- self["key_green_p"].instance.move(ePoint(*buttonPos))\r
- self["key_green"].instance.move(ePoint(*buttonPos))\r
- buttonPos = (buttonsGap+140+buttonsGap+140+buttonsGap, buttonsVPos)\r
- self["key_yellow_p"].instance.move(ePoint(*buttonPos))\r
- self["key_yellow"].instance.move(ePoint(*buttonPos))\r
- # move text\r
- self["text"].instance.move(ePoint(*textPos))\r
- # move pixmap\r
- self["FacePixmap"].instance.move(ePoint(*picPos))\r
- # center window\r
- self.instance.move(ePoint((DESKTOP_WIDTH-wSize.width())/2, (DESKTOP_HEIGHT-wSize.height())/2))\r
-\r
- def _setTextAndResize(self, message):\r
- # pylint: disable-msg=W0142\r
- self["text"].instance.resize(eSize(*(DESKTOP_WIDTH, DESKTOP_HEIGHT)))\r
- self["text"].setText(self._number + "\n\n" + message)\r
- self._finishLayout()\r
-\r
- def _lookup(self):\r
- phonebookLocation = config.plugins.FritzCall.phonebookLocation.value\r
- if self._lookupState == 0:\r
- self._lookupState = 1\r
- self._setTextAndResize(_("Reverse searching..."))\r
- ReverseLookupAndNotifier(self._number, self._lookedUp, "UTF-8", config.plugins.FritzCall.country.value)\r
- return\r
- if self._lookupState == 1 and os.path.exists(os.path.join(phonebookLocation, "PhoneBook.csv")):\r
- self._setTextAndResize(_("Searching in Outlook export..."))\r
- self._lookupState = 2\r
- self._lookedUp(self._number, FritzOutlookCSV.findNumber(self._number, os.path.join(phonebookLocation, "PhoneBook.csv"))) #@UndefinedVariable\r
- return\r
- else:\r
- self._lookupState = 2\r
- if self._lookupState == 2 and os.path.exists(os.path.join(phonebookLocation, "PhoneBook.ldif")):\r
- self._setTextAndResize(_("Searching in LDIF..."))\r
- self._lookupState = 0\r
- FritzLDIF.FindNumber(self._number, open(os.path.join(phonebookLocation, "PhoneBook.ldif")), self._lookedUp)\r
- return\r
- else:\r
- self._lookupState = 0\r
- self._lookup()\r
-\r
- def _lookedUp(self, number, name):\r
- name = handleReverseLookupResult(name)\r
- if not name:\r
- if self._lookupState == 1:\r
- name = _("No result from reverse lookup")\r
- elif self._lookupState == 2:\r
- name = _("No result from Outlook export")\r
- else:\r
- name = _("No result from LDIF")\r
- self._name = name\r
- self._number = number\r
- debug("[FritzOfferAction] lookedUp: " + str(name.replace(", ", "\n")))\r
- self._setTextAndResize(str(name.replace(", ", "\n")))\r
-\r
- def _call(self):\r
- debug("[FritzOfferAction] add: %s" %self._number)\r
- fritzbox.dial(self._number)\r
- self._exit()\r
-\r
- def _add(self):\r
- debug("[FritzOfferAction] add: %s, %s" %(self._number, self._name))\r
- phonebook.FritzDisplayPhonebook(self._session).add(self._parent, self._number, self._name)\r
- self._exit()\r
-\r
- def _exit(self):\r
- self.close()\r
-\r
-\r
-class FritzCallPhonebook:\r
- def __init__(self):\r
- debug("[FritzCallPhonebook] init")\r
- # Beware: strings in phonebook.phonebook have to be in utf-8!\r
- self.phonebook = {}\r
- self.reload()\r
-\r
- def reload(self):\r
- debug("[FritzCallPhonebook] reload")\r
- # Beware: strings in phonebook.phonebook have to be in utf-8!\r
- self.phonebook = {}\r
-\r
- if not config.plugins.FritzCall.enable.value:\r
- return\r
-\r
- phonebookFilename = os.path.join(config.plugins.FritzCall.phonebookLocation.value, "PhoneBook.txt")\r
- if config.plugins.FritzCall.phonebook.value and os.path.exists(phonebookFilename):\r
- debug("[FritzCallPhonebook] reload: read " + phonebookFilename)\r
- phonebookTxtCorrupt = False\r
- self.phonebook = {}\r
- for line in open(phonebookFilename):\r
- try:\r
- # Beware: strings in phonebook.phonebook have to be in utf-8!\r
- line = line.decode("utf-8")\r
- except UnicodeDecodeError: # this is just for the case, somebody wrote latin1 chars into PhoneBook.txt\r
- try:\r
- line = line.decode("iso-8859-1")\r
- debug("[FritzCallPhonebook] Fallback to ISO-8859-1 in %s" % line)\r
- phonebookTxtCorrupt = True\r
- except UnicodeDecodeError:\r
- debug("[FritzCallPhonebook] Could not parse internal Phonebook Entry %s" % line)\r
- phonebookTxtCorrupt = True\r
- line = line.encode("utf-8")\r
- elems = line.split('#')\r
- if len(elems) == 2:\r
- try:\r
- self.phonebook[elems[0]] = elems[1]\r
- except ValueError: # how could this possibly happen?!?!\r
- debug("[FritzCallPhonebook] Could not parse internal Phonebook Entry %s" % line)\r
- phonebookTxtCorrupt = True\r
- else:\r
- debug("[FritzCallPhonebook] Could not parse internal Phonebook Entry %s" % line)\r
- phonebookTxtCorrupt = True\r
- \r
- #===============================================================\r
- # found = re.match("^(\d+)#(.*)$", line)\r
- # if found:\r
- # try:\r
- # self.phonebook[found.group(1)] = found.group(2)\r
- # except ValueError: # how could this possibly happen?!?!\r
- # debug("[FritzCallPhonebook] Could not parse internal Phonebook Entry %s" % line)\r
- # phonebookTxtCorrupt = True\r
- # else:\r
- # debug("[FritzCallPhonebook] Could not parse internal Phonebook Entry %s" % line)\r
- # phonebookTxtCorrupt = True\r
- #===============================================================\r
-\r
- if phonebookTxtCorrupt:\r
- # dump phonebook to PhoneBook.txt\r
- debug("[FritzCallPhonebook] dump Phonebook.txt")\r
- try:\r
- os.rename(phonebookFilename, phonebookFilename + ".bck")\r
- fNew = open(phonebookFilename, 'w')\r
- # Beware: strings in phonebook.phonebook are utf-8!\r
- for (number, name) in self.phonebook.iteritems():\r
- # Beware: strings in PhoneBook.txt have to be in utf-8!\r
- fNew.write(number + "#" + name.encode("utf-8"))\r
- fNew.close()\r
- except (IOError, OSError):\r
- debug("[FritzCallPhonebook] error renaming or writing to %s" %phonebookFilename)\r
-\r
-#===============================================================================\r
-# #\r
-# # read entries from Outlook export\r
-# #\r
-# # not reliable with coding yet\r
-# # \r
-# # import csv exported from Outlook 2007 with csv(Windows)\r
-# csvFilename = "/tmp/PhoneBook.csv"\r
-# if config.plugins.FritzCall.phonebook.value and os.path.exists(csvFilename):\r
-# try:\r
-# readOutlookCSV(csvFilename, self.add)\r
-# os.rename(csvFilename, csvFilename + ".done")\r
-# except ImportError:\r
-# debug("[FritzCallPhonebook] CSV import failed" %line)\r
-#===============================================================================\r
-\r
- \r
-#===============================================================================\r
-# #\r
-# # read entries from LDIF\r
-# #\r
-# # import ldif exported from Thunderbird 2.0.0.19\r
-# ldifFilename = "/tmp/PhoneBook.ldif"\r
-# if config.plugins.FritzCall.phonebook.value and os.path.exists(ldifFilename):\r
-# try:\r
-# parser = MyLDIF(open(ldifFilename), self.add)\r
-# parser.parse()\r
-# os.rename(ldifFilename, ldifFilename + ".done")\r
-# except ImportError:\r
-# debug("[FritzCallPhonebook] LDIF import failed" %line)\r
-#===============================================================================\r
- \r
- if fritzbox and config.plugins.FritzCall.fritzphonebook.value:\r
- fritzbox.loadFritzBoxPhonebook()\r
-\r
- def search(self, number):\r
- # debug("[FritzCallPhonebook] Searching for %s" %number)\r
- name = ""\r
- if not self.phonebook or not number:\r
- return\r
-\r
- if config.plugins.FritzCall.prefix.value:\r
- prefix = config.plugins.FritzCall.prefix.value\r
- if number[0] != '0':\r
- number = prefix + number\r
- # debug("[FritzCallPhonebook] search: added prefix: %s" %number)\r
- elif number[:len(prefix)] == prefix and self.phonebook.has_key(number[len(prefix):]):\r
- # debug("[FritzCallPhonebook] search: same prefix")\r
- name = self.phonebook[number[len(prefix):]]\r
- # debug("[FritzCallPhonebook] search: result: %s" %name)\r
- else:\r
- prefix = ""\r
- \r
- if not name and self.phonebook.has_key(number):\r
- name = self.phonebook[number]\r
- \r
- return name.replace(", ", "\n").strip()\r
-\r
- def add(self, number, name):\r
- '''\r
- \r
- @param number: number of entry\r
- @param name: name of entry, has to be in utf-8\r
- '''\r
- debug("[FritzCallPhonebook] add")\r
- name = name.replace("\n", ", ").replace('#','') # this is just for safety reasons. add should only be called with newlines converted into commas\r
- self.remove(number)\r
- self.phonebook[number] = name\r
- if number and number != 0:\r
- if config.plugins.FritzCall.phonebook.value:\r
- try:\r
- name = name.strip() + "\n"\r
- string = "%s#%s" % (number, name)\r
- # Beware: strings in PhoneBook.txt have to be in utf-8!\r
- f = open(os.path.join(config.plugins.FritzCall.phonebookLocation.value, "PhoneBook.txt"), 'a')\r
- f.write(string)\r
- f.close()\r
- debug("[FritzCallPhonebook] added %s with %s to Phonebook.txt" % (number, name.strip()))\r
- return True\r
- \r
- except IOError:\r
- return False\r
-\r
- def remove(self, number):\r
- if number in self.phonebook:\r
- debug("[FritzCallPhonebook] remove entry in phonebook")\r
- del self.phonebook[number]\r
- if config.plugins.FritzCall.phonebook.value:\r
- try:\r
- phonebookFilename = os.path.join(config.plugins.FritzCall.phonebookLocation.value, "PhoneBook.txt")\r
- debug("[FritzCallPhonebook] remove entry in Phonebook.txt")\r
- fOld = open(phonebookFilename, 'r')\r
- fNew = open(phonebookFilename + str(os.getpid()), 'w')\r
- line = fOld.readline()\r
- while (line):\r
- elems = line.split('#')\r
- if len(elems) == 2 and not elems[0] == number:\r
- fNew.write(line)\r
- line = fOld.readline()\r
- fOld.close()\r
- fNew.close()\r
- # os.remove(phonebookFilename)\r
- eBackgroundFileEraser.getInstance().erase(phonebookFilename)\r
- os.rename(phonebookFilename + str(os.getpid()), phonebookFilename)\r
- debug("[FritzCallPhonebook] removed %s from Phonebook.txt" % number)\r
- return True\r
- \r
- except (IOError, OSError):\r
- debug("[FritzCallPhonebook] error removing %s from %s" %(number, phonebookFilename))\r
- return False\r
-\r
- class FritzDisplayPhonebook(Screen, HelpableScreen, NumericalTextInput):\r
- \r
- def __init__(self, session):\r
- self.width = scaleH(1100, 570)\r
- self.entriesWidth = scaleH(1040, 560)\r
- numberFieldWidth = scaleH(190, 150)\r
- fieldWidth = self.entriesWidth -5 -numberFieldWidth -10\r
- fontSize = scaleV(22, 18)\r
- fontHeight = scaleV(24, 20)\r
- debug("[FritzDisplayPhonebook] width: " + str(self.width))\r
- self.skin = """\r
- <screen name="FritzDisplayPhonebook" position="center,center" size="%d,%d" title="Phonebook" >\r
- <eLabel position="0,0" size="%d,2" backgroundColor="#aaaaaa" />\r
- <widget source="entries" render="Listbox" position="%d,%d" size="%d,%d" scrollbarMode="showOnDemand" transparent="1">\r
- <convert type="TemplatedMultiContent">\r
- {"template": [\r
- MultiContentEntryText(pos = (%d,%d), size = (%d,%d), font=0, flags = RT_HALIGN_LEFT, text = 1), # index 0 is the name, index 1 is shortname\r
- MultiContentEntryText(pos = (%d,%d), size = (%d,%d), font=0, flags = RT_HALIGN_LEFT, text = 2), # index 2 is number\r
- ],\r
- "fonts": [gFont("Regular", %d)],\r
- "itemHeight": %d\r
- }\r
- </convert>\r
- </widget>\r
- <eLabel position="0,%d" size="%d,2" backgroundColor="#aaaaaa" />\r
- <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />\r
- <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />\r
- <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />\r
- <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />\r
- <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" />\r
- <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" />\r
- <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" />\r
- <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" />\r
- </screen>""" % (\r
- # scaleH(90, 75), scaleV(100, 73), # position \r
- scaleH(1100, 570), scaleV(560, 430), # size\r
- scaleH(1100, 570), # eLabel width\r
- scaleH(40, 5), scaleV(20, 5), # entries position\r
- self.entriesWidth, scaleV(488, 380), # entries size\r
- 0, 0, fieldWidth, scaleH(24,20), # name pos/size\r
- fieldWidth +5, 0, numberFieldWidth, scaleH(24,20), # dir pos/size\r
- fontSize, # fontsize\r
- fontHeight, # itemHeight\r
- scaleV(518, 390), # eLabel position vertical\r
- scaleH(1100, 570), # eLabel width\r
- scaleH(20, 5), scaleV(525, 395), "skin_default/buttons/red.png", # ePixmap red\r
- scaleH(290, 145), scaleV(525, 395), "skin_default/buttons/green.png", # ePixmap green\r
- scaleH(560, 285), scaleV(525, 395), "skin_default/buttons/yellow.png", # ePixmap yellow\r
- scaleH(830, 425), scaleV(525, 395), "skin_default/buttons/blue.png", # ePixmap blue\r
- scaleH(20, 5), scaleV(525, 395), scaleV(22, 21), # widget red\r
- scaleH(290, 145), scaleV(525, 395), scaleV(22, 21), # widget green\r
- scaleH(560, 285), scaleV(525, 395), scaleV(22, 21), # widget yellow\r
- scaleH(830, 425), scaleV(525, 395), scaleV(22, 21), # widget blue\r
- )\r
- \r
- # debug("[FritzDisplayCalls] skin: " + self.skin)\r
- Screen.__init__(self, session)\r
- NumericalTextInput.__init__(self)\r
- HelpableScreen.__init__(self)\r
- \r
- # TRANSLATORS: keep it short, this is a button\r
- self["key_red"] = Button(_("Delete"))\r
- # TRANSLATORS: keep it short, this is a button\r
- self["key_green"] = Button(_("New"))\r
- # TRANSLATORS: keep it short, this is a button\r
- self["key_yellow"] = Button(_("Edit"))\r
- # TRANSLATORS: keep it short, this is a button\r
- self["key_blue"] = Button(_("Search"))\r
- \r
- self["setupActions"] = ActionMap(["OkCancelActions", "ColorActions"],\r
- {\r
- "red": self.delete,\r
- "green": self.add,\r
- "yellow": self.edit,\r
- "blue": self.search,\r
- "cancel": self.exit,\r
- "ok": self.showEntry, }, - 2)\r
- \r
- # TRANSLATORS: keep it short, this is a help text\r
- self.helpList.append((self["setupActions"], "OkCancelActions", [("ok", _("Show details of entry"))]))\r
- # TRANSLATORS: keep it short, this is a help text\r
- self.helpList.append((self["setupActions"], "OkCancelActions", [("cancel", _("Quit"))]))\r
- # TRANSLATORS: keep it short, this is a help text\r
- self.helpList.append((self["setupActions"], "ColorActions", [("red", _("Delete entry"))]))\r
- # TRANSLATORS: keep it short, this is a help text\r
- self.helpList.append((self["setupActions"], "ColorActions", [("green", _("Add entry to phonebook"))]))\r
- # TRANSLATORS: keep it short, this is a help text\r
- self.helpList.append((self["setupActions"], "ColorActions", [("yellow", _("Edit selected entry"))]))\r
- # TRANSLATORS: keep it short, this is a help text\r
- self.helpList.append((self["setupActions"], "ColorActions", [("blue", _("Search (case insensitive)"))]))\r
- \r
- self["entries"] = List([])\r
- debug("[FritzCallPhonebook] displayPhonebook init")\r
- self.help_window = None\r
- self.sortlist = []\r
- self.onLayoutFinish.append(self.setWindowTitle)\r
- self.display()\r
-\r
- def setWindowTitle(self):\r
- # TRANSLATORS: this is a window title.\r
- self.setTitle(_("Phonebook"))\r
-\r
- def display(self, filterNumber=""):\r
- debug("[FritzCallPhonebook] displayPhonebook/display")\r
- self.sortlist = []\r
- # Beware: strings in phonebook.phonebook are utf-8!\r
- sortlistHelp = sorted((name.lower(), name, number) for (number, name) in phonebook.phonebook.iteritems())\r
- for (low, name, number) in sortlistHelp:\r
- if number == "01234567890":\r
- continue\r
- try:\r
- low = low.decode("utf-8")\r
- except UnicodeDecodeError: # this should definitely not happen\r
- try:\r
- low = low.decode("iso-8859-1")\r
- except UnicodeDecodeError:\r
- debug("[FritzCallPhonebook] displayPhonebook/display: corrupt phonebook entry for %s" % number)\r
- # self.session.open(MessageBox, _("Corrupt phonebook entry\nfor number %s\nDeleting.") %number, type = MessageBox.TYPE_ERROR)\r
- phonebook.remove(number)\r
- continue\r
- else:\r
- if filterNumber:\r
- filterNumber = filterNumber.lower()\r
- if low.find(filterNumber) == - 1:\r
- continue\r
- name = name.strip().decode("utf-8")\r
- number = number.strip().decode("utf-8")\r
- comma = name.find(',')\r
- if comma != -1:\r
- shortname = name[:comma]\r
- else:\r
- shortname = name\r
- number = number.encode("utf-8", "replace")\r
- name = name.encode("utf-8", "replace")\r
- shortname = shortname.encode('utf-8', 'replace')\r
- self.sortlist.append((name, shortname, number))\r
- \r
- self["entries"].setList(self.sortlist)\r
- \r
- def showEntry(self):\r
- cur = self["entries"].getCurrent()\r
- if cur:\r
- debug("[FritzCallPhonebook] displayPhonebook/showEntry %s" % (repr(cur)))\r
- number = cur[2]\r
- name = cur[0]\r
- self.session.open(FritzOfferAction, self, number, name)\r
- \r
- def delete(self):\r
- cur = self["entries"].getCurrent()\r
- if cur:\r
- debug("[FritzCallPhonebook] displayPhonebook/delete %s" % (repr(cur)))\r
- self.session.openWithCallback(\r
- self.deleteConfirmed,\r
- MessageBox,\r
- _("Do you really want to delete entry for\n\n%(number)s\n\n%(name)s?") \r
- % { 'number':str(cur[2]), 'name':str(cur[0]).replace(", ", "\n") }\r
- )\r
- else:\r
- self.session.open(MessageBox, _("No entry selected"), MessageBox.TYPE_INFO)\r
- \r
- def deleteConfirmed(self, ret):\r
- debug("[FritzCallPhonebook] displayPhonebook/deleteConfirmed")\r
- #\r
- # if ret: delete number from sortlist, delete number from phonebook.phonebook and write it to disk\r
- #\r
- cur = self["entries"].getCurrent()\r
- if cur:\r
- if ret:\r
- # delete number from sortlist, delete number from phonebook.phonebook and write it to disk\r
- debug("[FritzCallPhonebook] displayPhonebook/deleteConfirmed %s" % (repr(cur)))\r
- phonebook.remove(cur[2])\r
- self.display()\r
- # else:\r
- # self.session.open(MessageBox, _("Not deleted."), MessageBox.TYPE_INFO)\r
- else:\r
- self.session.open(MessageBox, _("No entry selected"), MessageBox.TYPE_INFO)\r
- \r
- def add(self, parent=None, number="", name=""):\r
- class AddScreen(Screen, ConfigListScreen):\r
- '''ConfiglistScreen with two ConfigTexts for Name and Number'''\r
- \r
- def __init__(self, session, parent, number="", name=""):\r
- #\r
- # setup screen with two ConfigText and OK and ABORT button\r
- # \r
- noButtons = 2\r
- width = max(scaleH(-1, 570), noButtons*140)\r
- height = scaleV(-1, 100) # = 5 + 126 + 40 + 5; 6 lines of text possible\r
- buttonsGap = (width-noButtons*140)/(noButtons+1)\r
- buttonsVPos = height-40-5\r
- self.skin = """\r
- <screen position="center,center" size="%d,%d" title="Add entry to phonebook" >\r
- <widget name="config" position="5,5" size="%d,%d" scrollbarMode="showOnDemand" />\r
- <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />\r
- <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />\r
- <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" />\r
- <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" />\r
- </screen>""" % (\r
- width, height,\r
- width - 5 - 5, height - 5 - 40 - 5,\r
- buttonsGap, buttonsVPos, "skin_default/buttons/red.png",\r
- buttonsGap+140+buttonsGap, buttonsVPos, "skin_default/buttons/green.png",\r
- buttonsGap, buttonsVPos,\r
- buttonsGap+140+buttonsGap, buttonsVPos,\r
- )\r
- Screen.__init__(self, session)\r
- self.session = session\r
- self.parent = parent\r
- # TRANSLATORS: keep it short, this is a button\r
- self["key_red"] = Button(_("Cancel"))\r
- # TRANSLATORS: keep it short, this is a button\r
- self["key_green"] = Button(_("OK"))\r
- self["setupActions"] = ActionMap(["SetupActions", "ColorActions"],\r
- {\r
- "cancel": self.cancel,\r
- "red": self.cancel,\r
- "green": self.add,\r
- "ok": self.add,\r
- }, - 2)\r
- \r
- self.list = [ ]\r
- ConfigListScreen.__init__(self, self.list, session=session)\r
- self.name = name\r
- self.number = number\r
- config.plugins.FritzCall.name.value = name\r
- config.plugins.FritzCall.number.value = number\r
- self.list.append(getConfigListEntry(_("Name"), config.plugins.FritzCall.name))\r
- self.list.append(getConfigListEntry(_("Number"), config.plugins.FritzCall.number))\r
- self["config"].list = self.list\r
- self["config"].l.setList(self.list)\r
- self.onLayoutFinish.append(self.setWindowTitle)\r
- \r
- def setWindowTitle(self):\r
- # TRANSLATORS: this is a window title.\r
- self.setTitle(_("Add entry to phonebook"))\r
-\r
- def add(self):\r
- # get texts from Screen\r
- # add (number,name) to sortlist and phonebook.phonebook and disk\r
- self.name = config.plugins.FritzCall.name.value\r
- self.number = config.plugins.FritzCall.number.value\r
- if not self.number or not self.name:\r
- self.session.open(MessageBox, _("Entry incomplete."), type=MessageBox.TYPE_ERROR)\r
- return\r
- # add (number,name) to sortlist and phonebook.phonebook and disk\r
- # oldname = phonebook.search(self.number)\r
- # if oldname:\r
- # self.session.openWithCallback(\r
- # self.overwriteConfirmed,\r
- # MessageBox,\r
- # _("Do you really want to overwrite entry for %(number)s\n\n%(name)s\n\nwith\n\n%(newname)s?")\r
- # % {\r
- # 'number':self.number,\r
- # 'name': oldname,\r
- # 'newname':self.name.replace(", ","\n")\r
- # }\r
- # )\r
- # self.close()\r
- # return\r
- phonebook.add(self.number, self.name)\r
- self.close()\r
- self.parent.display()\r
- \r
- def overwriteConfirmed(self, ret):\r
- if ret:\r
- phonebook.remove(self.number)\r
- phonebook.add(self.number, self.name)\r
- self.parent.display()\r
- \r
- def cancel(self):\r
- self.close()\r
- \r
- debug("[FritzCallPhonebook] displayPhonebook/add")\r
- if not parent:\r
- parent = self\r
- self.session.open(AddScreen, parent, number, name)\r
- \r
- def edit(self):\r
- debug("[FritzCallPhonebook] displayPhonebook/edit")\r
- cur = self["entries"].getCurrent()\r
- if cur is None:\r
- self.session.open(MessageBox, _("No entry selected"), MessageBox.TYPE_INFO)\r
- else:\r
- (number, name) = cur[0]\r
- self.add(self, number, name)\r
- \r
- def search(self):\r
- debug("[FritzCallPhonebook] displayPhonebook/search")\r
- self.help_window = self.session.instantiateDialog(NumericalTextInputHelpDialog, self)\r
- self.help_window.show()\r
- # VirtualKeyboard instead of InputBox?\r
- self.session.openWithCallback(self.doSearch, InputBox, _("Enter Search Terms"), _("Search phonebook"))\r
- \r
- def doSearch(self, searchTerms):\r
- if not searchTerms:\r
- searchTerms = ""\r
- debug("[FritzCallPhonebook] displayPhonebook/doSearch: " + searchTerms)\r
- if self.help_window:\r
- self.session.deleteDialog(self.help_window)\r
- self.help_window = None\r
- self.display(searchTerms)\r
- \r
- def exit(self):\r
- self.close()\r
-\r
-phonebook = FritzCallPhonebook()\r
-\r
-class FritzCallSetup(Screen, ConfigListScreen, HelpableScreen):\r
-\r
- def __init__(self, session, args=None): #@UnusedVariable # pylint: disable-msg=W0613\r
- self.width = scaleH(20+4*(140+90)+2*(35+40)+20, 4*140+2*35)\r
- width = self.width\r
- debug("[FritzCallSetup] width: " + str(self.width))\r
- self.skin = """\r
- <screen name="FritzCallSetup" position="center,center" size="%d,%d" title="FritzCall Setup" >\r
- <eLabel position="0,0" size="%d,2" backgroundColor="#aaaaaa" />\r
- <widget name="consideration" position="%d,%d" halign="center" size="%d,%d" font="Regular;%d" backgroundColor="#20040404" transparent="1" />\r
- <eLabel position="0,%d" size="%d,2" backgroundColor="#aaaaaa" />\r
- <widget name="config" position="%d,%d" size="%d,%d" scrollbarMode="showOnDemand" backgroundColor="#20040404" transparent="1" />\r
- <eLabel position="0,%d" size="%d,2" backgroundColor="#aaaaaa" />\r
- <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />\r
- <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />\r
- <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />\r
- <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />\r
- <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" />\r
- <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" />\r
- <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" />\r
- <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" />\r
- <ePixmap position="%d,%d" zPosition="4" size="35,25" pixmap="%s" transparent="1" alphatest="on" />\r
- <ePixmap position="%d,%d" zPosition="4" size="35,25" pixmap="%s" transparent="1" alphatest="on" />\r
- </screen>""" % (\r
- # (DESKTOP_WIDTH-width)/2, scaleV(100, 73), # position \r
- width, scaleV(560, 430), # size\r
- width, # eLabel width\r
- scaleH(40, 20), scaleV(10, 5), # consideration position\r
- scaleH(width-80, width-40), scaleV(25, 45), # consideration size\r
- scaleV(22, 20), # consideration font size\r
- scaleV(40, 50), # eLabel position vertical\r
- width, # eLabel width\r
- scaleH(40, 5), scaleV(60, 57), # config position\r
- scaleH(width-80, width-10), scaleV(453, 328), # config size\r
- scaleV(518, 390), # eLabel position vertical\r
- width, # eLabel width\r
- scaleH(20, 0), scaleV(525, 395), "skin_default/buttons/red.png", # pixmap red\r
- scaleH(20+140+90, 140), scaleV(525, 395), "skin_default/buttons/green.png", # pixmap green\r
- scaleH(20+2*(140+90), 2*140), scaleV(525, 395), "skin_default/buttons/yellow.png", # pixmap yellow\r
- scaleH(20+3*(140+90), 3*140), scaleV(525, 395), "skin_default/buttons/blue.png", # pixmap blue\r
- scaleH(20, 0), scaleV(525, 395), scaleV(21, 21), # widget red\r
- scaleH(20+(140+90), 140), scaleV(525, 395), scaleV(21, 21), # widget green\r
- scaleH(20+2*(140+90), 2*140), scaleV(525, 395), scaleV(21, 21), # widget yellow\r
- scaleH(20+3*(140+90), 3*140), scaleV(525, 395), scaleV(21, 21), # widget blue\r
- scaleH(20+4*(140+90), 4*140), scaleV(532, 402), "skin_default/buttons/key_info.png", # button info\r
- scaleH(20+4*(140+90)+(35+40), 4*140+35), scaleV(532, 402), "skin_default/buttons/key_menu.png", # button menu\r
- )\r
-\r
- Screen.__init__(self, session)\r
- HelpableScreen.__init__(self)\r
- self.session = session\r
-\r
- self["consideration"] = Label(_("You need to enable the monitoring on your FRITZ!Box by dialing #96*5*!"))\r
- self.list = []\r
-\r
- # Initialize Buttons\r
- # TRANSLATORS: keep it short, this is a button\r
- self["key_red"] = Button(_("Cancel"))\r
- # TRANSLATORS: keep it short, this is a button\r
- self["key_green"] = Button(_("OK"))\r
- # TRANSLATORS: keep it short, this is a button\r
- self["key_yellow"] = Button(_("Phone calls"))\r
- # TRANSLATORS: keep it short, this is a button\r
- self["key_blue"] = Button(_("Phonebook"))\r
- # TRANSLATORS: keep it short, this is a button\r
- self["key_info"] = Button(_("About FritzCall"))\r
- # TRANSLATORS: keep it short, this is a button\r
- self["key_menu"] = Button(_("FRITZ!Box Fon Status"))\r
-\r
- self["setupActions"] = ActionMap(["ColorActions", "OkCancelActions", "MenuActions", "EPGSelectActions"],\r
- {\r
- "red": self.cancel,\r
- "green": self.save,\r
- "yellow": self.displayCalls,\r
- "blue": self.displayPhonebook,\r
- "cancel": self.cancel,\r
- "ok": self.save,\r
- "menu": self.menu,\r
- "info": self.about,\r
- }, - 2)\r
-\r
- # TRANSLATORS: keep it short, this is a help text\r
- self.helpList.append((self["setupActions"], "ColorActions", [("red", _("quit"))]))\r
- # TRANSLATORS: keep it short, this is a help text\r
- self.helpList.append((self["setupActions"], "ColorActions", [("green", _("save and quit"))]))\r
- # TRANSLATORS: keep it short, this is a help text\r
- self.helpList.append((self["setupActions"], "ColorActions", [("yellow", _("display calls"))]))\r
- # TRANSLATORS: keep it short, this is a help text\r
- self.helpList.append((self["setupActions"], "ColorActions", [("blue", _("display phonebook"))]))\r
- # TRANSLATORS: keep it short, this is a help text\r
- self.helpList.append((self["setupActions"], "OkCancelActions", [("ok", _("save and quit"))]))\r
- # TRANSLATORS: keep it short, this is a help text\r
- self.helpList.append((self["setupActions"], "OkCancelActions", [("cancel", _("quit"))]))\r
- # TRANSLATORS: keep it short, this is a help text\r
- self.helpList.append((self["setupActions"], "MenuActions", [("menu", _("FRITZ!Box Fon Status"))]))\r
- # TRANSLATORS: keep it short, this is a help text\r
- self.helpList.append((self["setupActions"], "EPGSelectActions", [("info", _("About FritzCall"))]))\r
-\r
- ConfigListScreen.__init__(self, self.list, session=session)\r
-\r
- # get new list of locations for PhoneBook.txt\r
- self._mountedDevs = getMountedDevs()\r
- self.createSetup()\r
- self.onLayoutFinish.append(self.setWindowTitle)\r
-\r
- def setWindowTitle(self):\r
- # TRANSLATORS: this is a window title.\r
- self.setTitle(_("FritzCall Setup") + " (" + "$Revision$"[1: - 1] + "$Date$"[7:23] + ")")\r
-\r
- def keyLeft(self):\r
- ConfigListScreen.keyLeft(self)\r
- self.createSetup()\r
-\r
- def keyRight(self):\r
- ConfigListScreen.keyRight(self)\r
- self.createSetup()\r
-\r
- def createSetup(self):\r
- self.list = [ ]\r
- self.list.append(getConfigListEntry(_("Call monitoring"), config.plugins.FritzCall.enable))\r
- if config.plugins.FritzCall.enable.value:\r
- self.list.append(getConfigListEntry(_("FRITZ!Box FON address (Name or IP)"), config.plugins.FritzCall.hostname))\r
-\r
- self.list.append(getConfigListEntry(_("Show after Standby"), config.plugins.FritzCall.afterStandby))\r
-\r
- self.list.append(getConfigListEntry(_("Show only calls for specific MSN"), config.plugins.FritzCall.filter))\r
- if config.plugins.FritzCall.filter.value:\r
- self.list.append(getConfigListEntry(_("MSN to show (separated by ,)"), config.plugins.FritzCall.filtermsn))\r
- self.list.append(getConfigListEntry(_("Filter also list of calls"), config.plugins.FritzCall.filterCallList))\r
- self.list.append(getConfigListEntry(_("Mute on call"), config.plugins.FritzCall.muteOnCall))\r
-\r
- self.list.append(getConfigListEntry(_("Show Outgoing Calls"), config.plugins.FritzCall.showOutgoing))\r
- # not only for outgoing: config.plugins.FritzCall.showOutgoing.value:\r
- self.list.append(getConfigListEntry(_("Areacode to add to calls without one (if necessary)"), config.plugins.FritzCall.prefix))\r
- self.list.append(getConfigListEntry(_("Timeout for Call Notifications (seconds)"), config.plugins.FritzCall.timeout))\r
- self.list.append(getConfigListEntry(_("Reverse Lookup Caller ID (select country below)"), config.plugins.FritzCall.lookup))\r
- if config.plugins.FritzCall.lookup.value:\r
- self.list.append(getConfigListEntry(_("Country"), config.plugins.FritzCall.country))\r
-\r
- # TODO: make password unreadable?\r
- self.list.append(getConfigListEntry(_("Password Accessing FRITZ!Box"), config.plugins.FritzCall.password))\r
- self.list.append(getConfigListEntry(_("Extension number to initiate call on"), config.plugins.FritzCall.extension))\r
- self.list.append(getConfigListEntry(_("Read PhoneBook from FRITZ!Box"), config.plugins.FritzCall.fritzphonebook))\r
- if config.plugins.FritzCall.fritzphonebook.value:\r
- self.list.append(getConfigListEntry(_("Append type of number"), config.plugins.FritzCall.showType))\r
- self.list.append(getConfigListEntry(_("Append shortcut number"), config.plugins.FritzCall.showShortcut))\r
- self.list.append(getConfigListEntry(_("Append vanity name"), config.plugins.FritzCall.showVanity))\r
-\r
- self.list.append(getConfigListEntry(_("Use internal PhoneBook"), config.plugins.FritzCall.phonebook))\r
- if config.plugins.FritzCall.phonebook.value:\r
- if config.plugins.FritzCall.phonebookLocation.value in self._mountedDevs:\r
- config.plugins.FritzCall.phonebookLocation.setChoices(self._mountedDevs, config.plugins.FritzCall.phonebookLocation.value)\r
- else:\r
- config.plugins.FritzCall.phonebookLocation.setChoices(self._mountedDevs)\r
- path = config.plugins.FritzCall.phonebookLocation.value\r
- # check whether we can write to PhoneBook.txt\r
- if os.path.exists(os.path.join(path[0], "PhoneBook.txt")):\r
- if not os.access(os.path.join(path[0], "PhoneBook.txt"), os.W_OK):\r
- debug("[FritzCallSetup] createSetup: %s/PhoneBook.txt not writable, resetting to default" %(path[0]))\r
- config.plugins.FritzCall.phonebookLocation.setChoices(self._mountedDevs)\r
- elif not (os.path.isdir(path[0]) and os.access(path[0], os.W_OK|os.X_OK)):\r
- debug("[FritzCallSetup] createSetup: directory %s not writable, resetting to default" %(path[0]))\r
- config.plugins.FritzCall.phonebookLocation.setChoices(self._mountedDevs)\r
-\r
- self.list.append(getConfigListEntry(_("PhoneBook Location"), config.plugins.FritzCall.phonebookLocation))\r
- if config.plugins.FritzCall.lookup.value:\r
- self.list.append(getConfigListEntry(_("Automatically add new Caller to PhoneBook"), config.plugins.FritzCall.addcallers))\r
-\r
- self.list.append(getConfigListEntry(_("Strip Leading 0"), config.plugins.FritzCall.internal))\r
- # self.list.append(getConfigListEntry(_("Default display mode for FRITZ!Box calls"), config.plugins.FritzCall.fbfCalls))\r
- self.list.append(getConfigListEntry(_("Display connection infos"), config.plugins.FritzCall.connectionVerbose))\r
- self.list.append(getConfigListEntry(_("Debug"), config.plugins.FritzCall.debug))\r
-\r
- self["config"].list = self.list\r
- self["config"].l.setList(self.list)\r
-\r
- def save(self):\r
-# debug("[FritzCallSetup] save"\r
- for x in self["config"].list:\r
- x[1].save()\r
- if config.plugins.FritzCall.phonebookLocation.isChanged():\r
- global phonebook\r
- phonebook = FritzCallPhonebook()\r
- if fritz_call:\r
- if config.plugins.FritzCall.enable.value:\r
- fritz_call.connect()\r
- else:\r
- fritz_call.shutdown()\r
- self.close()\r
-\r
- def cancel(self):\r
-# debug("[FritzCallSetup] cancel"\r
- for x in self["config"].list:\r
- x[1].cancel()\r
- self.close()\r
-\r
- def displayCalls(self):\r
- if config.plugins.FritzCall.enable.value:\r
- if fritzbox:\r
- self.session.open(FritzDisplayCalls)\r
- else:\r
- self.session.open(MessageBox, _("Cannot get calls from FRITZ!Box"), type=MessageBox.TYPE_INFO)\r
- else:\r
- self.session.open(MessageBox, _("Plugin not active"), type=MessageBox.TYPE_INFO)\r
-\r
- def displayPhonebook(self):\r
- if phonebook:\r
- if config.plugins.FritzCall.enable.value:\r
- self.session.open(phonebook.FritzDisplayPhonebook)\r
- else:\r
- self.session.open(MessageBox, _("Plugin not active"), type=MessageBox.TYPE_INFO)\r
- else:\r
- self.session.open(MessageBox, _("No phonebook"), type=MessageBox.TYPE_INFO)\r
-\r
- def about(self):\r
- self.session.open(FritzAbout)\r
-\r
- def menu(self):\r
- if config.plugins.FritzCall.enable.value:\r
- if fritzbox and fritzbox.info:\r
- self.session.open(FritzMenu)\r
- else:\r
- self.session.open(MessageBox, _("Cannot get infos from FRITZ!Box"), type=MessageBox.TYPE_INFO)\r
- else:\r
- self.session.open(MessageBox, _("Plugin not active"), type=MessageBox.TYPE_INFO)\r
-\r
-standbyMode = False\r
-\r
-class FritzCallList:\r
- def __init__(self):\r
- self.callList = [ ]\r
- \r
- def add(self, event, date, number, caller, phone):\r
- debug("[FritzCallList] add: %s %s" % (number, caller))\r
- if len(self.callList) > 10:\r
- if self.callList[0] != "Start":\r
- self.callList[0] = "Start"\r
- del self.callList[1]\r
-\r
- self.callList.append((event, number, date, caller, phone))\r
- \r
- def display(self):\r
- debug("[FritzCallList] display")\r
- global standbyMode\r
- standbyMode = False\r
- # Standby.inStandby.onClose.remove(self.display) object does not exist anymore...\r
- # build screen from call list\r
- text = "\n"\r
- if self.callList[0] == "Start":\r
- text = text + _("Last 10 calls:\n")\r
- del self.callList[0]\r
-\r
- for call in self.callList:\r
- (event, number, date, caller, phone) = call\r
- if event == "RING":\r
- direction = "->"\r
- else:\r
- direction = "<-"\r
-\r
- # shorten the date info\r
- date = date[:6] + date[9:14]\r
-\r
- # our phone could be of the form "0123456789 (home)", then we only take "home"\r
- oBrack = phone.find('(')\r
- cBrack = phone.find(')')\r
- if oBrack != -1 and cBrack != -1:\r
- phone = phone[oBrack+1:cBrack]\r
-\r
- # should not happen, for safety reasons\r
- if not caller:\r
- caller = _("UNKNOWN")\r
- \r
- # if we have an unknown number, show the number\r
- if caller == _("UNKNOWN") and number != "":\r
- caller = number\r
- else:\r
- # strip off the address part of the remote caller/callee, if there is any\r
- nl = caller.find('\n')\r
- if nl != -1:\r
- caller = caller[:nl]\r
- elif caller[0] == '[' and caller[-1] == ']':\r
- # that means, we've got an unknown number with a city added from avon.dat \r
- if (len(number) + 1 + len(caller) + len(phone)) <= 40:\r
- caller = number + ' ' + caller\r
- else:\r
- caller = number\r
-\r
- while (len(caller) + len(phone)) > 40:\r
- if len(caller) > len(phone):\r
- caller = caller[: - 1]\r
- else:\r
- phone = phone[: - 1]\r
-\r
- text = text + "%s %s %s %s\n" % (date, caller, direction, phone)\r
-\r
- debug("[FritzCallList] display: '%s %s %s %s'" % (date, caller, direction, phone))\r
- # display screen\r
- Notifications.AddNotification(MessageBox, text, type=MessageBox.TYPE_INFO)\r
- # TODO please HELP: from where can I get a session?\r
- # my_global_session.open(FritzDisplayCalls, text)\r
- self.callList = [ ]\r
-\r
-callList = FritzCallList()\r
-\r
-def findFace(number, name):\r
- debug("[FritzCall] findFace number/name: %s/%s" % (number, name))\r
- if name:\r
- sep = name.find(',')\r
- if sep != -1:\r
- name = name[:sep]\r
- sep = name.find('\n')\r
- if sep != -1:\r
- name = name[:sep]\r
- else:\r
- name = _("UNKNOWN")\r
-\r
- facesDir = os.path.join(config.plugins.FritzCall.phonebookLocation.value, "FritzCallFaces")\r
- numberFile = os.path.join(facesDir, number)\r
- nameFile = os.path.join(facesDir, name)\r
- facesFile = ""\r
- if number and os.path.exists(numberFile):\r
- facesFile = numberFile\r
- elif number and os.path.exists(numberFile + ".png"):\r
- facesFile = numberFile + ".png"\r
- elif number and os.path.exists(numberFile + ".PNG"):\r
- facesFile = numberFile + ".PNG"\r
- elif name and os.path.exists(nameFile + ".png"):\r
- facesFile = nameFile + ".png"\r
- elif name and os.path.exists(nameFile + ".PNG"):\r
- facesFile = nameFile + ".PNG"\r
- else:\r
- facesFile = resolveFilename(SCOPE_SKIN_IMAGE, "skin_default/icons/input_info.png")\r
-\r
- debug("[FritzCall] findFace result: %s" % (facesFile))\r
- return facesFile\r
-\r
-class MessageBoxPixmap(Screen):\r
- def __init__(self, session, text, number = "", name = "", timeout = -1):\r
- self.skin = """\r
- <screen name="MessageBoxPixmap" position="center,center" size="600,10" title="MessageBoxPixmap">\r
- <widget name="text" position="115,8" size="520,0" font="Regular;%d" />\r
- <widget name="InfoPixmap" pixmap="%s" position="5,5" size="100,100" alphatest="on" />\r
- </screen>\r
- """ % (\r
- # scaleH(350, 60), scaleV(175, 245),\r
- scaleV(24, 22), resolveFilename(SCOPE_SKIN_IMAGE, "skin_default/icons/input_info.png")\r
- )\r
- debug("[FritzCall] MessageBoxPixmap number: %s" % number)\r
- Screen.__init__(self, session)\r
- # MessageBox.__init__(self, session, text, type=MessageBox.TYPE_INFO, timeout=timeout)\r
- self["text"] = Label(text)\r
- self["InfoPixmap"] = Pixmap()\r
- self._session = session\r
- self._number = number\r
- self._name = name\r
- self._timerRunning = False\r
- self._timer = None\r
- self._timeout = timeout\r
- self._origTitle = None\r
- self._initTimeout()\r
- self.onLayoutFinish.append(self._finishLayout)\r
- self["actions"] = ActionMap(["OkCancelActions"],\r
- {\r
- "cancel": self._exit,\r
- "ok": self._exit, }, - 2)\r
-\r
- def _finishLayout(self):\r
- # pylint: disable-msg=W0142\r
- debug("[FritzCall] MessageBoxPixmap/setInfoPixmap number: %s/%s" % (self._number, self._name))\r
-\r
- faceFile = findFace(self._number, self._name)\r
- picPixmap = LoadPixmap(faceFile)\r
- if not picPixmap: # that means most probably, that the picture is not 8 bit...\r
- Notifications.AddNotification(MessageBox, _("Found picture\n\n%s\n\nBut did not load. Probably not PNG, 8-bit") %faceFile, type = MessageBox.TYPE_ERROR)\r
- picPixmap = LoadPixmap(resolveFilename(SCOPE_SKIN_IMAGE, "skin_default/icons/input_error.png"))\r
- picSize = picPixmap.size()\r
- self["InfoPixmap"].instance.setPixmap(picPixmap)\r
-\r
- # recalculate window size\r
- textSize = self["text"].getSize()\r
- textSize = (textSize[0]+20, textSize[1]+20) # don't know, why, but size is too small\r
- textSize = eSize(*textSize)\r
- width = max(scaleH(600, 280), picSize.width() + textSize.width() + 30)\r
- height = max(scaleV(300, 250), picSize.height()+10, textSize.height()+10)\r
- wSize = (width, height)\r
- wSize = eSize(*wSize)\r
-\r
- # center the smaller vertically\r
- hGap = (width-picSize.width()-textSize.width())/3\r
- picPos = (hGap, (height-picSize.height())/2+1)\r
- textPos = (hGap+picSize.width()+hGap, (height-textSize.height())/2+1)\r
-\r
- # resize screen\r
- self.instance.resize(wSize)\r
- # resize text\r
- self["text"].instance.resize(textSize)\r
- # resize pixmap\r
- self["InfoPixmap"].instance.resize(picSize)\r
- # move text\r
- self["text"].instance.move(ePoint(*textPos))\r
- # move pixmap\r
- self["InfoPixmap"].instance.move(ePoint(*picPos))\r
- # center window\r
- self.instance.move(ePoint((DESKTOP_WIDTH-wSize.width())/2, (DESKTOP_HEIGHT-wSize.height())/2))\r
-\r
- def _initTimeout(self):\r
- if self._timeout > 0:\r
- self._timer = eTimer()\r
- self._timer.callback.append(self._timerTick)\r
- self.onExecBegin.append(self._startTimer)\r
- self._origTitle = None\r
- if self.execing:\r
- self._timerTick()\r
- else:\r
- self.onShown.append(self.__onShown)\r
- self._timerRunning = True\r
- else:\r
- self._timerRunning = False\r
-\r
- def __onShown(self):\r
- self.onShown.remove(self.__onShown)\r
- self._timerTick()\r
-\r
- def _startTimer(self):\r
- self._timer.start(1000)\r
-\r
-#===============================================================================\r
-# def stopTimer(self):\r
-# if self._timerRunning:\r
-# del self._timer\r
-# self.setTitle(self._origTitle)\r
-# self._timerRunning = False\r
-#===============================================================================\r
-\r
- def _timerTick(self):\r
- if self.execing:\r
- self._timeout -= 1\r
- if self._origTitle is None:\r
- self._origTitle = self.instance.getTitle()\r
- self.setTitle(self._origTitle + " (" + str(self._timeout) + ")")\r
- if self._timeout == 0:\r
- self._timer.stop()\r
- self._timerRunning = False\r
- self._exit()\r
-\r
- def _exit(self):\r
- self.close()\r
-\r
-mutedOnConnID = None\r
-def notifyCall(event, date, number, caller, phone, connID):\r
- if Standby.inStandby is None or config.plugins.FritzCall.afterStandby.value == "each":\r
- if event == "RING":\r
- global mutedOnConnID\r
- if config.plugins.FritzCall.muteOnCall.value =="ring" and not mutedOnConnID:\r
- debug("[FritzCall] mute on connID: %s" % connID)\r
- mutedOnConnID = connID\r
- # eDVBVolumecontrol.getInstance().volumeMute() # with this, we get no mute icon...\r
- if not eDVBVolumecontrol.getInstance().isMuted():\r
- globalActionMap.actions["volumeMute"]()\r
- text = _("Incoming Call on %(date)s from\n---------------------------------------------\n%(number)s\n%(caller)s\n---------------------------------------------\nto: %(phone)s") % { 'date':date, 'number':number, 'caller':caller, 'phone':phone }\r
- else:\r
- text = _("Outgoing Call on %(date)s to\n---------------------------------------------\n%(number)s\n%(caller)s\n---------------------------------------------\nfrom: %(phone)s") % { 'date':date, 'number':number, 'caller':caller, 'phone':phone }\r
- debug("[FritzCall] notifyCall:\n%s" % text)\r
- # Notifications.AddNotification(MessageBox, text, type=MessageBox.TYPE_INFO, timeout=config.plugins.FritzCall.timeout.value)\r
- Notifications.AddNotification(MessageBoxPixmap, text, number=number, name=caller, timeout=config.plugins.FritzCall.timeout.value)\r
- elif config.plugins.FritzCall.afterStandby.value == "inList":\r
- #\r
- # if not yet done, register function to show call list\r
- global standbyMode\r
- if not standbyMode :\r
- standbyMode = True\r
- Standby.inStandby.onHide.append(callList.display) #@UndefinedVariable\r
- # add text/timeout to call list\r
- callList.add(event, date, number, caller, phone)\r
- debug("[FritzCall] notifyCall: added to callList")\r
- else: # this is the "None" case\r
- debug("[FritzCall] notifyCall: standby and no show")\r
-\r
-\r
-#===============================================================================\r
-# We need a separate class for each invocation of reverseLookup to retain\r
-# the necessary data for the notification\r
-#===============================================================================\r
-\r
-countries = { }\r
-reverselookupMtime = 0\r
-\r
-class FritzReverseLookupAndNotifier:\r
- def __init__(self, event, number, caller, phone, date, connID):\r
- '''\r
- \r
- Initiate a reverse lookup for the given number in the configured country\r
- \r
- @param event: CALL or RING\r
- @param number: number to be looked up\r
- @param caller: caller including name and address\r
- @param phone: Number (and name) of or own phone\r
- @param date: date of call\r
- '''\r
- debug("[FritzReverseLookupAndNotifier] reverse Lookup for %s!" % number)\r
- self.event = event\r
- self.number = number\r
- self.caller = caller\r
- self.phone = phone\r
- self.date = date\r
- self.connID = connID\r
-\r
- if number[0] != "0":\r
- self.notifyAndReset(number, caller)\r
- return\r
-\r
- ReverseLookupAndNotifier(number, self.notifyAndReset, "UTF-8", config.plugins.FritzCall.country.value)\r
-\r
- def notifyAndReset(self, number, caller):\r
- '''\r
- \r
- this gets called with the result of the reverse lookup\r
- \r
- @param number: number\r
- @param caller: name and address of remote. it comes in with name, address and city separated by commas\r
- '''\r
- debug("[FritzReverseLookupAndNotifier] got: " + caller)\r
- self.number = number\r
-#===============================================================================\r
-# if not caller and os.path.exists(config.plugins.FritzCall.phonebookLocation.value + "/PhoneBook.csv"):\r
-# caller = FritzOutlookCSV.findNumber(number, config.plugins.FritzCall.phonebookLocation.value + "/PhoneBook.csv") #@UndefinedVariable\r
-# debug("[FritzReverseLookupAndNotifier] got from Outlook csv: " + caller)\r
-#===============================================================================\r
-#===============================================================================\r
-# if not caller and os.path.exists(config.plugins.FritzCall.phonebookLocation.value + "/PhoneBook.ldif"):\r
-# caller = FritzLDIF.findNumber(number, open(config.plugins.FritzCall.phonebookLocation.value + "/PhoneBook.ldif"))\r
-# debug("[FritzReverseLookupAndNotifier] got from ldif: " + caller)\r
-#===============================================================================\r
-\r
- name = handleReverseLookupResult(caller)\r
- if name:\r
- self.caller = name.replace(", ", "\n").replace('#','')\r
- # TODO: I don't know, why we store only for incoming calls...\r
- # if self.number != 0 and config.plugins.FritzCall.addcallers.value and self.event == "RING":\r
- if self.number != 0 and config.plugins.FritzCall.addcallers.value:\r
- debug("[FritzReverseLookupAndNotifier] add to phonebook")\r
- phonebook.add(self.number, self.caller)\r
- else:\r
- name = resolveNumberWithAvon(self.number, config.plugins.FritzCall.country.value)\r
- if not name:\r
- self.caller = _("UNKNOWN")\r
- else:\r
- self.caller = name\r
- notifyCall(self.event, self.date, self.number, self.caller, self.phone, self.connID)\r
- # kill that object...\r
-\r
-class FritzProtocol(LineReceiver):\r
- def __init__(self):\r
- debug("[FritzProtocol] " + "$Revision$"[1:-1] + "$Date$"[7:23] + " starting")\r
- global mutedOnConnID\r
- mutedOnConnID = None\r
- self.number = '0'\r
- self.caller = None\r
- self.phone = None\r
- self.date = '0'\r
- self.event = None\r
- self.connID = None\r
-\r
- def resetValues(self):\r
- debug("[FritzProtocol] resetValues")\r
- self.number = '0'\r
- self.caller = None\r
- self.phone = None\r
- self.date = '0'\r
- self.event = None\r
- self.connID = None\r
-\r
- def notifyAndReset(self):\r
- notifyCall(self.event, self.date, self.number, self.caller, self.phone, self.connID)\r
- self.resetValues()\r
-\r
- def lineReceived(self, line):\r
- debug("[FritzProtocol] lineReceived: %s" % line)\r
-#15.07.06 00:38:54;CALL;1;4;<from/our msn>;<to/extern>;\r
-#15.07.06 00:38:58;DISCONNECT;1;0;\r
-#15.07.06 00:39:22;RING;0;<from/extern>;<to/our msn>;\r
-#15.07.06 00:39:27;DISCONNECT;0;0;\r
- anEvent = line.split(';')\r
- (self.date, self.event) = anEvent[0:2]\r
- self.connID = anEvent[2]\r
-\r
- filtermsns = config.plugins.FritzCall.filtermsn.value.split(",")\r
- for i in range(len(filtermsns)):\r
- filtermsns[i] = filtermsns[i].strip()\r
-\r
- # debug("[FritzProtocol] Volcontrol dir: %s" % dir(eDVBVolumecontrol.getInstance()))\r
- # debug("[FritzCall] unmute on connID: %s?" %self.connID)\r
- global mutedOnConnID\r
- if self.event == "DISCONNECT" and config.plugins.FritzCall.muteOnCall.value and mutedOnConnID == self.connID:\r
- debug("[FritzCall] unmute on connID: %s!" % self.connID)\r
- mutedOnConnID = None\r
- # eDVBVolumecontrol.getInstance().volumeUnMute()\r
- if eDVBVolumecontrol.getInstance().isMuted():\r
- globalActionMap.actions["volumeMute"]()\r
- # not supported so far, because, taht would mean muting on EVERY connect, regardless of RING or CALL or filter active\r
- #=======================================================================\r
- # elif self.event == "CONNECT" and config.plugins.FritzCall.muteOnCall.value == "connect":\r
- # debug("[FritzCall] mute on connID: %s" % self.connID)\r
- # mutedOnConnID = self.connID\r
- # # eDVBVolumecontrol.getInstance().volumeMute() # with this, we get no mute icon...\r
- # if not eDVBVolumecontrol.getInstance().isMuted():\r
- # globalActionMap.actions["volumeMute"]()\r
- #=======================================================================\r
- elif self.event == "RING" or (self.event == "CALL" and config.plugins.FritzCall.showOutgoing.value):\r
- phone = anEvent[4]\r
-\r
- if self.event == "RING":\r
- number = anEvent[3] \r
- if fritzbox and number in fritzbox.blacklist[0]:\r
- debug("[FritzProtocol] lineReceived phone: '''%s''' blacklisted number: '''%s'''" % (phone, number))\r
- return \r
- else:\r
- number = anEvent[5]\r
- if number in fritzbox.blacklist[1]:\r
- debug("[FritzProtocol] lineReceived phone: '''%s''' blacklisted number: '''%s'''" % (phone, number))\r
- return \r
-\r
- debug("[FritzProtocol] lineReceived phone: '''%s''' number: '''%s'''" % (phone, number))\r
-\r
- if not (config.plugins.FritzCall.filter.value and phone not in filtermsns):\r
- debug("[FritzProtocol] lineReceived no filter hit")\r
- if phone:\r
- phonename = phonebook.search(phone) # do we have a name for the number of our side?\r
- if phonename:\r
- self.phone = "%s (%s)" % (phone, phonename)\r
- else:\r
- self.phone = phone\r
- else:\r
- self.phone = _("UNKNOWN")\r
-\r
- if not number:\r
- debug("[FritzProtocol] lineReceived: no number")\r
- self.number = _("number suppressed")\r
- self.caller = _("UNKNOWN")\r
- else:\r
- if config.plugins.FritzCall.internal.value and len(number) > 3 and number[0] == "0":\r
- debug("[FritzProtocol] lineReceived: strip leading 0")\r
- self.number = number[1:]\r
- else:\r
- self.number = number\r
- if self.event == "CALL" and self.number[0] != '0': # should only happen for outgoing\r
- debug("[FritzProtocol] lineReceived: add local prefix")\r
- self.number = config.plugins.FritzCall.prefix.value + self.number\r
- \r
- # strip CbC prefixes\r
- if self.event == "CALL":\r
- number = stripCbCPrefix(self.number, config.plugins.FritzCall.country.value)\r
- \r
- debug("[FritzProtocol] lineReceived phonebook.search: %s" % self.number)\r
- self.caller = phonebook.search(self.number)\r
- debug("[FritzProtocol] lineReceived phonebook.search reault: %s" % self.caller)\r
- if not self.caller:\r
- if config.plugins.FritzCall.lookup.value:\r
- FritzReverseLookupAndNotifier(self.event, self.number, self.caller, self.phone, self.date, self.connID)\r
- return # reverselookup is supposed to handle the message itself\r
- else:\r
- self.caller = _("UNKNOWN")\r
-\r
- self.notifyAndReset()\r
-\r
-class FritzClientFactory(ReconnectingClientFactory):\r
- initialDelay = 20\r
- maxDelay = 30\r
-\r
- def __init__(self):\r
- self.hangup_ok = False\r
- def startedConnecting(self, connector): #@UnusedVariable # pylint: disable-msg=W0613\r
- if config.plugins.FritzCall.connectionVerbose.value:\r
- Notifications.AddNotification(MessageBox, _("Connecting to FRITZ!Box..."), type=MessageBox.TYPE_INFO, timeout=2)\r
-\r
- def buildProtocol(self, addr): #@UnusedVariable # pylint: disable-msg=W0613\r
- global fritzbox, phonebook\r
- if config.plugins.FritzCall.connectionVerbose.value:\r
- Notifications.AddNotification(MessageBox, _("Connected to FRITZ!Box!"), type=MessageBox.TYPE_INFO, timeout=4)\r
- self.resetDelay()\r
- initDebug()\r
- initCbC()\r
- initAvon()\r
- fritzbox = FritzCallFBF()\r
- phonebook = FritzCallPhonebook()\r
- return FritzProtocol()\r
-\r
- def clientConnectionLost(self, connector, reason):\r
- global fritzbox\r
- if not self.hangup_ok and config.plugins.FritzCall.connectionVerbose.value:\r
- Notifications.AddNotification(MessageBox, _("Connection to FRITZ!Box! lost\n (%s)\nretrying...") % reason.getErrorMessage(), type=MessageBox.TYPE_INFO, timeout=config.plugins.FritzCall.timeout.value)\r
- ReconnectingClientFactory.clientConnectionLost(self, connector, reason)\r
- # config.plugins.FritzCall.enable.value = False\r
- fritzbox = None\r
-\r
- def clientConnectionFailed(self, connector, reason):\r
- global fritzbox\r
- if config.plugins.FritzCall.connectionVerbose.value:\r
- Notifications.AddNotification(MessageBox, _("Connecting to FRITZ!Box failed\n (%s)\nretrying...") % reason.getErrorMessage(), type=MessageBox.TYPE_INFO, timeout=config.plugins.FritzCall.timeout.value)\r
- ReconnectingClientFactory.clientConnectionFailed(self, connector, reason)\r
- # config.plugins.FritzCall.enable.value = False\r
- fritzbox = None\r
- \r
-class FritzCall:\r
- def __init__(self):\r
- self.dialog = None\r
- self.desc = None\r
- if config.plugins.FritzCall.enable.value:\r
- self.connect()\r
-\r
- def connect(self):\r
- self.abort()\r
- if config.plugins.FritzCall.enable.value:\r
- fact = FritzClientFactory()\r
- self.desc = (fact, reactor.connectTCP(config.plugins.FritzCall.hostname.value, 1012, fact)) #@UndefinedVariable # pylint: disable-msg=E1101\r
-\r
- def shutdown(self):\r
- self.abort()\r
-\r
- def abort(self):\r
- if self.desc is not None:\r
- self.desc[0].hangup_ok = True\r
- self.desc[0].stopTrying()\r
- self.desc[1].disconnect()\r
- self.desc = None\r
-\r
-def displayCalls(session, servicelist=None): #@UnusedVariable # pylint: disable-msg=W0613\r
- if config.plugins.FritzCall.enable.value:\r
- if fritzbox:\r
- session.open(FritzDisplayCalls)\r
- else:\r
- Notifications.AddNotification(MessageBox, _("Cannot get calls from FRITZ!Box"), type=MessageBox.TYPE_INFO)\r
- else:\r
- Notifications.AddNotification(MessageBox, _("Plugin not active"), type=MessageBox.TYPE_INFO)\r
-\r
-def displayPhonebook(session, servicelist=None): #@UnusedVariable # pylint: disable-msg=W0613\r
- if phonebook:\r
- if config.plugins.FritzCall.enable.value:\r
- session.open(phonebook.FritzDisplayPhonebook)\r
- else:\r
- Notifications.AddNotification(MessageBox, _("Plugin not active"), type=MessageBox.TYPE_INFO)\r
- else:\r
- Notifications.AddNotification(MessageBox, _("No phonebook"), type=MessageBox.TYPE_INFO)\r
-\r
-def displayFBFStatus(session, servicelist=None): #@UnusedVariable # pylint: disable-msg=W0613\r
- if config.plugins.FritzCall.enable.value:\r
- if fritzbox and fritzbox.info:\r
- session.open(FritzMenu)\r
- else:\r
- Notifications.AddNotification(MessageBox, _("Cannot get infos from FRITZ!Box"), type=MessageBox.TYPE_INFO)\r
- else:\r
- Notifications.AddNotification(MessageBox, _("Plugin not active"), type=MessageBox.TYPE_INFO)\r
-\r
-def main(session):\r
- session.open(FritzCallSetup)\r
-\r
-fritz_call = None\r
-\r
-def autostart(reason, **kwargs):\r
- global fritz_call\r
-\r
- # ouch, this is a hack\r
- if kwargs.has_key("session"):\r
- global my_global_session\r
- my_global_session = kwargs["session"]\r
- return\r
-\r
- debug("[FRITZ!Call] - Autostart")\r
- if reason == 0:\r
- fritz_call = FritzCall()\r
- elif reason == 1:\r
- fritz_call.shutdown()\r
- fritz_call = None\r
-\r
-def Plugins(**kwargs): #@UnusedVariable # pylint: disable-msg=W0613,C0103\r
- what = _("Display FRITZ!box-Fon calls on screen")\r
- what_calls = _("Phone calls")\r
- what_phonebook = _("Phonebook")\r
- what_status = _("FRITZ!Box Fon Status")\r
- return [ PluginDescriptor(name="FritzCall", description=what, where=PluginDescriptor.WHERE_PLUGINMENU, icon="plugin.png", fnc=main),\r
- PluginDescriptor(name=what_calls, description=what_calls, where=PluginDescriptor.WHERE_EXTENSIONSMENU, fnc=displayCalls),\r
- PluginDescriptor(name=what_phonebook, description=what_phonebook, where=PluginDescriptor.WHERE_EXTENSIONSMENU, fnc=displayPhonebook),\r
- PluginDescriptor(name=what_status, description=what_status, where=PluginDescriptor.WHERE_EXTENSIONSMENU, fnc=displayFBFStatus),\r
- PluginDescriptor(where=[PluginDescriptor.WHERE_SESSIONSTART, PluginDescriptor.WHERE_AUTOSTART], fnc=autostart) ]\r
+# -*- coding: utf-8 -*-
+'''
+$Author$
+$Revision$
+$Date$
+$Id$
+'''
+from Screens.Screen import Screen
+from Screens.MessageBox import MessageBox
+from Screens.NumericalTextInputHelpDialog import NumericalTextInputHelpDialog
+from Screens.InputBox import InputBox
+from Screens import Standby
+from Screens.HelpMenu import HelpableScreen
+
+from enigma import eTimer, eSize, ePoint #@UnresolvedImport # pylint: disable-msg=E0611
+from enigma import eDVBVolumecontrol
+from enigma import eBackgroundFileEraser
+#BgFileEraser = eBackgroundFileEraser.getInstance()
+#BgFileEraser.erase("blabla.txt")
+
+from Components.ActionMap import ActionMap
+from Components.Label import Label
+from Components.Button import Button
+from Components.Pixmap import Pixmap
+from Components.Sources.List import List
+from Components.config import config, ConfigSubsection, ConfigSelection, ConfigEnableDisable, getConfigListEntry, ConfigText, ConfigInteger
+from Components.ConfigList import ConfigListScreen
+from Components.Harddisk import harddiskmanager
+try:
+ from Components.config import ConfigPassword
+except ImportError:
+ ConfigPassword = ConfigText
+
+from Plugins.Plugin import PluginDescriptor
+from Tools import Notifications
+from Tools.NumericalTextInput import NumericalTextInput
+from Tools.Directories import resolveFilename, SCOPE_PLUGINS, SCOPE_SKIN_IMAGE, SCOPE_CONFIG, SCOPE_MEDIA
+from Tools.LoadPixmap import LoadPixmap
+from GlobalActions import globalActionMap # for muting
+
+from twisted.internet import reactor #@UnresolvedImport
+from twisted.internet.protocol import ReconnectingClientFactory #@UnresolvedImport
+from twisted.protocols.basic import LineReceiver #@UnresolvedImport
+from twisted.web.client import getPage #@UnresolvedImport
+
+from urllib import urlencode
+import re, time, os, hashlib, traceback
+
+from nrzuname import ReverseLookupAndNotifier, html2unicode
+import FritzOutlookCSV, FritzLDIF
+from . import _, initDebug, debug #@UnresolvedImport # pylint: disable-msg=E0611,F0401
+
+from enigma import getDesktop
+DESKTOP_WIDTH = getDesktop(0).size().width()
+DESKTOP_HEIGHT = getDesktop(0).size().height()
+
+#
+# this is pure magic.
+# It returns the first value, if HD (1280x720),
+# the second if SD (720x576),
+# else something scaled accordingly
+# if one of the parameters is -1, scale proportionally
+#
+def scaleH(y2, y1):
+ if y2 == -1:
+ y2 = y1*1280/720
+ elif y1 == -1:
+ y1 = y2*720/1280
+ return scale(y2, y1, 1280, 720, DESKTOP_WIDTH)
+def scaleV(y2, y1):
+ if y2 == -1:
+ y2 = y1*720/576
+ elif y1 == -1:
+ y1 = y2*576/720
+ return scale(y2, y1, 720, 576, DESKTOP_HEIGHT)
+def scale(y2, y1, x2, x1, x):
+ return (y2 - y1) * (x - x1) / (x2 - x1) + y1
+
+my_global_session = None
+
+config.plugins.FritzCall = ConfigSubsection()
+config.plugins.FritzCall.debug = ConfigEnableDisable(default=False)
+#config.plugins.FritzCall.muteOnCall = ConfigSelection(choices=[(None, _("no")), ("ring", _("on ring")), ("connect", _("on connect"))])
+config.plugins.FritzCall.muteOnCall = ConfigSelection(choices=[(None, _("no")), ("ring", _("on ring"))])
+config.plugins.FritzCall.hostname = ConfigText(default="fritz.box", fixed_size=False)
+config.plugins.FritzCall.afterStandby = ConfigSelection(choices=[("none", _("show nothing")), ("inList", _("show as list")), ("each", _("show each call"))])
+config.plugins.FritzCall.filter = ConfigEnableDisable(default=False)
+config.plugins.FritzCall.filtermsn = ConfigText(default="", fixed_size=False)
+config.plugins.FritzCall.filtermsn.setUseableChars('0123456789,')
+config.plugins.FritzCall.filterCallList = ConfigEnableDisable(default=True)
+config.plugins.FritzCall.showOutgoing = ConfigEnableDisable(default=False)
+config.plugins.FritzCall.timeout = ConfigInteger(default=15, limits=(0, 60))
+config.plugins.FritzCall.lookup = ConfigEnableDisable(default=False)
+config.plugins.FritzCall.internal = ConfigEnableDisable(default=False)
+config.plugins.FritzCall.fritzphonebook = ConfigEnableDisable(default=False)
+config.plugins.FritzCall.phonebook = ConfigEnableDisable(default=False)
+config.plugins.FritzCall.addcallers = ConfigEnableDisable(default=False)
+config.plugins.FritzCall.enable = ConfigEnableDisable(default=False)
+config.plugins.FritzCall.password = ConfigPassword(default="", fixed_size=False)
+config.plugins.FritzCall.extension = ConfigText(default='1', fixed_size=False)
+config.plugins.FritzCall.extension.setUseableChars('0123456789')
+config.plugins.FritzCall.showType = ConfigEnableDisable(default=True)
+config.plugins.FritzCall.showShortcut = ConfigEnableDisable(default=False)
+config.plugins.FritzCall.showVanity = ConfigEnableDisable(default=False)
+config.plugins.FritzCall.prefix = ConfigText(default="", fixed_size=False)
+config.plugins.FritzCall.prefix.setUseableChars('0123456789')
+config.plugins.FritzCall.connectionVerbose = ConfigEnableDisable(default=True)
+
+
+def getMountedDevs():
+ def handleMountpoint(loc):
+ # debug("[FritzCall] handleMountpoint: %s" %repr(loc))
+ mp = loc[0]
+ while mp[-1] == '/':
+ mp = mp[:-1]
+ #=======================================================================
+ # if os.path.exists(os.path.join(mp, "PhoneBook.txt")):
+ # if os.access(os.path.join(mp, "PhoneBook.txt"), os.W_OK):
+ # desc = ' *'
+ # else:
+ # desc = ' -'
+ # else:
+ # desc = ''
+ # desc = loc[1] + desc
+ #=======================================================================
+ desc = loc[1]
+ return (mp, desc + " (" + mp + ")")
+
+ mountedDevs = [(resolveFilename(SCOPE_CONFIG), _("Flash")),
+ (resolveFilename(SCOPE_MEDIA, "cf"), _("Compact Flash")),
+ (resolveFilename(SCOPE_MEDIA, "usb"), _("USB Device"))]
+ mountedDevs += map(lambda p: (p.mountpoint, (_(p.description) if p.description else "")), harddiskmanager.getMountedPartitions(True))
+ mediaDir = resolveFilename(SCOPE_MEDIA)
+ for p in os.listdir(mediaDir):
+ if os.path.join(mediaDir, p) not in [path[0] for path in mountedDevs]:
+ mountedDevs.append((os.path.join(mediaDir, p), _("Media directory")))
+ debug("[FritzCall] getMountedDevs1: %s" %repr(mountedDevs))
+ mountedDevs = filter(lambda path: os.path.isdir(path[0]) and os.access(path[0], os.W_OK|os.X_OK), mountedDevs)
+ # put this after the write/executable check, that is far too slow...
+ netDir = resolveFilename(SCOPE_MEDIA, "net")
+ if os.path.isdir(netDir):
+ mountedDevs += map(lambda p: (os.path.join(netDir, p), _("Network mount")), os.listdir(netDir))
+ mountedDevs = map(handleMountpoint, mountedDevs)
+ return mountedDevs
+config.plugins.FritzCall.phonebookLocation = ConfigSelection(choices=getMountedDevs())
+
+countryCodes = [
+ ("0049", _("Germany")),
+ ("0031", _("The Netherlands")),
+ ("0033", _("France")),
+ ("0039", _("Italy")),
+ ("0041", _("Switzerland")),
+ ("0043", _("Austria"))
+ ]
+config.plugins.FritzCall.country = ConfigSelection(choices=countryCodes)
+
+FBF_ALL_CALLS = "."
+FBF_IN_CALLS = "1"
+FBF_MISSED_CALLS = "2"
+FBF_OUT_CALLS = "3"
+fbfCallsChoices = {FBF_ALL_CALLS: _("All calls"),
+ FBF_IN_CALLS: _("Incoming calls"),
+ FBF_MISSED_CALLS: _("Missed calls"),
+ FBF_OUT_CALLS: _("Outgoing calls")
+ }
+config.plugins.FritzCall.fbfCalls = ConfigSelection(choices=fbfCallsChoices)
+
+config.plugins.FritzCall.name = ConfigText(default="", fixed_size=False)
+config.plugins.FritzCall.number = ConfigText(default="", fixed_size=False)
+config.plugins.FritzCall.number.setUseableChars('0123456789')
+
+phonebook = None
+fritzbox = None
+
+avon = {}
+
+def initAvon():
+ avonFileName = resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/avon.dat")
+ if os.path.exists(avonFileName):
+ for line in open(avonFileName):
+ line = line.decode("iso-8859-1").encode('utf-8')
+ if line[0] == '#':
+ continue
+ parts = line.split(':')
+ if len(parts) == 2:
+ avon[parts[0].replace('-','').replace('*','').replace('/','')] = parts[1]
+
+def resolveNumberWithAvon(number, countrycode):
+ if not number or number[0] != '0':
+ return ""
+
+ countrycode = countrycode.replace('00','+')
+ if number[:2] == '00':
+ normNumber = '+' + number[2:]
+ elif number[:1] == '0':
+ normNumber = countrycode + number[1:]
+ else: # this should can not happen, but safety first
+ return ""
+
+ # debug('normNumer: ' + normNumber)
+ for i in reversed(range(min(10, len(number)))):
+ if avon.has_key(normNumber[:i]):
+ return '[' + avon[normNumber[:i]].strip() + ']'
+ return ""
+
+def handleReverseLookupResult(name):
+ found = re.match("NA: ([^;]*);VN: ([^;]*);STR: ([^;]*);HNR: ([^;]*);PLZ: ([^;]*);ORT: ([^;]*)", name)
+ if found:
+ ( name, firstname, street, streetno, zipcode, city ) = (found.group(1),
+ found.group(2),
+ found.group(3),
+ found.group(4),
+ found.group(5),
+ found.group(6)
+ )
+ if firstname:
+ name += ' ' + firstname
+ if street or streetno or zipcode or city:
+ name += ', '
+ if street:
+ name += street
+ if streetno:
+ name += ' ' + streetno
+ if (street or streetno) and (zipcode or city):
+ name += ', '
+ if zipcode and city:
+ name += zipcode + ' ' + city
+ elif zipcode:
+ name += zipcode
+ elif city:
+ name += city
+ return name
+
+from xml.dom.minidom import parse
+cbcInfos = {}
+def initCbC():
+ callbycallFileName = resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/callbycall_world.xml")
+ if os.path.exists(callbycallFileName):
+ dom = parse(callbycallFileName)
+ for top in dom.getElementsByTagName("callbycalls"):
+ for cbc in top.getElementsByTagName("country"):
+ code = cbc.getAttribute("code").replace("+","00")
+ cbcInfos[code] = cbc.getElementsByTagName("callbycall")
+ else:
+ debug("[FritzCall] initCbC: callbycallFileName does not exist?!?!")
+
+def stripCbCPrefix(number, countrycode):
+ if number and number[:2] != "00" and cbcInfos.has_key(countrycode):
+ for cbc in cbcInfos[countrycode]:
+ if len(cbc.getElementsByTagName("length"))<1 or len(cbc.getElementsByTagName("prefix"))<1:
+ debug("[FritzCall] stripCbCPrefix: entries for " + countrycode + " %s invalid")
+ return number
+ length = int(cbc.getElementsByTagName("length")[0].childNodes[0].data)
+ prefix = cbc.getElementsByTagName("prefix")[0].childNodes[0].data
+ # if re.match('^'+prefix, number):
+ if number[:len(prefix)] == prefix:
+ return number[length:]
+ return number
+
+class FritzAbout(Screen):
+
+ def __init__(self, session):
+ textFieldWidth = scaleV(350, 250)
+ width = 5 + 150 + 20 + textFieldWidth + 5 + 175 + 5
+ height = 5 + 175 + 5 + 25 + 5
+ self.skin = """
+ <screen name="FritzAbout" position="center,center" size="%d,%d" title="About FritzCall" >
+ <widget name="text" position="175,%d" size="%d,%d" font="Regular;%d" />
+ <ePixmap position="5,37" size="150,110" pixmap="%s" transparent="1" alphatest="blend" />
+ <ePixmap position="%d,5" size="175,175" pixmap="%s" transparent="1" alphatest="blend" />
+ <widget name="url" position="20,185" size="%d,25" font="Regular;%d" />
+ </screen>""" % (
+ width, height, # size
+ (height-scaleV(150,130)) / 2, # text vertical position
+ textFieldWidth,
+ scaleV(150,130), # text height
+ scaleV(24,21), # text font size
+ resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/images/fritz.png"), # 150x110
+ 5 + 150 + 5 + textFieldWidth + 5, # qr code horizontal offset
+ resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/images/website.png"), # 175x175
+ width-40, # url width
+ scaleV(24,21) # url font size
+ )
+ Screen.__init__(self, session)
+ self["aboutActions"] = ActionMap(["OkCancelActions"],
+ {
+ "cancel": self.exit,
+ "ok": self.exit,
+ }, -2)
+ self["text"] = Label(
+ "FritzCall Plugin" + "\n\n" +
+ "$Author$"[1:-2] + "\n" +
+ "$Revision$"[1:-2] + "\n" +
+ "$Date$"[1:23] + "\n"
+ )
+ self["url"] = Label("http://wiki.blue-panel.com/index.php/FritzCall")
+ self.onLayoutFinish.append(self.setWindowTitle)
+
+ def setWindowTitle(self):
+ # TRANSLATORS: this is a window title.
+ self.setTitle(_("About FritzCall"))
+
+ def exit(self):
+ self.close()
+
+FBF_boxInfo = 0
+FBF_upTime = 1
+FBF_ipAddress = 2
+FBF_wlanState = 3
+FBF_dslState = 4
+FBF_tamActive = 5
+FBF_dectActive = 6
+FBF_faxActive = 7
+FBF_rufumlActive = 8
+
+class FritzCallFBF:
+ def __init__(self):
+ debug("[FritzCallFBF] __init__")
+ self._callScreen = None
+ self._md5LoginTimestamp = None
+ self._md5Sid = '0000000000000000'
+ self._callTimestamp = 0
+ self._callList = []
+ self._callType = config.plugins.FritzCall.fbfCalls.value
+ self._phoneBookID = '0'
+ self.info = None # (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive)
+ self.getInfo(None)
+ self.blacklist = ([], [])
+ self.readBlacklist()
+
+ def _notify(self, text):
+ debug("[FritzCallFBF] notify: " + text)
+ self._md5LoginTimestamp = None
+ if self._callScreen:
+ debug("[FritzCallFBF] notify: try to close callScreen")
+ self._callScreen.close()
+ self._callScreen = None
+ Notifications.AddNotification(MessageBox, text, type=MessageBox.TYPE_ERROR, timeout=config.plugins.FritzCall.timeout.value)
+
+ def _login(self, callback=None):
+ debug("[FritzCallFBF] _login")
+ if self._callScreen:
+ self._callScreen.updateStatus(_("login"))
+ if self._md5LoginTimestamp and ((time.time() - self._md5LoginTimestamp) < float(9.5*60)) and self._md5Sid != '0000000000000000': # new login after 9.5 minutes inactivity
+ debug("[FritzCallFBF] _login: renew timestamp: " + time.ctime(self._md5LoginTimestamp) + " time: " + time.ctime())
+ self._md5LoginTimestamp = time.time()
+ callback(None)
+ else:
+ debug("[FritzCallFBF] _login: not logged in or outdated login")
+ # http://fritz.box/cgi-bin/webcm?getpage=../html/login_sid.xml
+ parms = urlencode({'getpage':'../html/login_sid.xml'})
+ url = "http://%s/cgi-bin/webcm" % (config.plugins.FritzCall.hostname.value)
+ debug("[FritzCallFBF] _login: '" + url + "' parms: '" + parms + "'")
+ getPage(url,
+ method="POST",
+ headers={'Content-Type': "application/x-www-form-urlencoded", 'Content-Length': str(len(parms))
+ }, postdata=parms).addCallback(lambda x: self._md5Login(callback,x)).addErrback(lambda x:self._oldLogin(callback,x))
+
+ def _oldLogin(self, callback, error):
+ debug("[FritzCallFBF] _oldLogin: " + repr(error))
+ self._md5LoginTimestamp = None
+ if config.plugins.FritzCall.password.value != "":
+ parms = "login:command/password=%s" % (config.plugins.FritzCall.password.value)
+ url = "http://%s/cgi-bin/webcm" % (config.plugins.FritzCall.hostname.value)
+ debug("[FritzCallFBF] _oldLogin: '" + url + "' parms: '" + parms + "'")
+ getPage(url,
+ method="POST",
+ agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
+ headers={'Content-Type': "application/x-www-form-urlencoded", 'Content-Length': str(len(parms))
+ }, postdata=parms).addCallback(self._gotPageLogin).addCallback(callback).addErrback(self._errorLogin)
+ elif callback:
+ debug("[FritzCallFBF] _oldLogin: no password, calling " + repr(callback))
+ callback(None)
+
+ def _md5Login(self, callback, sidXml):
+ def buildResponse(challenge, text):
+ debug("[FritzCallFBF] _md5Login7buildResponse: challenge: " + challenge + ' text: ' + text)
+ text = (challenge + '-' + text).decode('utf-8','ignore').encode('utf-16-le')
+ for i in range(len(text)):
+ if ord(text[i]) > 255:
+ text[i] = '.'
+ md5 = hashlib.md5()
+ md5.update(text)
+ debug("[FritzCallFBF] md5Login/buildResponse: " + md5.hexdigest())
+ return challenge + '-' + md5.hexdigest()
+
+ debug("[FritzCallFBF] _md5Login")
+ found = re.match('.*<SID>([^<]*)</SID>', sidXml, re.S)
+ if found:
+ self._md5Sid = found.group(1)
+ debug("[FritzCallFBF] _md5Login: SID "+ self._md5Sid)
+ else:
+ debug("[FritzCallFBF] _md5Login: no sid! That must be an old firmware.")
+ self._oldLogin(callback, 'No error')
+ return
+
+ debug("[FritzCallFBF] _md5Login: renew timestamp: " + time.ctime(self._md5LoginTimestamp) + " time: " + time.ctime())
+ self._md5LoginTimestamp = time.time()
+ if sidXml.find('<iswriteaccess>0</iswriteaccess>') != -1:
+ debug("[FritzCallFBF] _md5Login: logging in")
+ found = re.match('.*<Challenge>([^<]*)</Challenge>', sidXml, re.S)
+ if found:
+ challenge = found.group(1)
+ debug("[FritzCallFBF] _md5Login: challenge " + challenge)
+ else:
+ challenge = None
+ debug("[FritzCallFBF] _md5Login: login necessary and no challenge! That is terribly wrong.")
+ parms = urlencode({
+ 'getpage':'../html/de/menus/menu2.html', # 'var:pagename':'home', 'var:menu':'home',
+ 'login:command/response': buildResponse(challenge, config.plugins.FritzCall.password.value),
+ })
+ url = "http://%s/cgi-bin/webcm" % (config.plugins.FritzCall.hostname.value)
+ debug("[FritzCallFBF] _md5Login: '" + url + "' parms: '" + parms + "'")
+ getPage(url,
+ method="POST",
+ agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
+ headers={'Content-Type': "application/x-www-form-urlencoded", 'Content-Length': str(len(parms))
+ }, postdata=parms).addCallback(self._gotPageLogin).addCallback(callback).addErrback(self._errorLogin)
+ elif callback: # we assume value 1 here, no login necessary
+ debug("[FritzCallFBF] _md5Login: no login necessary")
+ callback(None)
+
+ def _gotPageLogin(self, html):
+ if self._callScreen:
+ self._callScreen.updateStatus(_("login verification"))
+ debug("[FritzCallFBF] _gotPageLogin: verify login")
+ start = html.find('<p class="errorMessage">FEHLER: ')
+ if start != -1:
+ start = start + len('<p class="errorMessage">FEHLER: ')
+ text = _("FRITZ!Box - Error logging in: %s") + html[start, html.find('</p>', start)]
+ self._notify(text)
+ else:
+ if self._callScreen:
+ self._callScreen.updateStatus(_("login ok"))
+
+ found = re.match('.*<input type="hidden" name="sid" value="([^\"]*)"', html, re.S)
+ if found:
+ self._md5Sid = found.group(1)
+ debug("[FritzCallFBF] _gotPageLogin: found sid: " + self._md5Sid)
+
+ def _errorLogin(self, error):
+ global fritzbox
+ debug("[FritzCallFBF] _errorLogin: %s" % (error))
+ text = _("FRITZ!Box - Error logging in: %s\nDisabling plugin.") % error.getErrorMessage()
+ # config.plugins.FritzCall.enable.value = False
+ fritzbox = None
+ self._notify(text)
+
+ def _logout(self):
+ if self._md5LoginTimestamp:
+ self._md5LoginTimestamp = None
+ parms = urlencode({
+ 'getpage':'../html/de/menus/menu2.html', # 'var:pagename':'home', 'var:menu':'home',
+ 'login:command/logout':'bye bye Fritz'
+ })
+ url = "http://%s/cgi-bin/webcm" % (config.plugins.FritzCall.hostname.value)
+ debug("[FritzCallFBF] logout: '" + url + "' parms: '" + parms + "'")
+ getPage(url,
+ method="POST",
+ agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
+ headers={'Content-Type': "application/x-www-form-urlencoded", 'Content-Length': str(len(parms))
+ }, postdata=parms).addErrback(self._errorLogout)
+
+ def _errorLogout(self, error):
+ debug("[FritzCallFBF] _errorLogout: %s" % (error))
+ text = _("FRITZ!Box - Error logging out: %s") % error.getErrorMessage()
+ self._notify(text)
+
+ def loadFritzBoxPhonebook(self):
+ debug("[FritzCallFBF] loadFritzBoxPhonebook")
+ if config.plugins.FritzCall.fritzphonebook.value:
+ self._phoneBookID = '0'
+ debug("[FritzCallFBF] loadFritzBoxPhonebook: logging in")
+ self._login(self._loadFritzBoxPhonebook)
+
+ def _loadFritzBoxPhonebook(self, html):
+ if html:
+ #===================================================================
+ # found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)
+ # if found:
+ # self._errorLoad('Login: ' + found.group(1))
+ # return
+ #===================================================================
+ start = html.find('<p class="errorMessage">FEHLER: ')
+ if start != -1:
+ start = start + len('<p class="errorMessage">FEHLER: ')
+ self._errorLoad('Login: ' + html[start, html.find('</p>', start)])
+ return
+ parms = urlencode({
+ 'getpage':'../html/de/menus/menu2.html',
+ 'var:lang':'de',
+ 'var:pagename':'fonbuch',
+ 'var:menu':'fon',
+ 'sid':self._md5Sid,
+ 'telcfg:settings/Phonebook/Books/Select':self._phoneBookID, # this selects always the first phonbook
+ })
+ url = "http://%s/cgi-bin/webcm" % (config.plugins.FritzCall.hostname.value)
+ debug("[FritzCallFBF] _loadFritzBoxPhonebook: '" + url + "' parms: '" + parms + "'")
+ getPage(url,
+ method="POST",
+ agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
+ headers={'Content-Type': "application/x-www-form-urlencoded", 'Content-Length': str(len(parms))
+ }, postdata=parms).addCallback(self._parseFritzBoxPhonebook).addErrback(self._errorLoad)
+
+ def _parseFritzBoxPhonebook(self, html):
+ debug("[FritzCallFBF] _parseFritzBoxPhonebook")
+
+ # first, let us get the charset
+ found = re.match('.*<meta http-equiv=content-type content="text/html; charset=([^"]*)">', html, re.S)
+ if found:
+ charset = found.group(1)
+ debug("[FritzCallFBF] _parseFritzBoxPhonebook: found charset: " + charset)
+ html = html2unicode(html.decode(charset), charset).encode('utf-8') # this looks silly, but has to be
+ else: # this is kind of emergency conversion...
+ try:
+ debug("[FritzCallFBF] _parseFritzBoxPhonebook: try charset utf-8")
+ charset = 'utf-8'
+ html = html2unicode(html.decode('utf-8'), 'utf-8').encode('utf-8') # this looks silly, but has to be
+ except UnicodeDecodeError:
+ debug("[FritzCallFBF] _parseFritzBoxPhonebook: try charset iso-8859-1")
+ charset = 'iso-8859-1'
+ html = html2unicode(html.decode('iso-8859-1'), 'iso-8859-1').encode('utf-8') # this looks silly, but has to be
+
+ # if re.search('document.write\(TrFon1\(\)', html):
+ if html.find('document.write(TrFon1()') != -1:
+ #===============================================================================
+ # 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)
+ # 7170 (FW 29.04.70) 22.03.2009
+ # 7141 (FW 40.04.68) 22.03.2009
+ # We expect one line with TrFonName followed by several lines with
+ # TrFonNr(Type,Number,Shortcut,Vanity), which all belong to the name in TrFonName.
+ #===============================================================================
+ debug("[FritzCallFBF] _parseFritzBoxPhonebook: discovered newer firmware")
+ found = re.match('.*<input type="hidden" name="telcfg:settings/Phonebook/Books/Name(\d+)" value="[Dd]reambox" id="uiPostPhonebookName\d+" disabled>', html, re.S)
+ if found:
+ phoneBookID = found.group(1)
+ debug("[FritzCallFBF] _parseFritzBoxPhonebook: found dreambox phonebook with id: " + phoneBookID)
+ if self._phoneBookID != phoneBookID:
+ self._phoneBookID = phoneBookID
+ debug("[FritzCallFBF] _parseFritzBoxPhonebook: reload phonebook")
+ self._loadFritzBoxPhonebook(self._phoneBookID) # reload with dreambox phonebook
+ return
+
+ entrymask = re.compile('(TrFonName\("[^"]+", "[^"]+", "[^"]*"(?:, "[^"]*")?\);.*?)document.write\(TrFon1\(\)', re.S)
+ entries = entrymask.finditer(html)
+ for entry in entries:
+ # TrFonName (id, name, category)
+ # TODO: replace re.match?
+ found = re.match('TrFonName\("[^"]*", "([^"]+)", "[^"]*"(?:, "[^"]*")?\);', entry.group(1))
+ if found:
+ debug("[FritzCallFBF] _parseFritzBoxPhonebook: name: %s" %found.group(1))
+ name = found.group(1).replace(',','').strip()
+ else:
+ debug("[FritzCallFBF] _parseFritzBoxPhonebook: could not find name")
+ continue
+ # TrFonNr (type, rufnr, code, vanity)
+ detailmask = re.compile('TrFonNr\("([^"]*)", "([^"]*)", "([^"]*)", "([^"]*)"\);', re.S)
+ details = detailmask.finditer(entry.group(1))
+ for found in details:
+ thisnumber = found.group(2).strip()
+ if not thisnumber:
+ debug("[FritzCallFBF] Ignoring entry with empty number for '''%s'''" % (name))
+ continue
+ else:
+ thisname = name
+ callType = found.group(1)
+ if config.plugins.FritzCall.showType.value:
+ if callType == "mobile":
+ thisname = thisname + " (" + _("mobile") + ")"
+ elif callType == "home":
+ thisname = thisname + " (" + _("home") + ")"
+ elif callType == "work":
+ thisname = thisname + " (" + _("work") + ")"
+
+ if config.plugins.FritzCall.showShortcut.value and found.group(3):
+ thisname = thisname + ", " + _("Shortcut") + ": " + found.group(3)
+ if config.plugins.FritzCall.showVanity.value and found.group(4):
+ thisname = thisname + ", " + _("Vanity") + ": " + found.group(4)
+
+ debug("[FritzCallFBF] Adding '''%s''' with '''%s''' from FRITZ!Box Phonebook!" % (thisname.strip(), thisnumber))
+ # Beware: strings in phonebook.phonebook have to be in utf-8!
+ phonebook.phonebook[thisnumber] = thisname
+
+ # elif re.search('document.write\(TrFon\(', html):
+ elif html.find('document.write(TrFon(') != -1:
+ #===============================================================================
+ # Old Style: 7050 (FW 14.04.33)
+ # We expect one line with TrFon(No,Name,Number,Shortcut,Vanity)
+ # Encoding should be plain Ascii...
+ #===============================================================================
+ entrymask = re.compile('TrFon\("[^"]*", "([^"]*)", "([^"]*)", "([^"]*)", "([^"]*)"\)', re.S)
+ entries = entrymask.finditer(html)
+ for found in entries:
+ name = found.group(1).strip().replace(',','')
+ # debug("[FritzCallFBF] pos: %s name: %s" %(found.group(0),name))
+ thisnumber = found.group(2).strip()
+ if config.plugins.FritzCall.showShortcut.value and found.group(3):
+ name = name + ", " + _("Shortcut") + ": " + found.group(3)
+ if config.plugins.FritzCall.showVanity.value and found.group(4):
+ name = name + ", " + _("Vanity") + ": " + found.group(4)
+ if thisnumber:
+ # name = name.encode('utf-8')
+ debug("[FritzCallFBF] Adding '''%s''' with '''%s''' from FRITZ!Box Phonebook!" % (name, thisnumber))
+ # Beware: strings in phonebook.phonebook have to be in utf-8!
+ phonebook.phonebook[thisnumber] = name
+ else:
+ debug("[FritzCallFBF] ignoring empty number for %s" % name)
+ continue
+ elif self._md5Sid == '0000000000000000': # retry, it could be a race condition
+ debug("[FritzCallFBF] _parseFritzBoxPhonebook: retry loading phonebook")
+ self.loadFritzBoxPhonebook()
+ else:
+ self._notify(_("Could not parse FRITZ!Box Phonebook entry"))
+
+ def _errorLoad(self, error):
+ debug("[FritzCallFBF] _errorLoad: %s" % (error))
+ text = _("FRITZ!Box - Could not load phonebook: %s") % error.getErrorMessage()
+ self._notify(text)
+
+ def getCalls(self, callScreen, callback, callType):
+ #
+ # call sequence must be:
+ # - login
+ # - getPage -> _gotPageLogin
+ # - loginCallback (_getCalls)
+ # - getPage -> _getCalls1
+ debug("[FritzCallFBF] getCalls")
+ self._callScreen = callScreen
+ self._callType = callType
+ if (time.time() - self._callTimestamp) > 180:
+ debug("[FritzCallFBF] getCalls: outdated data, login and get new ones: " + time.ctime(self._callTimestamp) + " time: " + time.ctime())
+ self._callTimestamp = time.time()
+ self._login(lambda x:self._getCalls(callback, x))
+ elif not self._callList:
+ debug("[FritzCallFBF] getCalls: time is ok, but no callList")
+ self._getCalls1(callback)
+ else:
+ debug("[FritzCallFBF] getCalls: time is ok, callList is ok")
+ self._gotPageCalls(callback)
+
+ def _getCalls(self, callback, html):
+ if html:
+ #===================================================================
+ # found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)
+ # if found:
+ # self._errorCalls('Login: ' + found.group(1))
+ # return
+ #===================================================================
+ start = html.find('<p class="errorMessage">FEHLER: ')
+ if start != -1:
+ start = start + len('<p class="errorMessage">FEHLER: ')
+ self._errorCalls('Login: ' + html[start, html.find('</p>', start)])
+ return
+ #
+ # we need this to fill Anrufliste.csv
+ # http://repeater1/cgi-bin/webcm?getpage=../html/de/menus/menu2.html&var:lang=de&var:menu=fon&var:pagename=foncalls
+ #
+ debug("[FritzCallFBF] _getCalls")
+ if html:
+ #===================================================================
+ # found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)
+ # if found:
+ # text = _("FRITZ!Box - Error logging in: %s") + found.group(1)
+ # self._notify(text)
+ # return
+ #===================================================================
+ start = html.find('<p class="errorMessage">FEHLER: ')
+ if start != -1:
+ start = start + len('<p class="errorMessage">FEHLER: ')
+ self._notify(_("FRITZ!Box - Error logging in: %s") + html[start, html.find('</p>', start)])
+ return
+
+ if self._callScreen:
+ self._callScreen.updateStatus(_("preparing"))
+ parms = urlencode({'getpage':'../html/de/menus/menu2.html', 'var:lang':'de', 'var:pagename':'foncalls', 'var:menu':'fon', 'sid':self._md5Sid})
+ url = "http://%s/cgi-bin/webcm?%s" % (config.plugins.FritzCall.hostname.value, parms)
+ getPage(url).addCallback(lambda x:self._getCalls1(callback)).addErrback(self._errorCalls) #@UnusedVariable # pylint: disable-msg=W0613
+
+ def _getCalls1(self, callback):
+ #
+ # finally we should have successfully lgged in and filled the csv
+ #
+ debug("[FritzCallFBF] _getCalls1")
+ if self._callScreen:
+ self._callScreen.updateStatus(_("finishing"))
+ parms = urlencode({'getpage':'../html/de/FRITZ!Box_Anrufliste.csv', 'sid':self._md5Sid})
+ url = "http://%s/cgi-bin/webcm?%s" % (config.plugins.FritzCall.hostname.value, parms)
+ getPage(url).addCallback(lambda x:self._gotPageCalls(callback, x)).addErrback(self._errorCalls)
+
+ def _gotPageCalls(self, callback, csv=""):
+ def resolveNumber(number):
+ if number.isdigit():
+ if config.plugins.FritzCall.internal.value and len(number) > 3 and number[0] == "0":
+ number = number[1:]
+ # strip CbC prefix
+ number = stripCbCPrefix(number, config.plugins.FritzCall.country.value)
+ if config.plugins.FritzCall.prefix.value and number and number[0] != '0': # should only happen for outgoing
+ number = config.plugins.FritzCall.prefix.value + number
+ name = phonebook.search(number)
+ if name:
+ #===========================================================
+ # found = re.match('(.*?)\n.*', name)
+ # if found:
+ # name = found.group(1)
+ #===========================================================
+ end = name.find('\n')
+ if end != -1:
+ name = name[:end]
+ number = name
+ else:
+ name = resolveNumberWithAvon(number, config.plugins.FritzCall.country.value)
+ if name:
+ number = number + ' ' + name
+ elif number == "":
+ number = _("UNKNOWN")
+ # if len(number) > 20: number = number[:20]
+ return number
+
+ if csv:
+ debug("[FritzCallFBF] _gotPageCalls: got csv, setting callList")
+ if self._callScreen:
+ self._callScreen.updateStatus(_("done"))
+ # check for error: wrong password or password not set... TODO
+ # found = re.search('Melden Sie sich mit dem Kennwort der FRITZ!Box an', csv)
+ if csv.find('Melden Sie sich mit dem Kennwort der FRITZ!Box an') != -1:
+ 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.")
+ # self.session.open(MessageBox, text, MessageBox.TYPE_ERROR, timeout=config.plugins.FritzCall.timeout.value)
+ self._notify(text)
+ return
+
+ csv = csv.decode('iso-8859-1', 'replace').encode('utf-8', 'replace')
+ lines = csv.splitlines()
+ self._callList = lines
+ elif self._callList:
+ debug("[FritzCallFBF] _gotPageCalls: got no csv, but have callList")
+ if self._callScreen:
+ self._callScreen.updateStatus(_("done, using last list"))
+ lines = self._callList
+ else:
+ debug("[FritzCallFBF] _gotPageCalls: got no csv, no callList, laving")
+ return
+
+ callListL = []
+ if config.plugins.FritzCall.filter.value and config.plugins.FritzCall.filterCallList.value:
+ filtermsns = map(lambda x: x.strip(), config.plugins.FritzCall.filtermsn.value.split(","))
+ debug("[FritzCallFBF] _gotPageCalls: filtermsns %s" % (repr(filtermsns)))
+ for line in lines:
+ # Typ;e;Rufnummer;Nebenstelle;Eigene Rufnummer;Dauer
+ elems = line.split(';')
+ # found = re.match("^(" + self._callType + ");([^;]*);([^;]*);([^;]*);([^;]*);([^;]*);([^;]*)", line)
+ if len(elems) != 7: # this happens, if someone puts a ';' in the name in the FBF phonebook
+ debug("[FritzCallFBF] _gotPageCalls: len != 7: %s" % (line))
+ if len(elems) == 7 and (self._callType == '.' or elems[0] == self._callType):
+ # debug("[FritzCallFBF] _gotPageCalls: elems %s" % (elems))
+ direct = elems[0]
+ date = elems[1]
+ length = elems[6]
+ remote = resolveNumber(elems[3])
+ if not remote and direct != FBF_OUT_CALLS and elems[2]:
+ remote = elems[2]
+ #===============================================================
+ # found1 = re.match('Internet: (.*)', found.group(6))
+ # if found1:
+ # here = found1.group(1)
+ # else:
+ # here = found.group(6)
+ #===============================================================
+ here = elems[5]
+ start = here.find('Internet: ')
+ if start != -1:
+ start += len('Internet: ')
+ here = here[start:]
+ else:
+ here = elems[5]
+ if config.plugins.FritzCall.filter.value and config.plugins.FritzCall.filterCallList.value:
+ # debug("[FritzCallFBF] _gotPageCalls: check %s" % (here))
+ if here not in filtermsns:
+ # debug("[FritzCallFBF] _gotPageCalls: skip %s" % (here))
+ continue
+ here = resolveNumber(here)
+
+ number = stripCbCPrefix(elems[3], config.plugins.FritzCall.country.value)
+ if config.plugins.FritzCall.prefix.value and number and number[0] != '0': # should only happen for outgoing
+ number = config.plugins.FritzCall.prefix.value + number
+ callListL.append((number, date, direct, remote, length, here))
+
+ # debug("[FritzCallFBF] _gotPageCalls result:\n" + text
+
+ if callback:
+ # debug("[FritzCallFBF] _gotPageCalls call callback with\n" + text
+ callback(callListL)
+ self._callScreen = None
+
+ def _errorCalls(self, error):
+ debug("[FritzCallFBF] _errorCalls: %s" % (error))
+ text = _("FRITZ!Box - Could not load calls: %s") % error.getErrorMessage()
+ self._notify(text)
+
+ def dial(self, number):
+ ''' initiate a call to number '''
+ self._login(lambda x: self._dial(number, x))
+
+ def _dial(self, number, html):
+ if html:
+ #===================================================================
+ # found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)
+ # if found:
+ # self._errorDial('Login: ' + found.group(1))
+ # return
+ #===================================================================
+ start = html.find('<p class="errorMessage">FEHLER: ')
+ if start != -1:
+ start = start + len('<p class="errorMessage">FEHLER: ')
+ self._errorDial('Login: ' + html[start, html.find('</p>', start)])
+ return
+ url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
+ parms = urlencode({
+ 'getpage':'../html/de/menus/menu2.html',
+ 'var:pagename':'fonbuch',
+ 'var:menu':'home',
+ 'telcfg:settings/UseClickToDial':'1',
+ 'telcfg:settings/DialPort':config.plugins.FritzCall.extension.value,
+ 'telcfg:command/Dial':number,
+ 'sid':self._md5Sid
+ })
+ debug("[FritzCallFBF] dial url: '" + url + "' parms: '" + parms + "'")
+ getPage(url,
+ method="POST",
+ agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
+ headers={
+ 'Content-Type': "application/x-www-form-urlencoded",
+ 'Content-Length': str(len(parms))},
+ postdata=parms).addCallback(self._okDial).addErrback(self._errorDial)
+
+ def _okDial(self, html): #@UnusedVariable # pylint: disable-msg=W0613
+ debug("[FritzCallFBF] okDial")
+
+ def _errorDial(self, error):
+ debug("[FritzCallFBF] errorDial: $s" % error)
+ text = _("FRITZ!Box - Dialling failed: %s") % error.getErrorMessage()
+ self._notify(text)
+
+ def changeWLAN(self, statusWLAN):
+ ''' get status info from FBF '''
+ debug("[FritzCallFBF] changeWLAN start")
+ if not statusWLAN or (statusWLAN != '1' and statusWLAN != '0'):
+ return
+ self._login(lambda x: self._changeWLAN(statusWLAN, x))
+
+ def _changeWLAN(self, statusWLAN, html):
+ if html:
+ #===================================================================
+ # found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)
+ # if found:
+ # self._errorChangeWLAN('Login: ' + found.group(1))
+ # return
+ #===================================================================
+ start = html.find('<p class="errorMessage">FEHLER: ')
+ if start != -1:
+ start = start + len('<p class="errorMessage">FEHLER: ')
+ self._errorChangeWLAN('Login: ' + html[start, html.find('</p>', start)])
+ return
+ url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
+ parms = urlencode({
+ 'getpage':'../html/de/menus/menu2.html',
+ 'var:lang':'de',
+ 'var:pagename':'wlan',
+ 'var:menu':'wlan',
+ 'wlan:settings/ap_enabled':str(statusWLAN),
+ 'sid':self._md5Sid
+ })
+ debug("[FritzCallFBF] changeWLAN url: '" + url + "' parms: '" + parms + "'")
+ getPage(url,
+ method="POST",
+ agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
+ headers={
+ 'Content-Type': "application/x-www-form-urlencoded",
+ 'Content-Length': str(len(parms))},
+ postdata=parms).addCallback(self._okChangeWLAN).addErrback(self._errorChangeWLAN)
+
+ def _okChangeWLAN(self, html): #@UnusedVariable # pylint: disable-msg=W0613
+ debug("[FritzCallFBF] _okChangeWLAN")
+
+ def _errorChangeWLAN(self, error):
+ debug("[FritzCallFBF] _errorChangeWLAN: $s" % error)
+ text = _("FRITZ!Box - Failed changing WLAN: %s") % error.getErrorMessage()
+ self._notify(text)
+
+ def changeMailbox(self, whichMailbox):
+ ''' switch mailbox on/off '''
+ debug("[FritzCallFBF] changeMailbox start: " + str(whichMailbox))
+ self._login(lambda x: self._changeMailbox(whichMailbox, x))
+
+ def _changeMailbox(self, whichMailbox, html):
+ if html:
+ #===================================================================
+ # found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)
+ # if found:
+ # self._errorChangeMailbox('Login: ' + found.group(1))
+ # return
+ #===================================================================
+ start = html.find('<p class="errorMessage">FEHLER: ')
+ if start != -1:
+ start = start + len('<p class="errorMessage">FEHLER: ')
+ self._errorChangeMailbox('Login: ' + html[start, html.find('</p>', start)])
+ return
+ debug("[FritzCallFBF] _changeMailbox")
+ url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
+ if whichMailbox == -1:
+ for i in range(5):
+ if self.info[FBF_tamActive][i+1]:
+ state = '0'
+ else:
+ state = '1'
+ parms = urlencode({
+ 'tam:settings/TAM'+str(i)+'/Active':state,
+ 'sid':self._md5Sid
+ })
+ debug("[FritzCallFBF] changeMailbox url: '" + url + "' parms: '" + parms + "'")
+ getPage(url,
+ method="POST",
+ agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
+ headers={
+ 'Content-Type': "application/x-www-form-urlencoded",
+ 'Content-Length': str(len(parms))},
+ postdata=parms).addCallback(self._okChangeMailbox).addErrback(self._errorChangeMailbox)
+ elif whichMailbox > 4:
+ debug("[FritzCallFBF] changeMailbox invalid mailbox number")
+ else:
+ if self.info[FBF_tamActive][whichMailbox+1]:
+ state = '0'
+ else:
+ state = '1'
+ parms = urlencode({
+ 'tam:settings/TAM'+str(whichMailbox)+'/Active':state,
+ 'sid':self._md5Sid
+ })
+ debug("[FritzCallFBF] changeMailbox url: '" + url + "' parms: '" + parms + "'")
+ getPage(url,
+ method="POST",
+ agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
+ headers={
+ 'Content-Type': "application/x-www-form-urlencoded",
+ 'Content-Length': str(len(parms))},
+ postdata=parms).addCallback(self._okChangeMailbox).addErrback(self._errorChangeMailbox)
+
+ def _okChangeMailbox(self, html): #@UnusedVariable # pylint: disable-msg=W0613
+ debug("[FritzCallFBF] _okChangeMailbox")
+
+ def _errorChangeMailbox(self, error):
+ debug("[FritzCallFBF] _errorChangeMailbox: $s" % error)
+ text = _("FRITZ!Box - Failed changing Mailbox: %s") % error.getErrorMessage()
+ self._notify(text)
+
+ def getInfo(self, callback):
+ ''' get status info from FBF '''
+ debug("[FritzCallFBF] getInfo")
+ self._login(lambda x:self._getInfo(callback, x))
+
+ def _getInfo(self, callback, html):
+ # http://192.168.178.1/cgi-bin/webcm?getpage=../html/de/menus/menu2.html&var:lang=de&var:pagename=home&var:menu=home
+ debug("[FritzCallFBF] _getInfo: verify login")
+ if html:
+ #===================================================================
+ # found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)
+ # if found:
+ # self._errorGetInfo('Login: ' + found.group(1))
+ # return
+ #===================================================================
+ start = html.find('<p class="errorMessage">FEHLER: ')
+ if start != -1:
+ start = start + len('<p class="errorMessage">FEHLER: ')
+ self._errorGetInfo('Login: ' + html[start, html.find('</p>', start)])
+ return
+
+ url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
+ parms = urlencode({
+ 'getpage':'../html/de/menus/menu2.html',
+ 'var:lang':'de',
+ 'var:pagename':'home',
+ 'var:menu':'home',
+ 'sid':self._md5Sid
+ })
+ debug("[FritzCallFBF] _getInfo url: '" + url + "' parms: '" + parms + "'")
+ getPage(url,
+ method="POST",
+ agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
+ headers={
+ 'Content-Type': "application/x-www-form-urlencoded",
+ 'Content-Length': str(len(parms))},
+ postdata=parms).addCallback(lambda x:self._okGetInfo(callback,x)).addErrback(self._errorGetInfo)
+
+ def _okGetInfo(self, callback, html):
+ def readInfo(html):
+ if self.info:
+ (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive) = self.info
+ else:
+ (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive) = (None, None, None, None, None, None, None, None, None)
+
+ debug("[FritzCallFBF] _okGetInfo/readinfo")
+ 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)
+ if found:
+ boxInfo = found.group(1)+ ', ' + found.group(2)
+ boxInfo = boxInfo.replace(' ',' ')
+ # debug("[FritzCallFBF] _okGetInfo Boxinfo: " + boxInfo)
+ else:
+ found = re.match('.*<p class="ac">([^<]*)</p>', html, re.S)
+ if found:
+ # debug("[FritzCallFBF] _okGetInfo Boxinfo: " + found.group(1))
+ boxInfo = found.group(1)
+
+ if html.find('home_coninf.txt') != -1:
+ url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
+ parms = urlencode({
+ 'getpage':'../html/de/home/home_coninf.txt',
+ 'sid':self._md5Sid
+ })
+ # debug("[FritzCallFBF] get coninfo: url: '" + url + "' parms: '" + parms + "'")
+ getPage(url,
+ method="POST",
+ agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
+ headers={
+ 'Content-Type': "application/x-www-form-urlencoded",
+ 'Content-Length': str(len(parms))},
+ postdata=parms).addCallback(lambda x:self._okSetConInfo(callback,x)).addErrback(self._errorGetInfo)
+ else:
+ found = re.match('.*if \(isNaN\(jetzt\)\)\s*return "";\s*var str = "([^"]*)";', html, re.S)
+ if found:
+ # debug("[FritzCallFBF] _okGetInfo Uptime: " + found.group(1))
+ upTime = found.group(1)
+ else:
+ found = re.match('.*str = g_pppSeit \+"([^<]*)<br>"\+mldIpAdr;', html, re.S)
+ if found:
+ # debug("[FritzCallFBF] _okGetInfo Uptime: " + found.group(1))
+ upTime = found.group(1)
+
+ found = re.match(".*IpAdrDisplay\('([.\d]+)'\)", html, re.S)
+ if found:
+ # debug("[FritzCallFBF] _okGetInfo IpAdrDisplay: " + found.group(1))
+ ipAddress = found.group(1)
+
+ if html.find('g_tamActive') != -1:
+ entries = re.compile('if \("(\d)" == "1"\) {\s*g_tamActive \+= 1;\s*}', re.S).finditer(html)
+ tamActive = [0, False, False, False, False, False]
+ i = 1
+ for entry in entries:
+ state = entry.group(1)
+ if state == '1':
+ tamActive[0] += 1
+ tamActive[i] = True
+ i += 1
+ # debug("[FritzCallFBF] _okGetInfo tamActive: " + str(tamActive))
+
+ if html.find('home_dect.txt') != -1:
+ url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
+ parms = urlencode({
+ 'getpage':'../html/de/home/home_dect.txt',
+ 'sid':self._md5Sid
+ })
+ # debug("[FritzCallFBF] get coninfo: url: '" + url + "' parms: '" + parms + "'")
+ getPage(url,
+ method="POST",
+ agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
+ headers={
+ 'Content-Type': "application/x-www-form-urlencoded",
+ 'Content-Length': str(len(parms))},
+ postdata=parms).addCallback(lambda x:self._okSetDect(callback,x)).addErrback(self._errorGetInfo)
+ else:
+ if html.find('countDect2') != -1:
+ entries = re.compile('if \("1" == "1"\) countDect2\+\+;', re.S).findall(html)
+ dectActive = len(entries)
+ # debug("[FritzCallFBF] _okGetInfo dectActive: " + str(dectActive))
+
+ found = re.match('.*var g_intFaxActive = "0";\s*if \("1" != ""\) {\s*g_intFaxActive = "1";\s*}\s*', html, re.S)
+ if found:
+ faxActive = True
+ # debug("[FritzCallFBF] _okGetInfo faxActive")
+
+ if html.find('cntRufumleitung') != -1:
+ entries = re.compile('mode = "1";\s*ziel = "[^"]+";\s*if \(mode == "1" \|\| ziel != ""\)\s*{\s*g_RufumleitungAktiv = true;', re.S).findall(html)
+ rufumlActive = len(entries)
+ entries = re.compile('if \("([^"]*)"=="([^"]*)"\) isAllIncoming\+\+;', re.S).finditer(html)
+ isAllIncoming = 0
+ for entry in entries:
+ # debug("[FritzCallFBF] _okGetInfo rufumlActive add isAllIncoming")
+ if entry.group(1) == entry.group(2):
+ isAllIncoming += 1
+ if isAllIncoming == 2 and rufumlActive > 0:
+ rufumlActive -= 1
+ # debug("[FritzCallFBF] _okGetInfo rufumlActive: " + str(rufumlActive))
+
+ # /cgi-bin/webcm?getpage=../html/de/home/home_dsl.txt
+ # { "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": "" }
+ if html.find('home_dsl.txt') != -1:
+ url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
+ parms = urlencode({
+ 'getpage':'../html/de/home/home_dsl.txt',
+ 'sid':self._md5Sid
+ })
+ # debug("[FritzCallFBF] get dsl state: url: '" + url + "' parms: '" + parms + "'")
+ getPage(url,
+ method="POST",
+ agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
+ headers={
+ 'Content-Type': "application/x-www-form-urlencoded",
+ 'Content-Length': str(len(parms))},
+ postdata=parms).addCallback(lambda x:self._okSetDslState(callback,x)).addErrback(self._errorGetInfo)
+ else:
+ found = re.match('.*function DslStateDisplay \(state\){\s*var state = "(\d+)";', html, re.S)
+ if found:
+ # debug("[FritzCallFBF] _okGetInfo DslState: " + found.group(1))
+ dslState = [ found.group(1), None ] # state, speed
+ found = re.match('.*function DslStateDisplay \(state\){\s*var state = "\d+";.*?if \("3130" != "0"\) str = "([^"]*)";', html, re.S)
+ if found:
+ # debug("[FritzCallFBF] _okGetInfo DslSpeed: " + found.group(1).strip())
+ dslState[1] = found.group(1).strip()
+
+ # /cgi-bin/webcm?getpage=../html/de/home/home_wlan.txt
+ # { "ap_enabled": "1", "active_stations": "0", "encryption": "4", "wireless_stickandsurf_enabled": "0", "is_macfilter_active": "0", "wmm_enabled": "1", "wlan_state": [ "end" ] }
+ if html.find('home_wlan.txt') != -1:
+ url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
+ parms = urlencode({
+ 'getpage':'../html/de/home/home_wlan.txt',
+ 'sid':self._md5Sid
+ })
+ # debug("[FritzCallFBF] get wlan state: url: '" + url + "' parms: '" + parms + "'")
+ getPage(url,
+ method="POST",
+ agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
+ headers={
+ 'Content-Type': "application/x-www-form-urlencoded",
+ 'Content-Length': str(len(parms))},
+ postdata=parms).addCallback(lambda x:self._okSetWlanState(callback,x)).addErrback(self._errorGetInfo)
+ else:
+ found = re.match('.*function WlanStateLed \(state\){.*?return StateLed\("(\d+)"\);\s*}', html, re.S)
+ if found:
+ # debug("[FritzCallFBF] _okGetInfo WlanState: " + found.group(1))
+ wlanState = [ found.group(1), 0, 0 ] # state, encryption, number of devices
+ found = re.match('.*var (?:g_)?encryption = "(\d+)";', html, re.S)
+ if found:
+ # debug("[FritzCallFBF] _okGetInfo WlanEncrypt: " + found.group(1))
+ wlanState[1] = found.group(1)
+
+ return (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive)
+
+ debug("[FritzCallFBF] _okGetInfo")
+ info = readInfo(html)
+ debug("[FritzCallFBF] _okGetInfo info: " + str(info))
+ self.info = info
+ if callback:
+ callback(info)
+
+ def _okSetDect(self, callback, html):
+ # debug("[FritzCallFBF] _okSetDect: " + html)
+ # found = re.match('.*"connection_status":"(\d+)".*"connection_ip":"([.\d]+)".*"connection_detail":"([^"]+)".*"connection_uptime":"([^"]+)"', html, re.S)
+ if html.find('"dect_enabled": "1"') != -1:
+ # debug("[FritzCallFBF] _okSetDect: dect_enabled")
+ found = re.match('.*"dect_device_list":.*\[([^\]]*)\]', html, re.S)
+ if found:
+ # debug("[FritzCallFBF] _okSetDect: dect_device_list: %s" %(found.group(1)))
+ entries = re.compile('"1"', re.S).findall(found.group(1))
+ dectActive = len(entries)
+ (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dummy, faxActive, rufumlActive) = self.info
+ self.info = (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive)
+ debug("[FritzCallFBF] _okSetDect info: " + str(self.info))
+ if callback:
+ callback(self.info)
+
+ def _okSetConInfo(self, callback, html):
+ # debug("[FritzCallFBF] _okSetConInfo: " + html)
+ # found = re.match('.*"connection_status":"(\d+)".*"connection_ip":"([.\d]+)".*"connection_detail":"([^"]+)".*"connection_uptime":"([^"]+)"', html, re.S)
+ found = re.match('.*"connection_ip": "([.\d]+)".*"connection_uptime": "([^"]+)"', html, re.S)
+ if found:
+ # debug("[FritzCallFBF] _okSetConInfo: connection_ip: %s upTime: %s" %( found.group(1), found.group(2)))
+ ipAddress = found.group(1)
+ upTime = found.group(2)
+ (boxInfo, dummy, dummy, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive) = self.info
+ self.info = (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive)
+ debug("[FritzCallFBF] _okSetWlanState info: " + str(self.info))
+ else:
+ found = re.match('.*_ip": "([.\d]+)".*"connection_uptime": "([^"]+)"', html, re.S)
+ if found:
+ # debug("[FritzCallFBF] _okSetConInfo: _ip: %s upTime: %s" %( found.group(1), found.group(2)))
+ ipAddress = found.group(1)
+ upTime = found.group(2)
+ (boxInfo, dummy, dummy, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive) = self.info
+ self.info = (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive)
+ debug("[FritzCallFBF] _okSetWlanState info: " + str(self.info))
+ if callback:
+ callback(self.info)
+
+ def _okSetWlanState(self, callback, html):
+ # debug("[FritzCallFBF] _okSetWlanState: " + html)
+ found = re.match('.*"ap_enabled": "(\d+)"', html, re.S)
+ if found:
+ # debug("[FritzCallFBF] _okSetWlanState: ap_enabled: " + found.group(1))
+ wlanState = [ found.group(1), None, None ]
+ found = re.match('.*"encryption": "(\d+)"', html, re.S)
+ if found:
+ # debug("[FritzCallFBF] _okSetWlanState: encryption: " + found.group(1))
+ wlanState[1] = found.group(1)
+ found = re.match('.*"active_stations": "(\d+)"', html, re.S)
+ if found:
+ # debug("[FritzCallFBF] _okSetWlanState: active_stations: " + found.group(1))
+ wlanState[2] = found.group(1)
+ (boxInfo, upTime, ipAddress, dummy, dslState, tamActive, dectActive, faxActive, rufumlActive) = self.info
+ self.info = (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive)
+ debug("[FritzCallFBF] _okSetWlanState info: " + str(self.info))
+ if callback:
+ callback(self.info)
+
+ def _okSetDslState(self, callback, html):
+ # debug("[FritzCallFBF] _okSetDslState: " + html)
+ found = re.match('.*"dsl_carrier_state": "(\d+)"', html, re.S)
+ if found:
+ # debug("[FritzCallFBF] _okSetDslState: dsl_carrier_state: " + found.group(1))
+ dslState = [ found.group(1), None ]
+ found = re.match('.*"dsl_ds_nrate": "(\d+)"', html, re.S)
+ if found:
+ # debug("[FritzCallFBF] _okSetDslState: dsl_ds_nrate: " + found.group(1))
+ dslState[1] = found.group(1)
+ found = re.match('.*"dsl_us_nrate": "(\d+)"', html, re.S)
+ if found:
+ # debug("[FritzCallFBF] _okSetDslState: dsl_us_nrate: " + found.group(1))
+ dslState[1] = dslState[1] + '/' + found.group(1)
+ (boxInfo, upTime, ipAddress, wlanState, dummy, tamActive, dectActive, faxActive, rufumlActive) = self.info
+ self.info = (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive)
+ debug("[FritzCallFBF] _okSetDslState info: " + str(self.info))
+ if callback:
+ callback(self.info)
+
+ def _errorGetInfo(self, error):
+ debug("[FritzCallFBF] _errorGetInfo: %s" % (error))
+ text = _("FRITZ!Box - Error getting status: %s") % error.getErrorMessage()
+ self._notify(text)
+ # linkP = open("/tmp/FritzCall_errorGetInfo.htm", "w")
+ # linkP.write(error)
+ # linkP.close()
+
+ def reset(self):
+ self._login(self._reset)
+
+ def _reset(self, html):
+ # 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
+ if html:
+ #===================================================================
+ # found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)
+ # if found:
+ # self._errorReset('Login: ' + found.group(1))
+ # return
+ #===================================================================
+ start = html.find('<p class="errorMessage">FEHLER: ')
+ if start != -1:
+ start = start + len('<p class="errorMessage">FEHLER: ')
+ self._errorReset('Login: ' + html[start, html.find('</p>', start)])
+ return
+ if self._callScreen:
+ self._callScreen.close()
+ url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
+ parms = urlencode({
+ 'getpage':'../html/reboot.html',
+ 'var:lang':'de',
+ 'var:pagename':'reset',
+ 'var:menu':'system',
+ 'logic:command/reboot':'../gateway/commands/saveconfig.html',
+ 'sid':self._md5Sid
+ })
+ debug("[FritzCallFBF] _reset url: '" + url + "' parms: '" + parms + "'")
+ getPage(url,
+ method="POST",
+ agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
+ headers={
+ 'Content-Type': "application/x-www-form-urlencoded",
+ 'Content-Length': str(len(parms))},
+ postdata=parms)
+
+ def _okReset(self, html): #@UnusedVariable # pylint: disable-msg=W0613
+ debug("[FritzCallFBF] _okReset")
+
+ def _errorReset(self, error):
+ debug("[FritzCallFBF] _errorReset: %s" % (error))
+ text = _("FRITZ!Box - Error resetting: %s") % error.getErrorMessage()
+ self._notify(text)
+
+ def readBlacklist(self):
+ self._login(self._readBlacklist)
+
+ def _readBlacklist(self, html):
+ if html:
+ #===================================================================
+ # found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)
+ # if found:
+ # self._errorBlacklist('Login: ' + found.group(1))
+ # return
+ #===================================================================
+ start = html.find('<p class="errorMessage">FEHLER: ')
+ if start != -1:
+ start = start + len('<p class="errorMessage">FEHLER: ')
+ self._errorBlacklist('Login: ' + html[start, html.find('</p>', start)])
+ return
+ # http://fritz.box/cgi-bin/webcm?getpage=../html/de/menus/menu2.html&var:lang=de&var:menu=fon&var:pagename=sperre
+ url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
+ parms = urlencode({
+ 'getpage':'../html/de/menus/menu2.html',
+ 'var:lang':'de',
+ 'var:pagename':'sperre',
+ 'var:menu':'fon',
+ 'sid':self._md5Sid
+ })
+ debug("[FritzCallFBF] _readBlacklist url: '" + url + "' parms: '" + parms + "'")
+ getPage(url,
+ method="POST",
+ agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
+ headers={
+ 'Content-Type': "application/x-www-form-urlencoded",
+ 'Content-Length': str(len(parms))},
+ postdata=parms).addCallback(self._okBlacklist).addErrback(self._errorBlacklist)
+
+ def _okBlacklist(self, html):
+ debug("[FritzCallFBF] _okBlacklist")
+ entries = re.compile('<script type="text/javascript">document.write\(Tr(Out|In)\("\d+", "(\d+)", "\w*"\)\);</script>', re.S).finditer(html)
+ self.blacklist = ([], [])
+ for entry in entries:
+ if entry.group(1) == "In":
+ self.blacklist[0].append(entry.group(2))
+ else:
+ self.blacklist[1].append(entry.group(2))
+ debug("[FritzCallFBF] _okBlacklist: %s" % repr(self.blacklist))
+
+ def _errorBlacklist(self, error):
+ debug("[FritzCallFBF] _errorBlacklist: %s" % (error))
+ text = _("FRITZ!Box - Error getting blacklist: %s") % error.getErrorMessage()
+ self._notify(text)
+
+#===============================================================================
+# def hangup(self):
+# ''' hangup call on port; not used for now '''
+# url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
+# parms = urlencode({
+# 'id':'uiPostForm',
+# 'name':'uiPostForm',
+# 'login:command/password': config.plugins.FritzCall.password.value,
+# 'telcfg:settings/UseClickToDial':'1',
+# 'telcfg:settings/DialPort':config.plugins.FritzCall.extension.value,
+# 'telcfg:command/Hangup':'',
+# 'sid':self._md5Sid
+# })
+# debug("[FritzCallFBF] hangup url: '" + url + "' parms: '" + parms + "'")
+# getPage(url,
+# method="POST",
+# headers={
+# 'Content-Type': "application/x-www-form-urlencoded",
+# 'Content-Length': str(len(parms))},
+# postdata=parms)
+#===============================================================================
+
+fritzbox = None
+
+class FritzMenu(Screen, HelpableScreen):
+ def __init__(self, session):
+ fontSize = scaleV(24, 21) # indeed this is font size +2
+ noButtons = 2 # reset, wlan
+
+ if not fritzbox or not fritzbox.info:
+ return
+
+ if fritzbox.info[FBF_tamActive]:
+ noButtons += 1 # toggle mailboxes
+ width = max(DESKTOP_WIDTH - scaleH(500, 250), noButtons*140+(noButtons+1)*10)
+ # boxInfo 2 lines, gap, internet 2 lines, gap, dsl/wlan each 1 line, gap, buttons
+ height = 5 + 2*fontSize + 10 + 2*fontSize + 10 + 2*fontSize + 10 + 40 + 5
+ if fritzbox.info[FBF_tamActive] is not None:
+ height += fontSize
+ if fritzbox.info[FBF_dectActive] is not None:
+ height += fontSize
+ if fritzbox.info[FBF_faxActive] is not None:
+ height += fontSize
+ if fritzbox.info[FBF_rufumlActive] is not None:
+ height += fontSize
+ buttonsGap = (width-noButtons*140)/(noButtons+1)
+ buttonsVPos = height-40-5
+
+ varLinePos = 4
+ if fritzbox.info[FBF_tamActive] is not None:
+ mailboxLine = """
+ <widget name="FBFMailbox" position="%d,%d" size="%d,%d" font="Regular;%d" />
+ <widget name="mailbox_inactive" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
+ <widget name="mailbox_active" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
+ <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
+ <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" />
+ """ % (
+ 40, 5+2*fontSize+10+varLinePos*fontSize+10, # position mailbox
+ width-40-20, fontSize, # size mailbox
+ fontSize-2,
+ "skin_default/buttons/button_green_off.png",
+ 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button mailbox
+ "skin_default/buttons/button_green.png",
+ 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button mailbox
+ noButtons*buttonsGap+(noButtons-1)*140, buttonsVPos,
+ noButtons*buttonsGap+(noButtons-1)*140, buttonsVPos,
+ )
+ varLinePos += 1
+ else:
+ mailboxLine = ""
+
+ if fritzbox.info[FBF_dectActive] is not None:
+ dectLine = """
+ <widget name="FBFDect" position="%d,%d" size="%d,%d" font="Regular;%d" />
+ <widget name="dect_inactive" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
+ <widget name="dect_active" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
+ """ % (
+ 40, 5+2*fontSize+10+varLinePos*fontSize+10, # position dect
+ width-40-20, fontSize, # size dect
+ fontSize-2,
+ "skin_default/buttons/button_green_off.png",
+ 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button dect
+ "skin_default/buttons/button_green.png",
+ 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button dect
+ )
+ varLinePos += 1
+ else:
+ dectLine = ""
+
+ if fritzbox.info[FBF_faxActive] is not None:
+ faxLine = """
+ <widget name="FBFFax" position="%d,%d" size="%d,%d" font="Regular;%d" />
+ <widget name="fax_inactive" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
+ <widget name="fax_active" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
+ """ % (
+ 40, 5+2*fontSize+10+varLinePos*fontSize+10, # position dect
+ width-40-20, fontSize, # size dect
+ fontSize-2,
+ "skin_default/buttons/button_green_off.png",
+ 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button dect
+ "skin_default/buttons/button_green.png",
+ 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button dect
+ )
+ varLinePos += 1
+ else:
+ faxLine = ""
+
+ if fritzbox.info[FBF_rufumlActive] is not None:
+ rufumlLine = """
+ <widget name="FBFRufuml" position="%d,%d" size="%d,%d" font="Regular;%d" />
+ <widget name="rufuml_inactive" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
+ <widget name="rufuml_active" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
+ """ % (
+ 40, 5+2*fontSize+10+varLinePos*fontSize+10, # position dect
+ width-40-20, fontSize, # size dect
+ fontSize-2,
+ "skin_default/buttons/button_green_off.png",
+ 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button dect
+ "skin_default/buttons/button_green.png",
+ 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button dect
+ )
+ varLinePos += 1
+ else:
+ rufumlLine = ""
+
+ self.skin = """
+ <screen name="FritzMenu" position="center,center" size="%d,%d" title="FRITZ!Box Fon Status" >
+ <widget name="FBFInfo" position="%d,%d" size="%d,%d" font="Regular;%d" />
+ <widget name="FBFInternet" position="%d,%d" size="%d,%d" font="Regular;%d" />
+ <widget name="internet_inactive" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
+ <widget name="internet_active" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
+ <widget name="FBFDsl" position="%d,%d" size="%d,%d" font="Regular;%d" />
+ <widget name="dsl_inactive" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
+ <widget name="dsl_active" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
+ <widget name="FBFWlan" position="%d,%d" size="%d,%d" font="Regular;%d" />
+ <widget name="wlan_inactive" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
+ <widget name="wlan_active" pixmap="%s" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
+ %s
+ %s
+ %s
+ %s
+ <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
+ <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" />
+ <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
+ <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" />
+ </screen>""" % (
+ width, height, # size
+ 40, 5, # position info
+ width-2*40, 2*fontSize, # size info
+ fontSize-2,
+ 40, 5+2*fontSize+10, # position internet
+ width-40, 2*fontSize, # size internet
+ fontSize-2,
+ "skin_default/buttons/button_green_off.png",
+ 20, 5+2*fontSize+10+(fontSize-16)/2, # position button internet
+ "skin_default/buttons/button_green.png",
+ 20, 5+2*fontSize+10+(fontSize-16)/2, # position button internet
+ 40, 5+2*fontSize+10+2*fontSize+10, # position dsl
+ width-40-20, fontSize, # size dsl
+ fontSize-2,
+ "skin_default/buttons/button_green_off.png",
+ 20, 5+2*fontSize+10+2*fontSize+10+(fontSize-16)/2, # position button dsl
+ "skin_default/buttons/button_green.png",
+ 20, 5+2*fontSize+10+2*fontSize+10+(fontSize-16)/2, # position button dsl
+ 40, 5+2*fontSize+10+3*fontSize+10, # position wlan
+ width-40-20, fontSize, # size wlan
+ fontSize-2,
+ "skin_default/buttons/button_green_off.png",
+ 20, 5+2*fontSize+10+3*fontSize+10+(fontSize-16)/2, # position button wlan
+ "skin_default/buttons/button_green.png",
+ 20, 5+2*fontSize+10+3*fontSize+10+(fontSize-16)/2, # position button wlan
+ mailboxLine,
+ dectLine,
+ faxLine,
+ rufumlLine,
+ buttonsGap, buttonsVPos, "skin_default/buttons/red.png", buttonsGap, buttonsVPos,
+ buttonsGap+140+buttonsGap, buttonsVPos, "skin_default/buttons/green.png", buttonsGap+140+buttonsGap, buttonsVPos,
+ )
+
+ Screen.__init__(self, session)
+ HelpableScreen.__init__(self)
+ # TRANSLATORS: keep it short, this is a button
+ self["key_red"] = Button(_("Reset"))
+ # TRANSLATORS: keep it short, this is a button
+ self["key_green"] = Button(_("Toggle WLAN"))
+ self._mailboxActive = False
+ if fritzbox.info[FBF_tamActive] is not None:
+ # TRANSLATORS: keep it short, this is a button
+ self["key_yellow"] = Button(_("Toggle Mailbox"))
+ self["menuActions"] = ActionMap(["OkCancelActions", "ColorActions", "NumberActions", "EPGSelectActions"],
+ {
+ "cancel": self._exit,
+ "ok": self._exit,
+ "red": self._reset,
+ "green": self._toggleWlan,
+ "yellow": (lambda: self._toggleMailbox(-1)),
+ "0": (lambda: self._toggleMailbox(0)),
+ "1": (lambda: self._toggleMailbox(1)),
+ "2": (lambda: self._toggleMailbox(2)),
+ "3": (lambda: self._toggleMailbox(3)),
+ "4": (lambda: self._toggleMailbox(4)),
+ "info": self._getInfo,
+ }, -2)
+ # TRANSLATORS: keep it short, this is a help text
+ self.helpList.append((self["menuActions"], "ColorActions", [("yellow", _("Toggle all mailboxes"))]))
+ # TRANSLATORS: keep it short, this is a help text
+ self.helpList.append((self["menuActions"], "NumberActions", [("0", _("Toggle 1. mailbox"))]))
+ # TRANSLATORS: keep it short, this is a help text
+ self.helpList.append((self["menuActions"], "NumberActions", [("1", _("Toggle 2. mailbox"))]))
+ # TRANSLATORS: keep it short, this is a help text
+ self.helpList.append((self["menuActions"], "NumberActions", [("2", _("Toggle 3. mailbox"))]))
+ # TRANSLATORS: keep it short, this is a help text
+ self.helpList.append((self["menuActions"], "NumberActions", [("3", _("Toggle 4. mailbox"))]))
+ # TRANSLATORS: keep it short, this is a help text
+ self.helpList.append((self["menuActions"], "NumberActions", [("4", _("Toggle 5. mailbox"))]))
+ self["FBFMailbox"] = Label(_('Mailbox'))
+ self["mailbox_inactive"] = Pixmap()
+ self["mailbox_active"] = Pixmap()
+ self["mailbox_active"].hide()
+ else:
+ self["menuActions"] = ActionMap(["OkCancelActions", "ColorActions", "EPGSelectActions"],
+ {
+ "cancel": self._exit,
+ "ok": self._exit,
+ "green": self._toggleWlan,
+ "red": self._reset,
+ "info": self._getInfo,
+ }, -2)
+
+ # TRANSLATORS: keep it short, this is a help text
+ self.helpList.append((self["menuActions"], "OkCancelActions", [("cancel", _("Quit"))]))
+ # TRANSLATORS: keep it short, this is a help text
+ self.helpList.append((self["menuActions"], "OkCancelActions", [("ok", _("Quit"))]))
+ # TRANSLATORS: keep it short, this is a help text
+ self.helpList.append((self["menuActions"], "ColorActions", [("green", _("Toggle WLAN"))]))
+ # TRANSLATORS: keep it short, this is a help text
+ self.helpList.append((self["menuActions"], "ColorActions", [("red", _("Reset"))]))
+ # TRANSLATORS: keep it short, this is a help text
+ self.helpList.append((self["menuActions"], "EPGSelectActions", [("info", _("Refresh status"))]))
+
+ self["FBFInfo"] = Label(_('Getting status from FRITZ!Box Fon...'))
+
+ self["FBFInternet"] = Label('Internet')
+ self["internet_inactive"] = Pixmap()
+ self["internet_active"] = Pixmap()
+ self["internet_active"].hide()
+
+ self["FBFDsl"] = Label('DSL')
+ self["dsl_inactive"] = Pixmap()
+ self["dsl_inactive"].hide()
+ self["dsl_active"] = Pixmap()
+ self["dsl_active"].hide()
+
+ self["FBFWlan"] = Label('WLAN ')
+ self["wlan_inactive"] = Pixmap()
+ self["wlan_inactive"].hide()
+ self["wlan_active"] = Pixmap()
+ self["wlan_active"].hide()
+ self._wlanActive = False
+
+ if fritzbox.info[FBF_dectActive] is not None:
+ self["FBFDect"] = Label('DECT')
+ self["dect_inactive"] = Pixmap()
+ self["dect_active"] = Pixmap()
+ self["dect_active"].hide()
+
+ if fritzbox.info[FBF_faxActive] is not None:
+ self["FBFFax"] = Label('Fax')
+ self["fax_inactive"] = Pixmap()
+ self["fax_active"] = Pixmap()
+ self["fax_active"].hide()
+
+ if fritzbox.info[FBF_rufumlActive] is not None:
+ self["FBFRufuml"] = Label(_('Call redirection'))
+ self["rufuml_inactive"] = Pixmap()
+ self["rufuml_active"] = Pixmap()
+ self["rufuml_active"].hide()
+
+ self._timer = eTimer()
+ self._timer.callback.append(self._getInfo)
+ self.onShown.append(lambda: self._timer.start(5000))
+ self.onHide.append(self._timer.stop)
+ self._getInfo()
+ self.onLayoutFinish.append(self.setWindowTitle)
+
+ def setWindowTitle(self):
+ # TRANSLATORS: this is a window title.
+ self.setTitle(_("FRITZ!Box Fon Status"))
+
+ def _getInfo(self):
+ fritzbox.getInfo(self._fillMenu)
+
+ def _fillMenu(self, status):
+ (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive) = status
+ self._wlanActive = (wlanState[0] == '1')
+ self._mailboxActive = False
+ try:
+ if not self.has_key("FBFInfo"): # screen is closed already
+ return
+
+ if boxInfo:
+ self["FBFInfo"].setText(boxInfo.replace(', ', '\n'))
+ else:
+ self["FBFInfo"].setText('BoxInfo ' + _('Status not available'))
+
+ if ipAddress:
+ if upTime:
+ self["FBFInternet"].setText('Internet ' + _('IP Address:') + ' ' + ipAddress + '\n' + _('Connected since') + ' ' + upTime)
+ else:
+ self["FBFInternet"].setText('Internet ' + _('IP Address:') + ' ' + ipAddress)
+ self["internet_inactive"].hide()
+ self["internet_active"].show()
+ else:
+ self["internet_active"].hide()
+ self["internet_inactive"].show()
+
+ if dslState:
+ if dslState[0] == '5':
+ self["dsl_inactive"].hide()
+ self["dsl_active"].show()
+ if dslState[1]:
+ self["FBFDsl"].setText('DSL ' + dslState[1])
+ else:
+ self["dsl_active"].hide()
+ self["dsl_inactive"].show()
+ else:
+ self["FBFDsl"].setText('DSL ' + _('Status not available'))
+ self["dsl_active"].hide()
+ self["dsl_inactive"].hide()
+
+ if wlanState:
+ if wlanState[0 ] == '1':
+ self["wlan_inactive"].hide()
+ self["wlan_active"].show()
+ message = 'WLAN'
+ if wlanState[1] == '0':
+ message += ' ' + _('not encrypted')
+ else:
+ message += ' ' + _('encrypted')
+ if wlanState[2]:
+ if wlanState[2] == '0':
+ message = message + ', ' + _('no device active')
+ elif wlanState[2] == '1':
+ message = message + ', ' + _('one device active')
+ else:
+ message = message + ', ' + wlanState[2] + ' ' + _('devices active')
+ self["FBFWlan"].setText(message)
+ else:
+ self["wlan_active"].hide()
+ self["wlan_inactive"].show()
+ self["FBFWlan"].setText('WLAN')
+ else:
+ self["FBFWlan"].setText('WLAN ' + _('Status not available'))
+ self["wlan_active"].hide()
+ self["wlan_inactive"].hide()
+
+ if fritzbox.info[FBF_tamActive]:
+ if not tamActive or tamActive[0] == 0:
+ self._mailboxActive = False
+ self["mailbox_active"].hide()
+ self["mailbox_inactive"].show()
+ self["FBFMailbox"].setText(_('No mailbox active'))
+ else:
+ self._mailboxActive = True
+ message = '('
+ for i in range(5):
+ if tamActive[i+1]:
+ message = message + str(i) + ','
+ message = message[:-1] + ')'
+ self["mailbox_inactive"].hide()
+ self["mailbox_active"].show()
+ if tamActive[0] == 1:
+ self["FBFMailbox"].setText(_('One mailbox active') + ' ' + message)
+ else:
+ self["FBFMailbox"].setText(str(tamActive[0]) + ' ' + _('mailboxes active') + ' ' + message)
+
+ if fritzbox.info[FBF_dectActive] and dectActive:
+ self["dect_inactive"].hide()
+ self["dect_active"].show()
+ if dectActive == 0:
+ self["FBFDect"].setText(_('No DECT phone registered'))
+ else:
+ if dectActive == 1:
+ self["FBFDect"].setText(_('One DECT phone registered'))
+ else:
+ self["FBFDect"].setText(str(dectActive) + ' ' + _('DECT phones registered'))
+
+ if fritzbox.info[FBF_faxActive] and faxActive:
+ self["fax_inactive"].hide()
+ self["fax_active"].show()
+ self["FBFFax"].setText(_('Software fax active'))
+
+ if fritzbox.info[FBF_rufumlActive] is not None and rufumlActive is not None:
+ if rufumlActive == 0:
+ self["rufuml_active"].hide()
+ self["rufuml_inactive"].show()
+ self["FBFRufuml"].setText(_('No call redirection active'))
+ else:
+ self["rufuml_inactive"].hide()
+ self["rufuml_active"].show()
+ if rufumlActive == 1:
+ self["FBFRufuml"].setText(_('One call redirection active'))
+ else:
+ self["FBFRufuml"].setText(str(rufumlActive) + ' ' + _('call redirections active'))
+
+ except KeyError:
+ debug("[FritzCallFBF] _fillMenu: " + traceback.format_exc())
+
+ def _toggleWlan(self):
+ if self._wlanActive:
+ debug("[FritzMenu] toggleWlan off")
+ fritzbox.changeWLAN('0')
+ else:
+ debug("[FritzMenu] toggleWlan off")
+ fritzbox.changeWLAN('1')
+
+ def _toggleMailbox(self, which):
+ debug("[FritzMenu] toggleMailbox")
+ if fritzbox.info[FBF_tamActive]:
+ debug("[FritzMenu] toggleMailbox off")
+ fritzbox.changeMailbox(which)
+
+ def _reset(self):
+ fritzbox.reset()
+ self._exit()
+
+ def _exit(self):
+ self._timer.stop()
+ self.close()
+
+
+class FritzDisplayCalls(Screen, HelpableScreen):
+
+ def __init__(self, session, text=""): #@UnusedVariable # pylint: disable-msg=W0613
+ self.width = DESKTOP_WIDTH * scaleH(75, 85)/100
+ self.height = DESKTOP_HEIGHT * 0.75
+ dateFieldWidth = scaleH(180, 105)
+ dirFieldWidth = 16
+ lengthFieldWidth = scaleH(55, 45)
+ scrollbarWidth = scaleH(35, 35)
+ entriesWidth = self.width -scaleH(40, 5) -5
+ hereFieldWidth = entriesWidth -dirFieldWidth -5 -dateFieldWidth -5 -lengthFieldWidth -scrollbarWidth
+ fieldWidth = entriesWidth -dirFieldWidth -5 -5 -scrollbarWidth
+ fontSize = scaleV(22, 20)
+ itemHeight = 2*fontSize+5
+ entriesHeight = self.height -scaleV(15, 10) -5 -fontSize -5 -5 -5 -40 -5
+ buttonGap = (self.width -4*140)/5
+ buttonV = self.height -40
+ debug("[FritzDisplayCalls] width: " + str(self.width))
+ self.skin = """
+ <screen name="FritzDisplayCalls" position="center,center" size="%d,%d" title="Phone calls" >
+ <eLabel position="0,0" size="%d,2" backgroundColor="#aaaaaa" />
+ <widget name="statusbar" position="%d,%d" size="%d,%d" font="Regular;%d" backgroundColor="#aaaaaa" transparent="1" />
+ <eLabel position="0,%d" size="%d,2" backgroundColor="#aaaaaa" />
+ <widget source="entries" render="Listbox" position="%d,%d" size="%d,%d" scrollbarMode="showOnDemand" transparent="1">
+ <convert type="TemplatedMultiContent">
+ {"template": [
+ 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
+ MultiContentEntryPixmapAlphaTest(pos = (%d,%d), size = (%d,%d), png = 2), # index 1 i direction pixmap
+ MultiContentEntryText(pos = (%d,%d), size = (%d,%d), font=1, flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER, text = 3), # index 2 is remote name/number
+ MultiContentEntryText(pos = (%d,%d), size = (%d,%d), font=0, flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER, text = 4), # index 3 is length of call
+ 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
+ ],
+ "fonts": [gFont("Regular", %d), gFont("Regular", %d)],
+ "itemHeight": %d
+ }
+ </convert>
+ </widget>
+ <eLabel position="0,%d" size="%d,2" backgroundColor="#aaaaaa" />
+ <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
+ <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
+ <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
+ <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
+ <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" />
+ <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" />
+ <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" />
+ <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" />
+ </screen>""" % (
+ # scaleH(90, 75), scaleV(100, 78), # position
+ self.width, self.height, # size
+ self.width, # eLabel width
+ scaleH(40, 5), scaleV(10, 5), # statusbar position
+ self.width, fontSize+5, # statusbar size
+ scaleV(21, 21), # statusbar font size
+ scaleV(10, 5)+5+fontSize+5, # eLabel position vertical
+ self.width, # eLabel width
+ scaleH(40, 5), scaleV(10, 5)+5+fontSize+5+5, # entries position
+ entriesWidth, entriesHeight, # entries size
+ 5+dirFieldWidth+5, fontSize+5, dateFieldWidth, fontSize, # date pos/size
+ 5, (itemHeight-dirFieldWidth)/2, dirFieldWidth, dirFieldWidth, # dir pos/size
+ 5+dirFieldWidth+5, 5, fieldWidth, fontSize, # caller pos/size
+ 2+dirFieldWidth+2+dateFieldWidth+5, fontSize+5, lengthFieldWidth, fontSize, # length pos/size
+ 2+dirFieldWidth+2+dateFieldWidth+5+lengthFieldWidth+5, fontSize+5, hereFieldWidth, fontSize, # my number pos/size
+ fontSize-4, fontSize, # fontsize
+ itemHeight, # itemHeight
+ buttonV-5, # eLabel position vertical
+ self.width, # eLabel width
+ buttonGap, buttonV, "skin_default/buttons/red.png", # widget red
+ 2*buttonGap+140, buttonV, "skin_default/buttons/green.png", # widget green
+ 3*buttonGap+2*140, buttonV, "skin_default/buttons/yellow.png", # widget yellow
+ 4*buttonGap+3*140, buttonV, "skin_default/buttons/blue.png", # widget blue
+ buttonGap, buttonV, scaleV(22, 21), # widget red
+ 2*buttonGap+140, buttonV, scaleV(22, 21), # widget green
+ 3*buttonGap+2*140, buttonV, scaleV(22, 21), # widget yellow
+ 4*buttonGap+3*140, buttonV, scaleV(22, 21), # widget blue
+ )
+ # debug("[FritzDisplayCalls] skin: " + self.skin)
+ Screen.__init__(self, session)
+ HelpableScreen.__init__(self)
+
+ # TRANSLATORS: keep it short, this is a button
+ self["key_yellow"] = Button(_("All"))
+ # TRANSLATORS: keep it short, this is a button
+ self["key_red"] = Button(_("Missed"))
+ # TRANSLATORS: keep it short, this is a button
+ self["key_blue"] = Button(_("Incoming"))
+ # TRANSLATORS: keep it short, this is a button
+ self["key_green"] = Button(_("Outgoing"))
+
+ self["setupActions"] = ActionMap(["OkCancelActions", "ColorActions"],
+ {
+ "yellow": (lambda: self.display(FBF_ALL_CALLS)),
+ "red": (lambda: self.display(FBF_MISSED_CALLS)),
+ "blue": (lambda: self.display(FBF_IN_CALLS)),
+ "green": (lambda: self.display(FBF_OUT_CALLS)),
+ "cancel": self.ok,
+ "ok": self.showEntry, }, - 2)
+
+ # TRANSLATORS: keep it short, this is a help text
+ self.helpList.append((self["setupActions"], "OkCancelActions", [("ok", _("Show details of entry"))]))
+ # TRANSLATORS: keep it short, this is a help text
+ self.helpList.append((self["setupActions"], "OkCancelActions", [("cancel", _("Quit"))]))
+ # TRANSLATORS: keep it short, this is a help text
+ self.helpList.append((self["setupActions"], "ColorActions", [("yellow", _("Display all calls"))]))
+ # TRANSLATORS: keep it short, this is a help text
+ self.helpList.append((self["setupActions"], "ColorActions", [("red", _("Display missed calls"))]))
+ # TRANSLATORS: keep it short, this is a help text
+ self.helpList.append((self["setupActions"], "ColorActions", [("blue", _("Display incoming calls"))]))
+ # TRANSLATORS: keep it short, this is a help text
+ self.helpList.append((self["setupActions"], "ColorActions", [("green", _("Display outgoing calls"))]))
+
+ self["statusbar"] = Label(_("Getting calls from FRITZ!Box..."))
+ self.list = []
+ self["entries"] = List(self.list)
+ #=======================================================================
+ # fontSize = scaleV(22, 18)
+ # fontHeight = scaleV(24, 20)
+ # self["entries"].l.setFont(0, gFont("Regular", fontSize))
+ # self["entries"].l.setItemHeight(fontHeight)
+ #=======================================================================
+ debug("[FritzDisplayCalls] init: '''%s'''" % config.plugins.FritzCall.fbfCalls.value)
+ self.display()
+ self.onLayoutFinish.append(self.setWindowTitle)
+
+ def setWindowTitle(self):
+ # TRANSLATORS: this is a window title.
+ self.setTitle(_("Phone calls"))
+
+ def ok(self):
+ self.close()
+
+ def display(self, which=config.plugins.FritzCall.fbfCalls.value):
+ debug("[FritzDisplayCalls] display")
+ config.plugins.FritzCall.fbfCalls.value = which
+ config.plugins.FritzCall.fbfCalls.save()
+ fritzbox.getCalls(self, lambda x: self.gotCalls(x, which), which)
+
+ def gotCalls(self, listOfCalls, which):
+ debug("[FritzDisplayCalls] gotCalls")
+ self.updateStatus(fbfCallsChoices[which] + " (" + str(len(listOfCalls)) + ")")
+
+ directout = LoadPixmap(resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/images/callout.png"))
+ directin = LoadPixmap(resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/images/callin.png"))
+ directfailed = LoadPixmap(resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/images/callinfailed.png"))
+ def pixDir(direct):
+ if direct == FBF_OUT_CALLS:
+ direct = directout
+ elif direct == FBF_IN_CALLS:
+ direct = directin
+ else:
+ direct = directfailed
+ return direct
+
+ self.list = [(number, date[:6] + ' ' + date[9:14], pixDir(direct), remote, length, here) for (number, date, direct, remote, length, here) in listOfCalls]
+ self["entries"].setList(self.list)
+
+ def updateStatus(self, text):
+ if self.has_key("statusbar"):
+ self["statusbar"].setText(_("Getting calls from FRITZ!Box...") + ' ' + text)
+
+ def showEntry(self):
+ debug("[FritzDisplayCalls] showEntry")
+ cur = self["entries"].getCurrent()
+ if cur:
+ if cur[0]:
+ debug("[FritzDisplayCalls] showEntry %s" % (cur[0]))
+ number = cur[0]
+ fullname = phonebook.search(cur[0])
+ if fullname:
+ # we have a name for this number
+ name = fullname
+ self.session.open(FritzOfferAction, self, number, name)
+ else:
+ # we don't
+ fullname = resolveNumberWithAvon(number, config.plugins.FritzCall.country.value)
+ if fullname:
+ name = fullname
+ self.session.open(FritzOfferAction, self, number, name)
+ else:
+ self.session.open(FritzOfferAction, self, number)
+ else:
+ # we do not even have a number...
+ self.session.open(MessageBox,
+ _("UNKNOWN"),
+ type=MessageBox.TYPE_INFO)
+
+
+class FritzOfferAction(Screen):
+
+ def __init__(self, session, parent, number, name=""):
+ # the layout will completely be recalculated in finishLayout
+ self.skin = """
+ <screen name="FritzOfferAction" title="Do what?" >
+ <widget name="text" size="%d,%d" font="Regular;%d" />
+ <widget name="FacePixmap" size="%d,%d" alphatest="on" />
+ <widget name="key_red_p" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
+ <widget name="key_green_p" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
+ <widget name="key_yellow_p" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
+ <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" />
+ <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" />
+ <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" />
+ </screen>""" % (
+ DESKTOP_WIDTH, DESKTOP_HEIGHT, # set maximum size
+ scaleH(22,21), # text
+ DESKTOP_WIDTH, DESKTOP_HEIGHT, # set maximum size
+ "skin_default/buttons/red.png",
+ "skin_default/buttons/green.png",
+ "skin_default/buttons/yellow.png",
+ )
+ debug("[FritzOfferAction] init: %s, %s" %(number, name))
+ Screen.__init__(self, session)
+
+ # TRANSLATORS: keep it short, this is a button
+ self["key_red"] = Button(_("Lookup"))
+ # TRANSLATORS: keep it short, this is a button
+ self["key_green"] = Button(_("Call"))
+ # TRANSLATORS: keep it short, this is a button
+ self["key_yellow"] = Button(_("Save"))
+ # TRANSLATORS: keep it short, this is a button
+ # self["key_blue"] = Button(_("Search"))
+
+ self["FritzOfferActions"] = ActionMap(["OkCancelActions", "ColorActions"],
+ {
+ "red": self._lookup,
+ "green": self._call,
+ "yellow": self._add,
+ "cancel": self._exit,
+ "ok": self._exit, }, - 2)
+
+ self._session = session
+ self._number = number
+ self._name = name.replace("\n", ", ")
+ self["text"] = Label(number + "\n\n" + name.replace(", ", "\n"))
+ self._parent = parent
+ self._lookupState = 0
+ self["key_red_p"] = Pixmap()
+ self["key_green_p"] = Pixmap()
+ self["key_yellow_p"] = Pixmap()
+ self["FacePixmap"] = Pixmap()
+ self.onLayoutFinish.append(self._finishLayout)
+ self.onLayoutFinish.append(self.setWindowTitle)
+
+ def setWindowTitle(self):
+ # TRANSLATORS: this is a window title.
+ self.setTitle(_("Do what?"))
+
+ def _finishLayout(self):
+ # pylint: disable-msg=W0142
+ debug("[FritzCall] FritzOfferAction/finishLayout number: %s/%s" % (self._number, self._name))
+
+ faceFile = findFace(self._number, self._name)
+ picPixmap = LoadPixmap(faceFile)
+ if not picPixmap: # that means most probably, that the picture is not 8 bit...
+ Notifications.AddNotification(MessageBox, _("Found picture\n\n%s\n\nBut did not load. Probably not PNG, 8-bit") %faceFile, type = MessageBox.TYPE_ERROR)
+ picPixmap = LoadPixmap(resolveFilename(SCOPE_SKIN_IMAGE, "skin_default/icons/input_error.png"))
+ picSize = picPixmap.size()
+ self["FacePixmap"].instance.setPixmap(picPixmap)
+
+ noButtons = 3
+ # recalculate window size
+ textSize = self["text"].getSize()
+ textSize = (textSize[0]+20, textSize[1]+20) # don't know, why, but size is too small
+ debug("[FritzCall] FritzOfferAction/finishLayout textsize: %s/%s" % textSize)
+ textSize = eSize(*textSize)
+ width = max(scaleH(620, 545), noButtons*145, picSize.width() + textSize.width() + 30)
+ height = max(picSize.height()+5, textSize.height()+5, scaleV(-1, 136)) + 5 + 40 + 5
+ buttonsGap = (width-noButtons*140)/(noButtons+1)
+ buttonsVPos = height-40-5
+ wSize = (width, height)
+ wSize = eSize(*wSize)
+
+ # center the smaller vertically
+ hGap = (width-picSize.width()-textSize.width())/3
+ picPos = (hGap, (height-50-picSize.height())/2+5)
+ textPos = (hGap+picSize.width()+hGap, (height-50-textSize.height())/2+5)
+
+ # resize screen
+ self.instance.resize(wSize)
+ # resize text
+ self["text"].instance.resize(textSize)
+ # resize pixmap
+ self["FacePixmap"].instance.resize(picSize)
+ # move buttons
+ buttonPos = (buttonsGap, buttonsVPos)
+ self["key_red_p"].instance.move(ePoint(*buttonPos))
+ self["key_red"].instance.move(ePoint(*buttonPos))
+ buttonPos = (buttonsGap+140+buttonsGap, buttonsVPos)
+ self["key_green_p"].instance.move(ePoint(*buttonPos))
+ self["key_green"].instance.move(ePoint(*buttonPos))
+ buttonPos = (buttonsGap+140+buttonsGap+140+buttonsGap, buttonsVPos)
+ self["key_yellow_p"].instance.move(ePoint(*buttonPos))
+ self["key_yellow"].instance.move(ePoint(*buttonPos))
+ # move text
+ self["text"].instance.move(ePoint(*textPos))
+ # move pixmap
+ self["FacePixmap"].instance.move(ePoint(*picPos))
+ # center window
+ self.instance.move(ePoint((DESKTOP_WIDTH-wSize.width())/2, (DESKTOP_HEIGHT-wSize.height())/2))
+
+ def _setTextAndResize(self, message):
+ # pylint: disable-msg=W0142
+ self["text"].instance.resize(eSize(*(DESKTOP_WIDTH, DESKTOP_HEIGHT)))
+ self["text"].setText(self._number + "\n\n" + message)
+ self._finishLayout()
+
+ def _lookup(self):
+ phonebookLocation = config.plugins.FritzCall.phonebookLocation.value
+ if self._lookupState == 0:
+ self._lookupState = 1
+ self._setTextAndResize(_("Reverse searching..."))
+ ReverseLookupAndNotifier(self._number, self._lookedUp, "UTF-8", config.plugins.FritzCall.country.value)
+ return
+ if self._lookupState == 1 and os.path.exists(os.path.join(phonebookLocation, "PhoneBook.csv")):
+ self._setTextAndResize(_("Searching in Outlook export..."))
+ self._lookupState = 2
+ self._lookedUp(self._number, FritzOutlookCSV.findNumber(self._number, os.path.join(phonebookLocation, "PhoneBook.csv"))) #@UndefinedVariable
+ return
+ else:
+ self._lookupState = 2
+ if self._lookupState == 2 and os.path.exists(os.path.join(phonebookLocation, "PhoneBook.ldif")):
+ self._setTextAndResize(_("Searching in LDIF..."))
+ self._lookupState = 0
+ FritzLDIF.FindNumber(self._number, open(os.path.join(phonebookLocation, "PhoneBook.ldif")), self._lookedUp)
+ return
+ else:
+ self._lookupState = 0
+ self._lookup()
+
+ def _lookedUp(self, number, name):
+ name = handleReverseLookupResult(name)
+ if not name:
+ if self._lookupState == 1:
+ name = _("No result from reverse lookup")
+ elif self._lookupState == 2:
+ name = _("No result from Outlook export")
+ else:
+ name = _("No result from LDIF")
+ self._name = name
+ self._number = number
+ debug("[FritzOfferAction] lookedUp: " + str(name.replace(", ", "\n")))
+ self._setTextAndResize(str(name.replace(", ", "\n")))
+
+ def _call(self):
+ debug("[FritzOfferAction] add: %s" %self._number)
+ fritzbox.dial(self._number)
+ self._exit()
+
+ def _add(self):
+ debug("[FritzOfferAction] add: %s, %s" %(self._number, self._name))
+ phonebook.FritzDisplayPhonebook(self._session).add(self._parent, self._number, self._name)
+ self._exit()
+
+ def _exit(self):
+ self.close()
+
+
+class FritzCallPhonebook:
+ def __init__(self):
+ debug("[FritzCallPhonebook] init")
+ # Beware: strings in phonebook.phonebook have to be in utf-8!
+ self.phonebook = {}
+ self.reload()
+
+ def reload(self):
+ debug("[FritzCallPhonebook] reload")
+ # Beware: strings in phonebook.phonebook have to be in utf-8!
+ self.phonebook = {}
+
+ if not config.plugins.FritzCall.enable.value:
+ return
+
+ phonebookFilename = os.path.join(config.plugins.FritzCall.phonebookLocation.value, "PhoneBook.txt")
+ if config.plugins.FritzCall.phonebook.value and os.path.exists(phonebookFilename):
+ debug("[FritzCallPhonebook] reload: read " + phonebookFilename)
+ phonebookTxtCorrupt = False
+ self.phonebook = {}
+ for line in open(phonebookFilename):
+ try:
+ # Beware: strings in phonebook.phonebook have to be in utf-8!
+ line = line.decode("utf-8")
+ except UnicodeDecodeError: # this is just for the case, somebody wrote latin1 chars into PhoneBook.txt
+ try:
+ line = line.decode("iso-8859-1")
+ debug("[FritzCallPhonebook] Fallback to ISO-8859-1 in %s" % line)
+ phonebookTxtCorrupt = True
+ except UnicodeDecodeError:
+ debug("[FritzCallPhonebook] Could not parse internal Phonebook Entry %s" % line)
+ phonebookTxtCorrupt = True
+ line = line.encode("utf-8")
+ elems = line.split('#')
+ if len(elems) == 2:
+ try:
+ self.phonebook[elems[0]] = elems[1]
+ except ValueError: # how could this possibly happen?!?!
+ debug("[FritzCallPhonebook] Could not parse internal Phonebook Entry %s" % line)
+ phonebookTxtCorrupt = True
+ else:
+ debug("[FritzCallPhonebook] Could not parse internal Phonebook Entry %s" % line)
+ phonebookTxtCorrupt = True
+
+ #===============================================================
+ # found = re.match("^(\d+)#(.*)$", line)
+ # if found:
+ # try:
+ # self.phonebook[found.group(1)] = found.group(2)
+ # except ValueError: # how could this possibly happen?!?!
+ # debug("[FritzCallPhonebook] Could not parse internal Phonebook Entry %s" % line)
+ # phonebookTxtCorrupt = True
+ # else:
+ # debug("[FritzCallPhonebook] Could not parse internal Phonebook Entry %s" % line)
+ # phonebookTxtCorrupt = True
+ #===============================================================
+
+ if phonebookTxtCorrupt:
+ # dump phonebook to PhoneBook.txt
+ debug("[FritzCallPhonebook] dump Phonebook.txt")
+ try:
+ os.rename(phonebookFilename, phonebookFilename + ".bck")
+ fNew = open(phonebookFilename, 'w')
+ # Beware: strings in phonebook.phonebook are utf-8!
+ for (number, name) in self.phonebook.iteritems():
+ # Beware: strings in PhoneBook.txt have to be in utf-8!
+ fNew.write(number + "#" + name.encode("utf-8"))
+ fNew.close()
+ except (IOError, OSError):
+ debug("[FritzCallPhonebook] error renaming or writing to %s" %phonebookFilename)
+
+#===============================================================================
+# #
+# # read entries from Outlook export
+# #
+# # not reliable with coding yet
+# #
+# # import csv exported from Outlook 2007 with csv(Windows)
+# csvFilename = "/tmp/PhoneBook.csv"
+# if config.plugins.FritzCall.phonebook.value and os.path.exists(csvFilename):
+# try:
+# readOutlookCSV(csvFilename, self.add)
+# os.rename(csvFilename, csvFilename + ".done")
+# except ImportError:
+# debug("[FritzCallPhonebook] CSV import failed" %line)
+#===============================================================================
+
+
+#===============================================================================
+# #
+# # read entries from LDIF
+# #
+# # import ldif exported from Thunderbird 2.0.0.19
+# ldifFilename = "/tmp/PhoneBook.ldif"
+# if config.plugins.FritzCall.phonebook.value and os.path.exists(ldifFilename):
+# try:
+# parser = MyLDIF(open(ldifFilename), self.add)
+# parser.parse()
+# os.rename(ldifFilename, ldifFilename + ".done")
+# except ImportError:
+# debug("[FritzCallPhonebook] LDIF import failed" %line)
+#===============================================================================
+
+ if fritzbox and config.plugins.FritzCall.fritzphonebook.value:
+ fritzbox.loadFritzBoxPhonebook()
+
+ def search(self, number):
+ # debug("[FritzCallPhonebook] Searching for %s" %number)
+ name = ""
+ if not self.phonebook or not number:
+ return
+
+ if config.plugins.FritzCall.prefix.value:
+ prefix = config.plugins.FritzCall.prefix.value
+ if number[0] != '0':
+ number = prefix + number
+ # debug("[FritzCallPhonebook] search: added prefix: %s" %number)
+ elif number[:len(prefix)] == prefix and self.phonebook.has_key(number[len(prefix):]):
+ # debug("[FritzCallPhonebook] search: same prefix")
+ name = self.phonebook[number[len(prefix):]]
+ # debug("[FritzCallPhonebook] search: result: %s" %name)
+ else:
+ prefix = ""
+
+ if not name and self.phonebook.has_key(number):
+ name = self.phonebook[number]
+
+ return name.replace(", ", "\n").strip()
+
+ def add(self, number, name):
+ '''
+
+ @param number: number of entry
+ @param name: name of entry, has to be in utf-8
+ '''
+ debug("[FritzCallPhonebook] add")
+ name = name.replace("\n", ", ").replace('#','') # this is just for safety reasons. add should only be called with newlines converted into commas
+ self.remove(number)
+ self.phonebook[number] = name
+ if number and number != 0:
+ if config.plugins.FritzCall.phonebook.value:
+ try:
+ name = name.strip() + "\n"
+ string = "%s#%s" % (number, name)
+ # Beware: strings in PhoneBook.txt have to be in utf-8!
+ f = open(os.path.join(config.plugins.FritzCall.phonebookLocation.value, "PhoneBook.txt"), 'a')
+ f.write(string)
+ f.close()
+ debug("[FritzCallPhonebook] added %s with %s to Phonebook.txt" % (number, name.strip()))
+ return True
+
+ except IOError:
+ return False
+
+ def remove(self, number):
+ if number in self.phonebook:
+ debug("[FritzCallPhonebook] remove entry in phonebook")
+ del self.phonebook[number]
+ if config.plugins.FritzCall.phonebook.value:
+ try:
+ phonebookFilename = os.path.join(config.plugins.FritzCall.phonebookLocation.value, "PhoneBook.txt")
+ debug("[FritzCallPhonebook] remove entry in Phonebook.txt")
+ fOld = open(phonebookFilename, 'r')
+ fNew = open(phonebookFilename + str(os.getpid()), 'w')
+ line = fOld.readline()
+ while (line):
+ elems = line.split('#')
+ if len(elems) == 2 and not elems[0] == number:
+ fNew.write(line)
+ line = fOld.readline()
+ fOld.close()
+ fNew.close()
+ # os.remove(phonebookFilename)
+ eBackgroundFileEraser.getInstance().erase(phonebookFilename)
+ os.rename(phonebookFilename + str(os.getpid()), phonebookFilename)
+ debug("[FritzCallPhonebook] removed %s from Phonebook.txt" % number)
+ return True
+
+ except (IOError, OSError):
+ debug("[FritzCallPhonebook] error removing %s from %s" %(number, phonebookFilename))
+ return False
+
+ class FritzDisplayPhonebook(Screen, HelpableScreen, NumericalTextInput):
+
+ def __init__(self, session):
+ self.entriesWidth = DESKTOP_WIDTH * scaleH(75, 85)/100
+ self.height = DESKTOP_HEIGHT * 0.75
+ numberFieldWidth = scaleH(190, 150)
+ fieldWidth = self.entriesWidth -5 -numberFieldWidth -10
+ fontSize = scaleV(22, 18)
+ fontHeight = scaleV(24, 20)
+ debug("[FritzDisplayPhonebook] width: " + str(self.width))
+ self.skin = """
+ <screen name="FritzDisplayPhonebook" position="center,center" size="%d,%d" title="Phonebook" >
+ <eLabel position="0,0" size="%d,2" backgroundColor="#aaaaaa" />
+ <widget source="entries" render="Listbox" position="%d,%d" size="%d,%d" scrollbarMode="showOnDemand" transparent="1">
+ <convert type="TemplatedMultiContent">
+ {"template": [
+ MultiContentEntryText(pos = (%d,%d), size = (%d,%d), font=0, flags = RT_HALIGN_LEFT, text = 1), # index 0 is the name, index 1 is shortname
+ MultiContentEntryText(pos = (%d,%d), size = (%d,%d), font=0, flags = RT_HALIGN_LEFT, text = 2), # index 2 is number
+ ],
+ "fonts": [gFont("Regular", %d)],
+ "itemHeight": %d
+ }
+ </convert>
+ </widget>
+ <eLabel position="0,%d" size="%d,2" backgroundColor="#aaaaaa" />
+ <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
+ <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
+ <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
+ <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
+ <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" />
+ <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" />
+ <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" />
+ <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" />
+ </screen>""" % (
+ # scaleH(90, 75), scaleV(100, 73), # position
+ scaleH(1100, 570), scaleV(560, 430), # size
+ scaleH(1100, 570), # eLabel width
+ scaleH(40, 5), scaleV(20, 5), # entries position
+ self.entriesWidth, scaleV(488, 380), # entries size
+ 0, 0, fieldWidth, scaleH(24,20), # name pos/size
+ fieldWidth +5, 0, numberFieldWidth, scaleH(24,20), # dir pos/size
+ fontSize, # fontsize
+ fontHeight, # itemHeight
+ scaleV(518, 390), # eLabel position vertical
+ scaleH(1100, 570), # eLabel width
+ scaleH(20, 5), scaleV(525, 395), "skin_default/buttons/red.png", # ePixmap red
+ scaleH(290, 145), scaleV(525, 395), "skin_default/buttons/green.png", # ePixmap green
+ scaleH(560, 285), scaleV(525, 395), "skin_default/buttons/yellow.png", # ePixmap yellow
+ scaleH(830, 425), scaleV(525, 395), "skin_default/buttons/blue.png", # ePixmap blue
+ scaleH(20, 5), scaleV(525, 395), scaleV(22, 21), # widget red
+ scaleH(290, 145), scaleV(525, 395), scaleV(22, 21), # widget green
+ scaleH(560, 285), scaleV(525, 395), scaleV(22, 21), # widget yellow
+ scaleH(830, 425), scaleV(525, 395), scaleV(22, 21), # widget blue
+ )
+
+ # debug("[FritzDisplayCalls] skin: " + self.skin)
+ Screen.__init__(self, session)
+ NumericalTextInput.__init__(self)
+ HelpableScreen.__init__(self)
+
+ # TRANSLATORS: keep it short, this is a button
+ self["key_red"] = Button(_("Delete"))
+ # TRANSLATORS: keep it short, this is a button
+ self["key_green"] = Button(_("New"))
+ # TRANSLATORS: keep it short, this is a button
+ self["key_yellow"] = Button(_("Edit"))
+ # TRANSLATORS: keep it short, this is a button
+ self["key_blue"] = Button(_("Search"))
+
+ self["setupActions"] = ActionMap(["OkCancelActions", "ColorActions"],
+ {
+ "red": self.delete,
+ "green": self.add,
+ "yellow": self.edit,
+ "blue": self.search,
+ "cancel": self.exit,
+ "ok": self.showEntry, }, - 2)
+
+ # TRANSLATORS: keep it short, this is a help text
+ self.helpList.append((self["setupActions"], "OkCancelActions", [("ok", _("Show details of entry"))]))
+ # TRANSLATORS: keep it short, this is a help text
+ self.helpList.append((self["setupActions"], "OkCancelActions", [("cancel", _("Quit"))]))
+ # TRANSLATORS: keep it short, this is a help text
+ self.helpList.append((self["setupActions"], "ColorActions", [("red", _("Delete entry"))]))
+ # TRANSLATORS: keep it short, this is a help text
+ self.helpList.append((self["setupActions"], "ColorActions", [("green", _("Add entry to phonebook"))]))
+ # TRANSLATORS: keep it short, this is a help text
+ self.helpList.append((self["setupActions"], "ColorActions", [("yellow", _("Edit selected entry"))]))
+ # TRANSLATORS: keep it short, this is a help text
+ self.helpList.append((self["setupActions"], "ColorActions", [("blue", _("Search (case insensitive)"))]))
+
+ self["entries"] = List([])
+ debug("[FritzCallPhonebook] displayPhonebook init")
+ self.help_window = None
+ self.sortlist = []
+ self.onLayoutFinish.append(self.setWindowTitle)
+ self.display()
+
+ def setWindowTitle(self):
+ # TRANSLATORS: this is a window title.
+ self.setTitle(_("Phonebook"))
+
+ def display(self, filterNumber=""):
+ debug("[FritzCallPhonebook] displayPhonebook/display")
+ self.sortlist = []
+ # Beware: strings in phonebook.phonebook are utf-8!
+ sortlistHelp = sorted((name.lower(), name, number) for (number, name) in phonebook.phonebook.iteritems())
+ for (low, name, number) in sortlistHelp:
+ if number == "01234567890":
+ continue
+ try:
+ low = low.decode("utf-8")
+ except UnicodeDecodeError: # this should definitely not happen
+ try:
+ low = low.decode("iso-8859-1")
+ except UnicodeDecodeError:
+ debug("[FritzCallPhonebook] displayPhonebook/display: corrupt phonebook entry for %s" % number)
+ # self.session.open(MessageBox, _("Corrupt phonebook entry\nfor number %s\nDeleting.") %number, type = MessageBox.TYPE_ERROR)
+ phonebook.remove(number)
+ continue
+ else:
+ if filterNumber:
+ filterNumber = filterNumber.lower()
+ if low.find(filterNumber) == - 1:
+ continue
+ name = name.strip().decode("utf-8")
+ number = number.strip().decode("utf-8")
+ comma = name.find(',')
+ if comma != -1:
+ shortname = name[:comma]
+ else:
+ shortname = name
+ number = number.encode("utf-8", "replace")
+ name = name.encode("utf-8", "replace")
+ shortname = shortname.encode('utf-8', 'replace')
+ self.sortlist.append((name, shortname, number))
+
+ self["entries"].setList(self.sortlist)
+
+ def showEntry(self):
+ cur = self["entries"].getCurrent()
+ if cur:
+ debug("[FritzCallPhonebook] displayPhonebook/showEntry %s" % (repr(cur)))
+ number = cur[2]
+ name = cur[0]
+ self.session.open(FritzOfferAction, self, number, name)
+
+ def delete(self):
+ cur = self["entries"].getCurrent()
+ if cur:
+ debug("[FritzCallPhonebook] displayPhonebook/delete %s" % (repr(cur)))
+ self.session.openWithCallback(
+ self.deleteConfirmed,
+ MessageBox,
+ _("Do you really want to delete entry for\n\n%(number)s\n\n%(name)s?")
+ % { 'number':str(cur[2]), 'name':str(cur[0]).replace(", ", "\n") }
+ )
+ else:
+ self.session.open(MessageBox, _("No entry selected"), MessageBox.TYPE_INFO)
+
+ def deleteConfirmed(self, ret):
+ debug("[FritzCallPhonebook] displayPhonebook/deleteConfirmed")
+ #
+ # if ret: delete number from sortlist, delete number from phonebook.phonebook and write it to disk
+ #
+ cur = self["entries"].getCurrent()
+ if cur:
+ if ret:
+ # delete number from sortlist, delete number from phonebook.phonebook and write it to disk
+ debug("[FritzCallPhonebook] displayPhonebook/deleteConfirmed %s" % (repr(cur)))
+ phonebook.remove(cur[2])
+ self.display()
+ # else:
+ # self.session.open(MessageBox, _("Not deleted."), MessageBox.TYPE_INFO)
+ else:
+ self.session.open(MessageBox, _("No entry selected"), MessageBox.TYPE_INFO)
+
+ def add(self, parent=None, number="", name=""):
+ class AddScreen(Screen, ConfigListScreen):
+ '''ConfiglistScreen with two ConfigTexts for Name and Number'''
+
+ def __init__(self, session, parent, number="", name=""):
+ #
+ # setup screen with two ConfigText and OK and ABORT button
+ #
+ noButtons = 2
+ width = max(scaleH(-1, 570), noButtons*140)
+ height = scaleV(-1, 100) # = 5 + 126 + 40 + 5; 6 lines of text possible
+ buttonsGap = (width-noButtons*140)/(noButtons+1)
+ buttonsVPos = height-40-5
+ self.skin = """
+ <screen position="center,center" size="%d,%d" title="Add entry to phonebook" >
+ <widget name="config" position="5,5" size="%d,%d" scrollbarMode="showOnDemand" />
+ <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
+ <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
+ <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" />
+ <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" />
+ </screen>""" % (
+ width, height,
+ width - 5 - 5, height - 5 - 40 - 5,
+ buttonsGap, buttonsVPos, "skin_default/buttons/red.png",
+ buttonsGap+140+buttonsGap, buttonsVPos, "skin_default/buttons/green.png",
+ buttonsGap, buttonsVPos,
+ buttonsGap+140+buttonsGap, buttonsVPos,
+ )
+ Screen.__init__(self, session)
+ self.session = session
+ self.parent = parent
+ # TRANSLATORS: keep it short, this is a button
+ self["key_red"] = Button(_("Cancel"))
+ # TRANSLATORS: keep it short, this is a button
+ self["key_green"] = Button(_("OK"))
+ self["setupActions"] = ActionMap(["SetupActions", "ColorActions"],
+ {
+ "cancel": self.cancel,
+ "red": self.cancel,
+ "green": self.add,
+ "ok": self.add,
+ }, - 2)
+
+ self.list = [ ]
+ ConfigListScreen.__init__(self, self.list, session=session)
+ self.name = name
+ self.number = number
+ config.plugins.FritzCall.name.value = name
+ config.plugins.FritzCall.number.value = number
+ self.list.append(getConfigListEntry(_("Name"), config.plugins.FritzCall.name))
+ self.list.append(getConfigListEntry(_("Number"), config.plugins.FritzCall.number))
+ self["config"].list = self.list
+ self["config"].l.setList(self.list)
+ self.onLayoutFinish.append(self.setWindowTitle)
+
+ def setWindowTitle(self):
+ # TRANSLATORS: this is a window title.
+ self.setTitle(_("Add entry to phonebook"))
+
+ def add(self):
+ # get texts from Screen
+ # add (number,name) to sortlist and phonebook.phonebook and disk
+ self.name = config.plugins.FritzCall.name.value
+ self.number = config.plugins.FritzCall.number.value
+ if not self.number or not self.name:
+ self.session.open(MessageBox, _("Entry incomplete."), type=MessageBox.TYPE_ERROR)
+ return
+ # add (number,name) to sortlist and phonebook.phonebook and disk
+ # oldname = phonebook.search(self.number)
+ # if oldname:
+ # self.session.openWithCallback(
+ # self.overwriteConfirmed,
+ # MessageBox,
+ # _("Do you really want to overwrite entry for %(number)s\n\n%(name)s\n\nwith\n\n%(newname)s?")
+ # % {
+ # 'number':self.number,
+ # 'name': oldname,
+ # 'newname':self.name.replace(", ","\n")
+ # }
+ # )
+ # self.close()
+ # return
+ phonebook.add(self.number, self.name)
+ self.close()
+ self.parent.display()
+
+ def overwriteConfirmed(self, ret):
+ if ret:
+ phonebook.remove(self.number)
+ phonebook.add(self.number, self.name)
+ self.parent.display()
+
+ def cancel(self):
+ self.close()
+
+ debug("[FritzCallPhonebook] displayPhonebook/add")
+ if not parent:
+ parent = self
+ self.session.open(AddScreen, parent, number, name)
+
+ def edit(self):
+ debug("[FritzCallPhonebook] displayPhonebook/edit")
+ cur = self["entries"].getCurrent()
+ if cur is None:
+ self.session.open(MessageBox, _("No entry selected"), MessageBox.TYPE_INFO)
+ else:
+ (number, name) = cur[0]
+ self.add(self, number, name)
+
+ def search(self):
+ debug("[FritzCallPhonebook] displayPhonebook/search")
+ self.help_window = self.session.instantiateDialog(NumericalTextInputHelpDialog, self)
+ self.help_window.show()
+ # VirtualKeyboard instead of InputBox?
+ self.session.openWithCallback(self.doSearch, InputBox, _("Enter Search Terms"), _("Search phonebook"))
+
+ def doSearch(self, searchTerms):
+ if not searchTerms:
+ searchTerms = ""
+ debug("[FritzCallPhonebook] displayPhonebook/doSearch: " + searchTerms)
+ if self.help_window:
+ self.session.deleteDialog(self.help_window)
+ self.help_window = None
+ self.display(searchTerms)
+
+ def exit(self):
+ self.close()
+
+phonebook = FritzCallPhonebook()
+
+class FritzCallSetup(Screen, ConfigListScreen, HelpableScreen):
+
+ def __init__(self, session, args=None): #@UnusedVariable # pylint: disable-msg=W0613
+ self.width = scaleH(20+4*(140+90)+2*(35+40)+20, 4*140+2*35)
+ width = self.width
+ debug("[FritzCallSetup] width: " + str(self.width))
+ self.skin = """
+ <screen name="FritzCallSetup" position="center,center" size="%d,%d" title="FritzCall Setup" >
+ <eLabel position="0,0" size="%d,2" backgroundColor="#aaaaaa" />
+ <widget name="consideration" position="%d,%d" halign="center" size="%d,%d" font="Regular;%d" backgroundColor="#20040404" transparent="1" />
+ <eLabel position="0,%d" size="%d,2" backgroundColor="#aaaaaa" />
+ <widget name="config" position="%d,%d" size="%d,%d" scrollbarMode="showOnDemand" backgroundColor="#20040404" transparent="1" />
+ <eLabel position="0,%d" size="%d,2" backgroundColor="#aaaaaa" />
+ <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
+ <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
+ <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
+ <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
+ <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" />
+ <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" />
+ <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" />
+ <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" />
+ <ePixmap position="%d,%d" zPosition="4" size="35,25" pixmap="%s" transparent="1" alphatest="on" />
+ <ePixmap position="%d,%d" zPosition="4" size="35,25" pixmap="%s" transparent="1" alphatest="on" />
+ </screen>""" % (
+ # (DESKTOP_WIDTH-width)/2, scaleV(100, 73), # position
+ width, scaleV(560, 430), # size
+ width, # eLabel width
+ scaleH(40, 20), scaleV(10, 5), # consideration position
+ scaleH(width-80, width-40), scaleV(25, 45), # consideration size
+ scaleV(22, 20), # consideration font size
+ scaleV(40, 50), # eLabel position vertical
+ width, # eLabel width
+ scaleH(40, 5), scaleV(60, 57), # config position
+ scaleH(width-80, width-10), scaleV(453, 328), # config size
+ scaleV(518, 390), # eLabel position vertical
+ width, # eLabel width
+ scaleH(20, 0), scaleV(525, 395), "skin_default/buttons/red.png", # pixmap red
+ scaleH(20+140+90, 140), scaleV(525, 395), "skin_default/buttons/green.png", # pixmap green
+ scaleH(20+2*(140+90), 2*140), scaleV(525, 395), "skin_default/buttons/yellow.png", # pixmap yellow
+ scaleH(20+3*(140+90), 3*140), scaleV(525, 395), "skin_default/buttons/blue.png", # pixmap blue
+ scaleH(20, 0), scaleV(525, 395), scaleV(21, 21), # widget red
+ scaleH(20+(140+90), 140), scaleV(525, 395), scaleV(21, 21), # widget green
+ scaleH(20+2*(140+90), 2*140), scaleV(525, 395), scaleV(21, 21), # widget yellow
+ scaleH(20+3*(140+90), 3*140), scaleV(525, 395), scaleV(21, 21), # widget blue
+ scaleH(20+4*(140+90), 4*140), scaleV(532, 402), "skin_default/buttons/key_info.png", # button info
+ scaleH(20+4*(140+90)+(35+40), 4*140+35), scaleV(532, 402), "skin_default/buttons/key_menu.png", # button menu
+ )
+
+ Screen.__init__(self, session)
+ HelpableScreen.__init__(self)
+ self.session = session
+
+ self["consideration"] = Label(_("You need to enable the monitoring on your FRITZ!Box by dialing #96*5*!"))
+ self.list = []
+
+ # Initialize Buttons
+ # TRANSLATORS: keep it short, this is a button
+ self["key_red"] = Button(_("Cancel"))
+ # TRANSLATORS: keep it short, this is a button
+ self["key_green"] = Button(_("OK"))
+ # TRANSLATORS: keep it short, this is a button
+ self["key_yellow"] = Button(_("Phone calls"))
+ # TRANSLATORS: keep it short, this is a button
+ self["key_blue"] = Button(_("Phonebook"))
+ # TRANSLATORS: keep it short, this is a button
+ self["key_info"] = Button(_("About FritzCall"))
+ # TRANSLATORS: keep it short, this is a button
+ self["key_menu"] = Button(_("FRITZ!Box Fon Status"))
+
+ self["setupActions"] = ActionMap(["ColorActions", "OkCancelActions", "MenuActions", "EPGSelectActions"],
+ {
+ "red": self.cancel,
+ "green": self.save,
+ "yellow": self.displayCalls,
+ "blue": self.displayPhonebook,
+ "cancel": self.cancel,
+ "ok": self.save,
+ "menu": self.menu,
+ "info": self.about,
+ }, - 2)
+
+ # TRANSLATORS: keep it short, this is a help text
+ self.helpList.append((self["setupActions"], "ColorActions", [("red", _("quit"))]))
+ # TRANSLATORS: keep it short, this is a help text
+ self.helpList.append((self["setupActions"], "ColorActions", [("green", _("save and quit"))]))
+ # TRANSLATORS: keep it short, this is a help text
+ self.helpList.append((self["setupActions"], "ColorActions", [("yellow", _("display calls"))]))
+ # TRANSLATORS: keep it short, this is a help text
+ self.helpList.append((self["setupActions"], "ColorActions", [("blue", _("display phonebook"))]))
+ # TRANSLATORS: keep it short, this is a help text
+ self.helpList.append((self["setupActions"], "OkCancelActions", [("ok", _("save and quit"))]))
+ # TRANSLATORS: keep it short, this is a help text
+ self.helpList.append((self["setupActions"], "OkCancelActions", [("cancel", _("quit"))]))
+ # TRANSLATORS: keep it short, this is a help text
+ self.helpList.append((self["setupActions"], "MenuActions", [("menu", _("FRITZ!Box Fon Status"))]))
+ # TRANSLATORS: keep it short, this is a help text
+ self.helpList.append((self["setupActions"], "EPGSelectActions", [("info", _("About FritzCall"))]))
+
+ ConfigListScreen.__init__(self, self.list, session=session)
+
+ # get new list of locations for PhoneBook.txt
+ self._mountedDevs = getMountedDevs()
+ self.createSetup()
+ self.onLayoutFinish.append(self.setWindowTitle)
+
+ def setWindowTitle(self):
+ # TRANSLATORS: this is a window title.
+ self.setTitle(_("FritzCall Setup") + " (" + "$Revision$"[1: - 1] + "$Date$"[7:23] + ")")
+
+ def keyLeft(self):
+ ConfigListScreen.keyLeft(self)
+ self.createSetup()
+
+ def keyRight(self):
+ ConfigListScreen.keyRight(self)
+ self.createSetup()
+
+ def createSetup(self):
+ self.list = [ ]
+ self.list.append(getConfigListEntry(_("Call monitoring"), config.plugins.FritzCall.enable))
+ if config.plugins.FritzCall.enable.value:
+ self.list.append(getConfigListEntry(_("FRITZ!Box FON address (Name or IP)"), config.plugins.FritzCall.hostname))
+
+ self.list.append(getConfigListEntry(_("Show after Standby"), config.plugins.FritzCall.afterStandby))
+
+ self.list.append(getConfigListEntry(_("Show only calls for specific MSN"), config.plugins.FritzCall.filter))
+ if config.plugins.FritzCall.filter.value:
+ self.list.append(getConfigListEntry(_("MSN to show (separated by ,)"), config.plugins.FritzCall.filtermsn))
+ self.list.append(getConfigListEntry(_("Filter also list of calls"), config.plugins.FritzCall.filterCallList))
+ self.list.append(getConfigListEntry(_("Mute on call"), config.plugins.FritzCall.muteOnCall))
+
+ self.list.append(getConfigListEntry(_("Show Outgoing Calls"), config.plugins.FritzCall.showOutgoing))
+ # not only for outgoing: config.plugins.FritzCall.showOutgoing.value:
+ self.list.append(getConfigListEntry(_("Areacode to add to calls without one (if necessary)"), config.plugins.FritzCall.prefix))
+ self.list.append(getConfigListEntry(_("Timeout for Call Notifications (seconds)"), config.plugins.FritzCall.timeout))
+ self.list.append(getConfigListEntry(_("Reverse Lookup Caller ID (select country below)"), config.plugins.FritzCall.lookup))
+ if config.plugins.FritzCall.lookup.value:
+ self.list.append(getConfigListEntry(_("Country"), config.plugins.FritzCall.country))
+
+ # TODO: make password unreadable?
+ self.list.append(getConfigListEntry(_("Password Accessing FRITZ!Box"), config.plugins.FritzCall.password))
+ self.list.append(getConfigListEntry(_("Extension number to initiate call on"), config.plugins.FritzCall.extension))
+ self.list.append(getConfigListEntry(_("Read PhoneBook from FRITZ!Box"), config.plugins.FritzCall.fritzphonebook))
+ if config.plugins.FritzCall.fritzphonebook.value:
+ self.list.append(getConfigListEntry(_("Append type of number"), config.plugins.FritzCall.showType))
+ self.list.append(getConfigListEntry(_("Append shortcut number"), config.plugins.FritzCall.showShortcut))
+ self.list.append(getConfigListEntry(_("Append vanity name"), config.plugins.FritzCall.showVanity))
+
+ self.list.append(getConfigListEntry(_("Use internal PhoneBook"), config.plugins.FritzCall.phonebook))
+ if config.plugins.FritzCall.phonebook.value:
+ if config.plugins.FritzCall.phonebookLocation.value in self._mountedDevs:
+ config.plugins.FritzCall.phonebookLocation.setChoices(self._mountedDevs, config.plugins.FritzCall.phonebookLocation.value)
+ else:
+ config.plugins.FritzCall.phonebookLocation.setChoices(self._mountedDevs)
+ path = config.plugins.FritzCall.phonebookLocation.value
+ # check whether we can write to PhoneBook.txt
+ if os.path.exists(os.path.join(path[0], "PhoneBook.txt")):
+ if not os.access(os.path.join(path[0], "PhoneBook.txt"), os.W_OK):
+ debug("[FritzCallSetup] createSetup: %s/PhoneBook.txt not writable, resetting to default" %(path[0]))
+ config.plugins.FritzCall.phonebookLocation.setChoices(self._mountedDevs)
+ elif not (os.path.isdir(path[0]) and os.access(path[0], os.W_OK|os.X_OK)):
+ debug("[FritzCallSetup] createSetup: directory %s not writable, resetting to default" %(path[0]))
+ config.plugins.FritzCall.phonebookLocation.setChoices(self._mountedDevs)
+
+ self.list.append(getConfigListEntry(_("PhoneBook Location"), config.plugins.FritzCall.phonebookLocation))
+ if config.plugins.FritzCall.lookup.value:
+ self.list.append(getConfigListEntry(_("Automatically add new Caller to PhoneBook"), config.plugins.FritzCall.addcallers))
+
+ self.list.append(getConfigListEntry(_("Strip Leading 0"), config.plugins.FritzCall.internal))
+ # self.list.append(getConfigListEntry(_("Default display mode for FRITZ!Box calls"), config.plugins.FritzCall.fbfCalls))
+ self.list.append(getConfigListEntry(_("Display connection infos"), config.plugins.FritzCall.connectionVerbose))
+ self.list.append(getConfigListEntry(_("Debug"), config.plugins.FritzCall.debug))
+
+ self["config"].list = self.list
+ self["config"].l.setList(self.list)
+
+ def save(self):
+# debug("[FritzCallSetup] save"
+ for x in self["config"].list:
+ x[1].save()
+ if config.plugins.FritzCall.phonebookLocation.isChanged():
+ global phonebook
+ phonebook = FritzCallPhonebook()
+ if fritz_call:
+ if config.plugins.FritzCall.enable.value:
+ fritz_call.connect()
+ else:
+ fritz_call.shutdown()
+ self.close()
+
+ def cancel(self):
+# debug("[FritzCallSetup] cancel"
+ for x in self["config"].list:
+ x[1].cancel()
+ self.close()
+
+ def displayCalls(self):
+ if config.plugins.FritzCall.enable.value:
+ if fritzbox:
+ self.session.open(FritzDisplayCalls)
+ else:
+ self.session.open(MessageBox, _("Cannot get calls from FRITZ!Box"), type=MessageBox.TYPE_INFO)
+ else:
+ self.session.open(MessageBox, _("Plugin not active"), type=MessageBox.TYPE_INFO)
+
+ def displayPhonebook(self):
+ if phonebook:
+ if config.plugins.FritzCall.enable.value:
+ self.session.open(phonebook.FritzDisplayPhonebook)
+ else:
+ self.session.open(MessageBox, _("Plugin not active"), type=MessageBox.TYPE_INFO)
+ else:
+ self.session.open(MessageBox, _("No phonebook"), type=MessageBox.TYPE_INFO)
+
+ def about(self):
+ self.session.open(FritzAbout)
+
+ def menu(self):
+ if config.plugins.FritzCall.enable.value:
+ if fritzbox and fritzbox.info:
+ self.session.open(FritzMenu)
+ else:
+ self.session.open(MessageBox, _("Cannot get infos from FRITZ!Box"), type=MessageBox.TYPE_INFO)
+ else:
+ self.session.open(MessageBox, _("Plugin not active"), type=MessageBox.TYPE_INFO)
+
+standbyMode = False
+
+class FritzCallList:
+ def __init__(self):
+ self.callList = [ ]
+
+ def add(self, event, date, number, caller, phone):
+ debug("[FritzCallList] add: %s %s" % (number, caller))
+ if len(self.callList) > 10:
+ if self.callList[0] != "Start":
+ self.callList[0] = "Start"
+ del self.callList[1]
+
+ self.callList.append((event, number, date, caller, phone))
+
+ def display(self):
+ debug("[FritzCallList] display")
+ global standbyMode
+ standbyMode = False
+ # Standby.inStandby.onClose.remove(self.display) object does not exist anymore...
+ # build screen from call list
+ text = "\n"
+ if self.callList[0] == "Start":
+ text = text + _("Last 10 calls:\n")
+ del self.callList[0]
+
+ for call in self.callList:
+ (event, number, date, caller, phone) = call
+ if event == "RING":
+ direction = "->"
+ else:
+ direction = "<-"
+
+ # shorten the date info
+ date = date[:6] + date[9:14]
+
+ # our phone could be of the form "0123456789 (home)", then we only take "home"
+ oBrack = phone.find('(')
+ cBrack = phone.find(')')
+ if oBrack != -1 and cBrack != -1:
+ phone = phone[oBrack+1:cBrack]
+
+ # should not happen, for safety reasons
+ if not caller:
+ caller = _("UNKNOWN")
+
+ # if we have an unknown number, show the number
+ if caller == _("UNKNOWN") and number != "":
+ caller = number
+ else:
+ # strip off the address part of the remote caller/callee, if there is any
+ nl = caller.find('\n')
+ if nl != -1:
+ caller = caller[:nl]
+ elif caller[0] == '[' and caller[-1] == ']':
+ # that means, we've got an unknown number with a city added from avon.dat
+ if (len(number) + 1 + len(caller) + len(phone)) <= 40:
+ caller = number + ' ' + caller
+ else:
+ caller = number
+
+ while (len(caller) + len(phone)) > 40:
+ if len(caller) > len(phone):
+ caller = caller[: - 1]
+ else:
+ phone = phone[: - 1]
+
+ text = text + "%s %s %s %s\n" % (date, caller, direction, phone)
+
+ debug("[FritzCallList] display: '%s %s %s %s'" % (date, caller, direction, phone))
+ # display screen
+ Notifications.AddNotification(MessageBox, text, type=MessageBox.TYPE_INFO)
+ # TODO please HELP: from where can I get a session?
+ # my_global_session.open(FritzDisplayCalls, text)
+ self.callList = [ ]
+
+callList = FritzCallList()
+
+def findFace(number, name):
+ debug("[FritzCall] findFace number/name: %s/%s" % (number, name))
+ if name:
+ sep = name.find(',')
+ if sep != -1:
+ name = name[:sep]
+ sep = name.find('\n')
+ if sep != -1:
+ name = name[:sep]
+ else:
+ name = _("UNKNOWN")
+
+ facesDir = os.path.join(config.plugins.FritzCall.phonebookLocation.value, "FritzCallFaces")
+ numberFile = os.path.join(facesDir, number)
+ nameFile = os.path.join(facesDir, name)
+ facesFile = ""
+ if number and os.path.exists(numberFile):
+ facesFile = numberFile
+ elif number and os.path.exists(numberFile + ".png"):
+ facesFile = numberFile + ".png"
+ elif number and os.path.exists(numberFile + ".PNG"):
+ facesFile = numberFile + ".PNG"
+ elif name and os.path.exists(nameFile + ".png"):
+ facesFile = nameFile + ".png"
+ elif name and os.path.exists(nameFile + ".PNG"):
+ facesFile = nameFile + ".PNG"
+ else:
+ facesFile = resolveFilename(SCOPE_SKIN_IMAGE, "skin_default/icons/input_info.png")
+
+ debug("[FritzCall] findFace result: %s" % (facesFile))
+ return facesFile
+
+class MessageBoxPixmap(Screen):
+ def __init__(self, session, text, number = "", name = "", timeout = -1):
+ self.skin = """
+ <screen name="MessageBoxPixmap" position="center,center" size="600,10" title="MessageBoxPixmap">
+ <widget name="text" position="115,8" size="520,0" font="Regular;%d" />
+ <widget name="InfoPixmap" pixmap="%s" position="5,5" size="100,100" alphatest="on" />
+ </screen>
+ """ % (
+ # scaleH(350, 60), scaleV(175, 245),
+ scaleV(24, 22), resolveFilename(SCOPE_SKIN_IMAGE, "skin_default/icons/input_info.png")
+ )
+ debug("[FritzCall] MessageBoxPixmap number: %s" % number)
+ Screen.__init__(self, session)
+ # MessageBox.__init__(self, session, text, type=MessageBox.TYPE_INFO, timeout=timeout)
+ self["text"] = Label(text)
+ self["InfoPixmap"] = Pixmap()
+ self._session = session
+ self._number = number
+ self._name = name
+ self._timerRunning = False
+ self._timer = None
+ self._timeout = timeout
+ self._origTitle = None
+ self._initTimeout()
+ self.onLayoutFinish.append(self._finishLayout)
+ self["actions"] = ActionMap(["OkCancelActions"],
+ {
+ "cancel": self._exit,
+ "ok": self._exit, }, - 2)
+
+ def _finishLayout(self):
+ # pylint: disable-msg=W0142
+ debug("[FritzCall] MessageBoxPixmap/setInfoPixmap number: %s/%s" % (self._number, self._name))
+
+ faceFile = findFace(self._number, self._name)
+ picPixmap = LoadPixmap(faceFile)
+ if not picPixmap: # that means most probably, that the picture is not 8 bit...
+ Notifications.AddNotification(MessageBox, _("Found picture\n\n%s\n\nBut did not load. Probably not PNG, 8-bit") %faceFile, type = MessageBox.TYPE_ERROR)
+ picPixmap = LoadPixmap(resolveFilename(SCOPE_SKIN_IMAGE, "skin_default/icons/input_error.png"))
+ picSize = picPixmap.size()
+ self["InfoPixmap"].instance.setPixmap(picPixmap)
+
+ # recalculate window size
+ textSize = self["text"].getSize()
+ textSize = (textSize[0]+20, textSize[1]+20) # don't know, why, but size is too small
+ textSize = eSize(*textSize)
+ width = max(scaleH(600, 280), picSize.width() + textSize.width() + 30)
+ height = max(scaleV(300, 250), picSize.height()+10, textSize.height()+10)
+ wSize = (width, height)
+ wSize = eSize(*wSize)
+
+ # center the smaller vertically
+ hGap = (width-picSize.width()-textSize.width())/3
+ picPos = (hGap, (height-picSize.height())/2+1)
+ textPos = (hGap+picSize.width()+hGap, (height-textSize.height())/2+1)
+
+ # resize screen
+ self.instance.resize(wSize)
+ # resize text
+ self["text"].instance.resize(textSize)
+ # resize pixmap
+ self["InfoPixmap"].instance.resize(picSize)
+ # move text
+ self["text"].instance.move(ePoint(*textPos))
+ # move pixmap
+ self["InfoPixmap"].instance.move(ePoint(*picPos))
+ # center window
+ self.instance.move(ePoint((DESKTOP_WIDTH-wSize.width())/2, (DESKTOP_HEIGHT-wSize.height())/2))
+
+ def _initTimeout(self):
+ if self._timeout > 0:
+ self._timer = eTimer()
+ self._timer.callback.append(self._timerTick)
+ self.onExecBegin.append(self._startTimer)
+ self._origTitle = None
+ if self.execing:
+ self._timerTick()
+ else:
+ self.onShown.append(self.__onShown)
+ self._timerRunning = True
+ else:
+ self._timerRunning = False
+
+ def __onShown(self):
+ self.onShown.remove(self.__onShown)
+ self._timerTick()
+
+ def _startTimer(self):
+ self._timer.start(1000)
+
+#===============================================================================
+# def stopTimer(self):
+# if self._timerRunning:
+# del self._timer
+# self.setTitle(self._origTitle)
+# self._timerRunning = False
+#===============================================================================
+
+ def _timerTick(self):
+ if self.execing:
+ self._timeout -= 1
+ if self._origTitle is None:
+ self._origTitle = self.instance.getTitle()
+ self.setTitle(self._origTitle + " (" + str(self._timeout) + ")")
+ if self._timeout == 0:
+ self._timer.stop()
+ self._timerRunning = False
+ self._exit()
+
+ def _exit(self):
+ self.close()
+
+mutedOnConnID = None
+def notifyCall(event, date, number, caller, phone, connID):
+ if Standby.inStandby is None or config.plugins.FritzCall.afterStandby.value == "each":
+ if event == "RING":
+ global mutedOnConnID
+ if config.plugins.FritzCall.muteOnCall.value =="ring" and not mutedOnConnID:
+ debug("[FritzCall] mute on connID: %s" % connID)
+ mutedOnConnID = connID
+ # eDVBVolumecontrol.getInstance().volumeMute() # with this, we get no mute icon...
+ if not eDVBVolumecontrol.getInstance().isMuted():
+ globalActionMap.actions["volumeMute"]()
+ text = _("Incoming Call on %(date)s from\n---------------------------------------------\n%(number)s\n%(caller)s\n---------------------------------------------\nto: %(phone)s") % { 'date':date, 'number':number, 'caller':caller, 'phone':phone }
+ else:
+ text = _("Outgoing Call on %(date)s to\n---------------------------------------------\n%(number)s\n%(caller)s\n---------------------------------------------\nfrom: %(phone)s") % { 'date':date, 'number':number, 'caller':caller, 'phone':phone }
+ debug("[FritzCall] notifyCall:\n%s" % text)
+ # Notifications.AddNotification(MessageBox, text, type=MessageBox.TYPE_INFO, timeout=config.plugins.FritzCall.timeout.value)
+ Notifications.AddNotification(MessageBoxPixmap, text, number=number, name=caller, timeout=config.plugins.FritzCall.timeout.value)
+ elif config.plugins.FritzCall.afterStandby.value == "inList":
+ #
+ # if not yet done, register function to show call list
+ global standbyMode
+ if not standbyMode :
+ standbyMode = True
+ Standby.inStandby.onHide.append(callList.display) #@UndefinedVariable
+ # add text/timeout to call list
+ callList.add(event, date, number, caller, phone)
+ debug("[FritzCall] notifyCall: added to callList")
+ else: # this is the "None" case
+ debug("[FritzCall] notifyCall: standby and no show")
+
+
+#===============================================================================
+# We need a separate class for each invocation of reverseLookup to retain
+# the necessary data for the notification
+#===============================================================================
+
+countries = { }
+reverselookupMtime = 0
+
+class FritzReverseLookupAndNotifier:
+ def __init__(self, event, number, caller, phone, date, connID):
+ '''
+
+ Initiate a reverse lookup for the given number in the configured country
+
+ @param event: CALL or RING
+ @param number: number to be looked up
+ @param caller: caller including name and address
+ @param phone: Number (and name) of or own phone
+ @param date: date of call
+ '''
+ debug("[FritzReverseLookupAndNotifier] reverse Lookup for %s!" % number)
+ self.event = event
+ self.number = number
+ self.caller = caller
+ self.phone = phone
+ self.date = date
+ self.connID = connID
+
+ if number[0] != "0":
+ self.notifyAndReset(number, caller)
+ return
+
+ ReverseLookupAndNotifier(number, self.notifyAndReset, "UTF-8", config.plugins.FritzCall.country.value)
+
+ def notifyAndReset(self, number, caller):
+ '''
+
+ this gets called with the result of the reverse lookup
+
+ @param number: number
+ @param caller: name and address of remote. it comes in with name, address and city separated by commas
+ '''
+ debug("[FritzReverseLookupAndNotifier] got: " + caller)
+ self.number = number
+#===============================================================================
+# if not caller and os.path.exists(config.plugins.FritzCall.phonebookLocation.value + "/PhoneBook.csv"):
+# caller = FritzOutlookCSV.findNumber(number, config.plugins.FritzCall.phonebookLocation.value + "/PhoneBook.csv") #@UndefinedVariable
+# debug("[FritzReverseLookupAndNotifier] got from Outlook csv: " + caller)
+#===============================================================================
+#===============================================================================
+# if not caller and os.path.exists(config.plugins.FritzCall.phonebookLocation.value + "/PhoneBook.ldif"):
+# caller = FritzLDIF.findNumber(number, open(config.plugins.FritzCall.phonebookLocation.value + "/PhoneBook.ldif"))
+# debug("[FritzReverseLookupAndNotifier] got from ldif: " + caller)
+#===============================================================================
+
+ name = handleReverseLookupResult(caller)
+ if name:
+ self.caller = name.replace(", ", "\n").replace('#','')
+ # TODO: I don't know, why we store only for incoming calls...
+ # if self.number != 0 and config.plugins.FritzCall.addcallers.value and self.event == "RING":
+ if self.number != 0 and config.plugins.FritzCall.addcallers.value:
+ debug("[FritzReverseLookupAndNotifier] add to phonebook")
+ phonebook.add(self.number, self.caller)
+ else:
+ name = resolveNumberWithAvon(self.number, config.plugins.FritzCall.country.value)
+ if not name:
+ self.caller = _("UNKNOWN")
+ else:
+ self.caller = name
+ notifyCall(self.event, self.date, self.number, self.caller, self.phone, self.connID)
+ # kill that object...
+
+class FritzProtocol(LineReceiver):
+ def __init__(self):
+ debug("[FritzProtocol] " + "$Revision$"[1:-1] + "$Date$"[7:23] + " starting")
+ global mutedOnConnID
+ mutedOnConnID = None
+ self.number = '0'
+ self.caller = None
+ self.phone = None
+ self.date = '0'
+ self.event = None
+ self.connID = None
+
+ def resetValues(self):
+ debug("[FritzProtocol] resetValues")
+ self.number = '0'
+ self.caller = None
+ self.phone = None
+ self.date = '0'
+ self.event = None
+ self.connID = None
+
+ def notifyAndReset(self):
+ notifyCall(self.event, self.date, self.number, self.caller, self.phone, self.connID)
+ self.resetValues()
+
+ def lineReceived(self, line):
+ debug("[FritzProtocol] lineReceived: %s" % line)
+#15.07.06 00:38:54;CALL;1;4;<from/our msn>;<to/extern>;
+#15.07.06 00:38:58;DISCONNECT;1;0;
+#15.07.06 00:39:22;RING;0;<from/extern>;<to/our msn>;
+#15.07.06 00:39:27;DISCONNECT;0;0;
+ anEvent = line.split(';')
+ (self.date, self.event) = anEvent[0:2]
+ self.connID = anEvent[2]
+
+ filtermsns = config.plugins.FritzCall.filtermsn.value.split(",")
+ for i in range(len(filtermsns)):
+ filtermsns[i] = filtermsns[i].strip()
+
+ # debug("[FritzProtocol] Volcontrol dir: %s" % dir(eDVBVolumecontrol.getInstance()))
+ # debug("[FritzCall] unmute on connID: %s?" %self.connID)
+ global mutedOnConnID
+ if self.event == "DISCONNECT" and config.plugins.FritzCall.muteOnCall.value and mutedOnConnID == self.connID:
+ debug("[FritzCall] unmute on connID: %s!" % self.connID)
+ mutedOnConnID = None
+ # eDVBVolumecontrol.getInstance().volumeUnMute()
+ if eDVBVolumecontrol.getInstance().isMuted():
+ globalActionMap.actions["volumeMute"]()
+ # not supported so far, because, taht would mean muting on EVERY connect, regardless of RING or CALL or filter active
+ #=======================================================================
+ # elif self.event == "CONNECT" and config.plugins.FritzCall.muteOnCall.value == "connect":
+ # debug("[FritzCall] mute on connID: %s" % self.connID)
+ # mutedOnConnID = self.connID
+ # # eDVBVolumecontrol.getInstance().volumeMute() # with this, we get no mute icon...
+ # if not eDVBVolumecontrol.getInstance().isMuted():
+ # globalActionMap.actions["volumeMute"]()
+ #=======================================================================
+ elif self.event == "RING" or (self.event == "CALL" and config.plugins.FritzCall.showOutgoing.value):
+ phone = anEvent[4]
+
+ if self.event == "RING":
+ number = anEvent[3]
+ if fritzbox and number in fritzbox.blacklist[0]:
+ debug("[FritzProtocol] lineReceived phone: '''%s''' blacklisted number: '''%s'''" % (phone, number))
+ return
+ else:
+ number = anEvent[5]
+ if number in fritzbox.blacklist[1]:
+ debug("[FritzProtocol] lineReceived phone: '''%s''' blacklisted number: '''%s'''" % (phone, number))
+ return
+
+ debug("[FritzProtocol] lineReceived phone: '''%s''' number: '''%s'''" % (phone, number))
+
+ if not (config.plugins.FritzCall.filter.value and phone not in filtermsns):
+ debug("[FritzProtocol] lineReceived no filter hit")
+ if phone:
+ phonename = phonebook.search(phone) # do we have a name for the number of our side?
+ if phonename:
+ self.phone = "%s (%s)" % (phone, phonename)
+ else:
+ self.phone = phone
+ else:
+ self.phone = _("UNKNOWN")
+
+ if not number:
+ debug("[FritzProtocol] lineReceived: no number")
+ self.number = _("number suppressed")
+ self.caller = _("UNKNOWN")
+ else:
+ if config.plugins.FritzCall.internal.value and len(number) > 3 and number[0] == "0":
+ debug("[FritzProtocol] lineReceived: strip leading 0")
+ self.number = number[1:]
+ else:
+ self.number = number
+ if self.event == "CALL" and self.number[0] != '0': # should only happen for outgoing
+ debug("[FritzProtocol] lineReceived: add local prefix")
+ self.number = config.plugins.FritzCall.prefix.value + self.number
+
+ # strip CbC prefixes
+ if self.event == "CALL":
+ number = stripCbCPrefix(self.number, config.plugins.FritzCall.country.value)
+
+ debug("[FritzProtocol] lineReceived phonebook.search: %s" % self.number)
+ self.caller = phonebook.search(self.number)
+ debug("[FritzProtocol] lineReceived phonebook.search reault: %s" % self.caller)
+ if not self.caller:
+ if config.plugins.FritzCall.lookup.value:
+ FritzReverseLookupAndNotifier(self.event, self.number, self.caller, self.phone, self.date, self.connID)
+ return # reverselookup is supposed to handle the message itself
+ else:
+ self.caller = _("UNKNOWN")
+
+ self.notifyAndReset()
+
+class FritzClientFactory(ReconnectingClientFactory):
+ initialDelay = 20
+ maxDelay = 30
+
+ def __init__(self):
+ self.hangup_ok = False
+ def startedConnecting(self, connector): #@UnusedVariable # pylint: disable-msg=W0613
+ if config.plugins.FritzCall.connectionVerbose.value:
+ Notifications.AddNotification(MessageBox, _("Connecting to FRITZ!Box..."), type=MessageBox.TYPE_INFO, timeout=2)
+
+ def buildProtocol(self, addr): #@UnusedVariable # pylint: disable-msg=W0613
+ global fritzbox, phonebook
+ if config.plugins.FritzCall.connectionVerbose.value:
+ Notifications.AddNotification(MessageBox, _("Connected to FRITZ!Box!"), type=MessageBox.TYPE_INFO, timeout=4)
+ self.resetDelay()
+ initDebug()
+ initCbC()
+ initAvon()
+ fritzbox = FritzCallFBF()
+ phonebook = FritzCallPhonebook()
+ return FritzProtocol()
+
+ def clientConnectionLost(self, connector, reason):
+ global fritzbox
+ if not self.hangup_ok and config.plugins.FritzCall.connectionVerbose.value:
+ Notifications.AddNotification(MessageBox, _("Connection to FRITZ!Box! lost\n (%s)\nretrying...") % reason.getErrorMessage(), type=MessageBox.TYPE_INFO, timeout=config.plugins.FritzCall.timeout.value)
+ ReconnectingClientFactory.clientConnectionLost(self, connector, reason)
+ # config.plugins.FritzCall.enable.value = False
+ fritzbox = None
+
+ def clientConnectionFailed(self, connector, reason):
+ global fritzbox
+ if config.plugins.FritzCall.connectionVerbose.value:
+ Notifications.AddNotification(MessageBox, _("Connecting to FRITZ!Box failed\n (%s)\nretrying...") % reason.getErrorMessage(), type=MessageBox.TYPE_INFO, timeout=config.plugins.FritzCall.timeout.value)
+ ReconnectingClientFactory.clientConnectionFailed(self, connector, reason)
+ # config.plugins.FritzCall.enable.value = False
+ fritzbox = None
+
+class FritzCall:
+ def __init__(self):
+ self.dialog = None
+ self.desc = None
+ if config.plugins.FritzCall.enable.value:
+ self.connect()
+
+ def connect(self):
+ self.abort()
+ if config.plugins.FritzCall.enable.value:
+ fact = FritzClientFactory()
+ self.desc = (fact, reactor.connectTCP(config.plugins.FritzCall.hostname.value, 1012, fact)) #@UndefinedVariable # pylint: disable-msg=E1101
+
+ def shutdown(self):
+ self.abort()
+
+ def abort(self):
+ if self.desc is not None:
+ self.desc[0].hangup_ok = True
+ self.desc[0].stopTrying()
+ self.desc[1].disconnect()
+ self.desc = None
+
+def displayCalls(session, servicelist=None): #@UnusedVariable # pylint: disable-msg=W0613
+ if config.plugins.FritzCall.enable.value:
+ if fritzbox:
+ session.open(FritzDisplayCalls)
+ else:
+ Notifications.AddNotification(MessageBox, _("Cannot get calls from FRITZ!Box"), type=MessageBox.TYPE_INFO)
+ else:
+ Notifications.AddNotification(MessageBox, _("Plugin not active"), type=MessageBox.TYPE_INFO)
+
+def displayPhonebook(session, servicelist=None): #@UnusedVariable # pylint: disable-msg=W0613
+ if phonebook:
+ if config.plugins.FritzCall.enable.value:
+ session.open(phonebook.FritzDisplayPhonebook)
+ else:
+ Notifications.AddNotification(MessageBox, _("Plugin not active"), type=MessageBox.TYPE_INFO)
+ else:
+ Notifications.AddNotification(MessageBox, _("No phonebook"), type=MessageBox.TYPE_INFO)
+
+def displayFBFStatus(session, servicelist=None): #@UnusedVariable # pylint: disable-msg=W0613
+ if config.plugins.FritzCall.enable.value:
+ if fritzbox and fritzbox.info:
+ session.open(FritzMenu)
+ else:
+ Notifications.AddNotification(MessageBox, _("Cannot get infos from FRITZ!Box"), type=MessageBox.TYPE_INFO)
+ else:
+ Notifications.AddNotification(MessageBox, _("Plugin not active"), type=MessageBox.TYPE_INFO)
+
+def main(session):
+ session.open(FritzCallSetup)
+
+fritz_call = None
+
+def autostart(reason, **kwargs):
+ global fritz_call
+
+ # ouch, this is a hack
+ if kwargs.has_key("session"):
+ global my_global_session
+ my_global_session = kwargs["session"]
+ return
+
+ debug("[FRITZ!Call] - Autostart")
+ if reason == 0:
+ fritz_call = FritzCall()
+ elif reason == 1:
+ fritz_call.shutdown()
+ fritz_call = None
+
+def Plugins(**kwargs): #@UnusedVariable # pylint: disable-msg=W0613,C0103
+ what = _("Display FRITZ!box-Fon calls on screen")
+ what_calls = _("Phone calls")
+ what_phonebook = _("Phonebook")
+ what_status = _("FRITZ!Box Fon Status")
+ return [ PluginDescriptor(name="FritzCall", description=what, where=PluginDescriptor.WHERE_PLUGINMENU, icon="plugin.png", fnc=main),
+ PluginDescriptor(name=what_calls, description=what_calls, where=PluginDescriptor.WHERE_EXTENSIONSMENU, fnc=displayCalls),
+ PluginDescriptor(name=what_phonebook, description=what_phonebook, where=PluginDescriptor.WHERE_EXTENSIONSMENU, fnc=displayPhonebook),
+ PluginDescriptor(name=what_status, description=what_status, where=PluginDescriptor.WHERE_EXTENSIONSMENU, fnc=displayFBFStatus),
+ PluginDescriptor(where=[PluginDescriptor.WHERE_SESSIONSTART, PluginDescriptor.WHERE_AUTOSTART], fnc=autostart) ]