verbunden seit ([^<]*) ', html, re.S)
if found:
upTime = found.group(1)
self.debug("[FritzCallFBF_05_27] _okGetInfo upTime: " + upTime)
found = re.match(r'.*IP-Adresse: ([^<]*)', html, re.S)
if found:
ipAddress = found.group(1)
self.debug("[FritzCallFBF_05_27] _okGetInfo ipAddress: " + ipAddress)
# wlanstate = [ active, encrypted, no of devices ]
found = re.match(r'.*
WLAN (aus|an)(|, gesichert) ', html, re.S)
if found:
if found.group(1) == "led_green":
if found.group(2):
wlanState = ['1', '1', '']
else:
wlanState = ['1', '0', '']
else:
wlanState = ['0', '0', '0']
self.debug("[FritzCallFBF_05_27] _okGetInfo wlanState: " + repr(wlanState))
found = re.match(r'.*', html, re.S)
if found:
if found.group(1) == "led_green":
dslState = ['5', None, None]
found = re.match(r'.*DSL bereit, ([^<]*) ([^<]*) ', html, re.S)
if found:
dslState[1] = found.group(1) + "/" + found.group(2)
else:
dslState = ['0', None, None]
self.debug("[FritzCallFBF_05_27] _okGetInfo dslState: " + repr(dslState))
found = re.match(r'.*
Anrufbeantworter ([\d]+) aktiv([^<]*) ', html, re.S)
if found:
# found.group(2) could be ', neue Nachrichten vorhanden'; ignore for now
tamActive = [found.group(1), False, False, False, False, False]
self.debug("[FritzCallFBF_05_27] _okGetInfo tamActive: " + repr(tamActive))
found = re.match(r'.*
DECT an, (ein|\d*) Schnurlostelefon', html, re.S)
if found:
dectActive = found.group(1)
self.debug("[FritzCallFBF_05_27] _okGetInfo dectActive: " + repr(dectActive))
found = re.match(r'.* Integriertes Fax aktiv ', html, re.S)
if found:
faxActive = True
self.debug("[FritzCallFBF_05_27] _okGetInfo faxActive: " + repr(faxActive))
found = re.match(r'.* Rufumleitung deaktiviert ', html, re.S)
if found:
rufumlActive = False
else:
rufumlActive = True
self.debug("[FritzCallFBF_05_27] _okGetInfo rufumlActive: " + repr(rufumlActive))
info = (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive, guestAccess)
self.debug("[FritzCallFBF_05_27] _okGetInfo information: " + str(info))
self.information = info
if callback:
callback(info)
def _okSetDect(self, callback, html): # @UnusedVariable pylint: disable=W0613
return
def _okSetConInfo(self, callback, html): # @UnusedVariable pylint: disable=W0613
return
def _okSetWlanState(self, callback, html): # @UnusedVariable pylint: disable=W0613
return
def _okSetDslState(self, callback, html): # @UnusedVariable pylint: disable=W0613
return
def _errorGetInfo(self, error):
self.debug("[FritzCallFBF_05_27] _errorGetInfo: %s", error)
text = _("FRITZ!Box - Error getting status: %s") % error.getErrorMessage()
self._notify(text)
return
def reset(self):
self._login(self._reset)
def _reset(self, html):
# POSTDATA=getpage=../html/reboot.html&errorpage=../html/de/menus/menu2.html&var:lang=de&var:pagename=home&var:errorpagename=home&var:menu=home&var:pagemaster=&time:settings/time=1242207340%2C-120&var:tabReset=0&logic:command/reboot=../gateway/commands/saveconfig.html
if html:
#===================================================================
# found = re.match(r'.*
FEHLER: ([^<]*)
', html, re.S)
# if found:
# self._errorReset('Login: ' + found.group(1))
# return
#===================================================================
start = html.find('
FEHLER: ')
if start != -1:
start = start + len('
FEHLER: ')
self._errorReset('Login: ' + html[start, html.find('
', start)])
return
if self._callScreen:
self._callScreen.close()
url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
parms = urlencode({
'getpage': '../html/reboot.html',
'var:lang': 'de',
'var:pagename': 'reset',
'var:menu': 'system',
'logic:command/reboot': '../gateway/commands/saveconfig.html',
'sid': self._md5Sid
})
self.debug("[FritzCallFBF_05_27] _reset url: '" + url + "' parms: '" + parms + "'")
getPage(url,
method="POST",
agent=USERAGENT,
headers={
'Content-Type': "application/x-www-form-urlencoded",
'Content-Length': str(len(parms))},
postdata=parms)
def _okReset(self, html): # @UnusedVariable # pylint: disable=W0613
self.debug("[FritzCallFBF_05_27] _okReset")
def _errorReset(self, error):
self.debug("[FritzCallFBF_05_27] _errorReset: %s", error)
text = _("FRITZ!Box - Error resetting: %s") % error.getErrorMessage()
self._notify(text)
def _readBlacklist(self):
# http://fritz.box/cgi-bin/webcm?getpage=../html/de/menus/menu2.html&var:lang=de&var:menu=fon&var:pagename=sperre
url = "http://%s/fon_num/sperre.lua" % config.plugins.FritzCall.hostname.value
parms = urlencode({
'sid': self._md5Sid
})
self.debug("[FritzCallFBF_05_27] _readBlacklist url: '" + url + "' parms: '" + parms + "'")
getPage(url,
method="POST",
agent=USERAGENT,
headers={
'Content-Type': "application/x-www-form-urlencoded",
'Content-Length': str(len(parms))},
postdata=parms).addCallback(self._okBlacklist).addErrback(self._errorBlacklist)
def _okBlacklist(self, html):
self.debug("[FritzCallFBF_05_27] _okBlacklist")
#=======================================================================
# linkP = open("/tmp/FritzCallBlacklist.htm", "w")
# linkP.write(html)
# linkP.close()
#=======================================================================
entries = re.compile(r'
(Ankommende|Ausgehende) Rufe ([\d]+) ', re.S).finditer(html)
self.blacklist = ([], [])
for entry in entries:
if entry.group(1) == "Ankommende":
self.blacklist[0].append(entry.group(2))
else:
self.blacklist[1].append(entry.group(2))
self.debug("[FritzCallFBF_05_27] _okBlacklist: %s", repr(self.blacklist))
def _errorBlacklist(self, error):
self.debug("[FritzCallFBF_05_27] _errorBlacklist: %s", error)
text = _("FRITZ!Box - Error getting blacklist: %s") % error.getErrorMessage()
self._notify(text)
class FritzCallFBF_05_50(object):
logger = logging.getLogger("FritzCall.FBF_05_50")
debug = logger.debug
info = logger.info
warning = logger.warning
error = logger.error
exception = logger.exception
def __init__(self):
self.debug("")
self._callScreen = None
self._callType = config.plugins.FritzCall.fbfCalls.value
self.password = decode(config.plugins.FritzCall.password.value)
self.guestPassword = decode(config.plugins.FritzCall.guestPassword.value)
self._phoneBookID = '0'
self.blacklist = ([], [])
self.information = None # (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, guestAccess)
self.phonebook = None
self.getInfo(None)
# self.readBlacklist() now in getInfo
def _notify(self, text):
self.debug(text)
if self._callScreen:
self.debug("try to close callScreen")
self._callScreen.close()
self._callScreen = None
Notifications.AddNotification(MessageBox, text, type=MessageBox.TYPE_ERROR, timeout=config.plugins.FritzCall.timeout.value)
def _login(self, callback=None):
# http://fritz.box/login_lua.xml
url = "http://%s/login_sid.lua" % (config.plugins.FritzCall.hostname.value)
self.debug(time.ctime() + " :" + url)
getPage(url,
method="GET",
headers={'Content-Type': "application/x-www-form-urlencoded"}).addCallback(self._md5Login, callback).addErrback(self._errorLogin)
def _md5Login(self, sidXml, callback):
def buildResponse(challenge, text):
self.debug("challenge: " + challenge + ' text: ' + __(text))
text = (challenge + '-' + text).decode('utf-8', 'ignore').encode('utf-16-le')
for i in range(len(text)): # consider-using-enumerate # pylint: disable=
if ord(text[i]) > 255:
text[i] = '.'
md5 = hashlib.md5()
md5.update(text) # pylint: disable=e1101
self.debug(md5.hexdigest())
return challenge + '-' + md5.hexdigest()
#=======================================================================
# linkP = open("/tmp/FritzDebug_sid.xml", "w")
# linkP.write(sidXml)
# linkP.close()
#=======================================================================
self.debug("")
sidX = ET.fromstring(sidXml)
#===========================================================================
# self._md5Sid = sidX.find("SID").text
# if self._md5Sid:
# self.debug("SID "+ self._md5Sid)
# else:
# self.debug("no sid! That must be an old firmware.")
# self._notify(_("FRITZ!Box - Error logging in\n\n") + _("wrong firmware version?"))
# return
#
# if self._md5Sid != "0000000000000000":
# self.debug("SID "+ self._md5Sid)
# for callback in self._loginCallbacks:
# self.debug("calling " + callback.__name__)
# callback(None)
# self._loginCallbacks = []
# return
#===========================================================================
challenge = sidX.find("Challenge").text
if challenge:
self.debug("challenge " + challenge)
else:
self.error("login necessary and no challenge! That is terribly wrong.")
parms = urlencode({
'username': config.plugins.FritzCall.username.value,
'response': buildResponse(challenge, self.password),
})
url = "http://%s/login_sid.lua" % (config.plugins.FritzCall.hostname.value)
self.debug(url + "?" + parms)
getPage(url,
method="POST",
agent=USERAGENT,
headers={'Content-Type': "application/x-www-form-urlencoded", 'Content-Length': str(len(parms))},
postdata=parms).addCallback(self._gotPageLogin, callback).addErrback(self._errorLogin)
def _gotPageLogin(self, sidXml, callback):
if self._callScreen:
self._callScreen.updateStatus(_("login verification"))
#=======================================================================
# linkP = open("/tmp/sid.xml", "w")
# linkP.write(sidXml)
# linkP.close()
#=======================================================================
sidX = ET.fromstring(sidXml)
md5Sid = sidX.find("SID").text
if md5Sid and md5Sid != "0000000000000000":
self.logger.debug("found sid: " + md5Sid)
else:
self.error("found no sid")
self._notify(_("FRITZ!Box - Error logging in\n\n") + _("wrong user or password?"))
return
if self._callScreen:
self._callScreen.updateStatus(_("login ok"))
self.debug("calling " + callback.__name__)
callback(md5Sid)
def _errorLogin(self, error):
global fritzbox # global-variable-undefined # pylint: disable=W0601
if type(error).__name__ == "str":
text = error
else:
text = error.getErrorMessage()
text = _("FRITZ!Box - Error logging in: %s\nDisabling plugin.") % text
fritzbox = None
self.exception(error)
self._notify(text)
def _logout(self, md5Sid, what):
parms = urlencode({
'sid': md5Sid,
'logout': 'bye bye Fritz'
})
url = "http://%s/login_sid.lua" % (config.plugins.FritzCall.hostname.value)
self.debug("(" + what + ") " + time.ctime() + ": " + url + "?" + parms)
getPage(url,
method="POST",
agent=USERAGENT,
headers={'Content-Type': "application/x-www-form-urlencoded", 'Content-Length': str(len(parms))},
postdata=parms).addErrback(self._errorLogout)
def _errorLogout(self, error):
self.exception(error)
text = _("FRITZ!Box - Error logging out: %s") % error.getErrorMessage()
self._notify(text)
def loadFritzBoxPhonebook(self, phonebook):
self.phonebook = phonebook
self._login(self._selectFritzBoxPhonebook)
def _selectFritzBoxPhonebook(self, md5Sid, html=None): # @UnusedVariable pylint: disable=W0613
parms = urlencode({
'sid': md5Sid,
})
url = "http://%s/fon_num/fonbook_select.lua" % (config.plugins.FritzCall.hostname.value)
self.debug(url + "?" + parms)
getPage(url,
method="POST",
agent=USERAGENT,
headers={'Content-Type': "application/x-www-form-urlencoded", 'Content-Length': str(len(parms))},
postdata=parms).addCallback(self._loadFritzBoxPhonebook, md5Sid).addErrback(self._errorLoad, md5Sid)
def _loadFritzBoxPhonebook(self, html, md5Sid):
# Firmware 05.27 onwards
# look for phonebook called [dD]reambox and get bookid
found = re.match(r'.*' + config.plugins.FritzCall.fritzphonebookName.value, html, re.S)
if found:
bookid = found.group(1)
else:
bookid = 1
self.debug("phonebook %s", bookid)
# http://192.168.178.1/fon_num/fonbook_list.lua?sid=2faec13b0000f3a2
parms = urlencode({
'bookid': bookid,
'sid': md5Sid,
'cancel': '',
'apply': 'uiApply',
})
url = "http://%s/fon_num/fonbook_select.lua" % (config.plugins.FritzCall.hostname.value)
self.debug(url + "?" + parms)
getPage(url,
method="POST",
agent=USERAGENT,
headers={'Content-Type': "application/x-www-form-urlencoded", 'Content-Length': str(len(parms))},
postdata=parms).addCallback(self._parseFritzBoxPhonebook, md5Sid).addErrback(self._errorLoad, md5Sid)
def _parseFritzBoxPhonebook(self, html, md5Sid):
self.debug("")
# first, let us get the charset
found = re.match(r'.* ', html, re.S)
if found:
charset = found.group(1)
self.debug("found charset: " + charset)
if charset != 'utf-8':
html = html2unicode(html.replace(chr(0xf6), '').decode(charset)).encode('utf-8')
else: # this is kind of emergency conversion...
try:
self.debug("try charset utf-8")
charset = 'utf-8'
html = html2unicode(html.decode('utf-8')).encode('utf-8') # this looks silly, but has to be
except UnicodeDecodeError:
self.debug("try charset iso-8859-1")
charset = 'iso-8859-1'
html = html2unicode(html.decode('iso-8859-1')).encode('utf-8') # this looks silly, but has to be
# cleanout hrefs
html = re.sub("]*>", "", html)
html = re.sub(" ", "", html)
#=======================================================================
# linkP = open("/tmp/FritzCall_Phonebook.htm", "w")
# linkP.write(html)
# linkP.close()
#=======================================================================
if html.find('class="zebra_reverse"') != -1:
entrymask = re.compile(r'[^<]* ([^<]+(?: [^<]+)*) ([^<]+(?: [^<]+)*) ([^<]*(?: [^<]*)*) ([^<]*(?: [^<]*)*) ', re.S)
entries = entrymask.finditer(html)
for found in entries:
# self.info("processing entry for '''%s'''" % repr(found.groups()))
name = html2unicode(re.sub(",", "", found.group(1)))
thisnumbers = found.group(2).split(" ")
thistypes = found.group(3).split(" ")
thiscodes = found.group(4).split(" ")
thisvanitys = found.group(5).split(" ")
for i in range(len(thisnumbers)): # consider-using-enumerate # pylint: disable=
if len(thisnumbers[i]) == 0:
continue
thisnumber = cleanNumber(thisnumbers[i])
if thisnumber in self.phonebook.phonebook:
# self.debug("Ignoring '%s' ('%s') with %s' ( have: '%s')" % (name, thistypes[i], __(thisnumber), self.phonebook.phonebook[thisnumber]))
continue
if not thisnumbers[i]:
# self.debug("Ignoring entry with empty number for '''%s'''" % (__(name)))
continue
else:
thisname = name.decode('utf-8')
if config.plugins.FritzCall.showType.value and thistypes[i]:
thisname = thisname + " (" + thistypes[i].decode('utf-8') + ")"
if config.plugins.FritzCall.showShortcut.value and thiscodes[i]:
thisname = thisname + ", " + _("Shortcut") + ": " + thiscodes[i]
if config.plugins.FritzCall.showVanity.value and thisvanitys[i]:
thisname = thisname + ", " + _("Vanity") + ": " + thisvanitys[i]
# self.debug("Adding '''%s''' with '''%s'''" % (__(thisname.strip()), __(thisnumber, False)))
# self.debug("Adding '''%s''' with '''%s'''" % (thisname.strip(), thisnumber))
# Beware: strings in phonebook.phonebook have to be in utf-8!
self.phonebook.phonebook[thisnumber] = thisname.encode('utf-8')
else:
self._notify(_("Could not parse FRITZ!Box Phonebook entry"))
self._logout(md5Sid, "_parseFritzBoxPhonebook")
def _errorLoad(self, error, md5Sid):
self.exception(error)
text = _("FRITZ!Box - ") + _("Could not load phonebook: %s") % error.getErrorMessage()
self._notify(text)
self._logout(md5Sid, "_errorLoad")
def getCalls(self, callScreen, callback, callType):
#
# FW 05.27 onwards
#
self.debug("")
self._callScreen = callScreen
self._callType = callType
self._login(lambda md5Sid: self._getCalls(callback, md5Sid))
def _getCalls(self, callback, md5Sid): # pylint: disable=W0613
self.debug("")
if self._callScreen:
self._callScreen.updateStatus(_("preparing"))
# besser csv mit: https://fritz.box/fon_num/foncalls_list.lua?sid=dea373c2d0257a41&csv=
parms = urlencode({'sid': md5Sid, 'csv': ''})
url = "http://%s/fon_num/foncalls_list.lua?%s" % (config.plugins.FritzCall.hostname.value, parms)
getPage(url).addCallback(lambda x: self._gotPageCalls(callback, x, md5Sid)).addErrback(self._errorCalls, md5Sid)
def _gotPageCalls(self, callback, csvString="", md5Sid=""):
self.debug("")
if self._callScreen:
self._callScreen.updateStatus(_("finishing"))
callListL = []
if config.plugins.FritzCall.filter.value and config.plugins.FritzCall.filterCallList.value:
filtermsns = [x.strip() for x in config.plugins.FritzCall.filtermsn.value.split(",")]
self.info("filtermsns %s", repr(list(map(__, filtermsns))))
else:
filtermsns = None
#=======================================================================
# linkP = open("/tmp/FritzCalls.csv", "w")
# linkP.write(csvString)
# linkP.close()
#=======================================================================
# 0: direct; 1: date; 2: Name; 3: Nummer; 4: Nebenstelle; 5: Eigene Rufnumme; 6: Dauer
calls = csv.reader(StringIO(csvString), delimiter=';')
next(calls) # skip sep
next(calls) # skip header line
for call in calls:
if len(call) != 7:
self.warning("skip %s len: %s", repr(call), str(len(call)))
continue
direct = call[0]
if direct == '1':
direct = FBF_IN_CALLS
elif direct == '4':
direct = FBF_OUT_CALLS
elif direct == '2':
direct = FBF_MISSED_CALLS
elif direct == '3':
direct = FBF_BLOCKED_CALLS
if self._callType != '.' and self._callType != direct:
continue
date = call[1]
length = call[6]
here = call[5]
start = here.find('Internet: ')
if start != -1:
start += len('Internet: ')
here = here[start:]
if filtermsns and here not in filtermsns:
# self.debug("skip %s" % (here))
continue
if call[4]:
here = resolveNumber(here, call[4] + " (" + here + ")", self.phonebook)
else:
here = resolveNumber(here, "", self.phonebook)
# self.debug("here: " + here)
number = stripCbCPrefix(call[3], config.plugins.FritzCall.countrycode.value)
if config.plugins.FritzCall.prefix.value and number and number[0] != '0': # should only happen for outgoing
number = config.plugins.FritzCall.prefix.value + number
# self.debug("number: " + number)
found = re.match(r"\d+ \((\d+)\)", call[2])
if found:
remote = resolveNumber(number, resolveNumber(found.group(1), None, self.phonebook), self.phonebook)
else:
remote = resolveNumber(number, re.sub(",", "", call[2]), self.phonebook)
# self.debug("remote. " + remote)
# self.debug("append: %s" % repr((__(number, False), date, direct, __(remote), length, __(here))))
# self.debug("append: %s" % repr((number, date, direct, remote, length, here)))
callListL.append((number, date, direct, remote, length, here))
if callback:
# self.debug("call callback with\n" + text
callback(callListL)
self._callScreen = None
self._logout(md5Sid, "_gotPageCalls")
def _errorCalls(self, error, md5Sid):
self.exception(error)
text = _("FRITZ!Box - Could not load calls: %s") % error.getErrorMessage()
self._notify(text)
self._logout(md5Sid, "_errorCalls")
def dial(self, number):
''' initiate a call to number '''
self._login(lambda md5Sid: self._dial(number, md5Sid))
def _dial(self, number, md5Sid):
url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
parms = urlencode({
'getpage': '../html/de/menus/menu2.html',
'var:pagename': 'fonbuch',
'var:menu': 'home',
'telcfg:settings/UseClickToDial': '1',
'telcfg:settings/DialPort': config.plugins.FritzCall.extension.value,
'telcfg:command/Dial': number,
'sid': md5Sid
})
self.info("url: " + url + "?" + parms)
getPage(url,
method="POST",
agent=USERAGENT,
headers={
'Content-Type': "application/x-www-form-urlencoded",
'Content-Length': str(len(parms))},
postdata=parms).addCallback(self._okDial, md5Sid).addErrback(self._errorDial, md5Sid)
def _okDial(self, html, md5Sid): # @UnusedVariable # pylint: disable=W0613
self.debug("")
if html:
found = re.match(r'.*([^<]*)
', html, re.S)
if found:
self._notify(found.group(1))
self._logout(md5Sid, "_okDial")
def _errorDial(self, error, md5Sid):
self.exception(error)
text = _("FRITZ!Box - Dialling failed: %s") % error.getErrorMessage()
self._notify(text)
self._logout(md5Sid, "_errorDial")
def changeWLAN(self, statusWLAN, callback):
''' get status information from FBF '''
self.debug("")
#=======================================================================
# Notifications.AddNotification(MessageBox, _("not available with this firmware version"), type=MessageBox.TYPE_ERROR, timeout=config.plugins.FritzCall.timeout.value)
# return
#=======================================================================
if not statusWLAN or (statusWLAN != '1' and statusWLAN != '0'):
return
self._login(lambda md5Sid: self._changeWLAN(statusWLAN, callback, md5Sid))
def _changeWLAN(self, statusWLAN, callback, md5Sid):
if statusWLAN == '0':
parms = urlencode({
'sid': md5Sid,
'apply': '',
'cancel': '',
'btn_refresh': ''
})
else:
parms = urlencode({
'sid': md5Sid,
'active': 'on',
'active_24': 'on',
'active_5': 'on',
'hidden_ssid': 'on',
'apply': '',
'cancel': '',
'btn_refresh': ''
})
url = "http://%s//wlan/wlan_settings.lua" % config.plugins.FritzCall.hostname.value
self.debug("url: " + url + "?" + parms)
getPage(url,
method="POST",
agent=USERAGENT,
headers={
'Content-Type': "application/x-www-form-urlencoded"},
postdata=parms).addCallback(self._okChangeWLAN, callback, md5Sid).addErrback(self._errorChangeWLAN, md5Sid)
def _okChangeWLAN(self, html, callback, md5Sid): # @UnusedVariable # pylint: disable=W0613
self.debug("")
if html:
found = re.match(r'.*([^<]*)
', html, re.S)
if found:
self._notify(found.group(1))
callback()
self._logout(md5Sid, "_okChangeWLAN")
def _errorChangeWLAN(self, error, md5Sid):
self.exception(error)
text = _("FRITZ!Box - Failed changing WLAN: %s") % error.getErrorMessage()
self._notify(text)
self._logout(md5Sid, "_errorChangeWLAN")
def changeGuestAccess(self, statusGuestAccess, callback):
self.debug("")
# if not statusGuestAccess:
# return
self._login(lambda md5Sid: self._changeGuestAccessWLAN(statusGuestAccess, callback, md5Sid))
def _changeGuestAccessWLAN(self, statusGuestAccess, callback, md5Sid):
parms = {
'sid': md5Sid,
'autoupdate': 'on',
'btnSave': '',
'btnChancel': ''
}
if statusGuestAccess.find('WLAN') != -1:
parms.update({
'print': '',
})
else:
parms.update({
'activate_guest_access': 'on',
'guest_ssid': config.plugins.FritzCall.guestSSID.value,
'disconnect_guest_access': 'on',
})
if config.plugins.FritzCall.guestUptime.value:
parms.update({
'down_time_activ': 'on',
'down_time_value': config.plugins.FritzCall.guestUptime.value,
'disconnect_guest_access': 'on',
})
if config.plugins.FritzCall.guestSecure.value:
parms.update({
'sec_mode': '4',
'wpa_key': self.guestPassword,
})
else:
parms.update({
'sec_mode': '5',
})
parms = urlencode(parms)
url = "http://%s/wlan/guest_access.lua" % config.plugins.FritzCall.hostname.value
self.debug("url: " + url + "?" + parms)
getPage(url,
method="POST",
agent=USERAGENT,
headers={
'Content-Type': "application/x-www-form-urlencoded"},
postdata=parms).addCallback(self._okChangeGuestAccess, callback, md5Sid).addErrback(self._errorChangeGuestAccess, md5Sid)
def _okChangeGuestAccess(self, html, callback, md5Sid): # @UnusedVariable # pylint: disable=W0613
self.debug("")
if html:
found = re.match(r'.*([^<]*)
', html, re.S)
if found:
self._notify(found.group(1))
callback()
self._logout(md5Sid, "_okChangeGuestAccess")
def _errorChangeGuestAccess(self, error, md5Sid):
self.exception(error)
text = _("FRITZ!Box - Failed changing GuestAccess: %s") % error.getErrorMessage()
self._notify(text)
self._logout(md5Sid, "_errorChangeGuestAccess")
def changeMailbox(self, whichMailbox, callback): # @UnusedVariable # pylint: disable=W0613
''' switch mailbox on/off '''
self.debug("start: " + str(whichMailbox))
Notifications.AddNotification(MessageBox, _("not available with this firmware version"), type=MessageBox.TYPE_ERROR, timeout=config.plugins.FritzCall.timeout.value)
def getInfo(self, callback):
''' get status information from FBF '''
self.debug("")
self._login(lambda md5Sid: self._getInfo(callback, md5Sid))
def _getInfo(self, callback, md5Sid):
self.debug("verify login")
self._login(self._readBlacklist)
url = "http://%s/home/home.lua" % config.plugins.FritzCall.hostname.value
parms = urlencode({
'sid': md5Sid
})
self.debug("url: " + url + "?" + parms)
getPage(url,
method="POST",
agent=USERAGENT,
headers={
'Content-Type': "application/x-www-form-urlencoded",
'Content-Length': str(len(parms))},
postdata=parms).addCallback(lambda x: self._okGetInfo(callback, x, md5Sid)).addErrback(self._errorGetInfo, md5Sid)
def _okGetInfo(self, callback, html, md5Sid):
self.debug("")
#=======================================================================
# linkP = open("/tmp/FritzCallInfo.htm", "w")
# linkP.write(html)
# linkP.close()
#=======================================================================
(boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive, guestAccess) = (None, None, None, None, None, None, None, None, None, None) # @UnusedVariable # pylint: disable=W0613
found = re.match(r'.* ([^<]*) ([^<]*)([^<]*) ', html, re.S)
if found:
boxInfo = found.group(1) + '\n' + found.group(2) + found.group(3)
boxInfo = boxInfo.replace(' ', ' ')
self.info("Boxinfo: " + boxInfo)
found = re.match(r'.*verbunden seit ([^<]*) ', html, re.S)
if found:
upTime = found.group(1)
self.info("upTime: " + upTime)
ipAddress = ""
found = re.match(r'.*IP-Adresse: ([^<]*)', html, re.S)
if found:
ipAddress = found.group(1)
self.info("ipAddress v4: " + ipAddress)
found = re.match(r'.*IPv6-Präfix: ([^<]*)', html, re.S)
if found:
if ipAddress:
ipAddress = ipAddress + ' / ' + found.group(1)
else:
ipAddress = found.group(1)
self.info("ipAddress v6: " + ipAddress)
# dslState = [ state, information, unused ]; state == '5' means up, everything else down
found = re.match(r'.*
', html, re.S)
if found:
if found.group(1) == "led_green":
dslState = ['5', None, None]
found = re.match(r'.*(DSL|Kabel) (?:bereit|verbunden), ([^<]*) ([^<]*) ', html, re.S)
if found:
dslState[1] = found.group(2) + " / " + found.group(3)
dslState[2] = found.group(1)
else:
dslState = ['0', None, None]
self.info("dslState: " + repr(dslState))
# wlanstate = [ active, encrypted, no of devices ]
# encrypted == 2 means unknown
#
WLAN WLAN an, Funknetz: mms
found = re.match(r'.*
WLAN ([^<]*) ', html, re.S)
if found:
if found.group(1) == "led_green":
if found.group(2):
wlanState = ['1', '2', '', '']
found1 = re.match(r'.*an, ([^"]+)', found.group(2), re.S)
if not found1:
found1 = re.match(r'.*an, ([^"]+)', found.group(3), re.S)
if found1:
wlans = found1.group(1)
else:
wlanState = ['0', '0', '', '']
found = re.match(r'.*Funknetz: ([^,"]*)', wlans, re.S)
if found:
wlanState[3] = found.group(1)
found = re.match(r'.*Funknetz \(2,4 GHz\): ([^,"]*)', wlans, re.S)
if found:
wlanState[3] = "2,4GHz: " + found.group(1)
found = re.match(r'.*Funknetz \(5 GHz\): ([^,"]*)', wlans, re.S)
if found:
if wlanState[3]:
wlanState[3] = wlanState[3] + " 5GHz: " + found.group(1)
else:
wlanState[3] = "5GHz: " + found.group(1)
else:
# das ist wahrscheinlich alles falsch hier...
if found.group(3) and found.group(3).find(", gesichert") != -1:
wlanState = ['1', '1', '']
else:
wlanState = ['1', '0', '']
else:
wlanState = ['0', '0', '0']
self.info("wlanState: " + repr(wlanState))
#=======================================================================
# found = re.match(r'.*Anrufbeantworter ([\d]+) aktiv([^<]*) ', html, re.S)
# if found:
# # found.group(2) could be ', neue Nachrichten vorhanden'; ignore for now
# tamActive = [ found.group(1), False, False, False, False, False]
# self.debug("tamActive: " + repr(tamActive))
#=======================================================================
found = re.match(r'.*
DECT (?:aus|an, (ein|\d*) Schnurlostelefon)', html, re.S)
if found:
self.debug("dectActive: " + repr(found.groups()))
if found.group(1) == "led_green":
dectActive = found.group(2)
self.info("dectActive: " + repr(dectActive))
found = re.match(r'.* Faxfunktion Integriertes Fax aktiv ', html, re.S)
if found:
faxActive = True
self.info("faxActive: " + repr(faxActive))
found = re.match(r'.*Rufumleitungaktiv ', html, re.S)
if found:
rufumlActive = -1 # means no number available
self.info("rufumlActive: " + repr(rufumlActive))
guestAccess = ""
# found = re.match(r'.*WLAN-Gastzugangaktiv ([^<]*) ', html, re.S)
# if found:
# # guestAccess = "WLAN " + found.group(1)
# if found.group(1).find(", gesichert"):
# guestAccess = "WLAN (gesichert)"
# else:
# guestAccess = "WLAN (ungesichert)"
# self.debug("guestAccess WLAN: " + repr(guestAccess))
# found = re.match(r'.*LAN-Gastzugangaktiv ', html, re.S)
# if found:
# if guestAccess:
# guestAccess = guestAccess + ", LAN"
# else:
# guestAccess = "LAN"
# self.debug("guestAccess LAN: " + repr(guestAccess))
# WLAN-Gastzugangaktiv (2,4 GHz), gesichert, 29 Minuten verbleiben, 0 Geräte
# found = re.match(r'.*linktxt": "WLAN-Gastzugang",\s*"details": "aktiv \(([^\)]+)\)(, (ungesichert|gesichert))?,( (\d+) (Minuten|Stunden) verbleiben,)? (\d+ Geräte), ([^"]+)",\s*"link": "wGuest"', html, re.S)
found = re.match(r'.*WLAN-Gastzugangaktiv \(([^\)]+)\)(, (ungesichert|gesichert))?,( (\d+) (Minuten|Stunden) verbleiben,)? (\d+ Gerät(?:e)?)(, (?:Funknetz: )?([^<]+))? ', html, re.S)
if found:
# guestAccess = "WLAN " + found.group(1)
if found.group(2):
if found.group(3).find('ungesichert') != -1:
guestAccess = "WLAN (unges.)"
else:
guestAccess = "WLAN (ges.)"
else:
guestAccess = "WLAN"
# if found.group(1):
# guestAccess = guestAccess + ', ' + found.group(1).replace('\\', '')
if found.group(4):
if found.group(6) == 'Minuten':
guestAccess = guestAccess + ', ' + found.group(5) + ' Min.' # n Minuten verbleiben
else:
guestAccess = guestAccess + ', ' + found.group(5) + ' Std.' # n Stunden verbleiben
if found.group(7):
guestAccess = guestAccess + ', ' + found.group(7) # Geräte
if found.group(8):
guestAccess = guestAccess + ', ' + found.group(9) # WLAN Name
self.info("guestAccess WLAN: " + repr(guestAccess))
info = (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive, guestAccess)
self.info("Information: " + str(info))
self.information = info
if callback:
callback(info)
self._logout(md5Sid, "_okGetInfo")
def _errorGetInfo(self, error, md5Sid):
self.exception(error)
text = _("FRITZ!Box - Error getting status: %s") % error.getErrorMessage()
self._notify(text)
self._logout(md5Sid, "_errorGetInfo")
def reset(self):
self._login(self._reset)
def _reset(self, md5Sid):
if self._callScreen:
self._callScreen.close()
url = "http://%s/system/reboot.lua" % config.plugins.FritzCall.hostname.value
parms = urlencode({
'reboot': '',
'sid': md5Sid
})
self.debug("url: " + url + "?" + parms)
getPage(url,
method="POST",
agent=USERAGENT,
headers={
'Content-Type': "application/x-www-form-urlencoded"},
postdata=parms).addCallback(self._okReset, md5Sid).addErrback(self._errorReset, md5Sid)
def _okReset(self, html, md5Sid): # @UnusedVariable # pylint: disable=W0613
self.debug("")
#=======================================================================
# linkP = open("/tmp/_okReset.htm", "w")
# linkP.write(html)
# linkP.close()
#=======================================================================
if html:
found = re.match(r'.*([^<]*)
', html, re.S)
if found:
self._notify(found.group(1))
self._logout(md5Sid, "_okReset")
def _errorReset(self, error, md5Sid):
self.exception(error)
text = _("FRITZ!Box - Error resetting: %s") % error.getErrorMessage()
self._notify(text)
self._logout(md5Sid, "_errorReset")
def _readBlacklist(self, md5Sid):
# http://fritz.box/cgi-bin/webcm?getpage=../html/de/menus/menu2.html&var:lang=de&var:menu=fon&var:pagename=sperre
url = "http://%s/fon_num/sperre.lua" % config.plugins.FritzCall.hostname.value
parms = urlencode({
'sid': md5Sid
})
self.debug("url: " + url + "?" + parms)
getPage(url,
method="POST",
agent=USERAGENT,
headers={
'Content-Type': "application/x-www-form-urlencoded",
'Content-Length': str(len(parms))},
postdata=parms).addCallback(self._okBlacklist, md5Sid).addErrback(self._errorBlacklist, md5Sid)
def _okBlacklist(self, html, md5Sid):
self.debug("")
#=======================================================================
# linkP = open("/tmp/FritzCallBlacklist.htm", "w")
# linkP.write(html)
# linkP.close()
#=======================================================================
entries = re.compile(r'(Ankommende|Ausgehende) Rufe ([\d]+) ', re.S).finditer(html)
self.blacklist = ([], [])
for entry in entries:
if entry.group(1) == "Ankommende":
self.blacklist[0].append(entry.group(2))
else:
self.blacklist[1].append(entry.group(2))
entries = re.compile(r'(Ankommende|Ausgehende) Rufe ([\d]+) ', re.S).finditer(html)
for entry in entries:
if entry.group(1) == "Ankommende":
self.blacklist[0].append(entry.group(2))
else:
self.blacklist[1].append(entry.group(2))
entries = re.compile(r'(Ankommende|Ausgehende) Rufe \s+([\d]+) ', re.S).finditer(html)
for entry in entries:
if entry.group(1) == "Ankommende":
self.blacklist[0].append(entry.group(2))
else:
self.blacklist[1].append(entry.group(2))
self.debug(repr(self.blacklist))
self._logout(md5Sid, "_okBlacklist")
def _errorBlacklist(self, error, md5Sid):
self.exception(error)
text = _("FRITZ!Box - Error getting blacklist: %s") % error.getErrorMessage()
self._notify(text)
self._logout(md5Sid, "_errorBlacklist")
class FritzCallFBF_06_35(object):
logger = logging.getLogger("FritzCall.FBF_06_35")
debug = logger.debug
info = logger.info
warning = logger.warning
error = logger.error
exception = logger.exception
def __init__(self):
self.debug("")
self._callScreen = None
self._callType = config.plugins.FritzCall.fbfCalls.value
self.password = decode(config.plugins.FritzCall.password.value)
self.guestPassword = decode(config.plugins.FritzCall.guestPassword.value)
self._phoneBookID = '0'
self.blacklist = ([], [])
self.information = None # (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, guestAccess)
self.phonebook = None
self.getInfo(None)
# self.readBlacklist() now in getInfo
def _notify(self, text):
self.info(text)
if self._callScreen:
self.debug("try to close callScreen")
self._callScreen.close()
self._callScreen = None
Notifications.AddNotification(MessageBox, text, type=MessageBox.TYPE_ERROR, timeout=config.plugins.FritzCall.timeout.value)
def _login(self, callback=None):
# http://fritz.box/login_lua.xml
url = "http://%s/login_sid.lua" % (config.plugins.FritzCall.hostname.value)
self.debug(time.ctime() + " :" + url)
getPage(url,
method="GET",
headers={'Content-Type': "application/x-www-form-urlencoded"}).addCallback(self._md5Login, callback).addErrback(self._errorLogin)
def _md5Login(self, sidXml, callback):
def buildResponse(challenge, text):
self.debug("_md5Login: challenge: " + challenge + ' text: ' + __(text))
text = (challenge + '-' + text).decode('utf-8', 'ignore').encode('utf-16-le')
for i in range(len(text)): # consider-using-enumerate # pylint: disable=
if ord(text[i]) > 255:
text[i] = '.'
md5 = hashlib.md5()
md5.update(text) # pylint: disable=e1101
self.debug("_md5Login: " + md5.hexdigest())
return challenge + '-' + md5.hexdigest()
#=======================================================================
# linkP = open("/tmp/FritzDebug_sid.xml", "w")
# linkP.write(sidXml)
# linkP.close()
#=======================================================================
self.debug("")
sidX = ET.fromstring(sidXml)
#===========================================================================
# self._md5Sid = sidX.find("SID").text
# if self._md5Sid:
# self.debug("SID "+ self._md5Sid)
# else:
# self.debug("no sid! That must be an old firmware.")
# self._notify(_("FRITZ!Box - Error logging in\n\n") + _("wrong firmware version?"))
# return
#
# if self._md5Sid != "0000000000000000":
# self.debug("SID "+ self._md5Sid)
# for callback in self._loginCallbacks:
# self.debug("calling " + callback.__name__)
# callback(None)
# self._loginCallbacks = []
# return
#===========================================================================
challenge = sidX.find("Challenge").text
if challenge:
self.debug("challenge " + challenge)
else:
self.error("login necessary and no challenge! That is terribly wrong.")
parms = urlencode({
'username': config.plugins.FritzCall.username.value,
'response': buildResponse(challenge, self.password),
})
url = "http://%s/login_sid.lua" % (config.plugins.FritzCall.hostname.value)
self.debug(url + "?" + parms)
getPage(url,
method="POST",
agent=USERAGENT,
headers={'Content-Type': "application/x-www-form-urlencoded", 'Content-Length': str(len(parms))},
postdata=parms).addCallback(self._gotPageLogin, callback).addErrback(self._errorLogin)
def _gotPageLogin(self, sidXml, callback):
if self._callScreen:
self._callScreen.updateStatus(_("login verification"))
#=======================================================================
# linkP = open("/tmp/sid.xml", "w")
# linkP.write(sidXml)
# linkP.close()
#=======================================================================
sidX = ET.fromstring(sidXml)
md5Sid = sidX.find("SID").text
if md5Sid and md5Sid != "0000000000000000":
self.debug("found sid: " + md5Sid)
else:
self.error("found no sid")
self._notify(_("FRITZ!Box - Error logging in\n\n") + _("wrong user or password?"))
return
if self._callScreen:
self._callScreen.updateStatus(_("login ok"))
self.info("calling " + callback.__name__)
callback(md5Sid)
def _errorLogin(self, error):
global fritzbox # global-variable-undefined # pylint: disable=W0601
if type(error).__name__ == "str":
text = error
else:
text = error.getErrorMessage()
text = _("FRITZ!Box - Error logging in: %s\nDisabling plugin.") % text
fritzbox = None
self.exception(error)
self._notify(text)
def _logout(self, md5Sid, what):
parms = urlencode({
'sid': md5Sid,
'logout': 'bye bye Fritz'
})
url = "http://%s/login_sid.lua" % (config.plugins.FritzCall.hostname.value)
self.debug("(" + what + ") " + time.ctime() + ": " + url + "?" + parms)
getPage(url,
method="POST",
agent=USERAGENT,
headers={'Content-Type': "application/x-www-form-urlencoded", 'Content-Length': str(len(parms))},
postdata=parms).addErrback(self._errorLogout)
def _errorLogout(self, error):
text = _("FRITZ!Box - Error logging out: %s") % error.getErrorMessage()
self.exception(error)
self._notify(text)
def loadFritzBoxPhonebook(self, phonebook):
self.phonebook = phonebook
self._login(self._loadFritzBoxPhonebook)
def _loadFritzBoxPhonebook(self, md5Sid):
parms = urlencode({
'sid': md5Sid,
'page': 'bookLi'
})
url = "http://%s/data.lua" % (config.plugins.FritzCall.hostname.value)
self.debug(url + "?" + parms)
getPage(url,
method="POST",
agent=USERAGENT,
headers={'Content-Type': "application/x-www-form-urlencoded", 'Content-Length': str(len(parms))},
postdata=parms).addCallback(self._parseFritzBoxPhonebook, md5Sid).addErrback(self._errorLoad, md5Sid)
def _parseFritzBoxPhonebook(self, html, md5Sid):
self.debug("")
# first, let us get the charset
try:
self.debug("try charset utf-8")
html = html2unicode(html.decode('utf-8')).encode('utf-8') # this looks silly, but has to be
except UnicodeDecodeError:
self.debug("try charset iso-8859-1")
html = html2unicode(html.decode('iso-8859-1')).encode('utf-8') # this looks silly, but has to be
# cleanout hrefs
html = re.sub("]*>", "", html)
html = re.sub(" ", "", html)
if self.logger.getEffectiveLevel() == logging.DEBUG:
linkP = open("/tmp/FritzCall_Phonebook.htm", "w")
linkP.write(html)
linkP.close()
entrymask = re.compile(r'[^<]* ((?:]+>)?[^<]+(?: (?: ]+>)?[^<]+)*) ([^<]*(?: [^<]*)*) ([^<]*(?: [^<]*)*) ([^<]*(?: [^<]*)*) ', re.S)
entries = entrymask.finditer(html)
for found in entries:
# self.debug("processing entry for '''%s'''" % repr(found.groups()))
name = html2unicode(re.sub(",", "", found.group(1)))
thisnumbers = found.group(2).split(" ")
thistypes = found.group(3).split(" ")
thiscodes = found.group(4).split(" ")
thisvanitys = found.group(5).split(" ")
for i in range(len(thisnumbers)): # consider-using-enumerate # pylint: disable=
if len(thisnumbers[i]) == 0:
continue
thisnumber = cleanNumber(thisnumbers[i])
if thisnumber in self.phonebook.phonebook:
# self.debug("Ignoring '%s' ('%s') with %s' ( have: '%s')" % (name, thistypes[i], __(thisnumber), self.phonebook.phonebook[thisnumber]))
continue
if not thisnumbers[i]:
# self.debug("Ignoring entry with empty number for '''%s'''" % (__(name)))
continue
else:
thisname = name.decode('utf-8')
if config.plugins.FritzCall.showType.value and thistypes[i]:
thisname = thisname + " (" + thistypes[i].decode('utf-8') + ")"
if config.plugins.FritzCall.showShortcut.value and thiscodes[i]:
thisname = thisname + ", " + _("Shortcut") + ": " + thiscodes[i]
if config.plugins.FritzCall.showVanity.value and thisvanitys[i]:
thisname = thisname + ", " + _("Vanity") + ": " + thisvanitys[i]
# self.debug("Adding '''%s''' with '''%s'''" % (__(thisname.strip()), __(thisnumber, False)))
# self.debug("Adding '''%s''' with '''%s'''" % (thisname.strip(), thisnumber))
# Beware: strings in phonebook.phonebook have to be in utf-8!
self.phonebook.phonebook[thisnumber] = thisname.encode('utf-8')
self._logout(md5Sid, "_parseFritzBoxPhonebook")
def _errorLoad(self, error, md5Sid):
text = _("FRITZ!Box - ") + _("Could not load phonebook: %s") % error.getErrorMessage()
self.exception(error)
self._notify(text)
self._logout(md5Sid, "_errorLoad")
def getCalls(self, callScreen, callback, callType):
self.debug("")
self._callScreen = callScreen
self._callType = callType
self._login(lambda md5Sid: self._getCalls(callback, md5Sid))
def _getCalls(self, callback, md5Sid): # pylint: disable=W0613
self.debug("")
if self._callScreen:
self._callScreen.updateStatus(_("preparing"))
# besser csv mit: https://fritz.box/fon_num/foncalls_list.lua?sid=dea373c2d0257a41&csv=
parms = urlencode({'sid': md5Sid, 'csv': ''})
url = "http://%s/fon_num/foncalls_list.lua?%s" % (config.plugins.FritzCall.hostname.value, parms)
getPage(url).addCallback(lambda x: self._gotPageCalls(callback, x, md5Sid)).addErrback(self._errorCalls, md5Sid)
def _gotPageCalls(self, callback, csvString="", md5Sid=""):
self.debug("")
if self._callScreen:
self._callScreen.updateStatus(_("finishing"))
callListL = []
if config.plugins.FritzCall.filter.value and config.plugins.FritzCall.filterCallList.value:
filtermsns = [x.strip() for x in config.plugins.FritzCall.filtermsn.value.split(",")]
self.info("filtermsns %s", repr(list(map(__, filtermsns))))
else:
filtermsns = None
#=======================================================================
# linkP = open("/tmp/FritzCalls.csv", "w")
# linkP.write(csvString)
# linkP.close()
#=======================================================================
# 0: direct; 1: date; 2: Name; 3: Nummer; 4: Nebenstelle; 5: Eigene Rufnumme; 6: Dauer
calls = csv.reader(StringIO(csvString), delimiter=';')
next(calls) # skip sep
next(calls) # skip header line
for call in calls:
if len(call) != 7:
self.warning("skip %s len: %s", repr(call), str(len(call)))
continue
direct = call[0]
if direct == '1':
direct = FBF_IN_CALLS
elif direct == '4':
direct = FBF_OUT_CALLS
elif direct == '2':
direct = FBF_MISSED_CALLS
elif direct == '3':
direct = FBF_BLOCKED_CALLS
if self._callType != '.' and self._callType != direct:
continue
date = call[1]
length = call[6]
here = call[5]
start = here.find('Internet: ')
if start != -1:
start += len('Internet: ')
here = here[start:]
if filtermsns and here not in filtermsns:
# self.debug("skip %s" % (here))
continue
if call[4]:
here = resolveNumber(here, call[4] + " (" + here + ")", self.phonebook)
else:
here = resolveNumber(here, "", self.phonebook)
# self.debug("here: " + here)
number = stripCbCPrefix(call[3], config.plugins.FritzCall.countrycode.value)
if config.plugins.FritzCall.prefix.value and number and number[0] != '0': # should only happen for outgoing
number = config.plugins.FritzCall.prefix.value + number
# self.debug("number: " + number)
found = re.match(r"\d+ \((\d+)\)", call[2])
if found:
remote = resolveNumber(number, resolveNumber(found.group(1), None, self.phonebook), self.phonebook)
else:
remote = resolveNumber(number, re.sub(",", "", call[2]), self.phonebook)
# self.debug("remote. " + remote)
# self.debug("append: %s" % repr((__(number, False), date, direct, __(remote), length, __(here))))
# self.debug("ppend: %s" % repr((number, date, direct, remote, length, here)))
callListL.append((number, date, direct, remote, length, here))
if callback:
# self.debug("call callback with\n" + text
callback(callListL)
self._callScreen = None
self._logout(md5Sid, "_gotPageCalls")
def _errorCalls(self, error, md5Sid):
text = _("FRITZ!Box - Could not load calls: %s") % error.getErrorMessage()
self.exception(error)
self._notify(text)
self._logout(md5Sid, "_errorCalls")
def dial(self, number): # @UnusedVariable # pylint: disable=W0613
'''
Dial a number on extension config.plugins.FritzCall.extension.value
@param number: number to dial
@type number: string
'''
self.debug("")
Notifications.AddNotification(MessageBox, _("not available with this firmware version"), type=MessageBox.TYPE_ERROR, timeout=config.plugins.FritzCall.timeout.value)
def changeWLAN(self, statusWLAN, callback):
'''
Change the status of the WLAN
@param state: '0' means: turn off, '1' turn on
@type state: string
'''
self.debug("")
#=======================================================================
# Notifications.AddNotification(MessageBox, _("not available with this firmware version"), type=MessageBox.TYPE_ERROR, timeout=config.plugins.FritzCall.timeout.value)
# return
#=======================================================================
if not statusWLAN or (statusWLAN != '1' and statusWLAN != '0'):
return
self._login(lambda md5Sid: self._changeWLAN(statusWLAN, callback, md5Sid))
def _changeWLAN(self, statusWLAN, callback, md5Sid):
if statusWLAN == '0':
parms = urlencode({
'sid': md5Sid,
'apply': '',
'cancel': '',
'btn_refresh': ''
})
else:
parms = urlencode({
'sid': md5Sid,
'active': 'on',
'active_24': 'on',
'active_5': 'on',
'hidden_ssid': 'on',
'apply': '',
'cancel': '',
'btn_refresh': ''
})
url = "http://%s//wlan/wlan_settings.lua" % config.plugins.FritzCall.hostname.value
self.debug("url: " + url + "?" + parms)
getPage(url,
method="POST",
agent=USERAGENT,
headers={
'Content-Type': "application/x-www-form-urlencoded"},
postdata=parms).addCallback(self._okChangeWLAN, callback, md5Sid).addErrback(self._errorChangeWLAN, md5Sid)
def _okChangeWLAN(self, html, callback, md5Sid): # @UnusedVariable # pylint: disable=W0613
self.debug("")
if html:
found = re.match(r'.*([^<]*)
', html, re.S)
if found:
self._notify(found.group(1))
callback()
self._logout(md5Sid, "_okChangeWLAN")
def _errorChangeWLAN(self, error, md5Sid):
text = _("FRITZ!Box - Failed changing WLAN: %s") % error.getErrorMessage()
self.exception(error)
self._notify(text)
self._logout(md5Sid, "_errorChangeWLAN")
def changeGuestAccess(self, statusGuestAccess, callback):
'''
Change the status of the WLAN guest access
@param statusGuestAccess: 'WLAN', 'WLAN, LAN' or 'LAN'
@type statusGuestAccess: string
'''
self.debug("")
# if not statusGuestAccess:
# return
self._login(lambda md5Sid: self._changeGuestAccessWLAN(statusGuestAccess, callback, md5Sid))
def _changeGuestAccessWLAN(self, statusGuestAccess, callback, md5Sid):
parms = {
'sid': md5Sid,
'autoupdate': 'on',
'apply': '',
'oldpage': '/wlan/guest_access.lua',
}
if statusGuestAccess.find('WLAN') != -1:
parms.update({
'print': '',
})
else:
parms.update({
'activate_guest_access': 'on',
'guest_ssid': config.plugins.FritzCall.guestSSID.value,
})
if config.plugins.FritzCall.guestUptime.value:
parms.update({
'down_time_activ': 'on',
'down_time_value': config.plugins.FritzCall.guestUptime.value,
'disconnect_guest_access': 'on',
})
if config.plugins.FritzCall.guestSecure.value:
parms.update({
'sec_mode': '3',
'wpa_key': self.guestPassword,
})
else:
parms.update({
'sec_mode': '5',
})
parms = urlencode(parms)
url = "http://%s/data.lua" % config.plugins.FritzCall.hostname.value
self.debug("url: " + url + "?" + parms)
getPage(url,
method="POST",
agent=USERAGENT,
headers={
'Content-Type': "application/x-www-form-urlencoded"},
postdata=parms).addCallback(self._okChangeGuestAccess, callback, md5Sid).addErrback(self._errorChangeGuestAccess, md5Sid)
def _okChangeGuestAccess(self, html, callback, md5Sid): # @UnusedVariable # pylint: disable=W0613
self.debug("")
if html:
found = re.match(r'.*([^<]*)
', html, re.S)
if found:
self._notify(found.group(1))
callback()
self._logout(md5Sid, "_okChangeGuestAccess")
def _errorChangeGuestAccess(self, error, md5Sid):
text = _("FRITZ!Box - Failed changing GuestAccess: %s") % error.getErrorMessage()
self.exception(error)
self._notify(text)
self._logout(md5Sid, "_errorChangeGuestAccess")
def changeMailbox(self, whichMailbox, callback): # @UnusedVariable # pylint: disable=W0613
'''
Toggle mailbox status
@param which: number, which mailbox to toggle; '-1' means all
@type which: string
'''
self.debug("")
Notifications.AddNotification(MessageBox, _("not available with this firmware version"), type=MessageBox.TYPE_ERROR, timeout=config.plugins.FritzCall.timeout.value)
def getInfo(self, callback):
'''
Retrieve information from box and fill in self.information and self.blacklist
'''
self.debug("")
self._login(lambda md5Sid: self._getInfo(callback, md5Sid))
def _getInfo(self, callback, md5Sid):
self.debug("verify login")
self._login(self._readBlacklist)
url = "http://%s/data.lua" % config.plugins.FritzCall.hostname.value
parms = urlencode({
'sid': md5Sid,
'page': 'overview',
'type': 'all'
})
self.debug("url: " + url + "?" + parms)
getPage(url,
method="POST",
agent=USERAGENT,
headers={
'Content-Type': "application/x-www-form-urlencoded",
'Content-Length': str(len(parms))},
postdata=parms).addCallback(lambda x: self._okGetInfo(callback, x, md5Sid)).addErrback(self._errorGetInfo, md5Sid)
def _okGetInfo(self, callback, html, md5Sid):
self.debug("")
if self.logger.getEffectiveLevel() == logging.DEBUG:
linkP = open("/tmp/FritzCallGetInfo.lua", "w")
linkP.write(html)
linkP.close()
(boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive, guestAccess) = (None, None, None, None, None, None, None, None, None, None) # @UnusedVariable # pylint: disable=W0613
boxData = json.loads(html)["data"]
fritzOs = boxData["fritzos"]
if fritzOs["Productname"]:
boxInfo = fritzOs["Productname"]
if fritzOs["nspver"]:
boxInfo = boxInfo + " FRITZ!OS: " + fritzOs["nspver"]
if fritzOs["isLabor"] and fritzOs["isLabor"] == "true":
boxInfo = boxInfo + " Labor"
if fritzOs["isUpdateAvail"]:
boxInfo = boxInfo + " (" + _("Update available") + ")"
boxInfo1 = ""
if fritzOs["fb_name"]:
boxInfo1 = "Name: " + fritzOs["fb_name"]
if boxData["fonnum"] and boxData["fonnum"]["txt"]:
boxInfo1 = boxInfo1 + (", " if boxInfo1 else "") + boxData["fonnum"]["txt"]
if boxData["tamcalls"] and boxData["tamcalls"]["count"]:
boxInfo1 = boxInfo1 + (", " if boxInfo1 else "") + str(boxData["tamcalls"]["count"]) + " " + _("calls in mailbox")
if boxInfo1:
boxInfo = boxInfo + "\n" + boxInfo1
self.info("Boxinfo: " + repr(boxInfo))
provider = None
if "ipv4" in boxData and "txt" in boxData["ipv4"]:
for item in boxData["ipv4"]["txt"]:
found = re.match(r'.*verbunden seit (.*)', item, re.S)
if found:
upTime = found.group(1)
else:
found = re.match(r'.*connected since (.*)', item, re.S)
if found:
upTime = found.group(1)
found = re.match(r'\s*Anbieter: (.*)', item, re.S)
if found:
provider = found.group(1)
else:
found = re.match(r'\s*Provider: (.*)', item, re.S)
if found:
provider = found.group(1)
found = re.match(r'IP(?:v4)?-Adresse: (.*)', item, re.S)
if found:
ipAddress = found.group(1)
else:
found = re.match(r'IP(?:v4)? address: (.*)', item, re.S)
if found:
ipAddress = found.group(1)
self.info("upTime: " + repr(upTime))
self.info("provider: " + repr(provider))
self.info("ipAddress: " + repr(ipAddress))
if "ipv6" in boxData and "txt" in boxData["ipv6"]:
upTime6 = None
provider6 = None
ipAddress6 = None
for item in boxData["ipv6"]["txt"]:
found = re.match(r'.*verbunden seit (.*)', item, re.S)
if found:
upTime6 = found.group(1)
else:
found = re.match(r'.*connected since (.*)', item, re.S)
if found:
upTime6 = found.group(1)
found = re.match(r'\s*Anbieter: (.*)', item, re.S)
if found:
provider6 = found.group(1)
else:
found = re.match(r'\s*Provider:: (.*)', item, re.S)
if found:
provider6 = found.group(1)
found = re.match(r'IP(?:v6)?-(?:Adresse|Prefix): (.*)', item, re.S)
if found:
ipAddress6 = found.group(1)
else:
found = re.match(r'IP(?:v6)? (?:address|prefix): (.*)', item, re.S)
if found:
ipAddress6 = found.group(1)
self.info("upTime6: " + repr(upTime6))
self.info("provider6: " + repr(provider6))
self.info("ipAddress6: " + repr(ipAddress6))
if upTime6:
if upTime and upTime.find(upTime6) == -1:
upTime = upTime + '/' + upTime6
else:
upTime = upTime6
if provider6:
if provider and provider.find(provider6) == -1:
provider = provider + '/' + provider6
else:
provider = provider6
if ipAddress6:
if ipAddress:
ipAddress = ipAddress + '/' + ipAddress6
else:
ipAddress = ipAddress6
if provider:
if upTime:
upTime = upTime + ' ' + _("with") + ' ' + provider
self.info("upTime final: " + repr(upTime))
self.info("provider final: " + repr(provider))
self.info("ipAddress final: " + repr(ipAddress))
if "dsl" in boxData or "docsis" in boxData or "cable" in boxData:
if "dsl" in boxData:
connData = boxData["dsl"]
elif "cable" in boxData:
connData = boxData["cable"]
else:
connData = boxData["docsis"]
if connData["led"] == "led_green":
dslState = ['5', None, None]
dslState[1] = connData["down"] + " / " + connData["up"]
dslState[1] = dslState[1].replace('\\', '')
dslState[2] = connData["title"]
self.info("dslState: " + repr(dslState))
if "wlan24" in boxData:
wlan24 = boxData["wlan24"]
if wlan24:
netName = re.sub(r".*: ", "", wlan24["txt"])
if wlan24["led"] == "led_green":
wlanState = ['1', '', '', "2,4GHz " + _("on") + ": " + netName]
else:
wlanState = ['0', '', '', "2,4GHz " + _("off") + ": " + netName]
self.info("wlanState24: " + repr(wlanState))
if "wlan5" in boxData:
wlan5 = boxData["wlan5"]
if wlan5:
netName = re.sub(r".*: ", "", wlan5["txt"])
if not wlanState:
if wlan5["led"] == "led_green":
wlanState = ['1', '', '', "5GHz " + _("on") + ": " + netName]
else:
wlanState = ['0', '', '', "5GHz " + _("off") + ": " + netName]
else:
if wlan5["led"] == "led_green":
wlanState[0] = '1'
wlanState[3] = wlanState[3] + ", 5GHz " + _("on") + ": " + netName
self.info("wlanState5: " + repr(wlanState))
if "dect" in boxData:
dect = boxData["dect"]
if dect and dect["led"] == "led_green":
found = re.match(r'an, ([\d+]+|ein) Schnurlostelefon(?:e)? angemeldet', dect["txt"], re.S)
if found:
dectActive = found.group(1)
else:
found = re.match(r'enabled, ([\d+]+|one) cordless telephone(?:s)? registered', dect["txt"], re.S)
if found:
dectActive = found.group(1)
self.info("dectActive: " + repr(dectActive))
self.debug("comfort")
if "comfort" in boxData and "func" in boxData["comfort"]:
comfortFuncs = boxData["comfort"]["func"]
guestAccess = ""
for fun in comfortFuncs:
if "linktxt" in fun:
if fun["linktxt"] == "Faxfunktion" and fun["details"] == "Integriertes Fax aktiv":
faxActive = True
if fun["linktxt"] == "Fax function" and fun["details"] == "Integrated fax enabled":
faxActive = True
elif fun["linktxt"] == "Rufumleitung" and fun["details"]:
if fun["details"] != "deaktiviert":
found = re.match(r'.*(?:(\d+) )?aktiv', fun["details"], re.S)
if found and found.group(1):
rufumlActive = int(found.group(1))
else:
rufumlActive = -1 # means no number available
elif fun["linktxt"] == "Call diversion" and fun["details"]:
if fun["details"] != "disabled":
found = re.match(r'.*(?:(\d+) )?active', fun["details"], re.S)
if found and found.group(1):
rufumlActive = int(found.group(1))
else:
rufumlActive = -1 # means no number available
elif fun["linktxt"] == "WLAN-Gastzugang" and fun["details"]:
found = re.match(r'.*aktiv \([^\)]+\)(?:, (ungesichert|gesichert))?,(?: (\d+) (Minuten|Stunden) verbleiben,)? (\d+ Geräte), (.+)', fun["details"], re.S)
if found:
if found.group(1):
if found.group().find('ungesichert') != -1:
guestAccess = "WLAN (unges.)"
else:
guestAccess = "WLAN (ges.)"
else:
guestAccess = "WLAN"
if found.group(3):
if found.group(3) == 'Minuten':
guestAccess = guestAccess + ', ' + found.group(2) + ' Min.' # n Minuten verbleiben
else:
guestAccess = guestAccess + ', ' + found.group(2) + ' Std.' # n Stunden verbleiben
if found.group(4):
guestAccess = guestAccess + ', ' + found.group(4) # Geräte
if found.group(5):
guestAccess = guestAccess + ', ' + found.group(5) # WLAN Name
elif fun["linktxt"] == "Wireless guest access" and fun["details"]:
found = re.match(r'.*enabled \([^\)]+\)(?:, (secured|unsecured))?,(?: (\d+) (minutes|hours) left,)? (\d+ devices), (.+)', fun["details"], re.S)
if found:
if found.group(1):
if found.group().find('secured') != -1:
guestAccess = "WIFI (sec.)"
else:
guestAccess = "WIFI (unsec.)"
else:
guestAccess = "WIFI"
if found.group(3):
if found.group(3) == 'minutes':
guestAccess = guestAccess + ', ' + found.group(2) + ' min.' # n Minuten verbleiben
else:
guestAccess = guestAccess + ', ' + found.group(2) + ' hrs.' # n Minuten verbleiben
if found.group(4):
guestAccess = guestAccess + ', ' + found.group(4) # Geräte
if found.group(5):
guestAccess = guestAccess + ', ' + found.group(5) # WLAN Name
elif fun["linktxt"] == "LAN-Gastzugang" and fun["details"]:
if fun["details"] == "aktiv":
if guestAccess:
guestAccess = 'LAN, ' + guestAccess
else:
guestAccess = "LAN"
self.info("faxActive: " + repr(faxActive))
self.info("rufumlActive: " + repr(rufumlActive))
self.info("guestAccess: " + repr(guestAccess))
info = (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive, guestAccess)
self.info("information: " + str(info))
self.information = info
if callback:
callback(info)
self._logout(md5Sid, "_okGetInfo")
def _errorGetInfo(self, error, md5Sid):
text = _("FRITZ!Box - Error getting status: %s") % error.getErrorMessage()
self.exception(error)
self._notify(text)
self._logout(md5Sid, "_errorGetInfo")
def reset(self):
self._login(self._reset)
def _reset(self, md5Sid):
if self._callScreen:
self._callScreen.close()
url = "http://%s/system/reboot.lua" % config.plugins.FritzCall.hostname.value
parms = urlencode({
'reboot': '',
'sid': md5Sid
})
self.debug("url: " + url + "?" + parms)
getPage(url,
method="POST",
agent=USERAGENT,
headers={
'Content-Type': "application/x-www-form-urlencoded"},
postdata=parms).addCallback(self._okReset, md5Sid).addErrback(self._errorReset, md5Sid)
def _okReset(self, html, md5Sid): # @UnusedVariable # pylint: disable=W0613
self.debug("")
#=======================================================================
# linkP = open("/tmp/_okReset.htm", "w")
# linkP.write(html)
# linkP.close()
#=======================================================================
if html:
found = re.match(r'.*([^<]*)
', html, re.S)
if found:
self._notify(found.group(1))
self._logout(md5Sid, "_okReset")
def _errorReset(self, error, md5Sid):
text = _("FRITZ!Box - Error resetting: %s") % error.getErrorMessage()
self.exception(error)
self._notify(text)
self._logout(md5Sid, "_errorReset")
def _readBlacklist(self, md5Sid):
# http://fritz.box/cgi-bin/webcm?getpage=../html/de/menus/menu2.html&var:lang=de&var:menu=fon&var:pagename=sperre
# https://217.245.196.140:699/data.lua?xhr=1&sid=e8fcf4f9a9186070&lang=de&no_sidrenew=&page=callLock
url = "http://%s/data.lua" % config.plugins.FritzCall.hostname.value
parms = urlencode({
'sid': md5Sid,
'page': 'callLock'
})
self.debug("url: " + url + "?" + parms)
getPage(url,
method="POST",
agent=USERAGENT,
headers={
'Content-Type': "application/x-www-form-urlencoded",
'Content-Length': str(len(parms))},
postdata=parms).addCallback(self._okBlacklist, md5Sid).addErrback(self._errorBlacklist, md5Sid)
def _okBlacklist(self, html, md5Sid):
self.debug("")
# linkP = open("/tmp/FritzCallBlacklist.htm", "w")
# linkP.write(html)
# linkP.close()
# entries = re.compile(r'(Ankommende|Ausgehende) Rufe ([\d]+) ', re.S).finditer(html)
entries = re.compile(r']*)?>(Ankommende|Ausgehende) Rufe ([\d]+) ', re.S).finditer(html)
self.blacklist = ([], [])
for entry in entries:
if entry.group(1) == "Ankommende":
self.blacklist[0].append(entry.group(2))
else:
self.blacklist[1].append(entry.group(2))
entries = re.compile(r'(Ankommende|Ausgehende) Rufe ([\d]+) ', re.S).finditer(html)
for entry in entries:
if entry.group(1) == "Ankommende":
self.blacklist[0].append(entry.group(2))
else:
self.blacklist[1].append(entry.group(2))
entries = re.compile(r'(Ankommende|Ausgehende) Rufe \s+([\d]+) ', re.S).finditer(html)
for entry in entries:
if entry.group(1) == "Ankommende":
self.blacklist[0].append(entry.group(2))
else:
self.blacklist[1].append(entry.group(2))
self.debug(repr(self.blacklist))
self._logout(md5Sid, "_okBlacklist")
def _errorBlacklist(self, error, md5Sid):
text = _("FRITZ!Box - Error getting blacklist: %s") % error.getErrorMessage()
self.exception(error)
self._notify(text)
self._logout(md5Sid, "_errorBlacklist")
TIMEOUT = 20
class FritzCallFBF_upnp():
logger = logging.getLogger("FritzCall.FBF_upnp")
debug = logger.debug
info = logger.info
warning = logger.warning
error = logger.error
exception = logger.exception
def __init__(self):
self._loginFailure = False
self._callScreen = None
self._callType = config.plugins.FritzCall.fbfCalls.value
self.password = decode(config.plugins.FritzCall.password.value)
# (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, guestAccess)
self.information = (None, None, None, None, None, [False, False, False, False, False, False], None, None, None, None)
self.phonebook = None
self.blacklist = ([], [])
self._timer = eTimer()
self._timeout = TIMEOUT
self._callback = None
self._phonebook_timer = eTimer()
self._phonebook_timeout = TIMEOUT
self._infoCallback = None
self._phonebook_timer_conn = None
self.version = None
self.fc = FritzConnection(address=config.plugins.FritzCall.hostname.value,
user=config.plugins.FritzCall.username.value,
port=(49443 if config.plugins.FritzCall.useHttps.value else 49000),
password=self.password,
servicesToGet=["DeviceConfig:1", "X_AVM-DE_OnTel:1", "WLANConfiguration:1", "WLANConfiguration:2", "WLANConfiguration:3"])
self.getInfo(None)
def _notify(self, text):
self.info(text)
if self._callScreen:
self.debug("try to close callScreen")
self._callScreen.close()
self._callScreen = None
Notifications.AddNotification(MessageBox, text, type=MessageBox.TYPE_ERROR, timeout=config.plugins.FritzCall.timeout.value)
def getInfo(self, callback=None):
'''
Retrieve information from box and fill in self.information and self.blacklist
'''
self.debug("")
if self._loginFailure:
self.debug("skip because of login failure")
self._infoCallback = callback
if "DeviceConfig:1" in list(self.fc.services.keys()):
self.fc.call_action(self._getInfo, "DeviceConfig", "X_AVM-DE_CreateUrlSID")
else:
try:
self._timer_conn = self._timer.timeout.connect(self._timerTick)
except AttributeError:
self._timer.callback.append(self._timerTick)
self._timer.start(1000)
self._timerTick()
def _timerTick(self):
self.debug(repr(list(self.fc.services.keys())))
self._timeout -= 1
if "DeviceConfig:1" in list(self.fc.services.keys()):
if self._loginFailure:
self.debug("skip because of login failure")
else:
self.fc.call_action(self._getInfo, "DeviceConfig", "X_AVM-DE_CreateUrlSID")
self._timer.stop()
self._timeout = TIMEOUT
if self._timeout == 0:
self._timer.stop()
self._timeout = TIMEOUT
def _getInfo(self, result):
self.debug(repr(result))
if isinstance(result, Failure):
text = _("FRITZ!Box - Error getting status: ") + _("wrong user or password?")
self._loginFailure = True
self._notify(text)
return
if "NewX_AVM-DE_UrlSID" not in result:
self.error("no UrlSID in response!")
return
md5Sid = result["NewX_AVM-DE_UrlSID"]
md5Sid = md5Sid[md5Sid.find("sid=") + 4:]
self.debug("md5sid: " + md5Sid)
self._readBlacklist()
url = "http://%s/data.lua" % config.plugins.FritzCall.hostname.value
parms = urlencode({
'sid': md5Sid,
'page': 'overview',
'type': 'all'
})
self.debug("url: " + url + "?" + parms)
headers = {
'Content-Type': "application/x-www-form-urlencoded",
'Content-Length': str(len(parms))}
newheaders = {}
for h in six.iterkeys(headers):
newheaders[six.ensure_binary(h)] = six.ensure_binary(headers[h])
getPage(six.ensure_binary(url),
method=six.ensure_binary("POST"),
agent=six.ensure_binary(USERAGENT),
headers=newheaders,
postdata=six.ensure_binary(parms)).addCallback(self._okGetInfo)
def _okGetInfo(self, html):
self.debug("")
html = six.ensure_str(html)
if self.logger.getEffectiveLevel() == logging.DEBUG:
self.debug("dumping info to /tmp/FritzCall_okGetInfo.json")
linkP = open("/tmp/FritzCall_okGetInfo.json", "w")
linkP.write(html)
linkP.close()
(boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive, guestAccess) = (None, None, None, None, None, None, None, None, None, "") # @UnusedVariable # pylint: disable=W0613
boxData = json.loads(html)["data"]
fritzOs = boxData["fritzos"]
if fritzOs["Productname"]:
boxInfo = fritzOs["Productname"]
if fritzOs["nspver"]:
boxInfo = boxInfo + " FRITZ!OS: " + fritzOs["nspver"]
if fritzOs["isLabor"] and fritzOs["isLabor"] == "true":
boxInfo = boxInfo + " Labor"
if fritzOs["isUpdateAvail"]:
boxInfo = boxInfo + " (" + _("Update available") + ")"
boxInfo1 = ""
if fritzOs["fb_name"]:
boxInfo1 = "Name: " + fritzOs["fb_name"]
if boxData["fonnum"] and boxData["fonnum"]["txt"]:
boxInfo1 = boxInfo1 + (", " if boxInfo1 else "") + boxData["fonnum"]["txt"]
if boxData["tamcalls"] and boxData["tamcalls"]["count"]:
boxInfo1 = boxInfo1 + (", " if boxInfo1 else "") + str(boxData["tamcalls"]["count"]) + " " + _("calls in mailbox")
if boxInfo1:
boxInfo = boxInfo + "\n" + boxInfo1
boxInfo = six.ensure_str(boxInfo)
self.info("Boxinfo: " + repr(boxInfo))
if "internet" in boxData and "led" in boxData["internet"] and boxData["internet"]["led"] == "globe_online":
upTime = _("Unknown")
if "txt" in boxData["internet"] and len(boxData["internet"]["txt"][0]) >= 1:
upTime = upTime + ' (' + boxData["internet"]["txt"][0].strip() + ')'
provider = None
if "internet" in boxData and "txt" in boxData["internet"]:
for item in boxData["internet"]["txt"]:
item = six.ensure_str(item)
found = re.match(r'.*verbunden (?:als WLAN-Repeater |über WAN )?seit (.*)', item, re.S)
if found:
upTime = found.group(1)
else:
found = re.match(r'.*connected (?:as WIFI repeater )?since (.*)', item, re.S)
if found:
upTime = found.group(1)
found = re.match(r'\s*Anbieter: (.*)', item, re.S)
if found:
provider = found.group(1)
else:
found = re.match(r'\s*Provider: (.*)', item, re.S)
if found:
provider = found.group(1)
found = re.match(r'IP(?:v4)?-Adresse: (.*)', item, re.S)
if found:
ipAddress = found.group(1)
else:
found = re.match(r'IP(?:v4)? address: (.*)', item, re.S)
if found:
ipAddress = found.group(1)
if "internet" in boxData and "down" in boxData["internet"] and "up" in boxData["internet"]:
connData = boxData["internet"]
internetSpeed = connData["down"] + " / " + connData["up"]
internetSpeed = internetSpeed.replace('\\', '')
else:
internetSpeed = None
self.info("upTime: " + repr(upTime))
self.info("provider: " + repr(provider))
self.info("ipAddress: " + repr(ipAddress))
if "ipv4" in boxData and "txt" in boxData["ipv4"]:
for item in boxData["ipv4"]["txt"]:
found = re.match(r'.*verbunden seit (.*)', item, re.S)
if found:
upTime = found.group(1)
else:
found = re.match(r'.*connected since (.*)', item, re.S)
if found:
upTime = found.group(1)
found = re.match(r'\s*Anbieter: (.*)', item, re.S)
if found:
provider = found.group(1)
else:
found = re.match(r'\s*Provider: (.*)', item, re.S)
if found:
provider = found.group(1)
found = re.match(r'IP(?:v4)?-Adresse: (.*)', item, re.S)
if found:
ipAddress = found.group(1)
else:
found = re.match(r'IP(?:v4)? address: (.*)', item, re.S)
if found:
ipAddress = found.group(1)
self.info("upTime: " + repr(upTime))
self.info("provider: " + repr(provider))
self.info("ipAddress: " + repr(ipAddress))
if "ipv6" in boxData and "txt" in boxData["ipv6"]:
upTime6 = None
provider6 = None
ipAddress6 = None
for item in boxData["ipv6"]["txt"]:
found = re.match(r'.*verbunden seit (.*)', item, re.S)
if found:
upTime6 = found.group(1)
else:
found = re.match(r'.*connected since (.*)', item, re.S)
if found:
upTime6 = found.group(1)
found = re.match(r'\s*Anbieter: (.*)', item, re.S)
if found:
provider6 = found.group(1)
else:
found = re.match(r'\s*Provider: (.*)', item, re.S)
if found:
provider6 = found.group(1)
found = re.match(r'IP(?:v6)?-(?:Adresse|Prefix): (.*)', item, re.S)
if found:
ipAddress6 = found.group(1)
else:
found = re.match(r'IP(?:v6)? (?:address|prefix): (.*)', item, re.S)
if found:
ipAddress6 = found.group(1)
self.info("upTime6: " + repr(upTime6))
self.info("provider6: " + repr(provider6))
self.info("ipAddress6: " + repr(ipAddress6))
if upTime6:
if upTime and upTime.find(upTime6) == -1:
upTime = upTime + '/' + upTime6
else:
upTime = upTime6
if provider6:
if provider and provider.find(provider6) == -1:
provider = provider + '/' + provider6
else:
provider = provider6
if ipAddress6:
if ipAddress:
ipAddress = ipAddress + '/' + ipAddress6
else:
ipAddress = ipAddress6
if provider:
if upTime:
upTime = upTime + ' ' + _("with") + ' ' + provider
self.info("upTime final: " + repr(upTime))
self.info("provider final: " + repr(provider))
self.info("ipAddress final: " + repr(ipAddress))
if "dsl" in boxData or "docsis" in boxData or "cable" in boxData:
if "dsl" in boxData:
connData = boxData["dsl"]
elif "cable" in boxData:
connData = boxData["cable"]
else:
connData = boxData["docsis"]
if connData["led"] == "led_green":
dslState = ['5', None, None]
dslState[1] = connData["down"] + " / " + connData["up"]
dslState[1] = dslState[1].replace('\\', '')
dslState[2] = connData["title"]
if internetSpeed:
dslState[1] = dslState[1] + "; Internet: " + internetSpeed
self.info("dslState: " + repr(dslState))
wlan24 = None
wlan24NetName = ""
if "wlan24" in boxData:
wlan24 = boxData["wlan24"]
elif "wlan24GHz" in boxData:
wlan24 = boxData["wlan24GHz"]
if wlan24:
wlan24NetName = six.ensure_str(re.sub(r".*: ", "", wlan24["txt"]))
if wlan24["led"] == "led_green":
wlanState = ['1', '', '', "2,4GHz " + _("on") + ": " + wlan24NetName]
else:
wlanState = ['0', '', '', "2,4GHz " + _("off") + ": " + wlan24NetName]
self.info("wlanState24: " + repr(wlanState))
wlan5 = None
if "wlan5" in boxData:
wlan5 = boxData["wlan5"]
elif "wlan5GHz" in boxData:
wlan5 = boxData["wlan5GHz"]
elif "wlan5GHzScnd" in boxData:
wlan5 = boxData["wlan5GHzScnd"]
if wlan5:
# self.info("wlanState5/1: " + repr(wlanState))
netName = six.ensure_str(re.sub(r".*: ", "", wlan5["txt"]))
# self.info("wlanState5/2: " + repr(netName))
if not wlanState:
if wlan5["led"] == "led_green":
wlanState = ['1', '', '', "5GHz " + _("on") + ": " + netName]
else:
wlanState = ['0', '', '', "5GHz " + _("off") + ": " + netName]
else:
if wlan5["led"] == "led_green":
wlanState[0] = '1'
if netName == wlan24NetName:
wlanState[3] = "2,4GHz/5GHz " + _("on") + ": " + netName
else:
wlanState[3] = wlanState[3] + ", 5GHz " + _("on") + ": " + netName
self.info("wlanState5: " + repr(wlanState))
# self.info("wlanState5/3: " + repr(wlanState))
if not wlanState and "wlan" in boxData:
wlan = boxData["wlan"]
# self.debug("wlan: " + repr(wlan))
netName = six.ensure_str(re.sub(r".*: ", "", wlan["txt"]))
# self.debug("netName: %s; led: %s", repr(netName), repr(wlan["led"]))
if wlan["led"] == "led_green":
wlanState = ['1', '', '', "2,4GHz/5GHz " + _("on") + ": " + netName]
else:
wlanState = ['0', '', '', "2,4GHz/5GHz " + _("off") + ": " + netName]
# self.info("wlanState2,4/5: " + repr(wlanState))
self.info("wlanState: " + repr(wlanState))
if "dect" in boxData:
dect = boxData["dect"]
if dect and dect["led"] == "led_green":
found = re.match(r'an, ([\d+]+|ein) Schnurlostelefon(?:e)? angemeldet', dect["txt"], re.S)
if found:
dectActive = six.ensure_str(found.group(1))
else:
found = re.match(r'enabled, ([\d+]+|one) cordless telephone(?:s)? registered', dect["txt"], re.S)
if found:
dectActive = six.ensure_str(found.group(1))
self.info("dectActive: " + repr(dectActive))
self.debug("comfort")
if "comfort" in boxData and "func" in boxData["comfort"]:
comfortFuncs = boxData["comfort"]["func"]
guestAccess = ""
for fun in comfortFuncs:
if "linktxt" in fun:
if fun["linktxt"] == "Faxfunktion" and fun["details"] == "Integriertes Fax aktiv":
faxActive = True
elif fun["linktxt"] == "Fax function" and fun["details"] == "Integrated fax enabled":
faxActive = True
elif fun["linktxt"] == "Rufumleitung" and fun["details"]:
if fun["details"] != "deaktiviert":
found = re.match(r'.*(?:(\d+) )?aktiv', fun["details"], re.S)
if found and found.group(1):
rufumlActive = int(found.group(1))
else:
rufumlActive = -1 # means no number available
elif fun["linktxt"] == "Call diversion" and fun["details"]:
if fun["details"] != "disabled":
found = re.match(r'.*(?:(\d+) )?active', fun["details"], re.S)
if found and found.group(1):
rufumlActive = int(found.group(1))
else:
rufumlActive = -1 # means no number available
elif fun["linktxt"] == "WLAN-Gastzugang" and fun["details"]:
found = re.match(r'.*aktiv \([^\)]+\)(?:, (ungesichert|gesichert))?,(?: (\d+) (Minuten|Stunden) verbleiben,)? (\d+ Gerät(?:e)?), (.+)', fun["details"], re.S)
if found:
if found.group(1):
if found.group().find('ungesichert') != -1:
guestAccess = "WLAN (unges.)"
else:
guestAccess = "WLAN (ges.)"
else:
guestAccess = "WLAN"
if found.group(3):
if found.group(3) == 'Minuten':
guestAccess = guestAccess + ', ' + found.group(2) + ' Min.' # n Minuten verbleiben
else:
guestAccess = guestAccess + ', ' + found.group(2) + ' Std.' # n Stunden verbleiben
if found.group(4):
guestAccess = guestAccess + ', ' + found.group(4) # Geräte
if found.group(5):
guestAccess = guestAccess + ', ' + found.group(5) # WLAN Name
elif (fun["linktxt"] == "Wireless guest access" or fun["linktxt"] == "Wi-Fi Guest Access") and fun["details"]:
found = re.match(r'.*enabled \([^\)]+\)(?:, (secured|unsecured))?,(?: (\d+) (minutes|hours) left,)? (\d+ devices), (.+)', fun["details"], re.S | re.I)
if found:
if found.group(1):
if found.group().find('secured') != -1:
guestAccess = "WIFI (sec.)"
else:
guestAccess = "WIFI (unsec.)"
else:
guestAccess = "WIFI"
if found.group(3):
if found.group(3) == 'minutes':
guestAccess = guestAccess + ', ' + found.group(2) + ' min.' # n Minuten verbleiben
else:
guestAccess = guestAccess + ', ' + found.group(2) + ' hrs.' # n Minuten verbleiben
if found.group(4):
guestAccess = guestAccess + ', ' + found.group(4) # Geräte
if found.group(5):
guestAccess = guestAccess + ', ' + found.group(5) # WLAN Name
elif fun["linktxt"] == "LAN-Gastzugang" and fun["details"]:
if fun["details"] == "aktiv":
if guestAccess:
guestAccess = 'LAN, ' + guestAccess
else:
guestAccess = "LAN"
self.info("faxActive: " + repr(faxActive))
self.info("rufumlActive: " + repr(rufumlActive))
self.info("guestAccess: " + repr(guestAccess))
info = (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive, guestAccess)
self.info("information: " + str(info))
self.information = info
if self._infoCallback:
self._infoCallback(info)
self._infoCallback = None
def getCalls(self, callScreen, callback, callType):
self.debug("callType: %s", callType)
if self._loginFailure:
self.debug("skip because of login failure")
self._callScreen = callScreen
self._callType = callType
if "X_AVM-DE_OnTel:1" in list(self.fc.services.keys()):
self.fc.call_action(lambda x: self._getCalls_cb1(x, callback), "X_AVM-DE_OnTel", "GetCallList")
else:
Notifications.AddNotification(MessageBox, _("Cannot get infos from FRITZ!Box yet\nStill initialising or wrong firmware version"), type=MessageBox.TYPE_ERROR, timeout=config.plugins.FritzCall.timeout.value)
def _getCalls_cb1(self, result, callback):
self.debug("")
if isinstance(result, Failure):
text = _("FRITZ!Box - Could not load calls: %s") % _("wrong user or password?")
self._loginFailure = True
self._notify(text)
return
if self._callScreen:
self._callScreen.updateStatus(_("preparing"))
url = result["NewCallListURL"]
getPage(six.ensure_binary(url)).addCallback(self._getCalls_cb2, callback)
def _getCalls_cb2(self, result, callback):
result = six.ensure_text(result)
# self.debug("")
if self.logger.getEffectiveLevel() == logging.DEBUG:
self.debug("dumping calls to /tmp/FritzCall_getCalls_cb2.xml")
linkP = open("/tmp/FritzCall_getCalls_cb2.xml", "w")
linkP.write(result)
linkP.close()
if self._callScreen:
self._callScreen.updateStatus(_("finishing"))
if config.plugins.FritzCall.filter.value and config.plugins.FritzCall.filterCallList.value:
filtermsns = [x.strip() for x in config.plugins.FritzCall.filtermsn.value.split(",")]
self.info("filtermsns %s", repr([__(x) for x in filtermsns]))
else:
filtermsns = None
callListL = []
root = ET.fromstring(result)
calls = root.iterfind("./Call")
for call in calls:
direct = call.find("./Type").text
# self.debug("direct: %s", direct)
if self._callType != '.' and self._callType != direct:
self.debug("skip: id %s of type %s", call.find("./Id").text, direct)
continue
if direct == FBF_OUT_CALLS:
# self.debug("FBF_OUT_CALLS: %s", direct)
number = call.find("./Called").text
remote = call.find("./Name").text
if not remote:
remote = resolveNumber(number, "", self.phonebook)
here = call.find("./Caller").text
if here.startswith("SIP: "):
here = here[5:]
if filtermsns and here not in filtermsns and call.find("./CallerNumber").text not in filtermsns:
self.debug("skip filter %s" % (here))
continue
if here.isdigit():
here = resolveNumber(here, call.find("./CallerNumber").text, self.phonebook)
else:
# self.debug("FBF_OUT_CALLS not: %s", direct)
number = call.find("./Caller").text
if not number:
number = _("Unknown")
remote = call.find("./Name").text
if not remote:
remote = resolveNumber(number, "", self.phonebook)
here = call.find("./Called").text
if here.startswith("SIP: "):
here = here[5:]
if filtermsns and here not in filtermsns and call.find("./CalledNumber").text not in filtermsns:
self.debug("skip %s" % (here))
continue
# self.debug("here: %s", here)
if here.isdigit():
# self.debug("resolveNumber(%s, %s)", here, call.find("./CalledNumber").text)
here = resolveNumber(here, call.find("./CalledNumber").text, self.phonebook, self.debug)
# self.debug("resolveNumber result: %s", here)
device = call.find("./Device").text
if device:
here = here + " (" + device + ")"
# self.debug("here: " + here)
number = stripCbCPrefix(number, config.plugins.FritzCall.countrycode.value)
if config.plugins.FritzCall.prefix.value and number and number[0] != '0': # should only happen for outgoing
number = config.plugins.FritzCall.prefix.value + number
date = call.find("./Date").text
length = call.find("./Duration").text
# self.debug("got: " + repr((number, date, direct, remote, length, here)))
callListL.append((number, date, direct, remote, length, here))
# self.debug(repr(callListL))
if callback:
callback(callListL)
self._callScreen = None
def loadFritzBoxPhonebook(self, phonebook):
'''
Load phonebook from device and add it to the phonebook
@param phonebook: phonebook to be amended
@type phonebook: dictionary of number, information
'''
self.debug("")
self.phonebook = phonebook
if self._loginFailure:
self.debug("skip because of login failure")
# newer OE versions don't have the callback
self._phonebook_timeout -= 1
if "X_AVM-DE_OnTel:1" in list(self.fc.services.keys()):
self.fc.call_action(self._loadFritzBoxPhonebook_cb1, "X_AVM-DE_OnTel", "GetPhonebookList")
else:
try:
self._phonebook_timer_conn = self._phonebook_timer.timeout.connect(self._phonebook_timerTick)
except AttributeError:
self._phonebook_timer.callback.append(self._phonebook_timerTick)
self._phonebook_timer.start(1000)
self._phonebook_timerTick()
def _phonebook_timerTick(self):
self.debug(repr(list(self.fc.services.keys())))
self._phonebook_timeout -= 1
if "X_AVM-DE_OnTel:1" in list(self.fc.services.keys()):
if self._loginFailure:
self.debug("skip because of login failure")
else:
self.fc.call_action(self._loadFritzBoxPhonebook_cb1, "X_AVM-DE_OnTel", "GetPhonebookList")
self._phonebook_timer.stop()
self._phonebook_timeout = TIMEOUT
if self._phonebook_timeout == 0:
self._phonebook_timer.stop()
self._phonebook_timeout = TIMEOUT
def _loadFritzBoxPhonebook_cb1(self, result):
self.debug(repr(result))
if isinstance(result, Failure):
text = _("FRITZ!Box - ") + _("Could not load phonebook: ") + _("wrong user or password?")
self._notify(text)
self._loginFailure = True
return
if 'NewPhonebookList' not in result:
self.error("no NewPhonebookList in response!")
return
ids = result['NewPhonebookList'].split(',')
ids = [int(x) for x in ids]
for ident in ids:
self.fc.call_action(self._loadFritzBoxPhonebook_cb2, "X_AVM-DE_OnTel", "GetPhonebook", NewPhonebookId=ident)
def _loadFritzBoxPhonebook_cb2(self, result):
self.debug(repr(result))
if isinstance(result, Failure):
text = _("FRITZ!Box - ") + _("Could not load phonebook: ") + _("wrong user or password?")
self._notify(text)
self._loginFailure = True
return
if 'NewPhonebookName' not in result or 'NewPhonebookURL' not in result:
text = _("FRITZ!Box - ") + _("Could not load phonebook: %s") % 'NewPhonebookName'
self._notify(text)
return
if result["NewPhonebookName"] == config.plugins.FritzCall.fritzphonebookName.value:
getPage(six.ensure_binary(result["NewPhonebookURL"])).addCallback(self._loadFritzBoxPhonebook_cb3)
def _loadFritzBoxPhonebook_cb3(self, result):
result = six.ensure_text(result)
root = ET.fromstring(result)
thisName = root.find(".//phonebook").attrib["name"]
self.debug("Phonebook: %s", thisName)
if self.logger.getEffectiveLevel() == logging.DEBUG:
self.debug("dumping phonebook to /tmp/FritzCall_loadFritzBoxPhonebook_cb3_%s.xml", thisName)
linkP = open("/tmp/FritzCall_loadFritzBoxPhonebook_cb3_%s.xml" % thisName, "w")
linkP.write(result)
linkP.close()
count = 0
contacts = root.iterfind(".//contact")
for contact in contacts:
name = contact.find("./person/realName").text
if not name:
self.info("Skipping entry with no realName")
continue
name = name.replace(",", "")
numbers = contact.iterfind("./telephony/number")
for number in numbers:
# self.debug("Name: " + name)
# self.debug("Number: " + number.text + " " + number.attrib["type"])
thisname = name
thisnumber = cleanNumber(number.text)
if thisnumber in self.phonebook.phonebook:
self.info("Number already exists, skipping '''%s'''", (__(thisnumber)))
continue
if not thisnumber:
self.info("Ignoring entry with empty number for '''%s'''", (__(thisname)))
continue
else:
dummy = _("fax_work") + _("fax_home") + _("pager") # this is just to trigger localisation; WTF?!?!
thisType = number.attrib["type"]
# self.debug("thisType: %s", thisType)
if thisType.startswith('label:'):
thisType = thisType[6:]
if not config.plugins.FritzCall.fritzphonebookShowInternal.value and (thisType == "intern" or thisType == "memo" or thisType == ""):
self.info("Skipping internal number %s", (__(thisnumber)))
continue
if config.plugins.FritzCall.showType.value and thisType:
thisname = thisname + " (" + _(thisType) + ")"
if config.plugins.FritzCall.showShortcut.value and "quickdial" in number.attrib and number.attrib["quickdial"]:
thisname = thisname + ", " + _("Shortcut") + ": " + number.attrib["quickdial"]
if config.plugins.FritzCall.showVanity.value and "vanity" in number.attrib and number.attrib["vanity"]:
thisname = thisname + ", " + _("Vanity") + ": " + number.attrib["vanity"]
# self.debug("Adding '''%s''' with '''%s'''", __(thisname.strip()), __(thisnumber, False))
# Beware: strings in phonebook.phonebook have to be in utf-8!
self.phonebook.phonebook[thisnumber] = thisname
count += 1
self.info("Added %d phone numbers", count)
def changeWLAN(self, statusWLAN, callback):
'''
Change the status of the WLAN
@param state: '0' means: turn off, '1' turn on
@type state: string
'''
self.debug("")
if self._loginFailure:
self.debug("skip because of login failure")
if not statusWLAN or (statusWLAN != '1' and statusWLAN != '0'):
return
if "WLANConfiguration:1" not in list(self.fc.services.keys()):
Notifications.AddNotification(MessageBox, _("Cannot get infos from FRITZ!Box yet\nStill initialising or wrong firmware version"), type=MessageBox.TYPE_ERROR, timeout=config.plugins.FritzCall.timeout.value)
return
if "WLANConfiguration:3" in list(self.fc.services.keys()):
if "WLANConfiguration:2" in list(self.fc.services.keys()):
self.fc.call_action(None, "WLANConfiguration:2", "SetEnable", NewEnable=int(statusWLAN))
self.fc.call_action(lambda x: self._general_cb(x, callback), "WLANConfiguration:1", "SetEnable", NewEnable=int(statusWLAN))
def changeGuestAccess(self, statusGuestAccess, callback):
'''
Change the status of the WLAN guest access
@param statusGuestAccess: 'WLAN', 'WLAN, LAN' or 'LAN'
@type statusGuestAccess: string
'''
self.debug("")
if self._loginFailure:
self.debug("skip because of login failure")
if "WLANConfiguration:2" not in list(self.fc.services.keys()):
Notifications.AddNotification(MessageBox, _("Cannot get infos from FRITZ!Box yet\nStill initialising or wrong firmware version"), type=MessageBox.TYPE_ERROR, timeout=config.plugins.FritzCall.timeout.value)
return
if statusGuestAccess.find('WLAN') != -1 or statusGuestAccess.find('WIFI') != -1:
self.debug("WLAN")
if "WLANConfiguration:3" in list(self.fc.services.keys()):
self.fc.call_action(lambda x: self._general_cb(x, callback), "WLANConfiguration:3", "SetEnable", NewEnable=0)
else:
self.fc.call_action(lambda x: self._general_cb(x, callback), "WLANConfiguration:2", "SetEnable", NewEnable=0)
else:
self.debug("no WLAN")
if "WLANConfiguration:3" in list(self.fc.services.keys()):
self.fc.call_action(lambda x: self._general_cb(x, callback), "WLANConfiguration:3", "SetEnable", NewEnable=1)
else:
self.fc.call_action(lambda x: self._general_cb(x, callback), "WLANConfiguration:2", "SetEnable", NewEnable=1)
callback()
def _general_cb(self, result, callback):
self.debug("result: " + repr(result))
if isinstance(result, Failure):
text = _("FRITZ!Box - Error logging in: %s") % _("wrong user or password?")
self._loginFailure = True
self._notify(text)
return
callback()
def _general_cb1(self, result):
self.debug("result: " + repr(result))
if isinstance(result, Failure):
text = _("FRITZ!Box - Error logging in: %s") % _("wrong user or password?")
self._loginFailure = True
self._notify(text)
return
def _readBlacklist(self):
self.debug("")
if self._loginFailure:
self.debug("skip because of login failure")
self.blacklist = ([], [])
if "X_AVM-DE_OnTel:1" not in list(self.fc.services.keys()):
Notifications.AddNotification(MessageBox, _("Cannot get infos from FRITZ!Box yet\nStill initialising or wrong firmware version"), type=MessageBox.TYPE_ERROR, timeout=config.plugins.FritzCall.timeout.value)
return
self.fc.call_action(self._readBlacklist_cb, "X_AVM-DE_OnTel", "GetDeflections")
def _readBlacklist_cb(self, result):
def _readPhonebookForBlacklist(result):
self.debug(repr(result))
if isinstance(result, Failure):
text = _("FRITZ!Box - ") + _("Could not load phonebook: ") + _("wrong user or password?")
self._notify(text)
self._loginFailure = True
return
if 'NewPhonebookName' not in result or 'NewPhonebookURL' not in result:
text = _("FRITZ!Box - ") + _("Could not load phonebook: %s") % 'NewPhonebookName'
self._notify(text)
return
getPage(six.ensure_binary(result["NewPhonebookURL"])).addCallback(_readPhonebookForBlacklist_cb)
def _readPhonebookForBlacklist_cb(result):
result = six.ensure_text(result)
root = ET.fromstring(result)
thisName = root.find(".//phonebook").attrib["name"]
self.debug("Phonebook: %s", thisName)
if self.logger.getEffectiveLevel() == logging.DEBUG:
self.debug("dumping phonebook to /tmp/FritzCall_readPhonebookForBlacklist_cb_%s.xml", thisName)
linkP = open("/tmp/FritzCall_readPhonebookForBlacklist_cb_%s.xml" % thisName, "w")
linkP.write(result)
linkP.close()
contacts = root.iterfind(".//contact")
for contact in contacts:
numbers = contact.iterfind("./telephony/number")
for number in numbers:
# self.debug("Number: " + number.text + " " + number.attrib["type"])
thisType = number.attrib["type"]
if thisType.startswith('label:'):
thisType = thisType[6:]
if (thisType == "intern" or thisType == "memo" or thisType == ""):
# self.info("Skipping internal number %s", (__(number)))
continue
thisnumber = cleanNumber(number.text)
if thisnumber in self.blacklist[0]:
# self.info("Number already exists, skipping '''%s'''", (__(thisnumber)))
continue
else:
# self.debug("Number: " + thisnumber + " added to blacklist.")
self.blacklist[0].append(thisnumber)
self.debug("After phonebook imput: %s", repr(self.blacklist))
self.debug("")
if isinstance(result, Failure):
text = _("FRITZ!Box - Error getting blacklist: %s") % _("wrong user or password?")
self._loginFailure = True
self._notify(text)
return
if self.logger.getEffectiveLevel() == logging.DEBUG:
self.debug("dumping result to /tmp/FritzCall_readBlacklist_cb.xml")
linkP = open("/tmp/FritzCall_readBlacklist_cb.xml", "w")
linkP.write(result["NewDeflectionList"])
linkP.close()
for deflection in ET.fromstring(result["NewDeflectionList"]).iterfind(".//Item"):
# self.debug("enable: " + deflection.find("./Enable").text)
if deflection.find("./Enable").text == '1':
if deflection.find("./Type").text == "fromNumber":
self.blacklist[0].append(deflection.find("./Number").text)
if deflection.find("./Type").text == "fromAnonymous":
self.blacklist[0].append("")
if deflection.find("./Type").text == "fromPB":
self.debug("get phonebook for blacklist")
if "X_AVM-DE_OnTel:1" in list(self.fc.services.keys()):
pbId = deflection.find("./PhonebookID").text
if pbId:
self.fc.call_action(_readPhonebookForBlacklist, "X_AVM-DE_OnTel", "GetPhonebook", NewPhonebookId=pbId)
else:
self.error("no phonebookId for blacklist? Strange")
else:
Notifications.AddNotification(MessageBox, _("Cannot get infos from FRITZ!Box yet\nStill initialising or wrong firmware version"), type=MessageBox.TYPE_ERROR, timeout=config.plugins.FritzCall.timeout.value)
self.debug(repr(self.blacklist))
def dial(self, number): # @UnusedVariable # pylint: disable=W0613
'''
Dial a number on extension config.plugins.FritzCall.extension.value
@param number: number to dial
@type number: string
'''
self.debug("")
Notifications.AddNotification(MessageBox, _("not yet implemented"), type=MessageBox.TYPE_ERROR, timeout=config.plugins.FritzCall.timeout.value)
def reset(self):
'''
Reset box
'''
self.debug("")
if self._loginFailure:
self.debug("skip because of login failure")
if "DeviceConfig:1" in list(self.fc.services.keys()):
self.fc.call_action(self._getInfo, "DeviceConfig", "Reboot")
else:
Notifications.AddNotification(MessageBox, _("Cannot get infos from FRITZ!Box yet\nStill initialising or wrong firmware version"), type=MessageBox.TYPE_ERROR, timeout=config.plugins.FritzCall.timeout.value)
class FritzCallFBF_dummy(object):
logger = logging.getLogger("FritzCall.FBF_dummy")
debug = logger.debug
def __init__(self):
'''
'''
self.debug("")
self.password = decode(config.plugins.FritzCall.password.value)
# self.information contains basic information about the (FBF) device:
# (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive)
# ('FRITZ!Box Fon WLAN 7390, FRITZ!OS 06.01', '21.01.2014, 05:02 Uhr', '87.185.104.85', ['0', '0', '0'], ['5', '6,7 Mbit/s / 667 kbit/s', None], None, '2', True, None)
# boxinfo: basic information like type, fw version
# uptime: up since when
# ipAddress: external ip address
# wlanState: status of WLAN: [ active, encrypted, no of devices active ]; active == '1' means active, encrypted == '0' means not encrypted
# dslState: whether connected via DSL or not: [ state, information, unused ]; state == '5' means up, everything else down
# tamActive: is a mailbox active: [ number of active mailboxes, infos, ... ]
# dectActive: is a dect device registered: if dect is active set to the number of connected dect devices
self.information = None
# numbers, which are blacklisted in the FBF and calls from them should also not be shown
self.blacklist = None
def getCalls(self, callScreen, callback, callType): # @UnusedVariable # pylint: disable=W0613
'''
Get list of recent calls in direction which (FBF_ALL_CALLS, FBF_IN_CALLS, FBF_MISSED_CALLS, FBF_OUT_CALLS)
@param callback: function to be called with list of (number, date, direction, remote, length, here) entries
@param which: direction of calls to be grabbed
'''
self.debug("")
Notifications.AddNotification(MessageBox, _("not yet implemented"), type=MessageBox.TYPE_ERROR, timeout=config.plugins.FritzCall.timeout.value)
def getInfo(self, callback):
'''
Retrieve information from box and fill in self.information and self.blacklist
'''
self.debug("")
Notifications.AddNotification(MessageBox, _("not yet implemented"), type=MessageBox.TYPE_ERROR, timeout=config.plugins.FritzCall.timeout.value)
def loadFritzBoxPhonebook(self, phonebook): # @UnusedVariable # pylint: disable=W0613
'''
Load phonebook from device and add it to the phonebook
@param phonebook: phonebook to be amended
@type phonebook: dictionary of number, information
'''
self.debug("")
Notifications.AddNotification(MessageBox, _("not yet implemented"), type=MessageBox.TYPE_ERROR, timeout=config.plugins.FritzCall.timeout.value)
def changeWLAN(self, state, callback): # @UnusedVariable # pylint: disable=W0613
'''
Change the status of the WLAN
@param state: '0' means: turn off, '1' turn on
@type state: string
'''
self.debug("")
Notifications.AddNotification(MessageBox, _("not yet implemented"), type=MessageBox.TYPE_ERROR, timeout=config.plugins.FritzCall.timeout.value)
def changeGuestAccess(self, statusGuestAccess, callback): # @UnusedVariable # pylint: disable=W0613
'''
Change the status of the WLAN guest access
@param statusGuestAccess: 'WLAN', 'WLAN, LAN' or 'LAN'
@type statusGuestAccess: string
'''
self.debug("")
Notifications.AddNotification(MessageBox, _("not yet implemented"), type=MessageBox.TYPE_ERROR, timeout=config.plugins.FritzCall.timeout.value)
def changeMailbox(self, which, callback): # @UnusedVariable # pylint: disable=W0613
'''
Toggle mailbox status
@param which: number, which mailbox to toggle; '-1' means all
@type which: string
'''
self.debug("")
Notifications.AddNotification(MessageBox, _("not yet implemented"), type=MessageBox.TYPE_ERROR, timeout=config.plugins.FritzCall.timeout.value)
def dial(self, number): # @UnusedVariable # pylint: disable=W0613
'''
Dial a number on extension config.plugins.FritzCall.extension.value
@param number: number to dial
@type number: string
'''
self.debug("")
Notifications.AddNotification(MessageBox, _("not yet implemented"), type=MessageBox.TYPE_ERROR, timeout=config.plugins.FritzCall.timeout.value)
def reset(self):
'''
Reset box
'''
self.debug("")
Notifications.AddNotification(MessageBox, _("not yet implemented"), type=MessageBox.TYPE_ERROR, timeout=config.plugins.FritzCall.timeout.value)