def validate(self, value): if value.startswith(('sip:', 'sips:')): uri = value else: uri = 'sip:' + value try: SIPURI.parse(uri) except SIPCoreError: raise ValueError('invalid SIP URI: {}'.format(value)) return value
def validate(self, value): prefix, sep, suffix = value.partition(':') if sep and prefix in ('sip', 'sips'): aor = suffix else: aor = value try: SIPURI.parse('sip:' + aor) except SIPCoreError: raise ValueError('invalid SIP URI: {}'.format(value)) return aor
def get_audio_recordings(self): result = [] historydir = self.get_audio_recordings_directory() for acct in os.listdir(historydir): dirname = historydir + "/" + acct if not os.path.isdir(dirname): continue files = [ dirname + "/" + f for f in os.listdir(dirname) if f.endswith(".wav") ] for file in files: try: toks = file.split("/")[-1].split("-", 2) if len(toks) == 3: date, time, rest = toks timestamp = date[:4] + "/" + date[4:6] + "/" + date[ 6:8] + " " + time[:2] + ":" + time[2:4] pos = rest.rfind("-") if pos >= 0: remote = rest[:pos] else: remote = rest try: identity = SIPURI.parse('sip:' + str(remote)) remote_party = format_identity_to_string( identity, check_contact=True) except SIPCoreError: remote_party = "%s" % (remote) else: try: identity = SIPURI.parse('sip:' + str(file[:-4])) remote_party = format_identity_to_string( identity, check_contact=True) except SIPCoreError: remote_party = file[:-4] timestamp = datetime.fromtimestamp(int( stat.st_ctime)).strftime("%E %T") stat = os.stat(file) result.append((timestamp, remote_party, file)) except: import traceback traceback.print_exc() pass result.sort(lambda a, b: cmp(a[0], b[0])) return result
def is_anonymous(uri): """ Check if the given URI is an anonymous uri """ anon_users = ('asterisk', 'unknown', 'anonymous') if isinstance(uri, (SIPURI, FrozenSIPURI)): if uri.user.lower() in anon_users: return True return (uri.user is None or uri.user.lower() == 'anonymous') and ( uri.host is None or uri.host.lower() == 'anonymous.invalid') else: if not (uri.startswith('sip:') or uri.startswith('sips:')): uri = "sip:%s" % uri try: sip_uri = SIPURI.parse(str(uri)) except: return False else: if sip_uri.user is not None and sip_uri.user.decode().lower( ) in anon_users: return True return (sip_uri.user is None or sip_uri.user.decode().lower() == 'anonymous') and (sip_uri.host is None or sip_uri.host.decode().lower() == 'anonymous.invalid')
def __init__(self, request): self.finished = False request.notifyFinish().addCallbacks(self._responseSucceeded, self._responseFailed) jsondata = request.content.getvalue() try: data = jsonlib.loads(jsondata) except (jsonlib.DecodeError, ValueError): if not self.finished: request.setResponseCode(400, 'Could not decode JSON data') request.finish() return try: target_uri = data.get('target_uri', '') if not re.match('^(sip:|sips:)', target_uri): target_uri = 'sip:%s' % target_uri target_uri = SIPURI.parse(target_uri) except SIPCoreError: if not self.finished: request.setResponseCode(400, 'Supplied SIP URI is invalid') request.finish() return cache = DataCache() data = cache.get(str(target_uri)) if data is not None: if not self.finished: request.setHeader('Content-Type', 'application/json') request.write(jsonlib.dumps(data)) request.finish() return self._target_uri = target_uri self._request = request self._handler = SIPOptionsRequestHandler(target_uri) NotificationCenter().add_observer(self, sender=self._handler) self._handler.start()
def parse(cls, value): if isinstance(value, BaseSIPURI): user = unicode(value.user) host = unicode(value.host) resource = unicode(value.parameters.get('gr', '')) or None return cls(user, host, resource) elif isinstance(value, JID): user = value.user host = value.host resource = value.resource return cls(user, host, resource) elif not isinstance(value, basestring): raise TypeError('uri needs to be a string') if not value.startswith(('sip:', 'sips:', 'xmpp:')): raise ValueError('invalid uri scheme for %s' % value) if value.startswith(('sip:', 'sips:')): try: uri = SIPURI.parse(value) except SIPCoreError: raise ValueError('invalid SIP uri: %s' % value) user = unicode(uri.user) host = unicode(uri.host) resource = unicode(uri.parameters.get('gr', '')) or None else: try: jid = JID(value[5:]) except Exception: raise ValueError('invalid XMPP uri: %s' % value) user = jid.user host = jid.host resource = jid.resource return cls(user, host, resource)
def start(self): if not self.refer_to_uri.startswith(('sip:', 'sips:')): self.refer_to_uri = 'sip:%s' % self.refer_to_uri try: self.refer_to_uri = SIPURI.parse(self.refer_to_uri) except SIPCoreError: log.msg('Room %s - failed to add %s' % (self.room_uri_str, self.refer_to_uri)) self._refer_request.reject(488) return notification_center = NotificationCenter() notification_center.add_observer(self, sender=self._refer_request) if self.method == 'INVITE': self._refer_request.accept() settings = SIPSimpleSettings() account = DefaultAccount() if account.sip.outbound_proxy is not None: uri = SIPURI(host=account.sip.outbound_proxy.host, port=account.sip.outbound_proxy.port, parameters={'transport': account.sip.outbound_proxy.transport}) else: uri = self.refer_to_uri lookup = DNSLookup() notification_center.add_observer(self, sender=lookup) lookup.lookup_sip_proxy(uri, settings.sip.transport_list) elif self.method == 'BYE': log.msg('Room %s - %s removed %s from the room' % (self.room_uri_str, self._refer_headers.get('From').uri, self.refer_to_uri)) self._refer_request.accept() conference_application = ConferenceApplication() conference_application.remove_participant(self.refer_to_uri, self.room_uri) self._refer_request.end(200) else: self._refer_request.reject(488)
def get_recordings(self, filter_uris=[]): result = [] historydir = self.get_recordings_directory() for acct in os.listdir(historydir): dirname = historydir + "/" + acct if not os.path.isdir(dirname): continue files = [dirname+"/"+f for f in os.listdir(dirname)] for file in files: try: recording_type = "audio" if file.endswith(".wav") else "video" stat = os.stat(file) toks = file.split("/")[-1].split("-", 2) if len(toks) == 3: date, time, rest = toks timestamp = date[:4]+"/"+date[4:6]+"/"+date[6:8]+" "+time[:2]+":"+time[2:4] pos = rest.rfind(".") if pos >= 0: remote = rest[:pos] else: remote = rest try: identity = SIPURI.parse('sip:'+str(remote)) remote_party = format_identity_to_string(identity, check_contact=True) except SIPCoreError: remote_party = "%s" % (remote) else: try: identity = SIPURI.parse('sip:'+str(file[:-4])) remote_party = format_identity_to_string(identity, check_contact=True) except SIPCoreError: remote_party = file[:-4] timestamp = datetime.fromtimestamp(int(stat.st_ctime)).strftime("%E %T") if filter_uris and remote_party not in filter_uris: continue result.append((timestamp, remote_party, file, recording_type)) except Exception: pass sorted(result, key=lambda x: x[0]) return result
def get_audio_recordings(self, filter_uris=[]): result = [] historydir = self.get_audio_recordings_directory() for acct in os.listdir(historydir): dirname = historydir + "/" + acct if not os.path.isdir(dirname): continue files = [dirname+"/"+f for f in os.listdir(dirname) if f.endswith(".wav")] for file in files: try: stat = os.stat(file) toks = file.split("/")[-1].split("-", 2) if len(toks) == 3: date, time, rest = toks timestamp = date[:4]+"/"+date[4:6]+"/"+date[6:8]+" "+time[:2]+":"+time[2:4] pos = rest.rfind("-") if pos >= 0: remote = rest[:pos] else: remote = rest try: identity = SIPURI.parse('sip:'+str(remote)) remote_party = format_identity_to_string(identity, check_contact=True) except SIPCoreError: remote_party = "%s" % (remote) else: try: identity = SIPURI.parse('sip:'+str(file[:-4])) remote_party = format_identity_to_string(identity, check_contact=True) except SIPCoreError: remote_party = file[:-4] timestamp = datetime.fromtimestamp(int(stat.st_ctime)).strftime("%E %T") if filter_uris and remote_party not in filter_uris: continue result.append((timestamp, remote_party, file)) except Exception: pass result.sort(lambda a,b: cmp(a[0],b[0])) return result
def checkURI(self, uri): if checkValidPhoneNumber(uri): return True if uri.startswith(('https:', 'http:')): url = urlparse.urlparse(uri) if url.scheme not in (u'http', u'https'): return False return True if not uri.startswith(('sip:', 'sips:')): uri = "sip:%s" % uri try: SIPURI.parse(str(uri)) except SIPCoreError: return False return True
def checkURI(self, uri): if checkValidPhoneNumber(uri): return True if uri.startswith(('https:', 'http:')): url = urllib.parse.urlparse(uri) if url.scheme not in ('http', 'https'): return False return True if not uri.startswith(('sip:', 'sips:')): uri = "sip:%s" % uri try: SIPURI.parse(str(uri)) except SIPCoreError: return False return True
def validateParticipant(uri): if not (uri.startswith('sip:') or uri.startswith('sips:')): uri = "sip:%s" % uri try: sip_uri = SIPURI.parse(str(uri)) except SIPCoreError: return False else: return sip_uri.user is not None and sip_uri.host is not None
def normalize_sip_uri_for_outgoing_session(target_uri, account): def format_uri(uri, default_domain, idd_prefix=None, prefix=None, strip_digits=None): if default_domain is not None: if "@" not in uri: if _pstn_match_regexp.match(uri): username = strip_addressbook_special_characters(uri) if idd_prefix: username = _pstn_plus_regexp.sub(idd_prefix, username) if strip_digits and len(username) > strip_digits: username = username[strip_digits:] if prefix: username = prefix + username else: username = uri uri = "%s@%s" % (username, default_domain) elif "." not in uri.split("@", 1)[1]: uri += "." + default_domain if not uri.startswith("sip:") and not uri.startswith("sips:"): uri = "sip:%s" % uri return uri try: target_uri = str(target_uri) except: show_error_panel( NSLocalizedString( "SIP address must not contain unicode characters: %s", "Label") % target_uri) return None if '@' not in target_uri and isinstance(account, BonjourAccount): show_error_panel( NSLocalizedString( "SIP address must contain host in bonjour mode: %s", "Label") % target_uri) return None target_uri = format_uri( target_uri, account.id.domain if not isinstance(account, BonjourAccount) else None, account.pstn.idd_prefix if not isinstance(account, BonjourAccount) else None, account.pstn.prefix if not isinstance(account, BonjourAccount) else None, account.pstn.strip_digits if not isinstance(account, BonjourAccount) else None) try: target_uri = SIPURI.parse(target_uri) except SIPCoreError: show_error_panel( NSLocalizedString("Invalid SIP address: %s", "Label") % target_uri) return None return target_uri
def _start_outgoing_jingle_session(self, streams): if self.xmpp_identity.uri.resource is not None: self.sip_session.reject() return xmpp_manager = XMPPManager() local_jid = self.sip_identity.uri.as_xmpp_jid() remote_jid = self.xmpp_identity.uri.as_xmpp_jid() # If this was an invitation to a conference, use the information in the Referred-By header if self.sip_identity.uri.host in xmpp_manager.muc_domains and self.sip_session.transfer_info and self.sip_session.transfer_info.referred_by: try: referred_by_uri = SIPURI.parse(self.sip_session.transfer_info.referred_by) except SIPCoreError: self.sip_session.reject(488) return else: inviter_uri = FrozenURI(referred_by_uri.user, referred_by_uri.host) local_jid = inviter_uri.as_xmpp_jid() # Use disco to gather potential JIDs to call d = xmpp_manager.disco_client_protocol.requestItems(remote_jid, sender=local_jid) try: items = block_on(d) except Exception: items = [] if not items: self.sip_session.reject(480) return # Check which items support Jingle valid = [] for item in items: d = xmpp_manager.disco_client_protocol.requestInfo(item.entity, nodeIdentifier=item.nodeIdentifier, sender=local_jid) try: info = block_on(d) except Exception: continue if jingle.NS_JINGLE in info.features and jingle.NS_JINGLE_APPS_RTP in info.features: valid.append(item.entity) if not valid: self.sip_session.reject(480) return # TODO: start multiple sessions? self._xmpp_identity = Identity(FrozenURI.parse(valid[0])) notification_center = NotificationCenter() if self.sip_identity.uri.host in xmpp_manager.muc_domains: self.jingle_session = JingleSession(xmpp_manager.jingle_coin_protocol) else: self.jingle_session = JingleSession(xmpp_manager.jingle_protocol) notification_center.add_observer(self, sender=self.jingle_session) self.jingle_session.connect(self.sip_identity, self.xmpp_identity, streams, is_focus=self.sip_session.remote_focus)
def create_uri(cls, account, address): if not address.startswith(('sip:', 'sips:')): address = 'sip:' + address username, separator, domain = address.partition('@') if not domain and isinstance(account, Account): domain = account.id.domain elif '.' not in domain and isinstance(account, Account): domain += '.' + account.id.domain elif not domain: raise ValueError('SIP address without domain') address = username + '@' + domain return SIPURI.parse(str(address))
def privmsg(self, user, channel, message): if channel == '*': return username = user.split('!', 1)[0] if username == self.nickname: return if channel == self.nickname: self.msg(username, "Sorry, I don't support private messages, I'm a bot.") return uri = SIPURI.parse('sip:%s@%s' % (urllib.quote(username), self.factory.config.server[0])) irc_message = IRCMessage(username, uri, message.decode('utf-8')) data = NotificationData(message=irc_message) NotificationCenter().post_notification('IRCBotGotMessage', self.factory, data)
def parse(cls, value): match = cls._re_format.match(value) if not match: raise ValueError('Cannot parse message/cpim identity header value: %r' % value) groupdict = match.groupdict() display_name = groupdict['display_name'] uri = groupdict['uri'] # FIXME: silly hack for sip-chatserver which sends incorrect URIs. -Luci if not uri.startswith(u'sip:') and not uri.startswith(u'sips:'): uri = u'sip:' + uri # FIXME: SIPURI is not unicode friendly and expects a str. -Luci uri = SIPURI.parse(str(uri)) return cls(uri, display_name)
def __eq__(self, other): if isinstance(other, ChatIdentity): return self.uri.user == other.uri.user and self.uri.host == other.uri.host elif isinstance(other, BaseSIPURI): return self.uri.user == other.user and self.uri.host == other.host elif isinstance(other, str): try: other_uri = SIPURI.parse(other) except Exception: return False else: return self.uri.user == other_uri.user and self.uri.host == other_uri.host else: return NotImplemented
def __eq__(self, other): if isinstance(other, ChatIdentity): return self.uri.user == other.uri.user and self.uri.host == other.uri.host elif isinstance(other, BaseSIPURI): return self.uri.user == other.user and self.uri.host == other.host elif isinstance(other, basestring): try: other_uri = SIPURI.parse(other) except Exception: return False else: return self.uri.user == other_uri.user and self.uri.host == other_uri.host else: return NotImplemented
def resolveAvatarUrl(self, url): if url.startswith("/avatar/"): uri = SIPURI.parse(url[8:].decode("hex")) # TODO: see if there is an official way to get this, including notification of changes # also needs fixing of webodf, allowing custom avatar renderer if self.account.uri == uri: avatar = IconManager().get('avatar') return avatar.filename if avatar != None else self.default_user_icon_filename contact, contact_uri = URIUtils.find_contact(uri) return contact.icon.filename return ""
def is_sip_aor_format(uri): """ Check if the given URI is a full SIP URI with username and host. """ if isinstance(uri, (SIPURI, FrozenSIPURI)): return uri.user is not None and uri.host is not None else: if not (uri.startswith('sip:') or uri.startswith('sips:')): uri = "sip:%s" % uri try: sip_uri = SIPURI.parse(str(uri)) except: return False else: return sip_uri.user is not None and sip_uri.host is not None
def is_anonymous(uri): """ Check if the given URI is an anonymous uri """ if isinstance(uri, (SIPURI, FrozenSIPURI)): return (uri.user is None or uri.user.lower() == 'anonymous') and (uri.host is None or uri.host.lower() == 'anonymous.invalid') else: if not (uri.startswith('sip:') or uri.startswith('sips:')): uri = "sip:%s" % uri try: sip_uri = SIPURI.parse(str(uri)) except: return False else: return (sip_uri.user is None or sip_uri.user.lower() == 'anonymous') and (sip_uri.host is None or sip_uri.host.lower() == 'anonymous.invalid')
def _lookup_sip_proxy(self, account): sip_uri = SIPURI.parse('sip:%s' % account) # The proxy dance: Sofia-SIP seems to do a DNS lookup per SIP message when a domain is passed # as the proxy, so do the resolution ourselves and give it pre-resolver proxy URL. Since we use # caching to avoid long delays, we randomize the results matching the highest priority route's # transport. proxy = GeneralConfig.outbound_sip_proxy if proxy is not None: proxy_uri = SIPURI(host=proxy.host, port=proxy.port, parameters={'transport': proxy.transport}) else: proxy_uri = SIPURI(host=sip_uri.host) settings = SIPSimpleSettings() try: routes = self.resolver.lookup_sip_proxy(proxy_uri, settings.sip.transport_list).wait() except DNSLookupError, e: raise DNSLookupError('DNS lookup error: %s' % e)
def _setup_new_subscriptions(self, urilist): # TODO: Add check to see active subscriptions so it doesn't subscribe twice # sets up a new subscription with the given list of URI's for uri in urilist: tempuri = uri if tempuri is None: tempuri = ToHeader( SIPURI(user=self.account.id.username, host=self.account.id.domain)) else: if '@' not in tempuri: tempuri = '%s@%s' % (tempuri, self.account.id.domain) if not uri.startswith('sip:') and not tempuri.startswith( 'sips:'): tempuri = 'sip:' + tempuri try: tempuri = ToHeader(SIPURI.parse(tempuri)) except SIPCoreError: self.output.put('Illegal SIP URI: %s' % tempuri) return 1 self.subscriptionqueue.append(tempuri) #reactor.callLater(0, self._subscribe) settings = SIPSimpleSettings() self._subscription_timeout = time() + 30 lookup = DNSLookup() notification_center = NotificationCenter() notification_center.add_observer(self, sender=lookup) proxyuri = None if self.account.sip.outbound_proxy is not None: proxyuri = SIPURI(host=self.account.sip.outbound_proxy.host, port=self.account.sip.outbound_proxy.port, parameters={ 'transport': self.account.sip.outbound_proxy.transport }) elif self.account.sip.always_use_my_proxy: proxyuri = SIPURI(host=self.account.id.domain) else: proxyuri = self.subscriptionqueue[0].uri lookup.lookup_sip_proxy(proxyuri, settings.sip.transport_list)
def __init__(self, account, contact, content, content_type='text/plain', recipients=None, courtesy_recipients=None, subject=None, timestamp=None, required=None, additional_headers=None, id=None): self.lookup = None self.account = account self.uri = contact.uri.uri self.content_type = content_type self.content = content self.id = id if id is not None else str(uuid.uuid4()) self.timestamp = timestamp if timestamp is not None else ISOTimestamp.now( ) self.sip_uri = SIPURI.parse('sip:%s' % self.uri)
def normalize_sip_uri_for_outgoing_session(target_uri, account): def format_uri(uri, default_domain, idd_prefix = None, prefix = None, strip_digits=None): if default_domain is not None: if "@" not in uri: if _pstn_match_regexp.match(uri): username = strip_addressbook_special_characters(uri) if idd_prefix: username = _pstn_plus_regexp.sub(idd_prefix, username) if strip_digits and len(username) > strip_digits: username = username[strip_digits:] if prefix: username = prefix + username else: username = uri uri = "%s@%s" % (username, default_domain) elif "." not in uri.split("@", 1)[1]: uri += "." + default_domain if not uri.startswith("sip:") and not uri.startswith("sips:"): uri = "sip:%s" % uri return uri try: target_uri = str(target_uri) except: show_error_panel(NSLocalizedString("SIP address must not contain unicode characters: %s", "Label") % target_uri) return None if '@' not in target_uri and isinstance(account, BonjourAccount): show_error_panel(NSLocalizedString("SIP address must contain host in bonjour mode: %s", "Label") % target_uri) return None target_uri = format_uri(target_uri, account.id.domain if not isinstance(account, BonjourAccount) else None, account.pstn.idd_prefix if not isinstance(account, BonjourAccount) else None, account.pstn.prefix if not isinstance(account, BonjourAccount) else None, account.pstn.strip_digits if not isinstance(account, BonjourAccount) else None) try: target_uri = SIPURI.parse(target_uri) except SIPCoreError: show_error_panel(NSLocalizedString("Invalid SIP address: %s", "Label") % target_uri) return None return target_uri
def call(self, account_name, callee, wave_file, length=None): logging.info("calling from: %s - to: %s", account_name, callee) # Setup wave playback self.player = WavePlayer(SIPApplication.voice_audio_mixer, wave_file, loop_count=0, initial_play=False) # configure callee and route to him/her callee_header = ToHeader(SIPURI.parse(callee)) routes = [Route("62.220.31.184", 5060, "udp")] # locate caller account = self.accounts.get(account_name, None) if account is None: raise Exception("No account with that name found") # finally make the call session = Session(account) session.connect(callee_header, routes, [AudioStream()]) # if we got a length, end the call after it if not length is None: time.sleep(length) session.end()
def _OH_account_add(self, data): transaction = data.get('transaction', None) if transaction is None: log.warn('Transaction not specified!') return try: try: account = data['account'] password = data['password'] except KeyError: raise APIError('Invalid parameters: "account" and "password" must be specified') if account in self.accounts_map: log.warn('Account %s already added' % account) data = dict(sylkrtc='error', transaction=transaction, error='Account already added') self._send_data(json.dumps(data)) return # Validate URI uri = 'sip:%s' % account try: sip_uri = SIPURI.parse(uri) except SIPCoreError: raise APIError('Invalid account specified: %s' % account) if not {'*', sip_uri.host}.intersection(GeneralConfig.sip_domains): raise APIError('SIP domain not allowed: %s' % sip_uri.host) # Create and store our mapping account_info = AccountInfo(account, password) self.accounts_map[account_info.id] = account_info data = dict(sylkrtc='ack', transaction=transaction) self._send_data(json.dumps(data)) log.msg('Account %s added' % account) except APIError, e: log.error('account_add: %s' % e) data = dict(sylkrtc='error', transaction=transaction, error=str(e)) self._send_data(json.dumps(data))
def is_anonymous(uri): """ Check if the given URI is an anonymous uri """ anon_users = ('asterisk', 'unknown', 'anonymous') if isinstance(uri, (SIPURI, FrozenSIPURI)): if uri.user.lower() in anon_users: return True return (uri.user is None or uri.user.lower() == 'anonymous') and (uri.host is None or uri.host.lower() == 'anonymous.invalid') else: if not (uri.startswith('sip:') or uri.startswith('sips:')): uri = "sip:%s" % uri try: sip_uri = SIPURI.parse(str(uri)) except: return False else: if sip_uri.user is not None and sip_uri.user.lower() in anon_users: return True return (sip_uri.user is None or sip_uri.user.lower() == 'anonymous') and (sip_uri.host is None or sip_uri.host.lower() == 'anonymous.invalid')
def parse(cls, value): match = cls._format_re.match(value) if match is None: raise ValueError('Cannot parse identity value: %r' % value) return cls(SIPURI.parse(match.group('uri')), match.group('display_name'))
def _CH_register(self, command): notification_center = NotificationCenter() settings = SIPSimpleSettings() if self._registration_timer is not None and self._registration_timer.active( ): self._registration_timer.cancel() self._registration_timer = None # Initialize the registration if self._registration is None: duration = command.refresh_interval or self.account.sip.register_interval self._registration = Registration( FromHeader(self.account.uri, self.account.display_name), credentials=self.account.credentials, duration=duration, extra_headers=[Header('Supported', 'gruu')]) notification_center.add_observer(self, sender=self._registration) notification_center.post_notification('SIPAccountWillRegister', sender=self.account) else: notification_center.post_notification( 'SIPAccountRegistrationWillRefresh', sender=self.account) try: # Lookup routes if self.account.sip.outbound_proxy is not None and self.account.sip.outbound_proxy.transport in settings.sip.transport_list: uri = SIPURI(host=self.account.sip.outbound_proxy.host, port=self.account.sip.outbound_proxy.port, parameters={ 'transport': self.account.sip.outbound_proxy.transport }) else: uri = SIPURI(host=self.account.id.domain) lookup = DNSLookup() try: routes = lookup.lookup_sip_proxy( uri, settings.sip.transport_list).wait() except DNSLookupError as e: retry_after = random.uniform(self._dns_wait, 2 * self._dns_wait) self._dns_wait = limit(2 * self._dns_wait, max=30) raise RegistrationError('DNS lookup failed: %s' % e, retry_after=retry_after) else: self._dns_wait = 1 # Register by trying each route in turn register_timeout = time() + 30 for route in routes: remaining_time = register_timeout - time() if remaining_time > 0: try: contact_uri = self.account.contact[NoGRUU, route] except KeyError: continue contact_header = ContactHeader(contact_uri) contact_header.parameters[ '+sip.instance'] = '"<%s>"' % settings.instance_id if self.account.nat_traversal.use_ice: contact_header.parameters['+sip.ice'] = None route_header = RouteHeader(route.uri) try: self._registration.register(contact_header, route_header, timeout=limit( remaining_time, min=1, max=10)) except SIPCoreError: raise RegistrationError('Internal error', retry_after=5) try: while True: notification = self._data_channel.wait() if notification.name == 'SIPRegistrationDidSucceed': break if notification.name == 'SIPRegistrationDidEnd': raise RegistrationError( 'Registration expired', retry_after=0 ) # registration expired while we were trying to re-register except SIPRegistrationDidFail as e: notification_data = NotificationData( code=e.data.code, reason=e.data.reason, registration=self._registration, registrar=route) notification_center.post_notification( 'SIPAccountRegistrationGotAnswer', sender=self.account, data=notification_data) if e.data.code == 401: # Authentication failed, so retry the registration in some time raise RegistrationError('Authentication failed', retry_after=random.uniform( 60, 120)) elif e.data.code == 423: # Get the value of the Min-Expires header if e.data.min_expires is not None and e.data.min_expires > self.account.sip.register_interval: refresh_interval = e.data.min_expires else: refresh_interval = None raise RegistrationError( 'Interval too short', retry_after=random.uniform(60, 120), refresh_interval=refresh_interval) else: # Otherwise just try the next route continue else: notification_data = NotificationData( code=notification.data.code, reason=notification.data.reason, registration=self._registration, registrar=route) notification_center.post_notification( 'SIPAccountRegistrationGotAnswer', sender=self.account, data=notification_data) self.registered = True # Save GRUU try: header = next( header for header in notification.data.contact_header_list if header.parameters.get('+sip.instance', ''). strip('"<>') == settings.instance_id) except StopIteration: self.account.contact.public_gruu = None self.account.contact.temporary_gruu = None else: public_gruu = header.parameters.get( 'pub-gruu', None) temporary_gruu = header.parameters.get( 'temp-gruu', None) try: self.account.contact.public_gruu = SIPURI.parse( public_gruu.strip('"')) except (AttributeError, SIPCoreError): self.account.contact.public_gruu = None try: self.account.contact.temporary_gruu = SIPURI.parse( temporary_gruu.strip('"')) except (AttributeError, SIPCoreError): self.account.contact.temporary_gruu = None notification_data = NotificationData( contact_header=notification.data.contact_header, contact_header_list=notification.data. contact_header_list, expires=notification.data.expires_in, registrar=route) notification_center.post_notification( 'SIPAccountRegistrationDidSucceed', sender=self.account, data=notification_data) self._register_wait = 1 command.signal() break else: # There are no more routes to try, reschedule the registration retry_after = random.uniform(self._register_wait, 2 * self._register_wait) self._register_wait = limit(self._register_wait * 2, max=30) raise RegistrationError('No more routes to try', retry_after=retry_after) except RegistrationError as e: self.registered = False notification_center.remove_observer(self, sender=self._registration) notification_center.post_notification( 'SIPAccountRegistrationDidFail', sender=self.account, data=NotificationData(error=e.error, retry_after=e.retry_after)) def register(): if self.active: self._command_channel.send( Command('register', command.event, refresh_interval=e.refresh_interval)) self._registration_timer = None self._registration_timer = reactor.callLater( e.retry_after, register) self._registration = None self.account.contact.public_gruu = None self.account.contact.temporary_gruu = None
try: header = next( header for header in notification.data.contact_header_list if header.parameters.get('+sip.instance', ''). strip('"<>') == settings.instance_id) except StopIteration: self.account.contact.public_gruu = None self.account.contact.temporary_gruu = None else: public_gruu = header.parameters.get( 'pub-gruu', None) temporary_gruu = header.parameters.get( 'temp-gruu', None) try: self.account.contact.public_gruu = SIPURI.parse( public_gruu.strip('"')) except (AttributeError, SIPCoreError): self.account.contact.public_gruu = None try: self.account.contact.temporary_gruu = SIPURI.parse( temporary_gruu.strip('"')) except (AttributeError, SIPCoreError): self.account.contact.temporary_gruu = None notification_data = NotificationData( contact_header=notification.data.contact_header, contact_header_list=notification.data. contact_header_list, expires=notification.data.expires_in, registrar=route) notification_center.post_notification( 'SIPAccountRegistrationDidSucceed',
continue else: notification_data = NotificationData(code=notification.data.code, reason=notification.data.reason, registration=self._registration, registrar=route) notification_center.post_notification('SIPAccountRegistrationGotAnswer', sender=self.account, data=notification_data) self.registered = True # Save GRUU try: header = next(header for header in notification.data.contact_header_list if header.parameters.get('+sip.instance', '').strip('"<>') == settings.instance_id) except StopIteration: self.account.contact.public_gruu = None self.account.contact.temporary_gruu = None else: public_gruu = header.parameters.get('pub-gruu', None) temporary_gruu = header.parameters.get('temp-gruu', None) try: self.account.contact.public_gruu = SIPURI.parse(public_gruu.strip('"')) except (AttributeError, SIPCoreError): self.account.contact.public_gruu = None try: self.account.contact.temporary_gruu = SIPURI.parse(temporary_gruu.strip('"')) except (AttributeError, SIPCoreError): self.account.contact.temporary_gruu = None notification_data = NotificationData(contact_header=notification.data.contact_header, contact_header_list=notification.data.contact_header_list, expires=notification.data.expires_in, registrar=route) notification_center.post_notification('SIPAccountRegistrationDidSucceed', sender=self.account, data=notification_data) self._register_wait = 1 command.signal() break else: # There are no more routes to try, reschedule the registration
def URIValidator(value): account = SIP_PREFIX_RE.sub('', value) try: SIPURI.parse('sip:%s' % account) except SIPCoreError: raise errors.ValidationError('invalid account: %s' % value)
def incoming_chat_session(self, session): # Check if this session is really an invitation to add a participant to a conference room / muc if session.remote_identity.uri.host in self.xmpp_manager.muc_domains and 'isfocus' in session._invitation.remote_contact_header.parameters: try: referred_by_uri = SIPURI.parse( session.transfer_info.referred_by) except SIPCoreError: log.info( "SIP multiparty session invitation %s failed: invalid Referred-By header" % session.call_id) session.reject(488) return muc_uri = FrozenURI(session.remote_identity.uri.user, session.remote_identity.uri.host) inviter_uri = FrozenURI(referred_by_uri.user, referred_by_uri.host) recipient_uri = FrozenURI(session.local_identity.uri.user, session.local_identity.uri.host) sender = Identity(muc_uri) recipient = Identity(recipient_uri) inviter = Identity(inviter_uri) try: handler = self.s2x_muc_add_participant_handlers[( muc_uri, recipient_uri)] except KeyError: handler = S2XMucInvitationHandler(session, sender, recipient, inviter) self.s2x_muc_add_participant_handlers[( muc_uri, recipient_uri)] = handler NotificationCenter().add_observer(self, sender=handler) handler.start() else: log.info( "SIP multiparty session invitation %s failed: there is another invitation in progress from %s to %s" % (session.call_id, format_uri(inviter_uri, 'sip'), format_uri(recipient_uri, 'xmpp'))) session.reject(480) return # Check domain if session.remote_identity.uri.host not in XMPPGatewayConfig.domains: log.info( 'Session rejected: From domain is not a local XMPP domain') session.reject(606, 'Not Acceptable') return # Get URI representing the SIP side contact_uri = session._invitation.remote_contact_header.uri if contact_uri.parameters.get('gr') is not None: sip_leg_uri = FrozenURI(contact_uri.user, contact_uri.host, contact_uri.parameters.get('gr')) else: tmp = session.remote_identity.uri sip_leg_uri = FrozenURI(tmp.user, tmp.host, generate_sylk_resource()) # Get URI representing the XMPP side request_uri = session.request_uri remote_resource = request_uri.parameters.get('gr', None) if remote_resource is not None: try: remote_resource = decode_resource(remote_resource) except (TypeError, UnicodeError): remote_resource = None xmpp_leg_uri = FrozenURI(request_uri.user, request_uri.host, remote_resource) try: handler = self.pending_sessions[(sip_leg_uri, xmpp_leg_uri)] except KeyError: pass else: # There is another pending session with same identifiers, can't accept this one log.info( 'Session rejected: other session with same identifiers in progress' ) session.reject(488) return sip_identity = Identity(sip_leg_uri, session.remote_identity.display_name) handler = ChatSessionHandler.new_from_sip_session( sip_identity, session) NotificationCenter().add_observer(self, sender=handler) key = (sip_leg_uri, xmpp_leg_uri) self.pending_sessions[key] = handler if xmpp_leg_uri.resource is not None: # Incoming session target contained GRUU, so create XMPPChatSession immediately xmpp_session = XMPPChatSession( local_identity=handler.sip_identity, remote_identity=Identity(xmpp_leg_uri)) handler.xmpp_identity = xmpp_session.remote_identity handler.xmpp_session = xmpp_session
def incoming_chat_session(self, session): # Check if this session is really an invitation to add a participant to a conference room / muc if ( session.remote_identity.uri.host in self.xmpp_manager.muc_domains and "isfocus" in session._invitation.remote_contact_header.parameters ): try: referred_by_uri = SIPURI.parse(session.transfer_info.referred_by) except SIPCoreError: log.msg("SIP multiparty session invitation %s failed: invalid Referred-By header" % session.call_id) session.reject(488) return muc_uri = FrozenURI(session.remote_identity.uri.user, session.remote_identity.uri.host) inviter_uri = FrozenURI(referred_by_uri.user, referred_by_uri.host) recipient_uri = FrozenURI(session.local_identity.uri.user, session.local_identity.uri.host) sender = Identity(muc_uri) recipient = Identity(recipient_uri) inviter = Identity(inviter_uri) try: handler = self.s2x_muc_add_participant_handlers[(muc_uri, recipient_uri)] except KeyError: handler = S2XMucInvitationHandler(session, sender, recipient, inviter) self.s2x_muc_add_participant_handlers[(muc_uri, recipient_uri)] = handler NotificationCenter().add_observer(self, sender=handler) handler.start() else: log.msg( "SIP multiparty session invitation %s failed: there is another invitation in progress from %s to %s" % (session.call_id, format_uri(inviter_uri, "sip"), format_uri(recipient_uri, "xmpp")) ) session.reject(480) return # Check domain if session.remote_identity.uri.host not in XMPPGatewayConfig.domains: log.msg("Session rejected: From domain is not a local XMPP domain") session.reject(606, "Not Acceptable") return # Get URI representing the SIP side contact_uri = session._invitation.remote_contact_header.uri if contact_uri.parameters.get("gr") is not None: sip_leg_uri = FrozenURI(contact_uri.user, contact_uri.host, contact_uri.parameters.get("gr")) else: tmp = session.remote_identity.uri sip_leg_uri = FrozenURI(tmp.user, tmp.host, generate_sylk_resource()) # Get URI representing the XMPP side request_uri = session.request_uri remote_resource = request_uri.parameters.get("gr", None) if remote_resource is not None: try: remote_resource = decode_resource(remote_resource) except (TypeError, UnicodeError): remote_resource = None xmpp_leg_uri = FrozenURI(request_uri.user, request_uri.host, remote_resource) try: handler = self.pending_sessions[(sip_leg_uri, xmpp_leg_uri)] except KeyError: pass else: # There is another pending session with same identifiers, can't accept this one log.msg("Session rejected: other session with same identifiers in progress") session.reject(488) return sip_identity = Identity(sip_leg_uri, session.remote_identity.display_name) handler = ChatSessionHandler.new_from_sip_session(sip_identity, session) NotificationCenter().add_observer(self, sender=handler) key = (sip_leg_uri, xmpp_leg_uri) self.pending_sessions[key] = handler if xmpp_leg_uri.resource is not None: # Incoming session target contained GRUU, so create XMPPChatSession immediately xmpp_session = XMPPChatSession(local_identity=handler.sip_identity, remote_identity=Identity(xmpp_leg_uri)) handler.xmpp_identity = xmpp_session.remote_identity handler.xmpp_session = xmpp_session