# -*- coding: utf-8 -*-
'''
Update rev
$Author: michael $
$Revision: 1553 $
$Date: 2019-04-25 09:36:05 +0200 (Thu, 25 Apr 2019) $
$Id: plugin.py 1553 2019-04-25 07:36:05Z michael $
'''
# C0111 (Missing docstring)
# C0103 (Invalid name)
# C0301 (line too long)
# W0603 (global statement)
# W0141 (map, filter, etc.)
# W0110 lambda with map,filter
# W0403 Relative import
# W1401 Anomalous backslash in string
# C0302 too-many-lines
# E401 multiple imports on one line
# E501 line too long (85 > 79 characters)
# pylint: disable=C0111,C0103,C0301,W0603,W0403,C0302,W0312
import re
import time
import os
import traceback
import json
from itertools import cycle, izip
import base64
from logging import NOTSET, DEBUG, INFO, WARNING, ERROR, CRITICAL
import logging
from xml.dom.minidom import parse
import binascii
from enigma import getDesktop
from Screens.Screen import Screen
from Screens.MessageBox import MessageBox
from Screens.NumericalTextInputHelpDialog import NumericalTextInputHelpDialog
# from Screens.InputBox import InputBox
from Screens.VirtualKeyBoard import VirtualKeyBoard
from Screens import Standby
from Screens.HelpMenu import HelpableScreen
from Screens.LocationBox import LocationBox
from enigma import eTimer, eSize, ePoint # @UnresolvedImport # pylint: disable=E0611
from enigma import eDVBVolumecontrol, eConsoleAppContainer # @UnresolvedImport # pylint: disable=E0611
# 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.ConfigList import ConfigListScreen
from Components.config import config, ConfigSubsection, ConfigSelection, ConfigDirectory, \
getConfigListEntry, ConfigText, ConfigInteger, ConfigYesNo, ConfigOnOff, ConfigPassword
from Plugins.Plugin import PluginDescriptor
from Tools import Notifications
from Tools.NumericalTextInput import NumericalTextInput
from Tools.Directories import resolveFilename, SCOPE_PLUGINS, SCOPE_CONFIG, SCOPE_CURRENT_SKIN, \
SCOPE_CURRENT_PLUGIN
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
import FritzOutlookCSV
import FritzLDIF
from nrzuname import ReverseLookupAndNotifier
from . import _, __ # @UnresolvedImport # pylint: disable=W0611,F0401
# import codecs
# encode = lambda x : codecs.encode(x, "rot13")
# decode = lambda x : codecs.decode(x, "rot13")
# decode = encode = lambda x : ''.join(chr(ord(c)^ord(k)) for c,k in izip(x, cycle('secret key')))
def encode(x):
return base64.encodestring(''.join(chr(ord(c) ^ ord(k)) for c, k in izip(x, cycle('secret key')))).strip()
def decode(x):
return ''.join(chr(ord(c) ^ ord(k)) for c, k in izip(base64.decodestring(x), cycle('secret key')))
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.fwVersion = ConfigSelection(choices=[(None, _("not configured")), ("old", _("before 05.27")), ("05.27", "05.27, 05.28"), ("05.50", _("05.29 until below 6.35")), ("06.35", _("06.35 and newer"))], default=None)
# config.plugins.FritzCall.fwVersion = ConfigSelection(choices = [(None, _("not configured")), ("old", _("before 05.27")), ("05.27", "05.27, 05.28"), ("05.50", _("05.29 until below 6.35")), ("06.35", _("06.35 and newer")), ("upnp", "Experimental")], default = None)
# config.plugins.FritzCall.fwVersion = ConfigSelection(choices=[(None, _("not configured")), ("old", _("before 05.27")), ("05.27", "05.27, 05.28"), ("05.50", _("05.29 and newer"))], default=None)
config.plugins.FritzCall.debug = ConfigSelection(choices=[
(str(NOTSET), _("nothing")),
(str(DEBUG), "DEBUG"),
(str(INFO), "INFO"),
(str(WARNING), "WARNING"),
(str(ERROR), "ERROR"),
(str(CRITICAL), "CRITICAL")],
default=str(ERROR))
# 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.muteOnCall = ConfigYesNo(default=False)
config.plugins.FritzCall.muteOnOutgoingCall = ConfigYesNo(default=False)
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 = ConfigYesNo(default=False)
config.plugins.FritzCall.filtermsn = ConfigText(default="", fixed_size=False)
config.plugins.FritzCall.filtermsn.setUseableChars('0123456789,')
config.plugins.FritzCall.filterCallList = ConfigYesNo(default=True)
config.plugins.FritzCall.showBlacklistedCalls = ConfigYesNo(default=False)
config.plugins.FritzCall.showOutgoingCalls = ConfigYesNo(default=False)
config.plugins.FritzCall.timeout = ConfigInteger(default=15, limits=(0, 65535))
config.plugins.FritzCall.lookup = ConfigYesNo(default=False)
config.plugins.FritzCall.internal = ConfigYesNo(default=False)
config.plugins.FritzCall.fritzphonebook = ConfigYesNo(default=False)
config.plugins.FritzCall.fritzphonebookName = ConfigText(default=_('Phonebook'), fixed_size=False)
config.plugins.FritzCall.fritzphonebookShowInternal = ConfigYesNo(default=True)
config.plugins.FritzCall.phonebook = ConfigYesNo(default=False)
config.plugins.FritzCall.addcallers = ConfigYesNo(default=False)
config.plugins.FritzCall.enable = ConfigOnOff(default=False)
config.plugins.FritzCall.username = ConfigText(default='BoxAdmin', fixed_size=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 = ConfigYesNo(default=True)
config.plugins.FritzCall.showShortcut = ConfigYesNo(default=False)
config.plugins.FritzCall.showVanity = ConfigYesNo(default=False)
config.plugins.FritzCall.prefix = ConfigText(default="", fixed_size=False)
config.plugins.FritzCall.prefix.setUseableChars('0123456789')
config.plugins.FritzCall.connectionVerbose = ConfigSelection(choices=[("on", _("on")), ("failed", _("only failed")), ("off", _("off"))])
config.plugins.FritzCall.ignoreUnknown = ConfigYesNo(default=False)
config.plugins.FritzCall.reloadPhonebookTime = ConfigInteger(default=8, limits=(0, 99))
config.plugins.FritzCall.FritzExtendedSearchFaces = ConfigYesNo(default=False)
config.plugins.FritzCall.FritzExtendedSearchNames = ConfigYesNo(default=False)
config.plugins.FritzCall.phonebookLocation = ConfigDirectory(default=resolveFilename(SCOPE_CONFIG))
config.plugins.FritzCall.advancedSkin = ConfigYesNo(default=False)
config.plugins.FritzCall.guestSSID = ConfigText(default="FRITZ!Box Gastzugang", fixed_size=False)
config.plugins.FritzCall.guestSecure = ConfigYesNo(default=True)
config.plugins.FritzCall.guestPassword = ConfigPassword(default=encode("guestguest!!!"), fixed_size=False)
config.plugins.FritzCall.useHttps = ConfigYesNo(default=False)
guestWLANUptime = [(None, _('Not deactivating after time')), "15", "30", "45", "60", "90", "120", "180", "240", "300", "360", "480", "600", "720", "900", "1080", "1260"]
config.plugins.FritzCall.guestUptime = ConfigSelection(choices=guestWLANUptime, default="30")
countryCodes = [
("0049", _("Germany")),
("0031", _("The Netherlands")),
("0033", _("France")),
("0039", _("Italy")),
("0041", _("Switzerland")),
("0043", _("Austria")),
("", _("Others"))
]
config.plugins.FritzCall.country = ConfigSelection(choices=countryCodes)
config.plugins.FritzCall.countrycode = ConfigText(default="0049", fixed_size=False)
config.plugins.FritzCall.countrycode.setUseableChars('0123456789')
FBF_ALL_CALLS = "."
FBF_IN_CALLS = "1"
FBF_MISSED_CALLS = "2"
FBF_OUT_CALLS = "3"
FBF_BLOCKED_CALLS = "4"
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')
logger = logging.getLogger("FritzCall")
logger.setLevel(int(config.plugins.FritzCall.debug.value))
fileHandler = logging.FileHandler('/tmp/FritzDebug.log', mode='w')
fileHandler.setFormatter(logging.Formatter('%(asctime)s %(levelname)-8s %(name)-26s %(funcName)s %(message)-15s', '%Y-%m-%d %H:%M:%S'))
logger.addHandler(fileHandler)
debug = logger.debug
info = logger.info
warn = logger.warn
error = logger.error
exception = logger.exception
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 countrycode or 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 normNumber[:i] in avon:
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
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:
error("[FritzCall] initCbC: callbycallFileName does not exist?!?!")
def stripCbCPrefix(number, countrycode):
if not countrycode:
return number
if number and number[:2] != "00" and countrycode in cbcInfos:
for cbc in cbcInfos[countrycode]:
if len(cbc.getElementsByTagName("length")) < 1 or len(cbc.getElementsByTagName("prefix")) < 1:
warn("[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
import FritzCallFBF # wrong-import-position # pylint: disable=
class FritzAbout(Screen):
def __init__(self, session):
if not config.plugins.FritzCall.advancedSkin.value:
textFieldWidth = scaleV(350, 250)
width = 5 + 150 + 20 + textFieldWidth + 5 + 175 + 5
height = 5 + 175 + 5 + 25 + 5
self.skin = """
""" % (
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_CURRENT_PLUGIN, "Extensions/FritzCall/images/fritz.png"), # 150x110
5 + 150 + 5 + textFieldWidth + 5, # qr code horizontal offset
resolveFilename(SCOPE_CURRENT_PLUGIN, "Extensions/FritzCall/images/website.png"), # 175x175
width - 40, # url width
scaleV(24, 21) # url font size
)
else:
if DESKTOP_WIDTH <= 720:
self.skin = """
"""
elif DESKTOP_WIDTH <= 1280:
self.skin = """
"""
elif DESKTOP_WIDTH <= 1920:
self.skin = """
"""
else:
self.skin = """
"""
Screen.__init__(self, session)
self["aboutActions"] = ActionMap(["OkCancelActions"],
{
"cancel": self.exit,
"ok": self.exit,
}, -2)
self["text"] = Label(
"FritzCall Plugin" + "\n\n" +
"$Author: michael $"[1:-2] + "\n" +
"$Revision: 1553 $"[1:-2] + "\n" +
"$Date: 2019-04-25 09:36:05 +0200 (Thu, 25 Apr 2019) $"[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()
from FritzCallFBF import FBF_dectActive, FBF_faxActive, FBF_rufumlActive, FBF_tamActive, FBF_wlanState # wrong-import-position # pylint: disable=
class FritzMenu(Screen, HelpableScreen):
def __init__(self, session):
if not fritzbox or not fritzbox.information:
return
if config.plugins.FritzCall.fwVersion.value == "old" or config.plugins.FritzCall.fwVersion.value == "05.27":
fontSize = scaleV(24, 21) # indeed this is font size +2
noButtons = 2 # reset, wlan
if fritzbox.information[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.information[FBF_tamActive] is not None:
height += fontSize
if fritzbox.information[FBF_dectActive] is not None:
height += fontSize
if fritzbox.information[FBF_faxActive] is not None:
height += fontSize
if fritzbox.information[FBF_rufumlActive] is not None:
height += fontSize
buttonsGap = (width - noButtons * 140) / (noButtons + 1)
buttonsVPos = height - 40 - 5
varLinePos = 4
if fritzbox.information[FBF_tamActive] is not None:
mailboxLine = """
""" % (
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.information[FBF_dectActive] is not None:
dectLine = """
""" % (
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.information[FBF_faxActive] is not None:
faxLine = """
""" % (
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.information[FBF_rufumlActive] is not None:
rufumlLine = """
""" % (
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 = """
%s
%s
%s
%s
""" % (
width, height, # size
40, 5, # position information
width - 2 * 40, 2 * fontSize, # size information
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.information[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.information[FBF_dectActive] is not None:
self["FBFDect"] = Label('DECT')
self["dect_inactive"] = Pixmap()
self["dect_active"] = Pixmap()
self["dect_active"].hide()
if fritzbox.information[FBF_faxActive] is not None:
self["FBFFax"] = Label('Fax')
self["fax_inactive"] = Pixmap()
self["fax_active"] = Pixmap()
self["fax_active"].hide()
if fritzbox.information[FBF_rufumlActive] is not None:
self["FBFRufuml"] = Label(_('Call diversion'))
self["rufuml_inactive"] = Pixmap()
self["rufuml_active"] = Pixmap()
self["rufuml_active"].hide()
else: # not (config.plugins.FritzCall.fwVersion.value == "old" or config.plugins.FritzCall.fwVersion.value == "05.27")
if not config.plugins.FritzCall.advancedSkin.value:
fontSize = scaleV(24, 21) # indeed this is font size +2
noButtons = 2
width = max(DESKTOP_WIDTH - scaleH(500, 250), noButtons * 140 + (noButtons + 1) * 10)
# boxInfo 2 lines, gap, internet 2 lines, gap, dsl/wlan/dect/fax/rufuml/gast each 1 line, gap
height = 5 + 2 * fontSize + 10 + 2 * fontSize + 10 + 6 * fontSize + 10 + 40 + 5
buttonsGap = (width - noButtons * 140) / (noButtons + 1)
buttonsVPos = height - 40 - 5
self.skin = """
""" % (
width, height, # size
40, 5, # position information
width - 2 * 40, 2 * fontSize, # size information
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
40, 5 + 2 * fontSize + 10 + 4 * fontSize + 10, # position dect
width - 40 - 20, fontSize, # size dect
fontSize - 2,
"skin_default/buttons/button_green_off.png",
20, 5 + 2 * fontSize + 10 + 4 * fontSize + 10 + (fontSize - 16) / 2, # position button dect
"skin_default/buttons/button_green.png",
20, 5 + 2 * fontSize + 10 + 4 * fontSize + 10 + (fontSize - 16) / 2, # position button dect
40, 5 + 2 * fontSize + 10 + 5 * fontSize + 10, # position fax
width - 40 - 20, fontSize, # size fax
fontSize - 2,
"skin_default/buttons/button_green_off.png",
20, 5 + 2 * fontSize + 10 + 5 * fontSize + 10 + (fontSize - 16) / 2, # position button fax
"skin_default/buttons/button_green.png",
20, 5 + 2 * fontSize + 10 + 5 * fontSize + 10 + (fontSize - 16) / 2, # position button fax
40, 5 + 2 * fontSize + 10 + 6 * fontSize + 10, # position rufuml
width - 40 - 20, fontSize, # size rufuml
fontSize - 2,
"skin_default/buttons/button_green_off.png",
20, 5 + 2 * fontSize + 10 + 6 * fontSize + 10 + (fontSize - 16) / 2, # position button rufuml
"skin_default/buttons/button_green.png",
20, 5 + 2 * fontSize + 10 + 6 * fontSize + 10 + (fontSize - 16) / 2, # position button rufuml
40, 5 + 2 * fontSize + 10 + 7 * fontSize + 10, # position gast
width - 40 - 20, fontSize, # size gast
fontSize - 2,
"skin_default/buttons/button_green_off.png",
20, 5 + 2 * fontSize + 10 + 7 * fontSize + 10 + (fontSize - 16) / 2, # position button gast
"skin_default/buttons/button_green.png",
20, 5 + 2 * fontSize + 10 + 7 * fontSize + 10 + (fontSize - 16) / 2, # position button gast
buttonsGap, buttonsVPos, "skin_default/buttons/green.png", buttonsGap, buttonsVPos,
2 * buttonsGap + 140, buttonsVPos, "skin_default/buttons/yellow.png", 2 * buttonsGap + 140, buttonsVPos,
)
else:
if DESKTOP_WIDTH <= 720:
self.skin = """
"""
elif DESKTOP_WIDTH <= 1280:
self.skin = """
"""
elif DESKTOP_WIDTH <= 1920:
self.skin = """
"""
else:
self.skin = """
"""
Screen.__init__(self, session)
HelpableScreen.__init__(self)
# TRANSLATORS: keep it short, this is a button
self["menuActions"] = ActionMap(["OkCancelActions", "ColorActions", "EPGSelectActions"],
{
"cancel": self._exit,
"ok": self._exit,
"green": self._toggleWlan,
"yellow": self._toggleGast,
"red": self._reset, # no button, does not work
"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", [("yellow", _("Toggle WLAN guest access"))]))
# 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"))]))
# 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"))
# TRANSLATORS: keep it short, this is a button
self["key_yellow"] = Button(_("Activate WLAN guest access"))
self["FBFInfo"] = Label(_('Getting status from FRITZ!Box Fon...'))
self["FBFInternet"] = Label('Internet')
self["internet_inactive"] = Pixmap()
self["internet_inactive"].hide()
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
self["FBFDect"] = Label('DECT')
self["dect_inactive"] = Pixmap()
self["dect_inactive"].hide()
self["dect_active"] = Pixmap()
self["dect_active"].hide()
self["FBFFax"] = Label('Fax')
self["fax_inactive"] = Pixmap()
self["fax_inactive"].hide()
self["fax_active"] = Pixmap()
self["fax_active"].hide()
self["FBFRufuml"] = Label(_('Call redirection'))
self["rufuml_inactive"] = Pixmap()
self["rufuml_inactive"].hide()
self["rufuml_active"] = Pixmap()
self["rufuml_active"].hide()
self["FBFGast"] = Label(_('Guest access'))
self["gast_inactive"] = Pixmap()
self["gast_inactive"].hide()
self["gast_active"] = Pixmap()
self["gast_active"].hide()
self._guestActive = ""
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):
if fritzbox:
fritzbox.getInfo(self._fillMenu)
self._fillMenu(fritzbox.information, True)
def _fillMenu(self, status, refreshing=False):
(boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive, guestAccess) = status
if wlanState:
self._wlanActive = (wlanState[0] == '1')
self._guestActive = guestAccess
self._mailboxActive = False
try:
if "FBFInfo" not in self: # screen is closed already
return
if refreshing:
self["FBFInfo"].setText(_("Refreshing..."))
else:
if boxInfo:
self["FBFInfo"].setText(str(boxInfo))
else:
self["FBFInfo"].setText('BoxInfo ' + _('Status not available'))
if ipAddress:
if upTime:
self["FBFInternet"].setText(str('Internet ' + _('IP Address:') + ' ' + ipAddress + '\n' + _('Connected since') + ' ' + upTime))
else:
self["FBFInternet"].setText(str('Internet ' + _('IP Address:') + ' ' + ipAddress))
self["internet_inactive"].hide()
self["internet_active"].show()
elif upTime:
self["FBFInternet"].setText(str(_('Connected since') + ' ' + upTime))
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[2]:
message = dslState[2]
else:
message = "DSL"
if dslState[1]:
message = message + ' ' + dslState[1]
self["FBFDsl"].setText(str(message))
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')
elif wlanState[1] == '1':
message += ' ' + _('encrypted')
if wlanState[2]:
if wlanState[2] == '0':
message = message + ', ' + _('no device active')
elif wlanState[2] == '1' or wlanState[2] == 'ein':
message = message + ', ' + _('one device active')
else:
message = message + ', ' + wlanState[2] + ' ' + _('devices active')
if len(wlanState) == 4:
message = message + ", " + wlanState[3]
self["FBFWlan"].setText(str(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.information[FBF_tamActive] and "mailbox_active" in self:
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(min(len(tamActive) - 1, 5)):
if tamActive[i + 1]:
message = message + str(i) + ','
if message:
message = '(' + message[:-1] + ')'
self["mailbox_inactive"].hide()
self["mailbox_active"].show()
if tamActive[0] == 1:
self["FBFMailbox"].setText(str(_('One mailbox active') + ' ' + message))
else:
self["FBFMailbox"].setText(str(tamActive[0]) + ' ' + _('mailboxes active') + ' ' + str(message))
if dectActive and "dect_inactive" in self:
self["dect_inactive"].hide()
self["dect_active"].show()
if dectActive == 0:
self["FBFDect"].setText(_('No DECT phone registered'))
else:
if dectActive == "ein" or dectActive == "1" or dectActive == 1:
self["FBFDect"].setText(_('One DECT phone registered'))
else:
self["FBFDect"].setText(str(dectActive) + ' ' + _('DECT phones registered'))
else:
self["dect_active"].hide()
self["dect_inactive"].show()
self["FBFDect"].setText(_('DECT inactive'))
if faxActive:
self["fax_inactive"].hide()
self["fax_active"].show()
self["FBFFax"].setText(_('Software fax active'))
else:
self["fax_active"].hide()
self["fax_inactive"].show()
self["FBFFax"].setText(_('Software fax inactive'))
if rufumlActive:
self["rufuml_inactive"].hide()
self["rufuml_active"].show()
if rufumlActive == -1: # means no number available
self["FBFRufuml"].setText(_('Call diversion active'))
elif rufumlActive == 1:
self["FBFRufuml"].setText(_('One call diversion active'))
else:
self["FBFRufuml"].setText(str(rufumlActive) + ' ' + _('call diversions active'))
else:
self["rufuml_active"].hide()
self["rufuml_inactive"].show()
self["FBFRufuml"].setText(_('No call diversion active'))
if guestAccess:
self["gast_inactive"].hide()
self["gast_active"].show()
self["FBFGast"].setText(str(_('Guest access on ') + guestAccess))
else:
self["gast_active"].hide()
self["gast_inactive"].show()
self["FBFGast"].setText(_('Guest access not active'))
if guestAccess and (guestAccess.find('WLAN') != -1 or guestAccess.find('WIFI') != -1):
# TRANSLATORS: keep it short, this is a button
self["key_yellow"].setText(_("Deactivate WLAN guest access"))
else:
# TRANSLATORS: keep it short, this is a button
self["key_yellow"].setText(_("Activate WLAN guest access"))
except KeyError:
error("[FritzCallFBF] _fillMenu: " + traceback.format_exc())
def _toggleWlan(self, callback=None):
self["FBFInfo"].setText(_("Setting...") + " WLAN")
if self._wlanActive:
info("[FritzMenu] toggleWlan off")
if callback:
fritzbox.changeWLAN('0', callback)
else:
fritzbox.changeWLAN('0', self._getInfo)
else:
info("[FritzMenu] toggleWlan on")
if callback:
fritzbox.changeWLAN('1', callback)
else:
fritzbox.changeWLAN('1', self._getInfo)
def _toggleMailbox(self, which):
debug("[FritzMenu]")
if fritzbox.information[FBF_tamActive]:
info("[FritzMenu] toggleMailbox off")
fritzbox.changeMailbox(which, self._getInfo)
def _toggleGast(self):
self["FBFInfo"].setText(_("Setting...") + ' ' + _("Guest access"))
if not self._wlanActive:
self["FBFInfo"].setText(_("WLAN not active"))
# self._toggleWlan(self._toggleGast)
return
fritzbox.changeGuestAccess(self._guestActive, self._getInfo)
def _reset(self):
fritzbox.reset()
self._exit()
def _exit(self):
self.close()
class FritzDisplayCalls(Screen, HelpableScreen):
def __init__(self, session, text=""): # @UnusedVariable # pylint: disable=W0613
if not config.plugins.FritzCall.advancedSkin.value:
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 = """
{"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
MultiContentEntryPixmapAlphaBlend(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
}
""" % (
# 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
)
else:
if DESKTOP_WIDTH <= 720:
self.skin = """
{"template": [
MultiContentEntryText(pos = (50,24), size = (150,21), font=1, flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER, text = 1), # index 0 is the number, index 1 is date
MultiContentEntryPixmapAlphaBlend(pos = (5,5), size = (35,35), png = 2), # index 1 i direction pixmap
MultiContentEntryText(pos = (50,0), size = (530,24), font=0, flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER, text = 3), # index 2 is remote name/number
MultiContentEntryText(pos = (220,24), size = (80,21), font=1, flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER, text = 4), # index 3 is length of call
MultiContentEntryText(pos = (320,24), size = (240,21), font=1, flags = RT_HALIGN_RIGHT|RT_VALIGN_CENTER, text = 5), # index 4 is my number/name for number
],
"fonts": [gFont("Regular", 18), gFont("Regular", 16)],
"itemHeight": 45
}
"""
elif DESKTOP_WIDTH <= 1280:
self.skin = """
{"template": [
MultiContentEntryText(pos = (55,30), size = (200,25), font=1, flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER, text = 1), # index 0 is the number, index 1 is date
MultiContentEntryPixmapAlphaBlend(pos = (5,10), size = (35,35), png = 2), # index 1 i direction pixmap
MultiContentEntryText(pos = (55,0), size = (760,30), font=0, flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER, text = 3), # index 2 is remote name/number
MultiContentEntryText(pos = (270,30), size = (100,25), font=1, flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER, text = 4), # index 3 is length of call
MultiContentEntryText(pos = (390,30), size = (400,25), font=1, flags = RT_HALIGN_RIGHT|RT_VALIGN_CENTER, text = 5), # index 4 is my number/name for number
],
"fonts": [gFont("Regular", 20), gFont("Regular", 18)],
"itemHeight": 55
}
"""
elif DESKTOP_WIDTH <= 1920:
self.skin = """
{"template": [
MultiContentEntryText(pos = (5,0), size = (180,40), flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER, text = 1), # index 0 is the number, index 1 is date
MultiContentEntryPixmapAlphaBlend(pos = (190,2), size = (35,35), png = 2), # index 1 i direction pixmap
MultiContentEntryText(pos = (245,2), size = (600,40), flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER, text = 3), # index 2 is remote name/number
MultiContentEntryText(pos = (860,0), size = (120,40), flags = RT_HALIGN_CENTER|RT_VALIGN_CENTER, text = 4), # index 3 is length of call
MultiContentEntryText(pos = (1000,0), size = (390,40), flags = RT_HALIGN_RIGHT|RT_VALIGN_CENTER, text = 5), # index 4 is my number/name for number
],
"fonts": [gFont("Regular", 28)],
"itemHeight": 40
}
"""
else:
self.skin = """
{"template": [
MultiContentEntryText(pos = (1100,0), size = (420,70), flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER, text = 1), # index 0 is the number, index 1 is date
MultiContentEntryPixmapAlphaBlend(pos = (5,10), size = (50,50), png = 2), # index 1 i direction pixmap
MultiContentEntryText(pos = (80,0), size = (1000,70), flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER, text = 3), # index 2 is remote name/number
MultiContentEntryText(pos = (1540,0), size = (200,70), flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER, text = 4), # index 3 is length of call
MultiContentEntryText(pos = (1760,0), size = (740,70), flags = RT_HALIGN_RIGHT|RT_VALIGN_CENTER, text = 5), # index 4 is my number/name for number
],
"fonts": [gFont("Regular", 58)],
"itemHeight": 70
}
"""
# 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] '''%s'''", config.plugins.FritzCall.fbfCalls.value)
self.display(config.plugins.FritzCall.fbfCalls.value)
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=None):
debug("[FritzDisplayCalls]")
if which:
config.plugins.FritzCall.fbfCalls.value = which
config.plugins.FritzCall.fbfCalls.save()
else:
which = config.plugins.FritzCall.fbfCalls.value
fritzbox.getCalls(self, lambda x: self.gotCalls(x, which), which)
def gotCalls(self, listOfCalls, which):
debug("[FritzDisplayCalls]")
self.updateStatus(fbfCallsChoices[which] + " (" + str(len(listOfCalls)) + ")")
callPngPath = "Extensions/FritzCall/images"
if config.plugins.FritzCall.advancedSkin.value:
callPngPath = callPngPath + "/MODERN"
debug("[FritzDisplayCalls] callPngPath: %s", callPngPath)
directout = LoadPixmap(resolveFilename(SCOPE_CURRENT_PLUGIN, callPngPath + "/callout.png"))
directin = LoadPixmap(resolveFilename(SCOPE_CURRENT_PLUGIN, callPngPath + "/callin.png"))
directfailed = LoadPixmap(resolveFilename(SCOPE_CURRENT_PLUGIN, callPngPath + "/callinfailed.png"))
directrejected = LoadPixmap(resolveFilename(SCOPE_CURRENT_PLUGIN, callPngPath + "/callrejected.png"))
def pixDir(param):
if param == FBF_OUT_CALLS:
direct = directout
elif param == FBF_IN_CALLS:
direct = directin
elif param == FBF_MISSED_CALLS:
direct = directfailed
else:
direct = directrejected
return direct
# debug("[FritzDisplayCalls] %s" %repr(listOfCalls))
self.list = [(number, date[:6] + ' ' + date[9:14], pixDir(direct), remote, length, here) for (number, date, direct, remote, length, here) in listOfCalls]
# debug("[FritzDisplayCalls] %s" %repr(self.list))
self["entries"].setList(self.list)
#=======================================================================
# if len(self.list) > 1:
# self["entries"].setIndex(1)
#=======================================================================
def updateStatus(self, text):
if "statusbar" in self:
self["statusbar"].setText(_("Getting calls from FRITZ!Box...") + ' ' + str(text))
def showEntry(self):
debug("[FritzDisplayCalls]")
cur = self["entries"].getCurrent()
if cur:
if cur[0]:
# debug("[FritzDisplayCalls] %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)
elif cur[3]:
name = cur[3]
self.session.open(FritzOfferAction, self, number, name)
else:
# we don't
fullname = resolveNumberWithAvon(number, config.plugins.FritzCall.countrycode.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=""):
if not config.plugins.FritzCall.advancedSkin.value:
# the layout will completely be recalculated in finishLayout
self.skin = """
""" % (
DESKTOP_WIDTH, DESKTOP_HEIGHT, scaleV(25, 22), # set maximum size
DESKTOP_WIDTH, DESKTOP_HEIGHT, # set maximum size
140, 40, "skin_default/buttons/red.png",
140, 40, "skin_default/buttons/green.png",
140, 40, "skin_default/buttons/yellow.png",
140, 40, scaleV(21, 21),
140, 40, scaleV(21, 21),
140, 40, scaleV(21, 21),
)
else:
if DESKTOP_WIDTH <= 720:
self.skin = """
"""
elif DESKTOP_WIDTH <= 1280:
self.skin = """
"""
elif DESKTOP_WIDTH <= 1920:
self.skin = """
"""
else:
self.skin = """
"""
debug("[FritzOfferAction] %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
if config.plugins.FritzCall.internal.value and len(number) > 3 and number[0] == "0":
number = number[1:]
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):
debug("[FritzOfferAction] 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)
if DESKTOP_WIDTH <= 720:
picPixmap = LoadPixmap(resolveFilename(SCOPE_CURRENT_PLUGIN, "Extensions/FritzCall/images/no-face-error-sd.png"))
elif DESKTOP_WIDTH <= 1280:
picPixmap = LoadPixmap(resolveFilename(SCOPE_CURRENT_PLUGIN, "Extensions/FritzCall/images/no-face-error-hd.png"))
elif DESKTOP_WIDTH <= 1920:
picPixmap = LoadPixmap(resolveFilename(SCOPE_CURRENT_PLUGIN, "Extensions/FritzCall/images/no-face-error-fhd.png"))
else:
picPixmap = LoadPixmap(resolveFilename(SCOPE_CURRENT_PLUGIN, "Extensions/FritzCall/images/no-face-error-uhd.png"))
picSize = picPixmap.size()
self["FacePixmap"].instance.setPixmap(picPixmap)
if config.plugins.FritzCall.advancedSkin.value:
debug("skip layout manipulation")
return
noButtons = 3
buttonSize = (self["key_red_p"].instance.size().width(), self["key_red_p"].instance.size().height())
debug("[FritzOfferAction] buttonSize:" + repr(buttonSize))
# recalculate window size
textSize = self["text"].getSize()
textSize = (textSize[0] + 20, textSize[1] + 20) # don't know, why, but size is too small
debug("[FritzOfferAction] textsize: " + repr(textSize))
textSize = eSize(*textSize)
gapSizeH = scaleH(-1, 5)
width = max(scaleH(-1, 545), noButtons * (buttonSize[0] + gapSizeH) + gapSizeH, picSize.width() + textSize.width() + 30)
height = max(picSize.height() + 5, textSize.height() + 5, scaleV(-1, 136)) + 5 + buttonSize[1] + 5
buttonsGap = (width - noButtons * buttonSize[0]) / (noButtons + 1)
buttonsVPos = height - buttonSize[1] - 5
wSize = (width, height)
wSize = eSize(*wSize)
# center the smaller vertically
hGap = (width - picSize.width() - textSize.width()) / 3
picPos = (hGap, (height - 5 - buttonSize[1] - picSize.height()) / 2 + 5)
textPos = (hGap + picSize.width() + hGap, (height - 5 - buttonSize[1] - 5 - textSize.height()) / 2 + 5)
# resize screen
self.instance.resize(wSize)
# resize text
self["text"].instance.resize(textSize)
# resize pixmap
self["FacePixmap"].instance.resize(picSize)
self["FacePixmap"].instance.setPixmap(picPixmap)
# move buttons
buttonPos = (buttonsGap, buttonsVPos)
self["key_red_p"].instance.move(ePoint(*buttonPos))
self["key_red"].instance.move(ePoint(*buttonPos))
buttonPos = (buttonsGap + buttonSize[0] + buttonsGap, buttonsVPos)
self["key_green_p"].instance.move(ePoint(*buttonPos))
self["key_green"].instance.move(ePoint(*buttonPos))
buttonPos = (buttonsGap + buttonSize[0] + buttonsGap + buttonSize[0] + 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):
self["text"].instance.resize(eSize(*(DESKTOP_WIDTH, DESKTOP_HEIGHT)))
self["text"].setText(str(self._number) + "\n\n" + str(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.countrycode.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
info("[FritzOfferAction]\n" + str(name.replace(", ", "\n")))
self._setTextAndResize(str(name.replace(", ", "\n")))
def _call(self):
if fritzbox:
debug("[FritzOfferAction] %s", self._number)
self.session.open(MessageBox, _("Calling %s") % self._number, type=MessageBox.TYPE_INFO)
fritzbox.dial(self._number)
else:
error("[FritzOfferAction] no fritzbox object?!?!")
self.session.open(MessageBox, _("FRITZ!Box not available for calling"), type=MessageBox.TYPE_INFO)
def _add(self):
debug("[FritzOfferAction] %s, %s", self._number, self._name)
phonebook.FritzDisplayPhonebook(self._session).add(self._parent, self._number, self._name)
self._exit()
def _exit(self):
self.close()
OneHour = 60 * 60 * 1000
# OneHour = 1000
class FritzCallPhonebook(object):
def __init__(self):
debug("[FritzCallPhonebook]")
# Beware: strings in phonebook.phonebook have to be in utf-8!
self.phonebook = {}
if config.plugins.FritzCall.reloadPhonebookTime.value > 0:
debug("[FritzCallPhonebook] start timer with " + repr(config.plugins.FritzCall.reloadPhonebookTime.value))
self.loop = eTimer()
# newer OE versions don't have the callback
try:
self.loop_conn = self.loop.timeout.connect(self.reload)
except AttributeError:
self.loop.callback.append(self.reload)
self.loop.start(config.plugins.FritzCall.reloadPhonebookTime.value * OneHour, False)
self.reload()
def reload(self):
debug("[FritzCallPhonebook] " + time.ctime())
# Beware: strings in phonebook.phonebook have to be in utf-8!
self.phonebook = {}
if not config.plugins.FritzCall.enable.value:
return
phonebookFilenameOld = os.path.join(config.plugins.FritzCall.phonebookLocation.value, "PhoneBook.txt")
phonebookFilename = os.path.join(config.plugins.FritzCall.phonebookLocation.value, "PhoneBook.json")
if config.plugins.FritzCall.phonebook.value:
if os.path.exists(phonebookFilename):
# read json
debug("[FritzCallPhonebook] read " + phonebookFilename)
try:
for k, v in json.loads(open(phonebookFilename).read().decode("utf-8")).items():
# TODO if we change the value to a list of lines, we have to adapt this here
self.phonebook[k.encode("utf-8")] = v.encode("utf-8")
except (ValueError, UnicodeError, IOError) as e:
error("[FritzCallPhonebook] Could not load %s: %s", phonebookFilename, str(e))
Notifications.AddNotification(MessageBox, _("Could not load phonebook: %s") % (phonebookFilename + ": " + str(e)), type=MessageBox.TYPE_ERROR)
# debug(repr(self.phonebook))
elif os.path.exists(phonebookFilenameOld): # read old format and dump to json
debug("[FritzCallPhonebook] read " + phonebookFilenameOld)
phonebookTxtCorrupt = False
self.phonebook = {}
for line in open(phonebookFilenameOld):
# debug("[FritzCallPhonebook] got line from Phonebook.txt: %s" % ___(line))
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:
error("[FritzCallPhonebook] Could not parse internal Phonebook Entry %s", line)
phonebookTxtCorrupt = True
line = line.encode("utf-8")
elems = line.split('#')
if len(elems) == 2:
try:
# debug("[FritzCallPhonebook] Adding '''%s''' with '''%s''' from internal phonebook!" % (__(elems[1].strip()), __(elems[0], False)))
self.phonebook[elems[0]] = elems[1].strip()
except ValueError: # how could this possibly happen?!?!
error("[FritzCallPhonebook] Could not parse internal Phonebook Entry %s", line)
phonebookTxtCorrupt = True
else:
error("[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(phonebookFilenameOld, phonebookFilenameOld + ".bck")
fNew = open(phonebookFilenameOld, '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):
error("[FritzCallPhonebook] error renaming or writing to %s", phonebookFilenameOld)
os.rename(phonebookFilenameOld, phonebookFilenameOld + ".old")
json.dump(self.phonebook, open(phonebookFilename, "w"), ensure_ascii=False, encoding="utf-8", indent=0, separators=(',', ': '), sort_keys=True)
if fritzbox:
if config.plugins.FritzCall.fritzphonebook.value:
debug("[FritzCallPhonebook] config.plugins.FritzCall.fritzphonebook.value %s", repr(config.plugins.FritzCall.fritzphonebook.value))
fritzbox.loadFritzBoxPhonebook(self)
else:
debug("[FritzCallPhonebook] config.plugins.FritzCall.fritzphonebook.value %s", repr(config.plugins.FritzCall.fritzphonebook.value))
fritzbox.phonebook = self
#===============================================================================
# #
# # 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)
#===============================================================================
def search(self, number, default=None, extended=True):
# debug("[FritzCallPhonebook] Searching for %s" %number)
name = ""
if not self.phonebook or not number:
return name
if config.plugins.FritzCall.prefix.value:
prefix = config.plugins.FritzCall.prefix.value
if number[0] != '0':
number = prefix + number
# debug("[FritzCallPhonebook] added prefix: %s" %number)
elif number[:len(prefix)] == prefix and number[len(prefix):] in self.phonebook:
# debug("[FritzCallPhonebook] same prefix")
name = self.phonebook[number[len(prefix):]]
# debug("[FritzCallPhonebook] result: %s" %name)
else:
prefix = ""
if not name and number in self.phonebook:
name = self.phonebook[number]
if not name and default:
name = default
if not name and extended and config.plugins.FritzCall.FritzExtendedSearchNames.value:
for k in range(len(number) - 1, 0, -1):
# debug("[FritzCallPhonebook] extended search: check: %s" %number[:k])
name = self.search(number[:k], default, False)
if name:
# debug("[FritzCallPhonebook] search result for shortened number: %s" % name)
break
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]")
name = name.replace("\n", ", ") # 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.json have to be in utf-8!
# f = open(os.path.join(config.plugins.FritzCall.phonebookLocation.value, "PhoneBook.txt"), 'a')
# f.write(string)
# f.close()
phonebookFilename = os.path.join(config.plugins.FritzCall.phonebookLocation.value, "PhoneBook.json")
# check whether PhoneBook.json exists, if not drop empty JSOn file
if not os.path.isfile(phonebookFilename):
json.dump({}, open(phonebookFilename, "w"), ensure_ascii=False, encoding="utf-8", indent=0, separators=(',', ': '), sort_keys=True)
info("[FritzCallPhonebook] empty Phonebook.json created")
phonebookTmp = {}
for k, v in json.loads(open(phonebookFilename).read().decode("utf-8")).items():
phonebookTmp[k.encode("utf-8")] = v.encode("utf-8")
phonebookTmp[number] = name
json.dump(phonebookTmp, open(phonebookFilename, "w"), ensure_ascii=False, encoding="utf-8", indent=0, separators=(',', ': '), sort_keys=True)
info("[FritzCallPhonebook] added %s with %s to Phonebook.json", number, name.strip())
return True
except IOError:
return False
def remove(self, number):
if number in self.phonebook:
debug("[FritzCallPhonebook]")
del self.phonebook[number]
if config.plugins.FritzCall.phonebook.value:
try:
# phonebookFilename = os.path.join(config.plugins.FritzCall.phonebookLocation.value, "PhoneBook.json")
# debug("[FritzCallPhonebook] remove entry in Phonebook.json")
# fOld = open(phonebookFilename, 'r')
# fNew = open(phonebookFilename + str(os.getpid()), 'w')
# line = fOld.readline()
# while line:
# elems = line.split('#')
# if len(elems) == 2 and 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)
phonebookFilename = os.path.join(config.plugins.FritzCall.phonebookLocation.value, "PhoneBook.json")
# check whether PhoneBook.json exists, if not drop empty JSOn file
if not os.path.isfile(phonebookFilename):
json.dump({}, open(phonebookFilename, "w"), ensure_ascii=False, encoding="utf-8", indent=0, separators=(',', ': '), sort_keys=True)
info("[FritzCallPhonebook] empty Phonebook.json created")
return True
phonebookTmp = {}
for k, v in json.loads(open(phonebookFilename).read().decode("utf-8")).items():
phonebookTmp[k.encode("utf-8")] = v.encode("utf-8")
if number in phonebookTmp:
del phonebookTmp[number]
json.dump(phonebookTmp, open(phonebookFilename, "w"), ensure_ascii=False, encoding="utf-8", indent=0, separators=(',', ': '), sort_keys=True)
info("[FritzCallPhonebook] removed %s from Phonebook.json", number)
return True
except (IOError, OSError):
error("[FritzCallPhonebook] error removing %s from %s", number, phonebookFilename)
return False
class FritzDisplayPhonebook(Screen, HelpableScreen, NumericalTextInput):
def __init__(self, session):
if not config.plugins.FritzCall.advancedSkin.value:
self.entriesWidth = DESKTOP_WIDTH * scaleH(75, 85) / 100
self.height = DESKTOP_HEIGHT * 0.75
numberFieldWidth = scaleH(220, 160)
fieldWidth = self.entriesWidth - 5 - numberFieldWidth - 10
fontSize = scaleV(22, 18)
fontHeight = scaleV(24, 20)
buttonGap = (self.entriesWidth - 4 * 140) / 5
debug("[FritzDisplayPhonebook] width: " + str(self.entriesWidth))
self.skin = """
{"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
}
""" % (
# scaleH(90, 75), scaleV(100, 73), # position
self.entriesWidth, self.height, # size
self.entriesWidth, # eLabel width
scaleH(40, 5), scaleV(20, 5), # entries position
self.entriesWidth - scaleH(40, 5), self.height - scaleV(20, 5) - 5 - 5 - 40, # 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
self.height - 40 - 5, # eLabel position vertical
self.entriesWidth, # eLabel width
buttonGap, self.height - 40, "skin_default/buttons/red.png", # ePixmap red
2 * buttonGap + 140, self.height - 40, "skin_default/buttons/green.png", # ePixmap green
3 * buttonGap + 2 * 140, self.height - 40, "skin_default/buttons/yellow.png", # ePixmap yellow
4 * buttonGap + 3 * 140, self.height - 40, "skin_default/buttons/blue.png", # ePixmap blue
buttonGap, self.height - 40, scaleV(22, 21), # widget red
2 * buttonGap + 140, self.height - 40, scaleV(22, 21), # widget green
3 * buttonGap + 2 * 140, self.height - 40, scaleV(22, 21), # widget yellow
4 * buttonGap + 3 * 140, self.height - 40, scaleV(22, 21), # widget blue
)
else:
if DESKTOP_WIDTH <= 720:
self.skin = """
{"template": [
MultiContentEntryText(pos = (5,0), size = (400,25), font=0, flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER, text = 1), # index 0 is the name, index 1 is shortname
MultiContentEntryText(pos = (415,0), size = (145,25), font=0, flags = RT_HALIGN_RIGHT|RT_VALIGN_CENTER, text = 2), # index 2 is number
],
"fonts": [gFont("Regular", 18)],
"itemHeight": 25
}
"""
elif DESKTOP_WIDTH <= 1280:
self.skin = """
{"template": [
MultiContentEntryText(pos = (5,0), size = (500,30), font=0, flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER, text = 1), # index 0 is the name, index 1 is shortname
MultiContentEntryText(pos = (520,0), size = (270,30), font=0, flags = RT_HALIGN_RIGHT|RT_VALIGN_CENTER, text = 2), # index 2 is number
],
"fonts": [gFont("Regular", 20)],
"itemHeight": 30
}
"""
elif DESKTOP_WIDTH <= 1920:
self.skin = """
{"template": [
MultiContentEntryText(pos = (5,0), size = (980,40), font=0, flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER, text = 1), # index 0 is the name, index 1 is shortname
MultiContentEntryText(pos = (1000,0), size = (390,40), font=0, flags = RT_HALIGN_RIGHT|RT_VALIGN_CENTER, text = 2), # index 2 is number
],
"fonts": [gFont("Regular", 28)],
"itemHeight": 40
}
"""
else:
self.skin = """
{"template": [
MultiContentEntryText(pos = (20,0), size = (1900,70), font=0, flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER, text = 1), # index 0 is the name, index 1 is shortname
MultiContentEntryText(pos = (1950,0), size = (550,70), font=0, flags = RT_HALIGN_RIGHT|RT_VALIGN_CENTER, text = 2), # index 2 is number
],
"fonts": [gFont("Regular", 58)],
"itemHeight": 70
}
"""
# 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.mySearch,
"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("[FritzDisplayPhonebook]")
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("[FritzDisplayPhonebook]")
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:
error("[FritzDisplayPhonebook] 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("[FritzDisplayPhonebook] %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("[FritzDisplayPhonebook] %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("[FritzDisplayPhonebook]")
#
# 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("[FritzDisplayPhonebook] %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=""):
if not config.plugins.FritzCall.advancedSkin.value: #
# 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 = """
""" % (
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,
)
else:
if DESKTOP_WIDTH <= 720:
self.skin = """
"""
elif DESKTOP_WIDTH <= 1280:
self.skin = """
"""
elif DESKTOP_WIDTH <= 1920:
self.skin = """
"""
else:
self.skin = """
"""
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):
if self.number != "":
# TRANSLATORS: this is a window title.
self.setTitle(_("Edit selected entry"))
else:
# 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("[FritzDisplayPhonebook]")
if not parent:
parent = self
self.session.open(AddScreen, parent, number, name)
def edit(self):
debug("[FritzDisplayPhonebook]")
cur = self["entries"].getCurrent()
if cur is None:
self.session.open(MessageBox, _("No entry selected"), MessageBox.TYPE_INFO)
else:
self.add(self, cur[2], cur[0])
def mySearch(self):
debug("[FritzDisplayPhonebook]")
# self.help_window = self.session.instantiateDialog(NumericalTextInputHelpDialog, self)
# self.help_window.show()
# VirtualKeyboard instead of InputBox?
self.session.openWithCallback(self.doSearch, VirtualKeyBoard, title=_("Search phonebook"))
def doSearch(self, searchTerms):
if not searchTerms:
searchTerms = ""
debug("[FritzDisplayPhonebook]: " + 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=W0613
if not config.plugins.FritzCall.advancedSkin.value:
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 = """
""" % (
# (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 information
scaleH(20 + 4 * (140 + 90) + (35 + 40), 4 * 140 + 35), scaleV(532, 402), "skin_default/buttons/key_menu.png", # button menu
)
else:
if DESKTOP_WIDTH <= 720:
self.skin = """
"""
elif DESKTOP_WIDTH <= 1280:
self.skin = """
"""
elif DESKTOP_WIDTH <= 1920:
self.skin = """
"""
else:
self.skin = """
"""
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)
try:
config.plugins.FritzCall.guestPassword.value = decode(config.plugins.FritzCall.guestPassword.value)
except binascii.Error:
config.plugins.FritzCall.guestPassword.value = ""
try:
config.plugins.FritzCall.password.value = decode(config.plugins.FritzCall.password.value)
except binascii.Error:
config.plugins.FritzCall.password.value = ""
# get new list of locations for Phonebook.json
self.createSetup()
self.onLayoutFinish.append(self.setWindowTitle)
def setWindowTitle(self):
# TRANSLATORS: this is a window title.
self.setTitle(_("FritzCall Setup") + " (" + "$Revision: 1553 $"[1:-1] + "$Date: 2019-04-25 09:36:05 +0200 (Thu, 25 Apr 2019) $"[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(_("FRITZ!Box FON firmware version"), config.plugins.FritzCall.fwVersion))
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 incoming call"), config.plugins.FritzCall.muteOnCall))
self.list.append(getConfigListEntry(_("Mute on outgoing calls"), config.plugins.FritzCall.muteOnOutgoingCall))
self.list.append(getConfigListEntry(_("Show Blocked Calls"), config.plugins.FritzCall.showBlacklistedCalls))
self.list.append(getConfigListEntry(_("Show Outgoing Calls"), config.plugins.FritzCall.showOutgoingCalls))
# not only for outgoing: config.plugins.FritzCall.showOutgoingCalls.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(_("Country"), config.plugins.FritzCall.country))
if config.plugins.FritzCall.country.value:
self.list.append(getConfigListEntry(_("Reverse Lookup Caller ID"), config.plugins.FritzCall.lookup))
config.plugins.FritzCall.countrycode.value = config.plugins.FritzCall.country.value
# else:
self.list.append(getConfigListEntry(_("Countrycode (e.g. 0044 for UK, 0034 for Spain, etc.)"), config.plugins.FritzCall.countrycode))
if config.plugins.FritzCall.fwVersion.value is not None:
if config.plugins.FritzCall.fwVersion.value == "05.50" or config.plugins.FritzCall.fwVersion.value == "06.35"or config.plugins.FritzCall.fwVersion.value == "upnp":
self.list.append(getConfigListEntry(_("User name Accessing FRITZ!Box"), config.plugins.FritzCall.username))
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))
# if config.plugins.FritzCall.fwVersion.value == "05.50" or config.plugins.FritzCall.fwVersion.value == "06.35":
# self.list.append(getConfigListEntry(_("Name of WLAN guest network"), config.plugins.FritzCall.guestSSID))
# self.list.append(getConfigListEntry(_("Secure WLAN guest network"), config.plugins.FritzCall.guestSecure))
# self.list.append(getConfigListEntry(_("Password of WLAN guest network"), config.plugins.FritzCall.guestPassword))
# self.list.append(getConfigListEntry(_("Minutes of uptime of WLAN guest network"), config.plugins.FritzCall.guestUptime))
self.list.append(getConfigListEntry(_("Read PhoneBook from FRITZ!Box"), config.plugins.FritzCall.fritzphonebook))
if config.plugins.FritzCall.fritzphonebook.value:
self.list.append(getConfigListEntry(_("FRITZ!Box PhoneBook to read"), config.plugins.FritzCall.fritzphonebookName))
if config.plugins.FritzCall.fwVersion.value == "06.35":
self.list.append(getConfigListEntry(_("Show also internal numbers"), config.plugins.FritzCall.fritzphonebookShowInternal))
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))
else:
config.plugins.FritzCall.fritzphonebook.value = False
self.list.append(getConfigListEntry(_("Use internal PhoneBook"), config.plugins.FritzCall.phonebook))
if config.plugins.FritzCall.phonebook.value:
if config.plugins.FritzCall.lookup.value:
self.list.append(getConfigListEntry(_("Automatically add new Caller to PhoneBook"), config.plugins.FritzCall.addcallers))
self.list.append(getConfigListEntry(_("PhoneBook and Faces Location"), config.plugins.FritzCall.phonebookLocation))
if config.plugins.FritzCall.phonebook.value or config.plugins.FritzCall.fritzphonebook.value:
self.list.append(getConfigListEntry(_("Reload interval for phonebooks (hours)"), config.plugins.FritzCall.reloadPhonebookTime))
if config.plugins.FritzCall.phonebook.value or config.plugins.FritzCall.fritzphonebook.value:
self.list.append(getConfigListEntry(_("Extended Search for names"), config.plugins.FritzCall.FritzExtendedSearchNames))
self.list.append(getConfigListEntry(_("Extended Search for faces"), config.plugins.FritzCall.FritzExtendedSearchFaces))
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(_("Ignore callers with no phone number"), config.plugins.FritzCall.ignoreUnknown))
self.list.append(getConfigListEntry(_("Log level"), config.plugins.FritzCall.debug))
self.list.append(getConfigListEntry(_("Make it more skin friendly"), config.plugins.FritzCall.advancedSkin))
self.list.append(getConfigListEntry(_("Use HTTPS to communicate with FRITZ!Box"), config.plugins.FritzCall.useHttps))
self["config"].list = self.list
self["config"].l.setList(self.list)
def save(self):
# debug("[FritzCallSetup]"
global fritzbox
if self["config"].getCurrent()[1] == config.plugins.FritzCall.phonebookLocation:
self.session.openWithCallback(self.LocationBoxClosed, LocationBox, _("PhoneBook and Faces Location"), currDir=config.plugins.FritzCall.phonebookLocation.value)
if fritzbox and config.plugins.FritzCall.password.isChanged():
fritzbox.password = config.plugins.FritzCall.password.value
config.plugins.FritzCall.password.value = encode(config.plugins.FritzCall.password.value)
if fritzbox and config.plugins.FritzCall.guestPassword.isChanged():
fritzbox.guestPassword = config.plugins.FritzCall.guestPassword.value
config.plugins.FritzCall.guestPassword.value = encode(config.plugins.FritzCall.guestPassword.value)
for x in self["config"].list:
# debug("Save " + repr(x[1].value))
x[1].save()
if not config.plugins.FritzCall.fwVersion.value:
Notifications.AddNotification(MessageBox, _("To enjoy more functionalities of your FRITZ!Box, configure the firmware version!"), type=MessageBox.TYPE_INFO, timeout=4)
fritzbox = FritzCallFBF.FritzCallFBF_dummy()
config.plugins.FritzCall.fritzphonebook.value = False
elif config.plugins.FritzCall.fwVersion.value == "old":
fritzbox = FritzCallFBF.FritzCallFBF()
elif config.plugins.FritzCall.fwVersion.value == "05.27":
fritzbox = FritzCallFBF.FritzCallFBF_05_27()
elif config.plugins.FritzCall.fwVersion.value == "05.50":
fritzbox = FritzCallFBF.FritzCallFBF_05_50()
elif config.plugins.FritzCall.fwVersion.value == "06.35":
# fritzbox = FritzCallFBF.FritzCallFBF_06_35()
# elif config.plugins.FritzCall.fwVersion.value == "upnp":
fritzbox = FritzCallFBF.FritzCallFBF_upnp()
else:
Notifications.AddNotification(MessageBox, _("FRITZ!Box firmware version not configured! Please set it in the configuration."), type=MessageBox.TYPE_INFO, timeout=0)
phonebook.reload()
logger.setLevel(int(config.plugins.FritzCall.debug.value))
if fritz_call:
if config.plugins.FritzCall.enable.value:
fritz_call.connect()
else:
fritz_call.shutdown()
self.close()
def LocationBoxClosed(self, path):
if path is not None:
config.plugins.FritzCall.phonebookLocation.setValue(path)
def cancel(self):
# debug("[FritzCallSetup]"
config.plugins.FritzCall.password.value = encode(config.plugins.FritzCall.password.value)
config.plugins.FritzCall.guestPassword.value = encode(config.plugins.FritzCall.guestPassword.value)
for x in self["config"].list:
x[1].cancel()
self.close()
def displayCalls(self):
if config.plugins.FritzCall.enable.value:
if fritzbox and config.plugins.FritzCall.fwVersion.value:
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 enabled"), 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 enabled"), 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.information:
self.session.open(FritzMenu)
else:
self.session.open(MessageBox, _("Cannot get infos from FRITZ!Box yet\nStill initialising or wrong firmware version"), type=MessageBox.TYPE_INFO)
else:
self.session.open(MessageBox, _("Plugin not enabled"), type=MessageBox.TYPE_INFO)
standbyMode = False
class FritzCallList(object):
def __init__(self):
self.callList = []
def add(self, event, date, number, caller, phone):
debug("[FritzCallList] %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]")
global standbyMode
standbyMode = False
# Standby.inStandby.onClose.remove(self.display) object does not exist anymore...
# build screen from call list
text = "\n"
if not self.callList: # why is this happening at all?!?!
text = _("no calls")
debug("[FritzCallList] %s", text)
return
else:
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 information
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] '%s %s %s %s'", date, caller, direction, phone)
# display screen
Notifications.AddNotification(MessageBox, text, type=MessageBox.TYPE_INFO)
self.callList = []
callList = FritzCallList()
def findFace(number, name):
# debug("[FritzCall] 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")
# debug("[FritzCall] looking for: %s" %name)
facesDir = os.path.join(config.plugins.FritzCall.phonebookLocation.value, "FritzCallFaces")
# debug("[FritzCall] looking in: %s" %facesDir)
facesFile = None
if not os.path.isdir(facesDir):
info("[FritzCall] findFace facesdir does not exist: %s", facesDir)
else:
files = os.listdir(facesDir)
# debug("[FritzCall] listdir: %s" %repr(files))
myFiles = [f for f in files if re.match(re.escape(number) + r"\.[png|PNG]", f)]
if not myFiles:
myFiles = [f for f in files if re.match(re.escape(name) + r"\.[png|PNG]", f)]
if not myFiles:
sep = name.find(' (')
if sep != -1:
name = name[:sep]
myFiles = [f for f in files if re.match(re.escape(name) + r"\.[png|PNG]", f)]
if myFiles:
# debug("[FritzCall] found: %s" %repr(myFiles))
facesFile = os.path.join(facesDir, myFiles[0])
if not facesFile and config.plugins.FritzCall.FritzExtendedSearchFaces.value:
for k in range(len(number) - 1, 0, -1):
# debug("[FritzCall] extended search: %s" %number[:k])
myFiles = [f for f in files if re.match(re.escape(number[:k]) + r"\.[png|PNG]", f)]
if myFiles:
facesFile = os.path.join(facesDir, myFiles[0])
break
if not facesFile:
if DESKTOP_WIDTH <= 720:
facesFile = resolveFilename(SCOPE_CURRENT_PLUGIN, "Extensions/FritzCall/images/no-face-sd.png")
elif DESKTOP_WIDTH <= 1280:
facesFile = resolveFilename(SCOPE_CURRENT_PLUGIN, "Extensions/FritzCall/images/no-face-hd.png")
elif DESKTOP_WIDTH <= 1920:
facesFile = resolveFilename(SCOPE_CURRENT_PLUGIN, "Extensions/FritzCall/images/no-face-fhd.png")
else:
facesFile = resolveFilename(SCOPE_CURRENT_PLUGIN, "Extensions/FritzCall/images/no-face-uhd.png")
info("[FritzCall] result: %s", __(facesFile))
return facesFile
class MessageBoxPixmap(Screen):
def __init__(self, session, text, number="", name="", timeout=-1):
if not config.plugins.FritzCall.advancedSkin.value:
self.skin = """
""" % (
# scaleH(350, 60), scaleV(175, 245),
scaleV(25, 22), resolveFilename(SCOPE_CURRENT_SKIN, "skin_default/icons/input_info.png")
)
debug("[FritzCall] MessageBoxPixmap number: %s", number)
else:
if DESKTOP_WIDTH <= 720:
self.skin = """
"""
elif DESKTOP_WIDTH <= 1280:
self.skin = """
"""
elif DESKTOP_WIDTH <= 1920:
self.skin = """
"""
else:
self.skin = """
"""
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):
debug("[FritzCall] MessageBoxPixmap/setInfoPixmap number: %s/%s", self._number, self._name)
self.setTitle(_("New call"))
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)
if DESKTOP_WIDTH <= 720:
picPixmap = LoadPixmap(resolveFilename(SCOPE_CURRENT_PLUGIN, "Extensions/FritzCall/images/no-face-error-sd.png"))
elif DESKTOP_WIDTH <= 1280:
picPixmap = LoadPixmap(resolveFilename(SCOPE_CURRENT_PLUGIN, "Extensions/FritzCall/images/no-face-error-hd.png"))
elif DESKTOP_WIDTH <= 1920:
picPixmap = LoadPixmap(resolveFilename(SCOPE_CURRENT_PLUGIN, "Extensions/FritzCall/images/no-face-error-fhd.png"))
else:
picPixmap = LoadPixmap(resolveFilename(SCOPE_CURRENT_PLUGIN, "Extensions/FritzCall/images/no-face-error-uhd.png"))
picSize = picPixmap.size()
self["InfoPixmap"].instance.setPixmap(picPixmap)
if config.plugins.FritzCall.advancedSkin.value:
debug("skip layout manipulation")
return
# 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)
self["InfoPixmap"].instance.setPixmap(picPixmap)
# 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()
# newer OE versions don't have the callback
try:
self._timer_conn = self._timer.timeout.connect(self._timerTick)
except AttributeError:
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()
def runUserActionScript(event, date, number, caller, phone):
# user exit
# call FritzCallserAction.sh in the same dir as Phonebook.json with the following parameters:
# event: "RING" (incomning) or "CALL" (outgoing)
# date of event, format: "dd.mm.yy hh.mm.ss"
# telephone number which is calling/is called
# caller's name and address, format Name\n Street\n ZIP City
# line/number which is called/which is used for calling
userActionScript = os.path.join(config.plugins.FritzCall.phonebookLocation.value, "FritzCallUserAction.sh")
if os.path.exists(userActionScript) and os.access(userActionScript, os.X_OK):
cmd = userActionScript + ' "' + event + '" "' + date + '" "' + number + '" "' + caller + '" "' + phone + '"'
info("[FritzCall] calling: %s", cmd)
eConsoleAppContainer().execute(cmd)
userActionList = [runUserActionScript]
def registerUserAction(fun):
#===========================================================================
# other plugins can register a function, which is then called for each displayed call
# it must take the arguments event,date,number,caller,phone
#
# example:
# def FritzCallEvent(event,date,number,caller,phone):
# ......
#
# try:
# from Plugins.Extensions.FritzCall.plugin import registerUserAction as FritzCallRegisterUserAction
# FritzCallRegisterUserAction(FritzCallEvent)
# except:
# print "import of FritzCall failed"
#===========================================================================
info("[FritzCall] register: %s", fun.__name__)
userActionList.append(fun)
mutedOnConnID = None
def notifyCall(event, date, number, caller, phone, connID): # @UnusedVariable # pylint: disable=W0613
if Standby.inStandby is None or config.plugins.FritzCall.afterStandby.value == "each":
if event == "RING":
text = _("Incoming Call on %(date)s at %(time)s from\n---------------------------------------------\n%(number)s\n%(caller)s\n---------------------------------------------\nto: %(phone)s") % {'date': date[:8], 'time': date[9:], 'number': number, 'caller': caller, 'phone': phone}
else:
text = _("Outgoing Call on %(date)s at %(time)s to\n---------------------------------------------\n%(number)s\n%(caller)s\n---------------------------------------------\nfrom: %(phone)s") % {'date': date[:8], 'time': date[9:], 'number': number, 'caller': caller, 'phone': phone}
info("[FritzCall]\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)
info("[FritzCall] added to callList")
else: # this is the "None" case
info("[FritzCall] standby and no show")
for fun in userActionList:
info("[FritzCall] call user action: %s", fun.__name__)
fun(event, date, number, caller, phone)
#===============================================================================
# We need a separate class for each invocation of reverseLookup to retain
# the necessary data for the notification
#===============================================================================
countries = {}
reverselookupMtime = 0
class FritzReverseLookupAndNotifier(object):
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
'''
info("[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.countrycode.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
'''
info("[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")
if self.number != 0 and config.plugins.FritzCall.addcallers.value:
info("[FritzReverseLookupAndNotifier] add to phonebook")
phonebook.add(self.number, self.caller)
else:
name = resolveNumberWithAvon(self.number, config.plugins.FritzCall.countrycode.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): # pylint: disable=W0223
def __init__(self):
info("[FritzProtocol] " + "$Revision: 1553 $"[1:-1] + "$Date: 2019-04-25 09:36:05 +0200 (Thu, 25 Apr 2019) $"[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]")
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 pauseEnigma2(self):
# debug("")
# getPage("http://127.0.0.1/web/remotecontrol?command=164").addCallback(self.pauseEnigma2_cb).addErrback(self.pauseEnigma2_eb)
#
# def pauseEnigma2_cb(self, result):
# debug(repr(result))
#
# def pauseEnigma2_eb(self, result):
# debug(repr(result))
def lineReceived(self, line):
debug("[FritzProtocol] %s", line)
# 15.07.06 00:38:54;CALL;1;4;;;
# 15.07.06 00:38:58;DISCONNECT;1;0;
# 15.07.06 00:39:22;RING;0;;;
# 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(",")
filtermsns = [i.strip() for i in filtermsns]
debug("Filtermsns: %s", filtermsns)
if config.plugins.FritzCall.ignoreUnknown.value:
if self.event == "RING":
if not anEvent[3]:
debug("[FritzProtocol] call from unknown phone; skipping")
return
elif not anEvent[5]:
debug("[FritzProtocol] call to unknown phone; skipping")
return
# debug("[FritzProtocol] Volcontrol dir: %s" % dir(eDVBVolumecontrol.getInstance()))
# debug("[FritzCall] unmute on connID: %s?" %self.connID)
global mutedOnConnID
phone = anEvent[4]
debug("Phone: %s", phone)
if Standby.inStandby is None and not mutedOnConnID:
if not (config.plugins.FritzCall.filter.value and phone not in filtermsns):
info("[FritzCall] check mute")
if (self.event == "RING" and config.plugins.FritzCall.muteOnCall.value) or (self.event == "CALL" and config.plugins.FritzCall.muteOnOutgoingCall.value):
info("[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"]()
# self.pauseEnigma2()
if self.event == "DISCONNECT"and (config.plugins.FritzCall.muteOnCall.value or config.plugins.FritzCall.muteOnOutgoingCall.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"]()
# self.pauseEnigma2()
# 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.showOutgoingCalls.value):
if self.event == "RING":
number = anEvent[3]
else:
number = anEvent[5]
if fritzbox and fritzbox.blacklist and not config.plugins.FritzCall.showBlacklistedCalls.value:
if self.event == "RING":
if number in fritzbox.blacklist[0]:
info("[FritzProtocol] phone: '''%s''' blacklisted number: '''%s'''", phone, number)
return
else:
if number in fritzbox.blacklist[1]:
info("[FritzProtocol] phone: '''%s''' blacklisted number: '''%s'''", phone, number)
return
info("[FritzProtocol] phone: '''%s''' number: '''%s'''", phone, number)
if not (config.plugins.FritzCall.filter.value and phone not in filtermsns):
debug("[FritzProtocol] 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] 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] 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] 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.countrycode.value)
info("[FritzProtocol] phonebook.search: %s", self.number)
self.caller = phonebook.search(self.number)
info("[FritzProtocol] phonebook.search result: %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):
def __init__(self):
self.hangup_ok = False
# self.initialDelay = 20
# self.maxDelay = 30
self.maxRetries = 5
def startedConnecting(self, connector): # @UnusedVariable # pylint: disable=W0613
#=======================================================================
# if not config.plugins.FritzCall.fwVersion.value:
# Notifications.AddNotification(MessageBox, _("FRITZ!Box firmware version not configured! Please set it in the configuration."), type=MessageBox.TYPE_INFO, timeout=0)
#=======================================================================
if config.plugins.FritzCall.connectionVerbose.value == "on":
info("[FRITZ!FritzClientFactory]")
Notifications.AddNotification(MessageBox, _("Connecting to FRITZ!Box..."), type=MessageBox.TYPE_INFO, timeout=2)
def buildProtocol(self, addr): # @UnusedVariable # pylint: disable=W0613
global fritzbox
if config.plugins.FritzCall.connectionVerbose.value == "on":
info("[FRITZ!FritzClientFactory]")
Notifications.AddNotification(MessageBox, _("Connected to FRITZ!Box!"), type=MessageBox.TYPE_INFO, timeout=4)
self.resetDelay()
# initDebug()
initCbC()
initAvon()
try:
decode(config.plugins.FritzCall.password.value)
except binascii.Error:
Notifications.AddNotification(MessageBox, _("There might be a problem with your FritzCall %spassword.\nCheck in the configuration.") % "", type=MessageBox.TYPE_WARNING)
config.plugins.FritzCall.password.value = encode(config.plugins.FritzCall.password.value)
config.plugins.FritzCall.password.save()
try:
decode(config.plugins.FritzCall.guestPassword.value)
except binascii.Error:
Notifications.AddNotification(MessageBox, _("There might be a problem with your FritzCall %spassword.\nCheck in the configuration.") % _("guest "), type=MessageBox.TYPE_WARNING)
config.plugins.FritzCall.guestPassword.value = encode(config.plugins.FritzCall.guestPassword.value)
config.plugins.FritzCall.guestPassword.save()
if not config.plugins.FritzCall.fwVersion.value:
Notifications.AddNotification(MessageBox, _("To enjoy more functionalities of your FRITZ!Box, configure the firmware version!"), type=MessageBox.TYPE_INFO, timeout=4)
fritzbox = FritzCallFBF.FritzCallFBF_dummy()
config.plugins.FritzCall.fritzphonebook.value = False
elif config.plugins.FritzCall.fwVersion.value == "old":
fritzbox = FritzCallFBF.FritzCallFBF()
elif config.plugins.FritzCall.fwVersion.value == "05.27":
fritzbox = FritzCallFBF.FritzCallFBF_05_27()
elif config.plugins.FritzCall.fwVersion.value == "05.50":
fritzbox = FritzCallFBF.FritzCallFBF_05_50()
elif config.plugins.FritzCall.fwVersion.value == "06.35":
# fritzbox = FritzCallFBF.FritzCallFBF_06_35()
# elif config.plugins.FritzCall.fwVersion.value == "upnp":
fritzbox = FritzCallFBF.FritzCallFBF_upnp()
else:
fritzbox = None
Notifications.AddNotification(MessageBox, _("FRITZ!Box firmware version not configured! Please set it in the configuration."), type=MessageBox.TYPE_INFO, timeout=0)
phonebook.reload()
return FritzProtocol()
def clientConnectionLost(self, connector, reason):
global fritzbox
if not self.hangup_ok and config.plugins.FritzCall.connectionVerbose.value != "off":
warn("[FRITZ!FritzClientFactory] - clientConnectionLost")
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)
fritzbox = None
def clientConnectionFailed(self, connector, reason):
global fritzbox
if config.plugins.FritzCall.connectionVerbose.value != "off":
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)
fritzbox = None
class FritzCall(object):
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=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=W0613
if config.plugins.FritzCall.enable.value:
if fritzbox and config.plugins.FritzCall.fwVersion.value:
session.open(FritzDisplayCalls)
else:
Notifications.AddNotification(MessageBox, _("Cannot get calls from FRITZ!Box"), type=MessageBox.TYPE_INFO)
else:
Notifications.AddNotification(MessageBox, _("Plugin not enabled"), type=MessageBox.TYPE_INFO)
def displayPhonebook(session, servicelist=None): # @UnusedVariable # pylint: disable=W0613
if phonebook:
if config.plugins.FritzCall.enable.value:
session.open(phonebook.FritzDisplayPhonebook)
else:
Notifications.AddNotification(MessageBox, _("Plugin not enabled"), type=MessageBox.TYPE_INFO)
else:
Notifications.AddNotification(MessageBox, _("No phonebook"), type=MessageBox.TYPE_INFO)
def displayFBFStatus(session, servicelist=None): # @UnusedVariable # pylint: disable=W0613
if config.plugins.FritzCall.enable.value:
if fritzbox and fritzbox.information:
session.open(FritzMenu)
else:
Notifications.AddNotification(MessageBox, _("Cannot get infos from FRITZ!Box yet\nStill initialising or wrong firmware version"), type=MessageBox.TYPE_INFO)
else:
Notifications.AddNotification(MessageBox, _("Plugin not enabled"), type=MessageBox.TYPE_INFO)
def main(session, **kwargs): # @UnusedVariable pylint: disable=W0613
session.open(FritzCallSetup)
fritz_call = None
def autostart(reason, **kwargs):
global fritz_call
# ouch, this is a hack
if "session" in kwargs:
global my_global_session
my_global_session = kwargs["session"]
return
info("[FRITZ!Call]")
if reason == 0:
if not fritz_call:
fritz_call = FritzCall()
elif reason == 1:
fritz_call.shutdown()
fritz_call = None
def Plugins(**kwargs): # @UnusedVariable # pylint: disable=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)]