if 'armv7' in platform.platform() and settings.audio.echo_canceller.enabled:
self.output.put("Disable echo canceller on ARM architecture\n")
settings.audio.echo_canceller.enabled = False
settings.save()
for account in account_manager.iter_accounts():
if isinstance(account, Account):
account.sip.register = False
account.presence.enabled = False
account.xcap.enabled = False
account.message_summary.enabled = False
if self.options.account is None:
self.account = account_manager.default_account
else:
possible_accounts = [account for account in account_manager.iter_accounts() if self.options.account in account.id and account.enabled]
if len(possible_accounts) > 1:
self.output.put('More than one account exists which matches %s: %s\n' % (self.options.account, ', '.join(sorted(account.id for account in possible_accounts))))
self.output.stop()
self.stop()
self.end_cancel_thread()
return
elif len(possible_accounts) == 0:
self.output.put('No enabled account that matches %s was found. Available and enabled accounts: %s\n' % (self.options.account, ', '.join(sorted(account.id for account in account_manager.get_accounts() if account.enabled))))
self.output.put("Initiating SIP %s session from %s to %s via %s...\n" % ('video' if self.enable_video else 'audio', local_identity, remote_identity, session.route))
on_hold_streams = [stream for stream in chain(*(session.streams for session in self.started_sessions)) if stream is not notification.sender and stream.on_hold]
if not on_hold_streams and self.hold_tone.is_active:
description = 'This script can sit idle waiting for an incoming audio session, or initiate an outgoing audio session to a SIP address. The program will close the session and quit when Ctrl+D is pressed.'
parser.add_option('-a', '--account', type='string', dest='account', help='The account name to use for any outgoing traffic. If not supplied, the default account will be used.', metavar='NAME')
parser.add_option('-c', '--config-directory', type='string', dest='config_directory', help='The configuration directory to use. This overrides the default location.')
parser.add_option('-s', '--trace-sip', action='store_true', dest='trace_sip', default=False, help='Dump the raw contents of incoming and outgoing SIP messages.')
parser.add_option('-n', '--trace-notifications', action='store_true', dest='trace_notifications', default=False, help='Print all notifications (disabled by default).')
parser.add_option('-S', '--disable-sound', action='store_true', dest='disable_sound', default=False, help='Disables initializing the sound card.')
parser.set_default('auto_answer_interval', None)
parser.add_option('--auto-answer', action='callback', callback=parse_handle_call_option, callback_args=('auto_answer_interval',), help='Interval after which to answer an incoming session (disabled by default). If the option is specified but the interval is not, it defaults to 0 (accept the session as soon as it starts ringing).', metavar='[INTERVAL]')
parser.add_option('-u', '--auto-answer-uris', type='string', dest='auto_answer_uris', default="", help='Optional list of SIP URIs for which auto-answer is allowed')
parser.add_option('-i', '--external-id', type='string', dest='external_id', help='id used for call control from external application')
parser.add_option('-v', '--spool-dir', type='string', dest='spool_dir', default=None, help='Spool dir for call control from external applications, default is /var/spool/sipclients/sessions')
parser.add_option('-V', '--enable-video', action='store_true', dest='enable_video', default=False, help='Enable video if camera is available')
parser.set_default('auto_hangup_interval', None)
parser.add_option('--auto-hangup', action='callback', callback=parse_handle_call_option, callback_args=('auto_hangup_interval',), help='Interval after which to hang up an established session (disabled by default). If the option is specified but the interval is not, it defaults to 0 (hangup the session as soon as it connects).', metavar='[INTERVAL]')
parser.add_option('-b', '--batch', action='store_true', dest='batch_mode', default=False, help='Run the program in batch mode: reading input from the console is disabled and the option --auto-answer is implied. This is particularly useful when running this script in a non-interactive environment.')
parser.add_option('-d', '--daemonize', action='store_true', dest='daemonize', default=False, help='Enable running this program as a deamon.')
options, args = parser.parse_args()
target = args[0] if args and not options.auto_answer_uris else None
application = SIPAudioApplication()
application.start(target, options)
signal.signal(signal.SIGINT, signal.SIG_DFL)
application.output.join()
sleep(0.1)
sys.exit(0 if application.success else 1)
diff --git a/sip-register3 b/sip-register3
index f457de3..50b52de 100755
--- a/sip-register3
+++ b/sip-register3
@@ -1,381 +1,397 @@
#!/usr/bin/env python3
import atexit
import os
import select
import signal
import sys
import termios
from datetime import datetime
from optparse import OptionParser
from threading import Thread
from time import sleep
from application import log
from application.notification import NotificationCenter, NotificationData
possible_accounts = [account for account in account_manager.iter_accounts() if self.options.account in account.id and account.enabled]
if len(possible_accounts) > 1:
self.output.put('More than one account exists which matches %s: %s\n' % (self.options.account, ', '.join(sorted(account.id for account in possible_accounts))))
self.output.stop()
self.stop()
return
elif len(possible_accounts) == 0:
self.output.put('No enabled account that matches %s was found. Available and enabled accounts: %s\n' % (self.options.account, ', '.join(sorted(account.id for account in account_manager.get_accounts() if account.enabled))))
self.output.put('%s An exception occured within the SIP core:\n%s\n' % (datetime.now().replace(microsecond=0), notification.data.traceback))
if __name__ == "__main__":
description = 'This script registers the contact address of the given SIP account to the SIP registrar and refresh it while the program is running. When Ctrl+D is pressed it will unregister.'
parser.add_option('-a', '--account', type='string', dest='account', help='The name of the account to use. If not supplied, the default account will be used.', metavar='NAME')
parser.add_option('-c', '--config-directory', type='string', dest='config_directory', help='The configuration directory to use. This overrides the default location.')
parser.add_option('-s', '--trace-sip', action='store_true', dest='trace_sip', default=False, help='Dump the raw contents of incoming and outgoing SIP messages (disabled by default).')
parser.add_option('-n', '--trace-notifications', action='store_true', dest='trace_notifications', default=False, help='Print all notifications (disabled by default).')
parser.add_option('-r', '--max-registers', type='int', dest='max_registers', default=1, help='Max number of REGISTERs sent (default 1, set to 0 for infinite).')
parser.add_option('-b', '--batch', action='store_true', dest='batch_mode', default=False, help='Run the program in batch mode: reading input from the console is disabled. This is particularly useful when running this script in a non-interactive environment.')
options, args = parser.parse_args()
application = RegistrationApplication()
application.start(options)
signal.signal(signal.SIGINT, signal.SIG_DFL)
application.output.join()
sleep(0.1)
sys.exit(0 if application.success else 1)
diff --git a/sip-session3 b/sip-session3
index 404d7f9..8f9e0a9 100755
--- a/sip-session3
+++ b/sip-session3
@@ -1,3249 +1,3263 @@
#!/usr/bin/env python3
import os
import re
import signal
import sys
import urllib.request, urllib.parse, urllib.error
import random
import requests
import uuid
from collections import defaultdict
from datetime import datetime, timedelta
from dateutil.tz import tzlocal
from itertools import chain
from lxml import html
from optparse import OptionParser
from threading import Event, Thread
from time import sleep
from application import log
from application.notification import IObserver, NotificationCenter
show_notice('%s Encrypted message %s to %s failed on %s: %s (%d)' % (datetime.now().replace(microsecond=0), message.id, self.remote_uri, server or client, notification.data.reason.decode(), notification.data.code))
else:
show_notice('%s Message %s to %s failed on %s: %s (%d)' % (datetime.now().replace(microsecond=0), message.id, self.remote_uri, server or client, notification.data.reason.decode() if isinstance(notification.data.reason, bytes) else notification.data.reason, notification.data.code))
self.question = Question("Incoming file transfer for %s from '%s', do you want to accept? (a)ccept/(r)eject" % (os.path.basename(self.filename), identity), 'ari', bold=True)
SIPApplication.start(self, FileStorage(options.config_directory or config_directory))
except ConfigurationError as e:
show_notice("Failed to load sipclient's configuration: %s\n" % str(e), bold=False)
show_notice("If an old configuration file is in place, delete it or move it and recreate the configuration using the sip_settings script.", bold=False)
ui.stop()
self.stopped_event.set()
else:
show_notice("SDK version %s, core version %s, PJSIP version %s (%s)" % (version, CORE_REVISION, PJ_VERSION.decode(), PJ_SVN_REVISION))
possible_accounts = [account for account in account_manager.iter_accounts() if self.options.account in account.id and account.enabled]
if len(possible_accounts) > 1:
show_notice('More than one account exists which matches %s: %s' % (self.options.account, ', '.join(sorted(account.id for account in possible_accounts))), bold=False)
self.stop()
return
elif len(possible_accounts) == 0:
show_notice('No enabled account which matches %s was found. Available and enabled accounts: %s' % (self.options.account, ', '.join(sorted(account.id for account in account_manager.get_accounts() if account.enabled))), bold=False)
lines = ['%s Registered contact "%s" of %s at %s:%d;transport=%s for %d seconds' % (now, contact_header.uri, account.id, registrar.address, registrar.port, registrar.transport, expires)]
if len(contact_header_list) > 1:
lines.append('%s Other registered contacts of %s:' % (now, account.id))
lines.extend('%s %s of %s for %s seconds' % (now, str(other_contact_header.uri), account.id, other_contact_header.expires) for other_contact_header in contact_header_list if other_contact_header.uri != notification.data.contact_header.uri)
if account.contact.public_gruu is not None:
lines.append('%s Public GRUU: %s' % (now, account.contact.public_gruu))
if data.question == self.smp_verification_question:
try:
audio_stream = next(stream for stream in session.streams if stream.type=='audio' and stream.encryption.type=='ZRTP' and stream.encryption.active and stream.encryption.zrtp.verified)
except StopIteration:
stream.encryption.smp_abort()
else:
show_notice("OTR verification requested by remote and replied automatically using ZRTP SAS", bold=False)
audio_stream = next(stream for stream in session.streams if stream.type=='audio' and stream.encryption.type=='ZRTP' and stream.encryption.active and stream.encryption.zrtp.verified)
show_notice('No camera present, video is disabled')
self.enable_video = False
def _CH_help(self):
self._print_help()
def _CH_quit(self):
self.stop()
def _CH_eof(self):
ui = UI()
if self.active_session is not None:
if self.active_session in self.sessions_with_proposals:
ui.status = 'Cancelling proposal...'
self.active_session.cancel_proposal()
else:
ui.status = 'Ending SIP session...'
self.active_session.end()
elif self.outgoing_session is not None:
ui.status = 'Cancelling SIP session...'
self.outgoing_session.end()
else:
self.stop()
def _CH_hangup(self):
if self.active_session is not None:
show_notice('Ending SIP session...')
self.active_session.end()
elif self.outgoing_session is not None:
show_notice('Cancelling SIP session...')
self.outgoing_session.end()
else:
try:
message_session = next((session for session in self.message_sessions if session.target == self.message_session_to and self.account == session.account))
except StopIteration:
pass
else:
message_session.end()
try:
self.message_sessions.remove(message_session)
except KeyError:
show_notice('Message session not found')
pass
@run_in_green_thread
def _CH_dtmf(self, tones):
if self.active_session is not None:
audio_stream = next((stream for stream in self.active_session.streams if stream.type == 'audio'), None)
show_notice('Accounts available: %s' % ", ".join(account.id for account in account_manager.iter_accounts() if account != self.account and account.enabled))
possible_accounts = [account for account in account_manager.iter_accounts() if new_account in account.id and account.enabled]
if len(possible_accounts) > 1:
show_notice('More than one account exists which matches %s: %s' % (new_account, ', '.join(sorted(account.id for account in possible_accounts))), bold=False)
elif len(possible_accounts) == 0:
show_notice('No enabled account which matches %s was found. Available and enabled accounts: %s' % (self.options.account, ', '.join(sorted(possible_accounts))), bold=False)
parser.add_option('-a', '--account', type='string', dest='account', help='The account name to use for any outgoing traffic. If not supplied, the default account will be used.', metavar='NAME')
parser.add_option('-c', '--config-directory', type='string', dest='config_directory', help='The configuration directory to use. This overrides the default location.')
parser.add_option('-s', '--trace-sip', action='store_true', dest='trace_sip', default=False, help='Dump the raw contents of incoming and outgoing SIP messages.')
parser.add_option('-m', '--trace-msrp', action='store_true', dest='trace_msrp', default=False, help='Dump msrp logging information and the raw contents of incoming and outgoing MSRP messages.')
parser.add_option('-n', '--trace-notifications', action='store_true', dest='trace_notifications', default=False, help='Print all notifications (disabled by default).')
parser.add_option('-S', '--disable-sound', action='store_true', dest='disable_sound', default=False, help='Disables initializing the sound card.')
parser.set_default('auto_answer_interval', None)
parser.add_option('--auto-answer', action='callback', callback=parse_handle_call_option, callback_args=('auto_answer_interval',), help='Interval after which to answer an incoming session (disabled by default). If the option is specified but the interval is not, it defaults to 0 (accept the session as soon as it starts ringing).', metavar='[INTERVAL]')
parser.set_default('auto_hangup_interval', None)
parser.add_option('--auto-hangup', action='callback', callback=parse_handle_call_option, callback_args=('auto_hangup_interval',), help='Interval after which to hang up an established session (disabled by default). If the option is specified but the interval is not, it defaults to 0 (hangup the session as soon as it connects).', metavar='[INTERVAL]')