diff --git a/daemon/tools/dringctl/__init__.py b/daemon/tools/dringctl/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..991f029774f57b1a8a354ae702efe5c7e5855e03 --- /dev/null +++ b/daemon/tools/dringctl/__init__.py @@ -0,0 +1,29 @@ +# +# Copyright (C) 2015 Savoir-Faire Linux Inc. +# Author: Guillaume Roguez <guillaume.roguez@savoirfairelinux.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Additional permission under GNU GPL version 3 section 7: +# +# If you modify this program, or any covered work, by linking or +# combining it with the OpenSSL project's OpenSSL library (or a +# modified version of that library), containing parts covered by the +# terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc. +# grants you additional permission to convey the resulting work. +# Corresponding Source for a non-source form of such a combination +# shall include the source code for the parts of OpenSSL used as well +# as that of the covered work. +# diff --git a/daemon/tools/dringctl/controler.py b/daemon/tools/dringctl/controler.py new file mode 100644 index 0000000000000000000000000000000000000000..9d8f08d4781adec8affea14b2071141297e996ab --- /dev/null +++ b/daemon/tools/dringctl/controler.py @@ -0,0 +1,592 @@ +# +# Copyright (C) 2015 Savoir-Faire Linux Inc. +# Author: Guillaume Roguez <guillaume.roguez@savoirfairelinux.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Additional permission under GNU GPL version 3 section 7: +# +# If you modify this program, or any covered work, by linking or +# combining it with the OpenSSL project's OpenSSL library (or a +# modified version of that library), containing parts covered by the +# terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc. +# grants you additional permission to convey the resulting work. +# Corresponding Source for a non-source form of such a combination +# shall include the source code for the parts of OpenSSL used as well +# as that of the covered work. +# + +"""DRing controling class through DBUS""" + +import os +import random +import time +import hashlib + +from threading import Thread +from functools import partial + +from gi.repository import GObject + +from errors import * + +try: + import dbus + from dbus.mainloop.glib import DBusGMainLoop +except ImportError as e: + raise DRingCtrlError("No python3-dbus module found") + + +DBUS_DEAMON_OBJECT = 'cx.ring.Ring' +DBUS_DEAMON_PATH = '/cx/ring/Ring' + + +class DRingCtrl(Thread): + def __init__(self, name): + super().__init__() + + self.activeCalls = {} # list of active calls (known by the client) + self.activeConferences = {} # list of active conferences + self.account = None # current active account + self.name = name # client name + + self.currentCallId = "" + self.currentConfId = "" + + self.isStop = False + + # Glib MainLoop for processing callbacks + self.loop = GObject.MainLoop() + + GObject.threads_init() + + # client registered to sflphoned ? + self.registered = False + self.register() + + def __del__(self): + if self.registered: + self.unregister() + self.loop.quit() + + def stopThread(self): + self.isStop = True + + def register(self): + if self.registered: + return + + try: + # register the main loop for d-bus events + DBusGMainLoop(set_as_default=True) + bus = dbus.SessionBus() + + except dbus.DBusException as e: + raise DRingCtrlDBusError("Unable to connect DBUS session bus") + + if not bus.name_has_owner(DBUS_DEAMON_OBJECT) : + raise DRingCtrlDBusError(("Unable to find %s in DBUS." % DBUS_DEAMON_OBJECT) + + " Check if dring is running") + + try: + proxy_instance = bus.get_object(DBUS_DEAMON_OBJECT, + DBUS_DEAMON_PATH+'/Instance', introspect=False) + proxy_callmgr = bus.get_object(DBUS_DEAMON_OBJECT, + DBUS_DEAMON_PATH+'/CallManager', introspect=False) + proxy_confmgr = bus.get_object(DBUS_DEAMON_OBJECT, + DBUS_DEAMON_PATH+'/ConfigurationManager', introspect=False) + + self.instance = dbus.Interface(proxy_instance, + DBUS_DEAMON_OBJECT+'.Instance') + self.callmanager = dbus.Interface(proxy_callmgr, + DBUS_DEAMON_OBJECT+'.CallManager') + self.configurationmanager = dbus.Interface(proxy_confmgr, + DBUS_DEAMON_OBJECT+'.ConfigurationManager') + + except dbus.DBusException as e: + raise DRingCtrlDBusError("Unable to bind to dring DBus API") + + try: + self.instance.Register(os.getpid(), self.name) + self.registered = True + + except: + raise DRingCtrlDeamonError("Client registration failed") + + try: + proxy_callmgr.connect_to_signal('incomingCall', self.onIncomingCall) + proxy_callmgr.connect_to_signal('callStateChanged', self.onCallStateChanged) + proxy_callmgr.connect_to_signal('conferenceCreated', self.onConferenceCreated) + + except dbus.DBusException as e: + raise DRingCtrlDBusError("Unable to connect to dring DBus signals") + + + def unregister(self): + if not self.registered: + return + + try: + self.instance.Unregister(os.getpid()) + self.registered = False + + except: + raise DRingCtrlDeamonError("Client unregistration failed") + + + def isRegistered(self): + return self.registered + + # + # Signal handling + # + + def onIncomingCall_cb(self): + pass + + def onCallHangup_cb(self, callId): + pass + + def onCallRinging_cb(self): + pass + + def onCallHold_cb(self): + pass + + def onCallCurrent_cb(self): + pass + + def onCallBusy_cb(self): + pass + + def onCallFailure_cb(self): + pass + + def onIncomingCall(self, account, callid, to): + """ On incoming call event, add the call to the list of active calls """ + + self.activeCalls[callid] = {'Account': account, + 'To': to, + 'State': ''} + self.currentCallId = callid + self.onIncomingCall_cb() + + + def onCallHangUp(self, callid): + """ Remove callid from call list """ + + self.onCallHangup_cb(callid) + self.currentCallId = "" + del self.activeCalls[callid] + + + def onCallRinging(self, callid, state): + """ Update state for this call to Ringing """ + + self.activeCalls[callid]['State'] = state + self.onCallRinging_cb() + + + def onCallHold(self, callid, state): + """ Update state for this call to Hold """ + + self.activeCalls[callid]['State'] = state + self.onCallHold_cb() + + + def onCallCurrent(self, callid, state): + """ Update state for this call to current """ + + self.activeCalls[callid]['State'] = state + self.onCallCurrent_cb() + + + def onCallBusy(self, callid, state): + """ Update state for this call to busy """ + + self.activeCalls[callid]['State'] = state + self.onCallBusy_cb() + + + def onCallFailure(self, callid, state): + """ Handle call failure """ + + self.onCallFailure_cb() + del self.activeCalls[callid] + + + def onCallStateChanged(self, callid, state): + """ On call state changed event, set the values for new calls, + or delete the call from the list of active calls + """ + + print(("On call state changed " + callid + " " + state)) + + if callid not in self.activeCalls: + print("This call didn't exist!: " + callid + ". Adding it to the list.") + callDetails = self.getCallDetails(callid) + self.activeCalls[callid] = {'Account': callDetails['ACCOUNTID'], + 'To': callDetails['PEER_NUMBER'], + 'State': state } + + + self.currentCallId = callid + + if state == "HUNGUP": + self.onCallHangUp(callid) + elif state == "RINGING": + self.onCallRinging(callid, state) + elif state == "CURRENT": + self.onCallCurrent(callid, state) + elif state == "HOLD": + self.onCallHold(callid, state) + elif state == "BUSY": + self.onCallBusy(callid, state) + elif state == "FAILURE": + self.onCallFailure(callid, state) + else: + print("unknown state") + + def onConferenceCreated_cb(self): + pass + + def onConferenceCreated(self, confId): + self.currentConfId = confId + self.onConferenceCreated_cb() + + # + # Account management + # + + def _valid_account(self, account): + account = account or self.account + if account is None: + raise DRingCtrlError("No provided or current account!") + return account + + def isAccountExists(self, account): + """ Checks if the account exists""" + + return account in self.getAllAccounts() + + def isAccountEnable(self, account=None): + """Return True if the account is enabled. If no account is provided, active account is used""" + + return self.getAccountDetails(self._valid_account(account))['Account.enable'] == "true" + + def isAccountRegistered(self, account=None): + """Return True if the account is registered. If no account is provided, active account is used""" + + return self.getAccountDetails(self._valid_account(account))['Account.registrationStatus'] in ('READY', 'REGISTERED') + + def isAccountOfType(self, account_type, account=None): + """Return True if the account type is the given one. If no account is provided, active account is used""" + + return self.getAccountDetails(self._valid_account(account))['Account.type'] == account_type + + def getAllAccounts(self, account_type=None): + """Return a list with all accounts""" + + acclist = map(str, self.configurationmanager.getAccountList()) + if account_type: + acclist = filter(partial(self.isAccountOfType, account_type), acclist) + return list(acclist) + + def getAllEnabledAccounts(self): + """Return a list with all enabled-only accounts""" + + return [x for x in self.getAllAccounts() if self.isAccountEnable(x)] + + def getAllRegisteredAccounts(self): + """Return a list with all registered-only accounts""" + + return [x for x in self.getAllAccounts() if self.isAccountRegistered(x)] + + def getAccountDetails(self, account=None): + """Return a list of string. If no account is provided, active account is used""" + + account = self._valid_account(account) + if self.isAccountExists(account): + return self.configurationmanager.getAccountDetails(account) + return [] + + def setActiveCodecList(self, account=None, codec_list=''): + """Activate given codecs on an account. If no account is provided, active account is used""" + + account = self._valid_account(account) + if self.isAccountExists(account): + codec_list = [dbus.UInt32(x) for x in codec_list.split(',')] + self.configurationmanager.setActiveCodecList(account, codec_list) + + def addAccount(self, details=None): + """Add a new account account + + Add a new account to the SFLphone-daemon. Default parameters are \ + used for missing account configuration field. + + Required parameters are type, alias, hostname, username and password + + input details + """ + + if details is None: + raise DRingCtrlAccountError("Must specifies type, alias, hostname, \ + username and password in \ + order to create a new account") + + return self.configurationmanager.addAccount(details) + + def removeAccount(self, accountID=None): + """Remove an account from internal list""" + + if accountID is None: + raise DRingCtrlAccountError("Account ID must be specified") + + self.configurationmanager.removeAccount(accountID) + + def setAccountByAlias(self, alias): + """Define as active the first account who match with the alias""" + + for testedaccount in self.getAllAccounts(): + details = self.getAccountDetails(testedaccount) + if (details['Account.enable'] == 'true' and + details['Account.alias'] == alias): + self.account = testedaccount + return + raise DRingCtrlAccountError("No enabled account matched with alias") + + def getAccountByAlias(self, alias): + """Get account name having its alias""" + + for account in self.getAllAccounts(): + details = self.getAccountDetails(account) + if details['Account.alias'] == alias: + return account + + raise DRingCtrlAccountError("No account matched with alias") + + def setAccount(self, account): + """Define the active account + + The active account will be used when sending a new call + """ + + if account in self.getAllAccounts(): + self.account = account + else: + print(account) + raise DRingCtrlAccountError("Not a valid account") + + def setFirstRegisteredAccount(self): + """Find the first enabled account and define it as active""" + + rAccounts = self.getAllRegisteredAccounts() + if 0 == len(rAccounts): + raise DRingCtrlAccountError("No registered account !") + self.account = rAccounts[0] + + def setFirstActiveAccount(self): + """Find the first enabled account and define it as active""" + + aAccounts = self.getAllEnabledAccounts() + if 0 == len(aAccounts): + raise DRingCtrlAccountError("No active account !") + self.account = aAccounts[0] + + def getAccount(self): + """Return the active account""" + + return self.account + + def setAccountEnable(self, account=None, enable=False): + """Set account enabled""" + + account = self._valid_account(account) + if enable == True: + details = self.getAccountDetails(account) + details['Account.enable'] = "true" + self.configurationmanager.setAccountDetails(account, details) + else: + details = self.getAccountDetails(account) + details['Account.enable'] = "false" + self.configurationmanager.setAccountDetails(account, details) + + def setAccountRegistered(self, account=None, register=False): + """ Tries to register the account""" + + account = self._valid_account(account) + self.configurationmanager.sendRegister(account, register) + + # + # Codec manager + # + + def getAllCodecs(self): + """ Return all codecs""" + + return [int(x) for x in self.configurationmanager.getCodecList()] + + # + # Call management + # + + def getCallDetails(self, callid): + """Return informations on this call if exists""" + + return self.callmanager.getCallDetails(callid) + + def printClientCallList(self): + print("Client active call list:") + print("------------------------") + for call in self.activeCalls: + print("\t" + call) + + def Call(self, dest): + """Start a call and return a CallID + + Use the current account previously set using setAccount(). + If no account specified, first registered one in account list is used. + + return callID Newly generated callidentifier for this call + """ + + if dest is None or dest == "": + raise SflPhoneError("Invalid call destination") + + # Set the account to be used for this call + if not self.account: + self.setFirstRegisteredAccount() + + if self.account is not "IP2IP" and not self.isAccountRegistered(): + raise DRingCtrlAccountError("Can't place a call without a registered account") + + # Send the request to the CallManager + callid = self.callmanager.placeCall(self.account, dest) + if callid: + # Add the call to the list of active calls and set status to SENT + self.activeCalls[callid] = {'Account': self.account, 'To': dest, 'State': 'SENT' } + + return callid + + + def HangUp(self, callid): + """End a call identified by a CallID""" + + if not self.account: + self.setFirstRegisteredAccount() + + if callid is None or callid == "": + pass # just to see + + self.callmanager.hangUp(callid) + + + def Transfer(self, callid, to): + """Transfert a call identified by a CallID""" + + if callid is None or callid == "": + raise DRingCtrlError("Invalid callID") + + self.callmanager.transfert(callid, to) + + + def Refuse(self, callid): + """Refuse an incoming call identified by a CallID""" + + print("Refuse call " + callid) + + if callid is None or callid == "": + raise DRingCtrlError("Invalid callID") + + self.callmanager.refuse(callid) + + + def Accept(self, callid): + """Accept an incoming call identified by a CallID""" + + print("Accept call " + callid) + if not self.account: + self.setFirstRegisteredAccount() + + if not self.isAccountRegistered(): + raise DRingCtrlAccountError("Can't accept a call without a registered account") + + if callid is None or callid == "": + raise DRingCtrlError("Invalid callID") + + self.callmanager.accept(callid) + + + def Hold(self, callid): + """Hold a call identified by a CallID""" + + if callid is None or callid == "": + raise DRingCtrlError("Invalid callID") + + self.callmanager.hold(callid) + + + def UnHold(self, callid): + """Unhold an incoming call identified by a CallID""" + + if callid is None or callid == "": + raise DRingCtrlError("Invalid callID") + + self.callmanager.unhold(callid) + + + def Dtmf(self, key): + """Send a DTMF""" + + self.callmanager.playDTMF(key) + + + def _GenerateCallID(self): + """Generate Call ID""" + + m = hashlib.md5() + t = int( time.time() * 1000 ) + r = int( random.random()*100000000000000000 ) + m.update(str(t) + str(r)) + callid = m.hexdigest() + return callid + + + def createConference(self, call1Id, call2Id): + """ Create a conference given the two call ids """ + + self.callmanager.joinParticipant(call1Id, call2Id) + + + def hangupConference(self, confId): + """ Hang up each call for this conference """ + + self.callmanager.hangUpConference(confId) + + + def run(self): + """Processing method for this thread""" + + context = self.loop.get_context() + + while True: + context.iteration(True) + + if self.isStop: + print("++++++++++++++++++++++++++++++++++++++++") + print("++++++++++++++++++++++++++++++++++++++++") + print("++++++++++++++++++++++++++++++++++++++++") + print("++++++++++++++++++++++++++++++++++++++++") + return diff --git a/tools/pysflphone/sflphoned.functest.yml b/daemon/tools/dringctl/dring.functest.yml similarity index 100% rename from tools/pysflphone/sflphoned.functest.yml rename to daemon/tools/dringctl/dring.functest.yml diff --git a/daemon/tools/dringctl/dringctl.py b/daemon/tools/dringctl/dringctl.py new file mode 100755 index 0000000000000000000000000000000000000000..2413ea89949947980f44be2851f941e64ec22be5 --- /dev/null +++ b/daemon/tools/dringctl/dringctl.py @@ -0,0 +1,259 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2015 Savoir-Faire Linux Inc. +# Author: Guillaume Roguez <guillaume.roguez@savoirfairelinux.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Additional permission under GNU GPL version 3 section 7: +# +# If you modify this program, or any covered work, by linking or +# combining it with the OpenSSL project's OpenSSL library (or a +# modified version of that library), containing parts covered by the +# terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc. +# grants you additional permission to convey the resulting work. +# Corresponding Source for a non-source form of such a combination +# shall include the source code for the parts of OpenSSL used as well +# as that of the covered work. +# + +import sys +import os +import random +import time +import argparse + +from gi.repository import GObject + +from errors import * +from controler import DRingCtrl + +def printAccountDetails(account): + details = ctrl.getAccountDetails(account) + print(account) + for k in sorted(details.keys()): + print(" %s: %s" % (k, details[k])) + print() + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument('--gaa', help='Get all accounts (of optionaly given type)', + nargs='?', metavar='<type>', type=str, default=argparse.SUPPRESS) + parser.add_argument('--gara', help='Get all registered accounts', action='store_true') + parser.add_argument('--gaea', help='Get all enabled accounts', action='store_true') + parser.add_argument('--gaad', help='Get all account details', action='store_true') + + parser.add_argument('--gac', help='Get all codecs', action='store_true') + + parser.add_argument('--gad', help='Get account details', + metavar='<account>', type=str) + + group = parser.add_mutually_exclusive_group() + group.add_argument('--enable', help='Enable the account', + metavar='<account>', type=str) + group.add_argument('--disable', help='Disable the account', + metavar='<account>', type=str) + + group = parser.add_mutually_exclusive_group() + group.add_argument('--register', help='Register the account', + metavar='<account>', type=str) + group.add_argument('--unregister', help='Unregister the account', + metavar='<account>', type=str) + + parser.add_argument('--sac', help='Set active account', + metavar='<account>', type=str) + + parser.add_argument('--sacl', help='Set active codecs for active account', + metavar='<codec list>', type=str) + + #parser.add_argument('--gcc', help='Get current callid', action='store_true') + parser.add_argument('--gcl', help='Get call list', action='store_true') + + group = parser.add_mutually_exclusive_group() + group.add_argument('--call', help='Call to number', metavar='<destination>') + #group.add_argument('--transfer', help='Transfer active call', metavar='<destination>') + + group = parser.add_mutually_exclusive_group() + group.add_argument('--accept', help='Accept the call', metavar='<account>') + group.add_argument('--hangup', help='Hangup the call', metavar='<account>') + group.add_argument('--refuse', help='Refuse the call', metavar='<account>') + + group = parser.add_mutually_exclusive_group() + group.add_argument('--hold', help='Hold the call', metavar='<call>') + group.add_argument('--unhold', help='Unhold the call', metavar='<call>') + + parser.add_argument('--dtmf', help='Send DTMF', metavar='<key>') + + args = parser.parse_args() + + ctrl = DRingCtrl(sys.argv[0]) + + if len(sys.argv) == 1: + ctrl.run() + sys.exit(0) + + if args.gac: + print(ctrl.getAllCodecs()) + + if hasattr(args, 'gaa'): + for account in ctrl.getAllAccounts(args.gaa): + print(account) + + if args.gara: + for account in ctrl.getAllRegisteredAccounts(): + print(account) + + if args.gaea: + for account in ctrl.getAllEnabledAccounts(): + print(account) + + if args.gaad: + for account in ctrl.getAllAccounts(): + printAccountDetails(account) + + if args.sac: + ctrl.setAccount(args.sac) + + if args.gad: + printAccountDetails(args.gad) + + if args.sacl: + ctrl.setActiveCodecList(codec_list=args.sacl) + + if args.enable: + ctrl.setAccountEnable(args.enable, True) + + if args.disable: + ctrl.setAccountEnable(args.enable, False) + + if args.register: + ctrl.setAccountRegistered(args.register, True) + + if args.unregister: + ctrl.setAccountRegistered(args.unregister, False) + + if args.gcl: + for call in ctrl.getAllCalls(): + print(call) + + if args.call: + ctrl.Call(args.call) + + if args.accept: + ctrl.Accept(args.accept) + + if args.refuse: + ctrl.Refuse(args.refuse) + + if args.hangup: + ctrl.HangUp(args.hangup) + + if args.hold: + ctrl.Hold(args.hold) + + if args.unhold: + ctrl.UnHold(args.unhold) + + if args.dtmf: + sflphone.Dtmf(dtmf) + +""" + + # Get call details + elif opt == "--gcd": + if arg == "current": arg = sflphone.getCurrentCallID() + + details = sflphone.getCallDetails(arg) + if details: + print "Call: " + arg + print "Account: " + details['ACCOUNTID'] + print "Peer: " + details['PEER_NAME'] + "<" + details['PEER_NUMBER'] + ">" + + elif opt == "--sac": + if arg is "": + print "Must specifies the accout to be set" + else: + sflphone.setAccount(arg) + + # Unhold a call + elif opt == "--unhold": + if arg == "current": arg = sflphone.getCurrentCallID() + sflphone.UnHold(arg) + + # Transfer the current call + elif opt == "--transfer": + call = sflphone.callmanager.getCurrentCallID() + sflphone.Transfert(call, arg) + + # Send DTMF + elif opt == "--dtmf": + sflphone.Dtmf(arg) + + + # + # account options + # + + # Register an account + elif opt == "--register": + if not sflphone.checkAccountExists(arg): + print "Account " + arg + ": no such account." + + elif arg in sflphone.getAllRegisteredAccounts(): + print "Account " + arg + ": already registered." + + else: + sflphone.setAccountRegistered(arg, True) + print arg + ": Sent register request." + + # Unregister an account + elif opt == "--unregister": + if not sflphone.checkAccountExists(arg): + print "Account " + arg + ": no such account." + + elif arg not in sflphone.getAllRegisteredAccounts(): + print "Account " + arg + ": is not registered." + + else: + sflphone.setAccountRegistered(arg, False) + print arg + ": Sent unregister request." + + # Enable an account + elif opt == "--enable": + if not sflphone.checkAccountExists(arg): + print "Account " + arg + ": no such account." + + elif sflphone.isAccountEnable(arg): + print "Account " + arg + ": already enabled." + + else: + sflphone.setAccountEnable(arg, True) + print arg + ": Account enabled." + + # Disable an account + elif opt == "--disable": + if not sflphone.checkAccountExists(arg): + print "Account " + arg + ": no such account." + + elif not sflphone.isAccountEnable(arg): + print "Account " + arg + ": already disabled." + + else: + sflphone.setAccountRegistered(arg, False) + sflphone.setAccountEnable(arg, False) + print arg + ": Account disabled." + + +""" diff --git a/tools/pysflphone/pysflphone_testdbus.py b/daemon/tools/dringctl/dringctl_testdbus.py similarity index 99% rename from tools/pysflphone/pysflphone_testdbus.py rename to daemon/tools/dringctl/dringctl_testdbus.py index 05b341a569b709be600c56b8f65a276f92d48462..fc2bc668350201978b2dcf3d074036611ee924ff 100644 --- a/tools/pysflphone/pysflphone_testdbus.py +++ b/daemon/tools/dringctl/dringctl_testdbus.py @@ -74,7 +74,7 @@ class SflPhoneTests(): HOSTNAME = "hostname" USERNAME = "username" PASSWORD = "password" - + accDetails = {CONFIG_ACCOUNT_TYPE:"SIP", CONFIG_ACCOUNT_ALIAS:"testsuiteaccount", HOSTNAME:"192.168.50.79", USERNAME:"31416", PASSWORD:"1234"} diff --git a/daemon/tools/dringctl/errors.py b/daemon/tools/dringctl/errors.py new file mode 100644 index 0000000000000000000000000000000000000000..685ef11f645ec0332f3eeddd26e7dd8ddf49be9f --- /dev/null +++ b/daemon/tools/dringctl/errors.py @@ -0,0 +1,53 @@ +# +# Copyright (C) 2015 Savoir-Faire Linux Inc. +# Author: Guillaume Roguez <guillaume.roguez@savoirfairelinux.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Additional permission under GNU GPL version 3 section 7: +# +# If you modify this program, or any covered work, by linking or +# combining it with the OpenSSL project's OpenSSL library (or a +# modified version of that library), containing parts covered by the +# terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc. +# grants you additional permission to convey the resulting work. +# Corresponding Source for a non-source form of such a combination +# shall include the source code for the parts of OpenSSL used as well +# as that of the covered work. +# + +"""Internal exceptions""" + +__all__ = ['DRingCtrlError', + 'DRingCtrlDBusError', + 'DRingCtrlDeamonError'] + +class DRingCtrlError(Exception): + """Base class for all our exceptions.""" + + def __init__(self, help=None): + self.help = str(help) + + def __str__(self): + return self.help + +class DRingCtrlDBusError(DRingCtrlError): + """General error for dbus communication""" + +class DRingCtrlDeamonError(DRingCtrlError): + """General error for daemon communication""" + +class DRingCtrlAccountError(DRingCtrlError): + """General error for account handling""" diff --git a/tools/pysflphone/sippwrap.py b/daemon/tools/dringctl/sippwrap.py similarity index 100% rename from tools/pysflphone/sippwrap.py rename to daemon/tools/dringctl/sippwrap.py diff --git a/tools/pysflphone/test_sflphone_dbus_interface.py b/daemon/tools/dringctl/test_dring_dbus_interface.py similarity index 100% rename from tools/pysflphone/test_sflphone_dbus_interface.py rename to daemon/tools/dringctl/test_dring_dbus_interface.py diff --git a/tools/pysflphone/Errors.py b/tools/pysflphone/Errors.py deleted file mode 100644 index 2a1e6b38693f22073d4073edb11d9656ecaa06af..0000000000000000000000000000000000000000 --- a/tools/pysflphone/Errors.py +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright (C) 2008 by the Free Software Foundation, Inc. -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -"""Our own Errors exceptions""" - -class SflPhoneError(Exception): - """Base class for all SflPhone exceptions.""" - def __init__(self, help=None): - self.help=help - def __str__(self): - return repr(self.help) - - -class SPdbusError(SflPhoneError): - """General error for dbus communication""" - -class SPdaemonError(SflPhoneError): - """General error for daemon communication""" - -class SPserverError(SflPhoneError): - """General error for server communication""" - -class SPconfigurationError(SflPhoneError): - """General error for configuration""" - -class SPaccountError(SflPhoneError): - """General error for account handling""" diff --git a/tools/pysflphone/__init__.py b/tools/pysflphone/__init__.py deleted file mode 100644 index 94ffb667d0fe679dc40c0db3b26216748a8ea362..0000000000000000000000000000000000000000 --- a/tools/pysflphone/__init__.py +++ /dev/null @@ -1,17 +0,0 @@ -# Copyright (C) 2008 by the Free Software Foundation, Inc. -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - - diff --git a/tools/pysflphone/pysflphone.py b/tools/pysflphone/pysflphone.py deleted file mode 100644 index b4a43ef50c293c7a55bed5211e6e7947b82732b7..0000000000000000000000000000000000000000 --- a/tools/pysflphone/pysflphone.py +++ /dev/null @@ -1,279 +0,0 @@ -#!/usr/bin/env python -# -# Copyright (C) 2009 by the Free Software Foundation, Inc. -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - - - -import sys -import os -import random -from traceback import print_exc - -import gobject -from gobject import GObject - -import getopt - -import time - -from threading import Thread - -from Errors import * - -try: - import dbus - from dbus.mainloop.glib import DBusGMainLoop -except ImportError, e: - raise SflPhoneError("No python-dbus module found") - - -from sflphonectrl import SflPhoneCtrl - -# -# Main application -# - - -def printHelp(): - """Print help""" - print sys.argv[0] + " usage:\n\ -\n\ - --help Print this help.\n\ -\n\ - --gaa Get all accounts.\n\ - --gara Get all registered accounts. \n\ - --gaea Get all enabled accounts. \n\ - --gasa Get all SIP accounts. \n\ - --gaia Get all IAX accounts. \n\ - --gcc Get current callid. \n\ - --gacl Get active codec list. \n\ - --sac Set accout for next call \n\ - \n\ - --gad <account> Get account details . \n\ - --enable <account> Enable the account. \n\ - --disable <account> Disable the account. \n\ - --register <account> Register the account. \n\ - --unregister <account> Unregister the account. \n\ - \n\ - --call <destination> Call to number \n\ - --transfer <destination> Transfer active call \n\ -\n\ - --gcd <callid|\"current\"> Get call details. \n\ - --accept <callid|\"current\"> Accept the call \n\ - --hangup <callid|\"current\"> Hangup the call \n\ - --refuse <callid|\"current\"> Refuse the call \n\ - --hold <callid|\"current\"> Hold the call \n\ - --unhold <callid|\"current\"> Unhold the call \n\ - --dtmf <key> Send DTMF\n" - - - -# Option definition -try: - opts, args = getopt.getopt(sys.argv[1:],"", - [ "help", "gaa", "gal", "gara", "gaea", "gasa", "gaia", - "gacl", "gac", "gcc", "hangup=", "refuse=", "hold", - "unhold=", "transfer=","dtmf=", "accept=", "gcd=", - "gad=", "register=", "unregister=", "enable=", "disable=", - "call=", "sac=" ]) -except getopt.GetoptError,err: - print str(err) - sys.exit(2) - - -# SFLPhone instance. -sflphone = SflPhoneCtrl() - -# If no arguments, run the d-bus event loop. -if len(sys.argv) == 1: - loop = gobject.MainLoop() - loop.run() - -# Parse all arguments -else: - for opt, arg in opts: - - if opt == "--help": - printHelp() - - # - # info options - # - - # Get all accounts - elif opt == "--gaa": - for account in sflphone.getAllAccounts(): - print account - - # Get all registered accounts - elif opt == "--gara": - for account in sflphone.getAllRegisteredAccounts(): - print account - - # Get all enabled accounts - elif opt == "--gaea": - for account in sflphone.getAllEnabledAccounts(): - print account - - # Get all SIP accounts - elif opt == "--gasa": - for account in sflphone.getAllSipAccounts(): - print account - - # Get all IAX accounts - elif opt == "--gaia": - for account in sflphone.getAllIaxAccounts(): - print account - - # Get current call - elif opt == "--gcc": - call = sflphone.getCurrentCallID() - if call: - print call - else: - print "No current call." - - # Get account details - elif opt == "--gad": - if sflphone.checkAccountExists(arg): - details = sflphone.getAccountDetails(arg) - for var in details: - print var + ": " + details[var] - else: - print "No such account: " + arg - - # Get active codec list - elif opt == "--gacl": - print "Not implemented." - - # Get call details - elif opt == "--gcd": - if arg == "current": arg = sflphone.getCurrentCallID() - - details = sflphone.getCallDetails(arg) - if details: - print "Call: " + arg - print "Account: " + details['ACCOUNTID'] - print "Peer: " + details['PEER_NAME'] + "<" + details['PEER_NUMBER'] + ">" - - elif opt == "--sac": - if arg is "": - print "Must specifies the accout to be set" - else: - sflphone.setAccount(arg) - - - # - # call options - # - - # Make a call - elif opt == "--call": - sflphone.Call(arg) - - # Hangup a call - elif opt == "--hangup": - if arg == "current": - arg = sflphone.getCurrentCallID() - - if arg: - sflphone.HangUp(arg) - - # Refuse a call - elif opt == "--refuse": - if arg == "current": arg = sflphone.getCurrentCallID() - sflphone.Refuse(arg) - - # Hold a call - elif opt == "--hold": - if arg == "current": arg = sflphone.getCurrentCallID() - sflphone.Hold(arg) - - # Unhold a call - elif opt == "--unhold": - if arg == "current": arg = sflphone.getCurrentCallID() - sflphone.UnHold(arg) - - # Transfer the current call - elif opt == "--transfer": - call = sflphone.callmanager.getCurrentCallID() - sflphone.Transfert(call, arg) - - # Send DTMF - elif opt == "--dtmf": - sflphone.Dtmf(arg) - - # Accept a call - elif opt == "--accept": - if arg == "current": arg = sflphone.getCurrentCallID() - sflphone.Accept(arg) - - - # - # account options - # - - # Register an account - elif opt == "--register": - if not sflphone.checkAccountExists(arg): - print "Account " + arg + ": no such account." - - elif arg in sflphone.getAllRegisteredAccounts(): - print "Account " + arg + ": already registered." - - else: - sflphone.setAccountRegistered(arg, True) - print arg + ": Sent register request." - - # Unregister an account - elif opt == "--unregister": - if not sflphone.checkAccountExists(arg): - print "Account " + arg + ": no such account." - - elif arg not in sflphone.getAllRegisteredAccounts(): - print "Account " + arg + ": is not registered." - - else: - sflphone.setAccountRegistered(arg, False) - print arg + ": Sent unregister request." - - # Enable an account - elif opt == "--enable": - if not sflphone.checkAccountExists(arg): - print "Account " + arg + ": no such account." - - elif sflphone.isAccountEnable(arg): - print "Account " + arg + ": already enabled." - - else: - sflphone.setAccountEnable(arg, True) - print arg + ": Account enabled." - - # Disable an account - elif opt == "--disable": - if not sflphone.checkAccountExists(arg): - print "Account " + arg + ": no such account." - - elif not sflphone.isAccountEnable(arg): - print "Account " + arg + ": already disabled." - - else: - sflphone.setAccountRegistered(arg, False) - sflphone.setAccountEnable(arg, False) - print arg + ": Account disabled." - - diff --git a/tools/pysflphone/sflphonectrl.py b/tools/pysflphone/sflphonectrl.py deleted file mode 100755 index b6a17226a21ec1a38df9699caf08fb740ec6408b..0000000000000000000000000000000000000000 --- a/tools/pysflphone/sflphonectrl.py +++ /dev/null @@ -1,705 +0,0 @@ -#!/usr/bin/env python -# -# Copyright (C) 2009 by the Free Software Foundation, Inc. -# -# Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com> -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -"""Simple class for controlling SflPhoned through DBUS""" - -import sys -import os -import random -from traceback import print_exc - -import gtk -import gobject -from gobject import GObject -from gobject import MainLoop - -import getopt - -import time -import hashlib - -from threading import Thread -from threading import Event - -from Errors import * - -try: - import dbus - from dbus.mainloop.glib import DBusGMainLoop -except ImportError, e: - raise SflPhoneError("No python-dbus module found") - - -class SflPhoneCtrl(Thread): - """ class for controlling SflPhoned through DBUS - - Classes deriving this class should reimplement signal handlers, - more especially: - onIncomingCall_cb - onCallHangup_cb - onCallRinging_cb - onCallHold_cb - onCallCurrent_cb - onCallBusy_cb - onCallFailure_cb - onConferenceCreated_cb - """ - - # list of active calls (known by the client) - activeCalls = {} - - # list of active conferences - activeConferences = {} - - def __init__(self, name=sys.argv[0]): - Thread.__init__(self) - - # current active account - self.account = None - - # client name - self.name = name - - self.currentCallId = "" - self.currentConfId = "" - - self.isStop = False - - # client registered to sflphoned ? - self.registered = False - self.register() - - # Glib MainLoop for processing callbacks - self.loop = MainLoop() - - gobject.threads_init() - - - def __del__(self): - if self.registered: - self.unregister() - self.loop.quit() - - - def stopThread(self): - self.isStop = True - - - def register(self): - if self.registered: - return - - try: - # register the main loop for d-bus events - DBusGMainLoop(set_as_default=True) - self.bus = dbus.SessionBus() - except dbus.DBusException, e: - raise SPdbusError("Unable to connect DBUS session bus") - - dbus_objects = dbus.Interface(self.bus.get_object( - 'org.freedesktop.DBus', '/org/freedesktop/DBus'), - 'org.freedesktop.DBus').ListNames() - - if not "org.sflphone.SFLphone" in dbus_objects: - raise SPdbusError("Unable to find org.sflphone.SFLphone in DBUS. Check if sflphoned is running") - - try: - proxy_instance = self.bus.get_object("org.sflphone.SFLphone", - "/org/sflphone/SFLphone/Instance", introspect=False) - proxy_callmgr = self.bus.get_object("org.sflphone.SFLphone", - "/org/sflphone/SFLphone/CallManager", introspect=False) - proxy_confmgr = self.bus.get_object("org.sflphone.SFLphone", - "/org/sflphone/SFLphone/ConfigurationManager", - introspect=False) - - self.instance = dbus.Interface(proxy_instance, - "org.sflphone.SFLphone.Instance") - self.callmanager = dbus.Interface(proxy_callmgr, - "org.sflphone.SFLphone.CallManager") - self.configurationmanager = dbus.Interface(proxy_confmgr, - "org.sflphone.SFLphone.ConfigurationManager") - - except dbus.DBusException, e: - - raise SPdbusError("Unable to bind to sflphoned api, ask core-dev team to implement getVersion method and start to pray.") - - try: - self.instance.Register(os.getpid(), self.name) - self.registered = True - except: - raise SPdaemonError("Client registration failed") - - try: - print "Adding Incoming call method" - proxy_callmgr.connect_to_signal('incomingCall', self.onIncomingCall) - proxy_callmgr.connect_to_signal('callStateChanged', self.onCallStateChanged) - proxy_callmgr.connect_to_signal('conferenceCreated', self.onConferenceCreated) - except dbus.DBusException, e: - print e - - - def unregister(self): - - if not self.registered: - return - try: - self.instance.Unregister(os.getpid()) - self.registered = False - except: - raise SPdaemonError("Client unregistration failed") - - - def isRegistered(self): - return self.registered - - - # - # Signal handling - # - - def onIncomingCall_cb(self): - pass - - def onCallHangup_cb(self, callId): - pass - - def onCallRinging_cb(self): - pass - - def onCallHold_cb(self): - pass - - def onCallCurrent_cb(self): - pass - - def onCallBusy_cb(self): - pass - - def onCallFailure_cb(self): - pass - - def onIncomingCall(self, account, callid, to): - """ On incoming call event, add the call to the list of active calls """ - - self.activeCalls[callid] = {'Account': account, - 'To': to, - 'State': ''} - self.currentCallId = callid - self.onIncomingCall_cb() - - - def onCallHangUp(self, callid): - """ Remove callid from call list """ - - self.onCallHangup_cb(callid) - self.currentCallId = "" - del self.activeCalls[callid] - - - def onCallRinging(self, callid, state): - """ Update state for this call to Ringing """ - - self.activeCalls[callid]['State'] = state - self.onCallRinging_cb() - - - def onCallHold(self, callid, state): - """ Update state for this call to Hold """ - - self.activeCalls[callid]['State'] = state - self.onCallHold_cb() - - - def onCallCurrent(self, callid, state): - """ Update state for this call to current """ - - self.activeCalls[callid]['State'] = state - self.onCallCurrent_cb() - - - def onCallBusy(self, callid, state): - """ Update state for this call to busy """ - - self.activeCalls[callid]['State'] = state - self.onCallBusy_cb() - - - def onCallFailure(self, callid, state): - """ Handle call failure """ - - self.onCallFailure_cb(self) - del self.activeCalls[callid] - - - def onCallStateChanged(self, callid, state): - """ On call state changed event, set the values for new calls, - or delete the call from the list of active calls - """ - - print "On call state changed " + callid + " " + state - - if callid not in self.activeCalls: - print "This call didn't exist!: " + callid + ". Adding it to the list." - callDetails = self.getCallDetails(callid) - self.activeCalls[callid] = {'Account': callDetails['ACCOUNTID'], - 'To': callDetails['PEER_NUMBER'], - 'State': state } - - - self.currentCallId = callid - - if state == "HUNGUP": - self.onCallHangUp(callid) - elif state == "RINGING": - self.onCallRinging(callid, state) - elif state == "CURRENT": - self.onCallCurrent(callid, state) - elif state == "HOLD": - self.onCallHold(callid, state) - elif state == "BUSY": - self.onCallBusy(callid, state) - elif state == "FAILURE": - self.onCallFailure(self, callid, state) - else: - print "unknown state" - - def onConferenceCreated_cb(self): - pass - - def onConferenceCreated(self, confId): - self.currentConfId = confId - self.onConferenceCreated_cb() - - # - # Account management - # - def addAccount(self, details=None): - """Add a new account account - - Add a new account to the SFLphone-daemon. Default parameters are \ - used for missing account configuration field. - - Required parameters are type, alias, hostname, username and password - - input details - - """ - - if details is None: - raise SPaccountError("Must specifies type, alias, hostname, \ - username and password in \ - order to create a new account") - - return self.configurationmanager.addAccount(details) - - - def removeAccount(self, accountID=None): - """Remove an account from internal list""" - - if accountID is None: - raise SPaccountError("Account ID must be specified") - - self.configurationmanager.removeAccount(accountID) - - - def getAllAccounts(self): - """Return a list with all accounts""" - - return self.configurationmanager.getAccountList() - - - def getAllEnabledAccounts(self): - """Return a list with all enabled accounts""" - - accounts = self.getAllAccounts() - activeaccounts = [] - for testedaccount in accounts: - if self.isAccountEnable(testedaccount): - activeaccounts.append(testedaccount) - return activeaccounts - - - def getAccountDetails(self, account=None): - """Return a list of string. If no account is provided, active account is used""" - - if account is None: - if self.account is None: - raise SflPhoneError("No provided or current account !") - if checkAccountExists(self.account): - return self.configurationmanager.getAccountDetails(self.account) - else: - if self.checkAccountExists(account): - - return self.configurationmanager.getAccountDetails(account) - - - def setAccountByAlias(self, alias): - """Define as active the first account who match with the alias""" - - for testedaccount in self.getAllAccounts(): - details = self.getAccountDetails(testedaccount) - if ( details['Account.enable'] == "TRUE" and - details['Account.alias'] == alias ): - self.account = testedaccount - return - raise SPaccountError("No enabled account matched with alias") - - - def getAccountByAlias(self, alias): - """Get account name having its alias""" - - for account in self.getAllAccounts(): - details = self.getAccountDetails(account) - if details['Account.alias'] == alias: - return account - - raise SPaccountError("No account matched with alias") - - - def setAccount(self, account): - """Define the active account - - The active account will be used when sending a new call - """ - - if account in self.getAllAccounts(): - self.account = account - else: - print account - raise SflPhoneError("Not a valid account") - - - def setFirstRegisteredAccount(self): - """Find the first enabled account and define it as active""" - - rAccounts = self.getAllRegisteredAccounts() - if 0 == len(rAccounts): - raise SflPhoneError("No registered account !") - self.account = rAccounts[0] - - - def setFirstActiveAccount(self): - """Find the first enabled account and define it as active""" - - aAccounts = self.getAllEnabledAccounts() - if 0 == len(aAccounts): - raise SflPhoneError("No active account !") - self.account = aAccounts[0] - - - def getAccount(self): - """Return the active account""" - - return self.account - - - def isAccountRegistered(self, account=None): - """Return True if the account is registered. If no account is provided, active account is used""" - - if account is None: - if self.account is None: - raise SflPhoneError("No provided or current account !") - account = self.account - return self.getAccountDetails(account)['Registration.Status'] == "REGISTERED" - - - def isAccountEnable(self, account=None): - """Return True if the account is enabled. If no account is provided, active account is used""" - - if account is None: - if self.account is None: - raise SflPhoneError("No provided or current account !") - account = self.account - return self.getAccountDetails(account)['Account.enable'] == "TRUE" - - - def setAccountEnable(self, account=None, enable=False): - """Set account enabled""" - if account is None: - if self.account is None: - raise SflPhoneError("No provided or current account !") - account = self.account - - if enable == True: - details = self.getAccountDetails(account) - details['Account.enable'] = "true" - self.configurationmanager.setAccountDetails(account, details) - else: - details = self.getAccountDetails(account) - details['Account.enable'] = "false" - self.configurationmanager.setAccountDetails(account, details) - - - def checkAccountExists(self, account=None): - """ Checks if the account exists """ - - if account is None: - raise SflPhoneError("No provided or current account !") - return account in self.getAllAccounts() - - - def getAllRegisteredAccounts(self): - """Return a list of registered accounts""" - - registeredAccountsList = [] - for account in self.getAllAccounts(): - if self.isAccountRegistered(account): - registeredAccountsList.append(account) - - return registeredAccountsList - - - def getAllEnabledAccounts(self): - """Return a list of enabled accounts""" - - enabledAccountsList = [] - for accountName in self.getAllAccounts(): - if self.getAccountDetails(accountName)['Account.enable'] == "TRUE": - enabledAccountsList.append(accountName) - - return enabledAccountsList - - - def getAllSipAccounts(self): - """Return a list of SIP accounts""" - - sipAccountsList = [] - for accountName in self.getAllAccounts(): - if self.getAccountDetails(accountName)['Account.type'] == "SIP": - sipAccountsList.append(accountName) - - return sipAccountsList - - - def getAllIaxAccounts(self): - """Return a list of IAX accounts""" - - iaxAccountsList = [] - for accountName in self.getAllAccounts(): - if self.getAccountDetails(accountName)['Account.type'] == "IAX": - iaxAccountsList.append(accountName) - - return iaxAccountsList - - - def setAccountRegistered(self, account=None, register=False): - """ Tries to register the account """ - - if account is None: - if self.account is None: - raise SflPhoneError("No provided or current account !") - account = self.account - - try: - if register: - self.configurationmanager.sendRegister(account, int(1)) - else: - self.configurationmanager.sendRegister(account, int(0)) - except SflPhoneError, e: - print e - - # - # Codec manager - # - - def getCodecList(self): - """ Return the codec list """ - - return self.configurationmanager.getCodecList() - - - def getActiveCodecList(self): - """ Return the active codec list """ - - return self.configurationmanager.getActiveCodecList() - - - # - # Call management - # - - def getCurrentCallID(self): - """Return the callID of the current call if any""" - - return self.callmanager.getCurrentCallID() - - - def getCurrentCallDetails(self): - """Return informations on the current call if any""" - - return self.callmanager.getCallDetails(self.getCurrentCallID()) - - def getCallDetails(self, callid): - """Return informations on this call if exists""" - - return self.callmanager.getCallDetails(callid) - - def printClientCallList(self): - print "Client active call list:" - print "------------------------" - for call in self.activeCalls: - print "\t" + call - - def Call(self, dest): - """Start a call and return a CallID - - Use the current account previously set using setAccount(). - If no account specified, first registered one in account list is used. - - For phone number prefixed using SIP scheme (i.e. sip: or sips:), - IP2IP profile is automatically selected and set as the default account - - return callID Newly generated callidentifier for this call - """ - - if dest is None or dest == "": - raise SflPhoneError("Invalid call destination") - - # Set the account to be used for this call - if dest.find('sip:') is 0 or dest.find('sips:') is 0: - print "Ip 2 IP call" - self.setAccount("IP2IP") - elif not self.account: - self.setFirstRegisteredAccount() - - if self.account is "IP2IP" and self.isAccountRegistered(): - raise SflPhoneError("Can't place a call without a registered account") - - # Generate a call ID for this call - callid = self.GenerateCallID() - - # Add the call to the list of active calls and set status to SENT - self.activeCalls[callid] = {'Account': self.account, 'To': dest, 'State': 'SENT' } - - # Send the request to the CallManager - self.callmanager.placeCall(self.account, callid, dest) - - return callid - - - def HangUp(self, callid): - """End a call identified by a CallID""" - - if not self.account: - self.setFirstRegisteredAccount() - - if callid is None or callid == "": - pass # just to see - - self.callmanager.hangUp(callid) - - - def Transfer(self, callid, to): - """Transfert a call identified by a CallID""" - - if callid is None or callid == "": - raise SflPhoneError("Invalid callID") - - self.callmanager.transfert(callid, to) - - - def Refuse(self, callid): - """Refuse an incoming call identified by a CallID""" - - print "Refuse call " + callid - - if callid is None or callid == "": - raise SflPhoneError("Invalid callID") - - self.callmanager.refuse(callid) - - - def Accept(self, callid): - """Accept an incoming call identified by a CallID""" - - print "Accept call " + callid - if not self.account: - self.setFirstRegisteredAccount() - - if not self.isAccountRegistered(): - raise SflPhoneError("Can't accept a call without a registered account") - - if callid is None or callid == "": - raise SflPhoneError("Invalid callID") - - self.callmanager.accept(callid) - - - def Hold(self, callid): - """Hold a call identified by a CallID""" - - if callid is None or callid == "": - raise SflPhoneError("Invalid callID") - - self.callmanager.hold(callid) - - - def UnHold(self, callid): - """Unhold an incoming call identified by a CallID""" - - if callid is None or callid == "": - raise SflPhoneError("Invalid callID") - - self.callmanager.unhold(callid) - - - def Dtmf(self, key): - """Send a DTMF""" - - self.callmanager.playDTMF(key) - - - def GenerateCallID(self): - """Generate Call ID""" - - m = hashlib.md5() - t = long( time.time() * 1000 ) - r = long( random.random()*100000000000000000L ) - m.update(str(t) + str(r)) - callid = m.hexdigest() - return callid - - - def createConference(self, call1Id, call2Id): - """ Create a conference given the two call ids """ - - self.callmanager.joinParticipant(call1Id, call2Id) - - - def hangupConference(self, confId): - """ Hang up each call for this conference """ - - self.callmanager.hangUpConference(confId) - - - def run(self): - """Processing method for this thread""" - - context = self.loop.get_context() - - while True: - context.iteration(True) - - if self.isStop: - print "++++++++++++++++++++++++++++++++++++++++" - print "++++++++++++++++++++++++++++++++++++++++" - print "++++++++++++++++++++++++++++++++++++++++" - print "++++++++++++++++++++++++++++++++++++++++" - return