コード例 #1
0
ファイル: default.py プロジェクト: kodinerds/repo
    def getPhonebook(self):

        if self.__phoneBookFacade is None:
            self.__phoneBookFacade = PhoneBookFacade(imagepath=__ImageCache__)
            setting_keys = self.__phoneBookFacade.get_setting_keys()
            for key in setting_keys: setting_keys[key] = __addon__.getSetting(key)
            self.__phoneBookFacade.set_settings(setting_keys)

        if self.__phonebook is None:
            try:
                self.__phonebook = self.__phoneBookFacade.getPhonebook()
                self.notifyLog('%s entries from %s loaded, %s images cached' % (
                    len(self.__phonebook), self.__server, self.__phoneBookFacade.imagecount()))
            except self.__phoneBookFacade.HostUnreachableException:
                self.notifyOSD(__LS__(30030), __LS__(30031) % (self.__server, LISTENPORT), __IconError__)
            except self.__phoneBookFacade.LoginFailedException:
                self.notifyOSD(__LS__(30033), __LS__(30034), __IconError__)
            except self.__phoneBookFacade.InternalServerErrorException:
                self.notifyOSD(__LS__(30035), __LS__(30036), __IconError__)
コード例 #2
0
class FritzCallmonitor(object):
    __phoneBookFacade = None
    __phonebook = None
    __hide = False
    __s = None

    def __init__(self):

        self.PlayerProps = PlayerProperties()
        self.Mon = tools.Monitor()
        self.getPhonebook()

        self.ScreensaverActive = xbmc.getCondVisibility(
            'System.ScreenSaverActive')

        HOME.setProperty('FritzCallMon.InCall', 'false')

    class CallMonitorLine(dict):
        def __init__(self, line):
            if isinstance(line, str):

                token = line.split(';')
                self.command = token[1]
                self['connection_id'] = token[2]

                if self.command == 'CALL':
                    self['extension'] = token[3]
                    self['number_used'] = token[4]
                    self['number_called'] = token[5]
                    self['sip'] = token[6]

                elif self.command == 'RING':
                    self['date'] = token[0]
                    self['number_caller'] = token[3]
                    self['number_called'] = token[4]
                    self['sip'] = token[5]

                elif self.command == 'CONNECT':
                    self['date'] = token[0]
                    self['extension'] = token[3]
                    self['number'] = token[4]

                elif self.command == 'DISCONNECT':
                    self['date'] = token[0]
                    self['duration'] = token[3]

        def __getattr__(self, item):
            if item in self:
                return self[item]
            else:
                return False

    # END OF CLASS CallMonitorLine #

    # Get the Phonebook

    def getPhonebook(self):

        if self.__phoneBookFacade is None:
            self.__phoneBookFacade = PhoneBookFacade(imagepath=IMAGECACHE)
            setting_keys = self.__phoneBookFacade.get_setting_keys()
            for key in setting_keys:
                setting_keys[key] = ADDON.getSetting(key)
            self.__phoneBookFacade.set_settings(setting_keys)

        if self.__phonebook is None:
            try:
                self.__phonebook = self.__phoneBookFacade.getPhonebook()
                tools.writeLog(
                    '%s entries from %s loaded, %s images cached' %
                    (len(self.__phonebook), self.Mon.server,
                     self.__phoneBookFacade.imagecount()), xbmc.LOGNOTICE)
            except self.__phoneBookFacade.HostUnreachableException:
                tools.writeLog('Host %s unreachable' % (self.Mon.server),
                               level=xbmc.LOGERROR)
                tools.notify(LOC(30030),
                             LOC(30031) % (self.Mon.server, LISTENPORT),
                             ICON_ERROR)
            except self.__phoneBookFacade.LoginFailedException:
                tools.writeLog('Login failed. Check username/password',
                               level=xbmc.LOGERROR)
                tools.notify(LOC(30033), LOC(30034), ICON_ERROR)
            except self.__phoneBookFacade.InternalServerErrorException:
                tools.writeLog('Internal server error', level=xbmc.LOGERROR)
                tools.notify(LOC(30035), LOC(30036), ICON_ERROR)

    def getRecordByNumber(self, request_number):

        name = ''
        imageBMP = None

        if isinstance(self.__phonebook, dict):
            for item in self.__phonebook:
                for number in self.__phonebook[item]['numbers']:
                    if self.__phoneBookFacade.compareNumbers(
                            number, request_number, ccode=self.Mon.cCode):
                        tools.writeLog(
                            'Match an entry in database for %s: %s' %
                            (tools.mask(request_number), tools.mask(item)),
                            xbmc.LOGNOTICE)
                        name = item
                        fname = os.path.join(
                            IMAGECACHE,
                            re.sub('\D', '', number.replace('+', '00')) +
                            '.jpg')
                        if os.path.isfile(fname):
                            tools.writeLog('Load image from cache',
                                           xbmc.LOGNOTICE)
                            imageBMP = fname
                            break

        return {'name': name, 'imageBMP': imageBMP}

    def handlePlayerProps(self, state):

        tools.writeLog('Handle Player Properties for state \'%s\'' % (state))
        try:
            if self.Mon.optEarlyPause and (state == 'incoming'
                                           or state == 'outgoing'):
                self.PlayerProps.getConnectConditions(state)
                #
                # handle sound
                #
                if self.Mon.optMute and \
                        not self.PlayerProps.connCondition.get('muted', False) and \
                        not self.PlayerProps.connCondition.get('volChanged', False):
                    vol = self.PlayerProps.connCondition[
                        'volume'] * self.Mon.volume
                    tools.writeLog('Change volume to %s' % (vol),
                                   xbmc.LOGNOTICE)
                    self.PlayerProps.setVolume(vol)
                    self.PlayerProps.connCondition['volChanged'] = True
                #
                # handle audio, video & TV
                #
                if (self.Mon.optPauseAudio and self.PlayerProps.connCondition['playAudio']) \
                        or (self.Mon.optPauseVideo and self.PlayerProps.connCondition['playVideo']
                            and not self.PlayerProps.connCondition['playTV']) \
                        or (self.Mon.optPauseTV and self.PlayerProps.connCondition['playTV']):
                    tools.writeLog('Pausing audio, video or tv...',
                                   xbmc.LOGNOTICE)
                    xbmc.executebuiltin('PlayerControl(Play)')
                self.PlayerProps.getCallingConditions(state)

            elif not self.Mon.optEarlyPause and state == 'connected':
                self.PlayerProps.getConnectConditions(state)
                #
                # handle sound
                #
                if self.Mon.optMute and \
                        not self.PlayerProps.connCondition.get('muted', False) and \
                        not self.PlayerProps.connCondition.get('volChanged', False):
                    vol = self.PlayerProps.connCondition[
                        'volume'] * self.Mon.volume
                    tools.writeLog('Change volume to %s' % (vol),
                                   xbmc.LOGNOTICE)
                    self.PlayerProps.setVolume(vol)
                    self.PlayerProps.connCondition['volChanged'] = True
                #
                # handle audio, video & TV
                #
                if (self.Mon.optPauseAudio and self.PlayerProps.connCondition['playAudio']) \
                        or (self.Mon.optPauseVideo and self.PlayerProps.connCondition['playVideo']
                            and not self.PlayerProps.connCondition['playTV']) \
                        or (self.Mon.optPauseTV and self.PlayerProps.connCondition['playTV']):
                    tools.writeLog('Pausing audio, video or tv...',
                                   xbmc.LOGNOTICE)
                    xbmc.executebuiltin('PlayerControl(Play)')
                self.PlayerProps.getCallingConditions(state)

            elif state == 'disconnected':
                self.PlayerProps.getDisconnectConditions(state)
                #
                # nothing to do, all properties of disconnect are the same as connect properties
                #
                if self.PlayerProps.connCondition == self.PlayerProps.discCondition:
                    return
                #
                # handle sound
                #
                if self.Mon.optMute and not self.PlayerProps.connCondition.get('muted', False) \
                        and self.PlayerProps.discCondition['volume'] != self.PlayerProps.connCondition['volume']:
                    if self.PlayerProps.callCondition[
                            'volume'] == self.PlayerProps.discCondition[
                                'volume']:
                        tools.writeLog('Volume hasn\'t changed during call',
                                       xbmc.LOGNOTICE)
                        vol = self.PlayerProps.setVolume(
                            self.PlayerProps.connCondition['volume'])
                        tools.writeLog('Changed volume back to %s' % (vol),
                                       xbmc.LOGNOTICE)
                    else:
                        tools.writeLog(
                            'Volume has changed during call, don\'t change it back',
                            xbmc.LOGNOTICE)
                    self.PlayerProps.connCondition['volChanged'] = False

                #
                # handle audio, video & TV
                #
                if (self.Mon.optPauseAudio and self.PlayerProps.connCondition['playAudio']
                    and not self.PlayerProps.discCondition['playAudio']) \
                        or (self.Mon.optPauseVideo and self.PlayerProps.connCondition['playVideo']
                            and not self.PlayerProps.discCondition['playVideo']) \
                        or (self.Mon.optPauseTV and self.PlayerProps.connCondition['playTV']
                            and not self.PlayerProps.discCondition['playTV']):
                    tools.writeLog('Resume audio, video or tv...',
                                   xbmc.LOGNOTICE)
                    xbmc.executebuiltin('PlayerControl(Play)')
            else:
                tools.writeLog('don\'t handle properties for state %s' % state,
                               xbmc.LOGERROR)
                # self.PlayerProps.getConnectConditions(state)
        except Exception, e:
            tools.writeLog(
                'Error at line %s' % (str(sys.exc_info()[-1].tb_lineno)),
                xbmc.LOGERROR)
            tools.writeLog(str(type(e).__name__), xbmc.LOGERROR)
            tools.writeLog(e.message, level=xbmc.LOGERROR)
コード例 #3
0
class FritzCallmonitor(PlayerProperties):
    __phoneBookFacade = None
    __phonebook = None
    __klicktel = None
    __hide = None
    __s = None

    def __init__(self):

        self.PlayerProperties = PlayerProperties()
        self.getSettings()
        self.getPhonebook()

        self.ScreensaverActive = xbmc.getCondVisibility(
            'System.ScreenSaverActive')
        self.screensaver = None

        self.connectionEstablished = None
        self.userActionPlay = None
        self.userActionMute = None

    def error(*args, **kwargs):
        xbmc.log('%s %s' % (args, kwargs), xbmc.LOGERROR)

    class CallMonitorLine(dict):
        def __init__(self, line, **kwargs):
            if isinstance(line, str):

                token = line.split(';')
                self.command = token[1]
                self['connection_id'] = token[2]

                if self.command == 'CALL':
                    self['extension'] = token[3]
                    self['number_used'] = token[4]
                    self['number_called'] = token[5]
                    self['sip'] = token[6]

                elif self.command == 'RING':
                    self['date'] = token[0]
                    self['number_caller'] = token[3]
                    self['number_called'] = token[4]
                    self['sip'] = token[5]

                elif self.command == 'CONNECT':
                    self['date'] = token[0]
                    self['extension'] = token[3]
                    self['number'] = token[4]

                elif self.command == 'DISCONNECT':
                    self['date'] = token[0]
                    self['duration'] = token[3]

        def __getattr__(self, item):
            if item in self:
                return self[item]
            else:
                return False

    # END OF CLASS CallMonitorLine #

    # Get the Addon-Settings

    def getSettings(self):

        self.__server = __addon__.getSetting('phoneserver')
        __exnums = __addon__.getSetting('excludeNums')

        # transform possible userinput from e.g. 'p1, p2,,   p3 p4  '
        # to a list like this: ['p1','p2','p3','p4']

        __exnums = __exnums.replace(',', ' ')
        __exnums = __exnums.join(' '.join(line.split())
                                 for line in __exnums.splitlines())
        self.__exnum_list = __exnums.split(' ')

        self.__dispMsgTime = int(
            re.match('\d+', __addon__.getSetting('dispTime')).group()) * 1000
        self.__cCode = __addon__.getSetting('cCode')
        self.__optShowOutgoing = True if __addon__.getSetting(
            'showOutgoingCalls').upper() == 'TRUE' else False
        self.__optMute = True if __addon__.getSetting(
            'optMute').upper() == 'TRUE' else False
        self.__optPauseAudio = True if __addon__.getSetting(
            'optPauseAudio').upper() == 'TRUE' else False
        self.__optPauseVideo = True if __addon__.getSetting(
            'optPauseVideo').upper() == 'TRUE' else False
        self.__optPauseTV = True if __addon__.getSetting(
            'optPauseTV').upper() == 'TRUE' else False
        self.__optEarlyPause = True if __addon__.getSetting(
            'optEarlyPause').upper() == 'TRUE' else False
        self.__useKlickTelReverse = True if __addon__.getSetting(
            'useKlickTelReverse').upper() == 'TRUE' else False

        self.notifyLog('Settings (re)loaded', level=xbmc.LOGDEBUG)

    # Get the Phonebook

    def getPhonebook(self):

        if self.__phoneBookFacade is None:
            self.__phoneBookFacade = PhoneBookFacade(imagepath=__ImageCache__)
            setting_keys = self.__phoneBookFacade.get_setting_keys()
            for key in setting_keys:
                setting_keys[key] = __addon__.getSetting(key)
            self.__phoneBookFacade.set_settings(setting_keys)

        if self.__phonebook is None:
            try:
                self.__phonebook = self.__phoneBookFacade.getPhonebook()
                self.notifyLog('%s entries from %s loaded, %s images cached' %
                               (len(self.__phonebook), self.__server,
                                self.__phoneBookFacade.imagecount()))
            except self.__phoneBookFacade.HostUnreachableException:
                self.notifyOSD(__LS__(30030),
                               __LS__(30031) % (self.__server, LISTENPORT),
                               __IconError__)
            except self.__phoneBookFacade.LoginFailedException:
                self.notifyOSD(__LS__(30033), __LS__(30034), __IconError__)
            except self.__phoneBookFacade.InternalServerErrorException:
                self.notifyOSD(__LS__(30035), __LS__(30036), __IconError__)

    def getNameByKlickTel(self, request_number):

        if self.__useKlickTelReverse:
            if self.__klicktel is None:
                self.__klicktel = KlickTel.KlickTelReverseSearch()
            try:
                return self.__klicktel.search(request_number)
            except Exception as e:
                self.notifyLog(str(e), level=xbmc.LOGERROR)
        return False

    def getRecordByNumber(self, request_number):

        name = ''
        imageBMP = None

        if isinstance(self.__phonebook, dict):
            for item in self.__phonebook:
                for number in self.__phonebook[item]['numbers']:
                    if self.__phoneBookFacade.compareNumbers(
                            number, request_number, ccode=self.__cCode):
                        self.notifyLog(
                            'Match an entry in database for %s: %s' %
                            (request_number, item))
                        name = item
                        fname = os.path.join(
                            __ImageCache__,
                            hashlib.md5(item.encode('utf-8')).hexdigest() +
                            '.jpg')
                        if os.path.isfile(fname):
                            self.notifyLog('Load image from cache: %s' %
                                           (os.path.basename(fname)))
                            imageBMP = fname
                            break

        return {'name': name, 'imageBMP': imageBMP}

    def isExcludedNumber(self, exnum):
        self.__hide = False
        if exnum in self.__exnum_list:
            self.notifyLog('%s is excluded from monitoring, do not notify...' %
                           (exnum))
            self.__hide = True
        return self.__hide

    def handlePlayerProperties(self):
        self.PlayerProperties.getConnectConditions()
        if self.PlayerProperties.isPause != self.PlayerProperties.isConnectPause:
            self.userActionPlay = True
        if self.PlayerProperties.isMute != self.PlayerProperties.isConnectMute:
            self.userActionMute = True
        #
        # Save connection for handleDisconnected:
        # this condition determines whether the play and mute commands has to be executed again
        #
        self.connectionEstablished = True

        # Extra condition: only do this if the user hasn't changed the status of the player

        if (
                self.__optPauseAudio or self.__optPauseVideo
        ) and not self.PlayerProperties.isPause and not self.userActionPlay:
            if self.__optPauseTV and self.PlayerProperties.isPlayTV:
                self.notifyLog('Player is playing TV, pausing...')
                xbmc.executebuiltin('PlayerControl(Play)')
                # Save the status of the player for later comparison
                self.PlayerProperties.isConnectPause = True
            elif self.__optPauseVideo and self.PlayerProperties.isPlayVideo and not self.PlayerProperties.isPlayTV:
                self.notifyLog('Player is playing Video, pausing...')
                xbmc.executebuiltin('PlayerControl(Play)')
                # Save the status of the player for later comparison
                self.PlayerProperties.isConnectPause = True
            elif self.__optPauseAudio and self.PlayerProperties.isPlayAudio and not self.PlayerProperties.isPlayTV:
                self.notifyLog('Player is playing Audio, pausing...')
                xbmc.executebuiltin('PlayerControl(Play)')
                # Save the status of the player for later comparison
                self.PlayerProperties.isConnectPause = True

        if self.__optMute and not self.PlayerProperties.isMute and not self.userActionMute:
            if not (self.__optPauseAudio or self.__optPauseVideo) or (
                    not self.__optPauseTV and self.PlayerProperties.isPlayTV):
                self.notifyLog('Muting Volume...')
                xbmc.executebuiltin('Mute')
                # Save the status of the player for later comparison
                self.PlayerProperties.isConnectMute = True

    def handleOutgoingCall(self, line):
        self.PlayerProperties.getConditions()
        self.connectionEstablished = False
        self.userActionPlay = False
        self.userActionMute = False
        if not self.isExcludedNumber(line.number_used):
            if self.__optShowOutgoing:
                record = self.getRecordByNumber(line.number_called)
                name = __LS__(
                    30012) if record['name'] == '' else record['name']
                icon = __IconDefault__ if record['imageBMP'] == '' else record[
                    'imageBMP']
                self.notifyOSD(__LS__(30013),
                               __LS__(30014) % (name, line.number_called),
                               icon)
            self.notifyLog('Outgoing call from %s to %s' %
                           (line.number_used, line.number_called))

    def handleIncomingCall(self, line):
        self.PlayerProperties.getConditions()
        self.connectionEstablished = False
        self.userActionPlay = False
        self.userActionMute = False
        if not self.isExcludedNumber(line.number_called):
            if len(line.number_caller) > 0:
                caller_num = line.number_caller
                self.notifyLog(
                    'trying to resolve name from incoming number %s' %
                    (caller_num))
                record = self.getRecordByNumber(caller_num)
                name = record['name']
                icon = __IconOk__ if record['imageBMP'] == '' else record[
                    'imageBMP']
                if not name:
                    name = self.getNameByKlickTel(caller_num)
                    if name:
                        icon = __IconKlickTel__
                    else:
                        icon = __IconUnknown__
                        name = __LS__(30012)
            else:
                name = __LS__(30012)
                caller_num = __LS__(30016)
                icon = __IconUnknown__

            if self.__optEarlyPause: self.handlePlayerProperties()

            # TODO: read actual screensaver via JSON, set screensaver to None
            '''
            query = {
                "jsonrpc": "2.0",
                "method": "Settings.getSettingValue",
                "params": {"setting": "screensaver.mode"},
                "id": 0
            }
            res = json.loads(xbmc.executeJSONRPC(json.dumps(query, encoding='utf-8')))
            self.screensaver = res['result']['value']
            query = {
                "jsonrpc": "2.0",
                "method": "Settings.setSettingValue",
                "params": {"setting": "screensaver.mode", "value": ""},
                "id": 0
            }
            res = json.loads(xbmc.executeJSONRPC(json.dumps(query, encoding='utf-8')))
            self.notifyLog('Setting Screensaver %s to None' % (self.screensaver))
            '''

            self.notifyOSD(__LS__(30010),
                           __LS__(30011) % (name, caller_num), icon,
                           self.__dispMsgTime)
            self.notifyLog('Incoming call from %s (%s)' % (name, caller_num))

    def handleConnected(self, line):
        self.notifyLog('Line connected')
        if not self.__hide:
            if not self.__optEarlyPause: self.handlePlayerProperties()

    def handleDisconnected(self, line):
        if not self.__hide:
            self.notifyLog('Line disconnected')

            # Use the conditions before connect. These are the real conditions to give back.
            # Check whether the status of the player has changed in the meantime by the user

            self.PlayerProperties.getDisconnectConditions()
            if self.connectionEstablished and self.PlayerProperties.isConnectPause != self.PlayerProperties.isDisconnectPause:
                self.userActionPlay = True
            if self.connectionEstablished and self.PlayerProperties.isConnectMute != self.PlayerProperties.isDisconnectMute:
                self.userActionMute = True

            # Use condition before connect.
            # Also, only do this if connection was established and user hasn't changed the status of the player

            if self.__optPauseAudio and self.PlayerProperties.isPlayAudio and not self.PlayerProperties.isPause and self.connectionEstablished and not self.userActionPlay:
                self.notifyLog('Player was not pausing Audio, resume...')
                xbmc.executebuiltin('PlayerControl(Play)')
            elif self.__optPauseVideo and self.PlayerProperties.isPlayVideo and not self.PlayerProperties.isPause and self.connectionEstablished and not self.userActionPlay:
                self.notifyLog('Player was not playing Video, resume...')
                xbmc.executebuiltin('PlayerControl(Play)')

            # Use condition before connect.
            # Also, only do this if connection was established and user hasn't changed the condition of the player

            if self.__optMute and not self.PlayerProperties.isMute and self.connectionEstablished and not self.userActionMute:
                # Extra condition: You don't want another condition to unmute than to mute.
                if not (self.__optPauseAudio or self.__optPauseVideo) or (
                        not self.__optPauseTV
                        and self.PlayerProperties.isPlayTV):
                    self.notifyLog('Volume was not muted, unmute...')
                    xbmc.executebuiltin('Mute')

            # TODO: set screensaver to default module
            '''
            query = {
                "jsonrpc": "2.0",
                "method": "Settings.setSettingValue",
                "params": {"setting": "screensaver.mode", "value": self.screensaver},
                "id": 0
            }
            res = json.loads(xbmc.executeJSONRPC(json.dumps(query, encoding='utf-8')))
            self.notifyLog('Setting Screensaver back to %s' % (self.screensaver))
            '''

        else:
            self.notifyLog(
                'excluded number seems disconnected, reset status of callmonitor'
            )
            self.__hide = False

    def notifyOSD(self, header, message, icon=__IconDefault__, dispTime=5000):
        OSD.notification(header.encode('utf-8'), message.encode('utf-8'), icon,
                         dispTime)

    def notifyLog(self, message, level=xbmc.LOGNOTICE):
        xbmc.log('[%s] %s' % (__addonname__, message.encode('utf-8')), level)

    def connect(self, notify=False):
        if self.__s is not None:
            self.__s.close()
            self.__s = None
        try:
            self.__s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.__s.settimeout(30)
            self.__s.connect((self.__server, LISTENPORT))
        except socket.error as e:
            if notify:
                self.notifyOSD(__LS__(30030),
                               __LS__(30031) % (self.__server, LISTENPORT),
                               __IconError__)
            self.notifyLog('Could not connect to %s:%s' %
                           (self.__server, LISTENPORT),
                           level=xbmc.LOGERROR)
            self.notifyLog('%s' % (e), level=xbmc.LOGERROR)
            return False
        except Exception as e:
            self.notifyLog('%s' % (e), level=xbmc.LOGERROR)
            return False
        else:
            self.notifyLog('Connected, listen to %s on port %s' %
                           (self.__server, LISTENPORT))
            self.__s.settimeout(0.2)
            return True

    def start(self):

        if self.connect(notify=True):

            # MAIN SERVICE

            Mon = XBMCMonitor()
            while not Mon.abortRequested():

                if Mon.settingsChanged:
                    self.getSettings()
                    Mon.settingsChanged = False

                # ToDo: investigate more from https://pymotw.com/2/select/index.html#module-select
                # i.e check exception handling

                try:
                    fbdata = self.__s.recv(512)
                    line = self.CallMonitorLine(fbdata)

                    {
                        'CALL': self.handleOutgoingCall,
                        'RING': self.handleIncomingCall,
                        'CONNECT': self.handleConnected,
                        'DISCONNECT': self.handleDisconnected
                    }.get(line.command, self.error)(line)

                except socket.timeout:
                    pass
                except socket.error as e:
                    self.notifyLog('No connection to %s, try to respawn' %
                                   (self.__server),
                                   level=xbmc.LOGERROR)
                    self.notifyLog('%s' % (e), level=xbmc.LOGERROR)
                    self.connect()
                except IndexError:
                    self.notifyLog('Communication failure',
                                   level=xbmc.LOGERROR)
                    self.connect()
                except Exception as e:
                    self.notifyLog('%s' % (e), level=xbmc.LOGERROR)
                    break

            self.__s.close()
コード例 #4
0
ファイル: default.py プロジェクト: kodinerds/repo
class FritzCallmonitor(PlayerProperties):
    __phoneBookFacade = None
    __phonebook = None
    __klicktel = None
    __hide = None
    __s = None

    def __init__(self):

        self.PlayerProperties = PlayerProperties()
        self.getSettings()
        self.getPhonebook()

        self.ScreensaverActive = xbmc.getCondVisibility('System.ScreenSaverActive')
        self.screensaver = None

        self.connectionEstablished = None
        self.userActionPlay = None
        self.userActionMute = None

    def error(*args, **kwargs):
        xbmc.log('%s %s' % (args, kwargs), xbmc.LOGERROR)

    class CallMonitorLine(dict):

        def __init__(self, line, **kwargs):
            if isinstance(line, str):

                token = line.split(';')
                self.command = token[1]
                self['connection_id'] = token[2]

                if self.command == 'CALL':
                    self['extension'] = token[3]
                    self['number_used'] = token[4]
                    self['number_called'] = token[5]
                    self['sip'] = token[6]

                elif self.command == 'RING':
                    self['date'] = token[0]
                    self['number_caller'] = token[3]
                    self['number_called'] = token[4]
                    self['sip'] = token[5]

                elif self.command == 'CONNECT':
                    self['date'] = token[0]
                    self['extension'] = token[3]
                    self['number'] = token[4]

                elif self.command == 'DISCONNECT':
                    self['date'] = token[0]
                    self['duration'] = token[3]

        def __getattr__(self, item):
            if item in self:
                return self[item]
            else:
                return False

    # END OF CLASS CallMonitorLine #

    # Get the Addon-Settings

    def getSettings(self):

        self.__server = __addon__.getSetting('phoneserver')
        __exnums = __addon__.getSetting('excludeNums')

        # transform possible userinput from e.g. 'p1, p2,,   p3 p4  '
        # to a list like this: ['p1','p2','p3','p4']

        __exnums = __exnums.replace(',', ' ')
        __exnums = __exnums.join(' '.join(line.split()) for line in __exnums.splitlines())
        self.__exnum_list = __exnums.split(' ')

        self.__dispMsgTime = int(re.match('\d+', __addon__.getSetting('dispTime')).group()) * 1000
        self.__cCode = __addon__.getSetting('cCode')
        self.__optShowOutgoing = True if __addon__.getSetting('showOutgoingCalls').upper() == 'TRUE' else False
        self.__optMute = True if __addon__.getSetting('optMute').upper() == 'TRUE' else False
        self.__optPauseAudio = True if __addon__.getSetting('optPauseAudio').upper() == 'TRUE' else False
        self.__optPauseVideo = True if __addon__.getSetting('optPauseVideo').upper() == 'TRUE' else False
        self.__optPauseTV = True if __addon__.getSetting('optPauseTV').upper() == 'TRUE' else False
        self.__optEarlyPause = True if __addon__.getSetting('optEarlyPause').upper() == 'TRUE' else False
        self.__useKlickTelReverse = True if __addon__.getSetting('useKlickTelReverse').upper() == 'TRUE' else False

        self.notifyLog('Settings (re)loaded', level=xbmc.LOGDEBUG)

    # Get the Phonebook

    def getPhonebook(self):

        if self.__phoneBookFacade is None:
            self.__phoneBookFacade = PhoneBookFacade(imagepath=__ImageCache__)
            setting_keys = self.__phoneBookFacade.get_setting_keys()
            for key in setting_keys: setting_keys[key] = __addon__.getSetting(key)
            self.__phoneBookFacade.set_settings(setting_keys)

        if self.__phonebook is None:
            try:
                self.__phonebook = self.__phoneBookFacade.getPhonebook()
                self.notifyLog('%s entries from %s loaded, %s images cached' % (
                    len(self.__phonebook), self.__server, self.__phoneBookFacade.imagecount()))
            except self.__phoneBookFacade.HostUnreachableException:
                self.notifyOSD(__LS__(30030), __LS__(30031) % (self.__server, LISTENPORT), __IconError__)
            except self.__phoneBookFacade.LoginFailedException:
                self.notifyOSD(__LS__(30033), __LS__(30034), __IconError__)
            except self.__phoneBookFacade.InternalServerErrorException:
                self.notifyOSD(__LS__(30035), __LS__(30036), __IconError__)

    def getNameByKlickTel(self, request_number):

        if self.__useKlickTelReverse:
            if self.__klicktel is None: self.__klicktel = KlickTel.KlickTelReverseSearch()
            try:
                return self.__klicktel.search(request_number)
            except Exception as e:
                self.notifyLog(str(e), level=xbmc.LOGERROR)
        return False

    def getRecordByNumber(self, request_number):

        name = ''
        imageBMP = None

        if isinstance(self.__phonebook, dict):
            for item in self.__phonebook:
                for number in self.__phonebook[item]['numbers']:
                    if self.__phoneBookFacade.compareNumbers(number, request_number, ccode=self.__cCode):
                        self.notifyLog('Match an entry in database for %s: %s' % (request_number, item))
                        name = item
                        fname = os.path.join(__ImageCache__, hashlib.md5(item.encode('utf-8')).hexdigest() + '.jpg')
                        if os.path.isfile(fname):
                            self.notifyLog('Load image from cache: %s' % (os.path.basename(fname)))
                            imageBMP = fname
                            break

        return {'name': name, 'imageBMP': imageBMP}

    def isExcludedNumber(self, exnum):
        self.__hide = False
        if exnum in self.__exnum_list:
            self.notifyLog('%s is excluded from monitoring, do not notify...' % (exnum))
            self.__hide = True
        return self.__hide

    def handlePlayerProperties(self):
        self.PlayerProperties.getConnectConditions()
        if self.PlayerProperties.isPause != self.PlayerProperties.isConnectPause:
            self.userActionPlay = True
        if self.PlayerProperties.isMute != self.PlayerProperties.isConnectMute:
            self.userActionMute = True
        #
        # Save connection for handleDisconnected:
        # this condition determines whether the play and mute commands has to be executed again
        #
        self.connectionEstablished = True

        # Extra condition: only do this if the user hasn't changed the status of the player

        if (
            self.__optPauseAudio or self.__optPauseVideo) and not self.PlayerProperties.isPause and not self.userActionPlay:
            if self.__optPauseTV and self.PlayerProperties.isPlayTV:
                self.notifyLog('Player is playing TV, pausing...')
                xbmc.executebuiltin('PlayerControl(Play)')
                # Save the status of the player for later comparison
                self.PlayerProperties.isConnectPause = True
            elif self.__optPauseVideo and self.PlayerProperties.isPlayVideo and not self.PlayerProperties.isPlayTV:
                self.notifyLog('Player is playing Video, pausing...')
                xbmc.executebuiltin('PlayerControl(Play)')
                # Save the status of the player for later comparison
                self.PlayerProperties.isConnectPause = True
            elif self.__optPauseAudio and self.PlayerProperties.isPlayAudio and not self.PlayerProperties.isPlayTV:
                self.notifyLog('Player is playing Audio, pausing...')
                xbmc.executebuiltin('PlayerControl(Play)')
                # Save the status of the player for later comparison
                self.PlayerProperties.isConnectPause = True

        if self.__optMute and not self.PlayerProperties.isMute and not self.userActionMute:
            if not (self.__optPauseAudio or self.__optPauseVideo) or (
                        not self.__optPauseTV and self.PlayerProperties.isPlayTV):
                self.notifyLog('Muting Volume...')
                xbmc.executebuiltin('Mute')
                # Save the status of the player for later comparison
                self.PlayerProperties.isConnectMute = True

    def handleOutgoingCall(self, line):
        self.PlayerProperties.getConditions()
        self.connectionEstablished = False
        self.userActionPlay = False
        self.userActionMute = False
        if not self.isExcludedNumber(line.number_used):
            if self.__optShowOutgoing:
                record = self.getRecordByNumber(line.number_called)
                name = __LS__(30012) if record['name'] == '' else record['name']
                icon = __IconDefault__ if record['imageBMP'] == '' else record['imageBMP']
                self.notifyOSD(__LS__(30013), __LS__(30014) % (name, line.number_called), icon)
            self.notifyLog('Outgoing call from %s to %s' % (line.number_used, line.number_called))
            if self.__optEarlyPause: self.handlePlayerProperties()

    def handleIncomingCall(self, line):
        self.PlayerProperties.getConditions()
        self.connectionEstablished = False
        self.userActionPlay = False
        self.userActionMute = False
        if not self.isExcludedNumber(line.number_called):
            if len(line.number_caller) > 0:
                caller_num = line.number_caller
                self.notifyLog('trying to resolve name from incoming number %s' % (caller_num))
                record = self.getRecordByNumber(caller_num)
                name = record['name']
                icon = __IconOk__ if record['imageBMP'] == '' else record['imageBMP']
                if not name:
                    name = self.getNameByKlickTel(caller_num)
                    if name:
                        icon = __IconKlickTel__
                    else:
                        icon = __IconUnknown__
                        name = __LS__(30012)
            else:
                name = __LS__(30012)
                caller_num = __LS__(30016)
                icon = __IconUnknown__

            if self.__optEarlyPause: self.handlePlayerProperties()

            # TODO: read actual screensaver via JSON, set screensaver to None
            '''
            query = {
                "jsonrpc": "2.0",
                "method": "Settings.getSettingValue",
                "params": {"setting": "screensaver.mode"},
                "id": 0
            }
            res = json.loads(xbmc.executeJSONRPC(json.dumps(query, encoding='utf-8')))
            self.screensaver = res['result']['value']
            query = {
                "jsonrpc": "2.0",
                "method": "Settings.setSettingValue",
                "params": {"setting": "screensaver.mode", "value": ""},
                "id": 0
            }
            res = json.loads(xbmc.executeJSONRPC(json.dumps(query, encoding='utf-8')))
            self.notifyLog('Setting Screensaver %s to None' % (self.screensaver))
            '''

            self.notifyOSD(__LS__(30010), __LS__(30011) % (name, caller_num), icon, self.__dispMsgTime)
            self.notifyLog('Incoming call from %s (%s)' % (name, caller_num))


    def handleConnected(self, line):
        self.notifyLog('Line connected')
        if not self.__hide:
            if not self.__optEarlyPause: self.handlePlayerProperties()

    def handleDisconnected(self, line):
        if not self.__hide:
            self.notifyLog('Line disconnected')

            # Use the conditions before connect. These are the real conditions to give back.
            # Check whether the status of the player has changed in the meantime by the user

            self.PlayerProperties.getDisconnectConditions()
            if self.connectionEstablished and self.PlayerProperties.isConnectPause != self.PlayerProperties.isDisconnectPause:
                self.userActionPlay = True
            if self.connectionEstablished and self.PlayerProperties.isConnectMute != self.PlayerProperties.isDisconnectMute:
                self.userActionMute = True

            # Use condition before connect.
            # Also, only do this if connection was established and user hasn't changed the status of the player

            if self.__optPauseAudio and self.PlayerProperties.isPlayAudio and not self.PlayerProperties.isPause and self.connectionEstablished and not self.userActionPlay:
                self.notifyLog('Player was not pausing Audio, resume...')
                xbmc.executebuiltin('PlayerControl(Play)')
            elif self.__optPauseVideo and self.PlayerProperties.isPlayVideo and not self.PlayerProperties.isPause and self.connectionEstablished and not self.userActionPlay:
                self.notifyLog('Player was not playing Video, resume...')
                xbmc.executebuiltin('PlayerControl(Play)')

            # Use condition before connect.
            # Also, only do this if connection was established and user hasn't changed the condition of the player

            if self.__optMute and not self.PlayerProperties.isMute and self.connectionEstablished and not self.userActionMute:
                # Extra condition: You don't want another condition to unmute than to mute.
                if not (self.__optPauseAudio or self.__optPauseVideo) or (
                            not self.__optPauseTV and self.PlayerProperties.isPlayTV):
                    self.notifyLog('Volume was not muted, unmute...')
                    xbmc.executebuiltin('Mute')

            # TODO: set screensaver to default module
            '''
            query = {
                "jsonrpc": "2.0",
                "method": "Settings.setSettingValue",
                "params": {"setting": "screensaver.mode", "value": self.screensaver},
                "id": 0
            }
            res = json.loads(xbmc.executeJSONRPC(json.dumps(query, encoding='utf-8')))
            self.notifyLog('Setting Screensaver back to %s' % (self.screensaver))
            '''

        else:
            self.notifyLog('excluded number seems disconnected, reset status of callmonitor')
            self.__hide = False

    def notifyOSD(self, header, message, icon=__IconDefault__, dispTime=5000):
        OSD.notification(header.encode('utf-8'), message.encode('utf-8'), icon, dispTime)

    def notifyLog(self, message, level=xbmc.LOGNOTICE):
        xbmc.log('[%s] %s' % (__addonname__, message.encode('utf-8')), level)

    def connect(self, notify=False):
        if self.__s is not None:
            self.__s.close()
            self.__s = None
        try:
            self.__s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.__s.settimeout(30)
            self.__s.connect((self.__server, LISTENPORT))
        except socket.error as e:
            if notify: self.notifyOSD(__LS__(30030), __LS__(30031) % (self.__server, LISTENPORT), __IconError__)
            self.notifyLog('Could not connect to %s:%s' % (self.__server, LISTENPORT), level=xbmc.LOGERROR)
            self.notifyLog('%s' % (e), level=xbmc.LOGERROR)
            return False
        except Exception as e:
            self.notifyLog('%s' % (e), level=xbmc.LOGERROR)
            return False
        else:
            self.notifyLog('Connected, listen to %s on port %s' % (self.__server, LISTENPORT))
            self.__s.settimeout(0.2)
            return True

    def start(self):

        if self.connect(notify=True):

            # MAIN SERVICE

            Mon = XBMCMonitor()
            while not Mon.abortRequested():

                if Mon.settingsChanged:
                    self.getSettings()
                    Mon.settingsChanged = False

                # ToDo: investigate more from https://pymotw.com/2/select/index.html#module-select
                # i.e check exception handling

                try:
                    fbdata = self.__s.recv(512)
                    line = self.CallMonitorLine(fbdata)

                    {
                        'CALL': self.handleOutgoingCall,
                        'RING': self.handleIncomingCall,
                        'CONNECT': self.handleConnected,
                        'DISCONNECT': self.handleDisconnected
                    }.get(line.command, self.error)(line)

                except socket.timeout:
                    pass
                except socket.error as e:
                    self.notifyLog('No connection to %s, try to respawn' % (self.__server), level=xbmc.LOGERROR)
                    self.notifyLog('%s' % (e), level=xbmc.LOGERROR)
                    self.connect()
                except IndexError:
                    self.notifyLog('Communication failure', level=xbmc.LOGERROR)
                    self.connect()
                except Exception as e:
                    self.notifyLog('%s' % (e), level=xbmc.LOGERROR)
                    break

            self.__s.close()
コード例 #5
0
class FritzCallmonitor(object):
    __phoneBookFacade = None
    __phonebook = None
    __klicktel = None
    __hide = False
    __s = None

    def __init__(self):

        self.PlayerProps = PlayerProperties()
        self.Mon = tools.Monitor()
        self.getPhonebook()

        self.ScreensaverActive = xbmc.getCondVisibility(
            'System.ScreenSaverActive')
        self.screensaver = None

    class CallMonitorLine(dict):
        def __init__(self, line, **kwargs):
            if isinstance(line, str):

                token = line.split(';')
                self.command = token[1]
                self['connection_id'] = token[2]

                if self.command == 'CALL':
                    self['extension'] = token[3]
                    self['number_used'] = token[4]
                    self['number_called'] = token[5]
                    self['sip'] = token[6]

                elif self.command == 'RING':
                    self['date'] = token[0]
                    self['number_caller'] = token[3]
                    self['number_called'] = token[4]
                    self['sip'] = token[5]

                elif self.command == 'CONNECT':
                    self['date'] = token[0]
                    self['extension'] = token[3]
                    self['number'] = token[4]

                elif self.command == 'DISCONNECT':
                    self['date'] = token[0]
                    self['duration'] = token[3]

        def __getattr__(self, item):
            if item in self:
                return self[item]
            else:
                return False

    # END OF CLASS CallMonitorLine #

    # Get the Phonebook

    def getPhonebook(self):

        if self.__phoneBookFacade is None:
            self.__phoneBookFacade = PhoneBookFacade(imagepath=__ImageCache__)
            setting_keys = self.__phoneBookFacade.get_setting_keys()
            for key in setting_keys:
                setting_keys[key] = __addon__.getSetting(key)
            self.__phoneBookFacade.set_settings(setting_keys)

        if self.__phonebook is None:
            try:
                self.__phonebook = self.__phoneBookFacade.getPhonebook()
                tools.writeLog(
                    '%s entries from %s loaded, %s images cached' %
                    (len(self.__phonebook), self.Mon.server,
                     self.__phoneBookFacade.imagecount()), xbmc.LOGNOTICE)
            except self.__phoneBookFacade.HostUnreachableException:
                tools.writeLog('Host %s unreachable' % (self.Mon.server),
                               level=xbmc.LOGERROR)
                tools.notify(__LS__(30030),
                             __LS__(30031) % (self.Mon.server, LISTENPORT),
                             __IconError__)
            except self.__phoneBookFacade.LoginFailedException:
                tools.writeLog('Login failed. Check username/password',
                               level=xbmc.LOGERROR)
                tools.notify(__LS__(30033), __LS__(30034), __IconError__)
            except self.__phoneBookFacade.InternalServerErrorException:
                tools.writeLog('Internal server error', level=xbmc.LOGERROR)
                tools.notify(__LS__(30035), __LS__(30036), __IconError__)

    def getNameByKlickTel(self, request_number):

        if self.Mon.useKlickTelReverse:
            if self.__klicktel is None:
                self.__klicktel = KlickTel.KlickTelReverseSearch()
            try:
                return self.__klicktel.search(request_number)
            except Exception, e:
                tools.writeLog('Error at line %s' %
                               (sys.exc_info()[-1].tb_lineno))
                tools.writeLog(e.message, level=xbmc.LOGERROR)
        return False