/*
-@version: 0.2
-@author: Sudheer K. <scifi.guy@hotmail.com>
+@version: 0.5
+@author: Sudheer K. <scifi1947 at gmail.com>
@license: GNU General Public License
*/
#include "callrouter.h"
+#include "vicardbusadaptor.h"
#include <dbusutility.h>
#include <gconfutility.h>
+#include <databaseutility.h>
+#include <telepathyutility.h>
#include <QDebug>
#include <QRegExp>
#include <QDBusConnection>
-#include <QTimer>
+#include <QDBusMessage>
#include <QStringListIterator>
-//Create a statis Dbus utility object that will be shared across all member functions
-static DbusUtility dbusUtility = DbusUtility();
-static QString strLastDialedNumber = QString();
+
+//static QString strLastDialedNumber = QString();
+//static org::maemo::vicar::Profile currentProfile;
+
+class CallRouterPrivate
+{
+public:
+ CallRouterPrivate(CallRouter * p) :
+ databaseUtility(new DatabaseUtility(p)),
+ dbusAdaptor(new VicarDbusAdaptor(p)),
+ dbusUtility(new DbusUtility(p)),
+ gconfUtility(new GConfUtility(p)),
+ tpUtility(new TelepathyUtility(p)),
+ parent(p)
+ {
+ Q_ASSERT(0 != dbusAdaptor);
+ //Do not open here - Unable to capture changes to DB if it is open too early and closed late.
+ //databaseUtility->openDatabase();
+ }
+
+ ~CallRouterPrivate()
+ {
+ qDebug() << "VICaR: Call Router Destructing";
+ //databaseUtility->closeDatabase();
+ }
+
+ DatabaseUtility *databaseUtility;
+ VicarDbusAdaptor * dbusAdaptor;
+ DbusUtility * dbusUtility;
+ GConfUtility * gconfUtility;
+ TelepathyUtility *tpUtility;
+ QString strLastDialedNumber;
+ org::maemo::vicar::Profile *currentProfile;
+ CallRouter * const parent;
+};
+
+// ---------------------------------------------------------------------------
CallRouter::CallRouter(QObject *parent) :
- QObject(parent)
+ QObject(parent),
+ d(new CallRouterPrivate(this))
{
- gconfUtility = new GConfUtility();
+ Q_ASSERT(0 != d);
+ this->registerDBusService();
+ qDebug() << "Registered DBus Service " << APPLICATION_DBUS_SERVICE;
}
CallRouter::~CallRouter(){
- delete gconfUtility;
- gconfUtility = 0;
}
void CallRouter::registerDBusService(){
- QDBusConnection connection = dbusUtility.getConnection();
+ //Connect to Session Bus
+ QDBusConnection connection = d->dbusUtility->getConnection(false);
+
+ if (!connection.interface()->isServiceRegistered(APPLICATION_DBUS_SERVICE)){
- if (!connection.registerService(APPLICATION_DBUS_SERVICE)) {
- qDebug() << dbusUtility.getErrorMessage();
- exit(1);
+ if (!connection.registerService(APPLICATION_DBUS_SERVICE)) {
+ qDebug() << d->dbusUtility->getErrorMessage();
+ exit(1);
+ }
}
- if (!connection.registerObject(APPLICATION_DBUS_PATH, this,
- QDBusConnection::ExportScriptableSlots)) {
- qDebug() << dbusUtility.getErrorMessage();
+ if (!connection.registerObject(APPLICATION_DBUS_PATH, this, QDBusConnection::ExportAdaptors)) {
+ qDebug() << d->dbusUtility->getErrorMessage();
exit(2);
}
- this->connectToDBusSignals();
-
}
void CallRouter::unregisterDBusService(){
- this->disconnectFromDBusSignals();
-
- QDBusConnection connection = dbusUtility.getConnection();
+ //Disconnect from Session bus
+ QDBusConnection connection = d->dbusUtility->getConnection(false);
connection.unregisterObject(APPLICATION_DBUS_PATH,QDBusConnection::UnregisterTree);
if (!connection.unregisterService(APPLICATION_DBUS_SERVICE)) {
- qDebug() << dbusUtility.getErrorMessage();
+ qDebug() << d->dbusUtility->getErrorMessage();
exit(3);
}
}
-void CallRouter::connectToDBusSignals(){
+QString CallRouter::callViaCallingCard(QString strDestinationNumber){
- QDBusConnection connection = dbusUtility.getConnection();
+ d->currentProfile = new org::maemo::vicar::Profile();
+ d->currentProfile->profileID = 0;
- // Connect to the signal to enable call routing
- bool success = connection.connect(QString(""),QString(""),
- APPLICATION_DBUS_INTERFACE,
- QString("startOutgoingCallMonitor"),this,
- SLOT(startOutgoingCallMonitor()));
-
- if (success){
- qDebug() << "Successfully connected to Dbus signal org.maemo.vicar.startOutgoingCallMonitor";
- }
- else{
- qDebug() << "Failed to connect to Dbus signal org.maemo.vicar.startOutgoingCallMonitor";
- qDebug() <<"DBus Error: "<< qPrintable(dbusUtility.getErrorMessage());
- }
-
- // Connect to the signal to disable call routing
- success = connection.connect(QString(""),QString(""),
- APPLICATION_DBUS_INTERFACE,
- QString("stopOutgoingCallMonitor"),this,
- SLOT(stopOutgoingCallMonitor()));
-
- if (success){
- qDebug() << "Successfully connected to Dbus signal org.maemo.vicar.stopOutgoingCallMonitor";
- }
- else{
- qDebug() << "Failed to connect to Dbus signal org.maemo.vicar.stopOutgoingCallMonitor";
- qDebug() <<"DBus Error: "<< qPrintable(dbusUtility.getErrorMessage());
- }
-
-}
+ d->databaseUtility->openDatabase();
+ bool result = d->databaseUtility->findProfileByNumber(strDestinationNumber,d->currentProfile);
-void CallRouter::disconnectFromDBusSignals(){
-
- QDBusConnection connection = dbusUtility.getConnection();
-
- // Disconnect from the signal to enable call routing
- bool success = connection.disconnect(QString(""),QString(""),
- APPLICATION_DBUS_INTERFACE,
- QString("startOutgoingCallMonitor"),this,
- SLOT(startOutgoingCallMonitor()));
-
- if (success){
- qDebug() << "Successfully disconnected from Dbus signal org.maemo.vicar.startOutgoingCallMonitor";
- }
- else{
- qDebug() << "Failed to disconnect from Dbus signal org.maemo.vicar.startOutgoingCallMonitor";
- qDebug() <<"DBus Error: "<< qPrintable(dbusUtility.getErrorMessage());
- }
-
- // Disconnect from the signal to disable call routing
- success = connection.connect(QString(""),QString(""),
- APPLICATION_DBUS_INTERFACE,
- QString("stopOutgoingCallMonitor"),this,
- SLOT(stopOutgoingCallMonitor()));
-
- if (success){
- qDebug() << "Successfully disconnected from Dbus signal org.maemo.vicar.stopOutgoingCallMonitor";
- }
- else{
- qDebug() << "Failed to disconnect from Dbus signal org.maemo.vicar.stopOutgoingCallMonitor";
- qDebug() <<"DBus Error: "<< qPrintable(dbusUtility.getErrorMessage());
- }
-
-}
-
-void CallRouter::startOutgoingCallMonitor(){
-
- // Connect to DBus to monitor all outgoing calls
-
- QDBusConnection connection = dbusUtility.getConnection();
-
-
- // Declare the slot to be executed when new calls are placed
-
- bool success = connection.connect(QString(""),
- CSD_CALL_PATH,
- CSD_CALL_INTERFACE,
- QString("CreateRequested"),this,
- SLOT(processOutgoingCall(const QDBusMessage&)));
-
- if (success){
- qDebug() << "Successfully connected to Dbus signal CreateRequested in interface "<< CSD_CALL_INTERFACE;
- }
- else{
- qDebug() << "Failed to connect to Dbus signal CreateRequested in interface " << CSD_CALL_INTERFACE;
- qDebug() <<"DBus Error: "<< dbusUtility.getErrorMessage();
- }
-
-
-}
-
-void CallRouter::stopOutgoingCallMonitor(){
-
- this->stopCallStatusMonitors();
-
- //Disconnect the slots from Dbus signals
- QDBusConnection connection = dbusUtility.getConnection();
-
- // Disconnect the slot for new calls
- bool status = connection.disconnect(QString(""),
- CSD_CALL_PATH,
- CSD_CALL_INTERFACE,
- QString("CreateRequested"),this,
- SLOT(processOutgoingCall(const QDBusMessage&)));
-
- if (status){
- qDebug() << "Successfully disconnected from Dbus signal CreateRequested in interface "<< CSD_CALL_INTERFACE;
- }
- else{
- qDebug() << "Failed to disconnect from Dbus signal CreateRequested in interface "<< CSD_CALL_INTERFACE;
- qDebug() <<"DBus Error: "<< dbusUtility.getErrorMessage();
- }
-
-}
-
-void CallRouter::processOutgoingCall(const QDBusMessage& dbusMessage){
-
- //Verify Whether Call Routing is Enabled
- bool isRoutingEnabled = gconfUtility->getGconfValueBoolean("routing_enabled");
-
- if (isRoutingEnabled){
- //User is making a phone call. Get the phone number and verify if it is an international number
- QList<QVariant> listArguments = dbusMessage.arguments();
- QString strInternationalNumber = listArguments.first().toString();
-
- qDebug() << "New Call Identified. Destination number is " << strInternationalNumber;
-
- if (strInternationalNumber.startsWith("+") ||
- strInternationalNumber.startsWith("00"))
- {
- qDebug() << "International number "<< strInternationalNumber << " recognized. Starting proceedings..";
-
- //Check whether this is one of the excluded country codes
- if (!isExcludedNumber(strInternationalNumber)){
-
- //International number. Disconnect the current call (A new call will be placed)
-
- //No arguments required to cancel the current call
- QList<QVariant> argsToSend;
- bool status = dbusUtility.sendMethodCall(CSD_CALL_SERVICE,
- CSD_CALL_PATH,
- CSD_CALL_INTERFACE,
- QString("Release"),argsToSend);
-
- QString strUserMessage;
- if (status){
- strUserMessage = QString("Routing international call via ").append(APPLICATION_FRIENDLY_NAME).append("..");
- qDebug() << strUserMessage;
- strLastDialedNumber = strInternationalNumber;
- }
- else{
- strUserMessage = QString("Call could not be cancelled.");
- qDebug() << dbusUtility.getErrorMessage();
- }
-
- dbusUtility.displayNotification(strUserMessage);
-
- //Wait for a few seconds before the current call is completely disconnected
- QTimer *timer = new QTimer(this);
- timer->setSingleShot(true);
- connect(timer, SIGNAL(timeout()), this, SLOT(callViaCallingCard()));
- timer->start(3000);
- }
+ QString strErrorMessage;
+ if (!result){
+ strErrorMessage = QString("Error finding VICaR profile. %1").arg(d->databaseUtility->lastError().text());
}
- }
-}
-
-void CallRouter::callViaCallingCard(){
- //Now call the calling card number. This is generally a local and/or tollfree number
+ else if (d->currentProfile->profileID == 0){
+ bool routeOnDefault = d->gconfUtility->getGconfValueBoolean("route_on_default");
+ if (routeOnDefault){
+ qDebug() << "Routing directly as per configuration";
+ this->placeCall(strDestinationNumber);
+ }
+ else{
+ qDebug() << "No profile found. Stopping..";
+ strErrorMessage = "VICaR: No routing profile defined for this number.";
+ d->dbusUtility->displayNotification(strErrorMessage );
+ }
+ }
+ else{
+ //Now call the calling card number. This is generally a local and/or tollfree number
+ QString strCallingCardNumber = d->currentProfile->gatewayNumber;
+ qDebug() << "Initiating call to "<< strCallingCardNumber;
+ bool status = this->placeCall(strCallingCardNumber);
+ d->strLastDialedNumber = strDestinationNumber;
- QString strCallingCardNumber = gconfUtility->getGconfValueString("calling_card_number");
+ QString strUserMessage;
- qDebug() << "Wait time elapsed. Initiating call to "<< strCallingCardNumber;
+ if (status){
+ qDebug() << "Call initiated successfully. Connecting DBus slot for audio connection monitor";
+ startCallStatusMonitors();
+ }
+ else {
+ strUserMessage = QString("Unable to initiate new call to ").append(strCallingCardNumber);
+ strErrorMessage = d->dbusUtility->getErrorMessage();
+ qDebug() << strErrorMessage;
+ d->strLastDialedNumber.clear();
+ delete d->currentProfile;
+ d->currentProfile = 0;
+ }
+ d->dbusUtility->displayNotification(strUserMessage);
+ }
- QList<QVariant> argsToSend;
- argsToSend.append(strCallingCardNumber);
- argsToSend.append(0);
+ d->databaseUtility->closeDatabase();
+ return strErrorMessage;
+}
- bool status = dbusUtility.sendMethodCall(CSD_SERVICE,
- CSD_CALL_PATH,
- CSD_CALL_INTERFACE,
- QString("CreateWith"),argsToSend);
+bool CallRouter::placeCall(QString number){
- QString strUserMessage;
- if (status){
- qDebug() << "Call initiated successfully. Connecting DBus slot for audio connection monitor";
- startCallStatusMonitors();
- }
- else {
- strUserMessage = QString("Unable to initiate new call to ").append(strCallingCardNumber);
- qDebug() << dbusUtility.getErrorMessage();
- strLastDialedNumber.clear();
- }
+ QList<QVariant> argsToSend;
+ argsToSend.append(number);
+ argsToSend.append(0);
- dbusUtility.displayNotification(strUserMessage);
+ bool status = d->dbusUtility->sendMethodCall(CSD_SERVICE,
+ CSD_CALL_PATH,
+ CSD_CALL_INTERFACE,
+ QString("CreateWith"),argsToSend);
+ return status;
}
We need this to confirm whether a call went though successfully.
*/
- QDBusConnection connection = dbusUtility.getConnection();
+ QDBusConnection connection = d->dbusUtility->getConnection();
bool success = connection.connect(QString(""),
CSD_CALL_INSTANCE_PATH,
}
else{
qDebug() << "Failed to connect to Dbus signal AudioConnect in interface "<< CSD_CALL_INSTANCE_INTERFACE;
- qDebug() <<"DBus Error: "<< dbusUtility.getErrorMessage();
+ qDebug() <<"DBus Error: "<< d->dbusUtility->getErrorMessage();
}
/* Declare the slot to be executed when the call is terminated (due to connection errors etc).
}
else{
qDebug() << "Failed to connect to Dbus signal Terminated in interface "<< CSD_CALL_INSTANCE_INTERFACE;
- qDebug() <<"DBus Error: "<< dbusUtility.getErrorMessage();
+ qDebug() <<"DBus Error: "<< d->dbusUtility->getErrorMessage();
}
/* Declare the slot to be executed when a call is received
}
else{
qDebug() << "Failed to connect to Dbus signal Coming in interface" << CSD_CALL_INTERFACE;
- qDebug() <<"DBus Error: "<< dbusUtility.getErrorMessage();
+ qDebug() <<"DBus Error: "<< d->dbusUtility->getErrorMessage();
}
}
void CallRouter::stopCallStatusMonitors(){
- strLastDialedNumber.clear();
+ d->strLastDialedNumber.clear();
+ delete d->currentProfile;
+ d->currentProfile = 0;
- QDBusConnection connection = dbusUtility.getConnection();
+ QDBusConnection connection = d->dbusUtility->getConnection();
// Disconnect the slot for audio connection status
bool status = connection.disconnect(QString(""),
}
else{
qDebug() << "Failed to disconnect from Dbus signal AudioConnect in interface "<< CSD_CALL_INSTANCE_INTERFACE;
- qDebug() <<"DBus Error: "<< dbusUtility.getErrorMessage();
+ qDebug() <<"DBus Error: "<< d->dbusUtility->getErrorMessage();
}
// Disconnect the slot for monitoring terminated calls
}
else{
qDebug() << "Failed to disconnect from Dbus signal Terminated in interface "<< CSD_CALL_INSTANCE_INTERFACE;
- qDebug() <<"DBus Error: "<< dbusUtility.getErrorMessage();
+ qDebug() <<"DBus Error: "<< d->dbusUtility->getErrorMessage();
}
// Disconnect the slot for monitoring incoming calls
}
else{
qDebug() << "Failed to disconnect from Dbus signal Coming in interface" << CSD_CALL_INTERFACE;
- qDebug() <<"DBus Error: "<< dbusUtility.getErrorMessage();
+ qDebug() <<"DBus Error: "<< d->dbusUtility->getErrorMessage();
}
}
void CallRouter::sendNumberAsDTMFCode(const QDBusMessage& dbusMessage){
- if (!strLastDialedNumber.isEmpty()){
+ if (!d->strLastDialedNumber.isEmpty() && d->currentProfile != 0){
//Verify whether we have the last dialed number available
QList<QVariant> listArguments = dbusMessage.arguments();
if (audioConnected){
// Now that the call to Calling card number is successful. We can send the original number as DTMF tones
- QString strDTMFCode = convertToDTMFCode(strLastDialedNumber);
+ QString strDTMFCode = convertToDTMFCode(d->strLastDialedNumber);
qDebug() << "Audio connection established. Sending DTMF code "<< strDTMFCode;
QList<QVariant> argsToSend;
argsToSend.append(strDTMFCode);
- bool status = dbusUtility.sendMethodCall(CSD_SERVICE,
+ bool status = d->dbusUtility->sendMethodCall(CSD_SERVICE,
CSD_CALL_PATH,
CSD_CALL_INTERFACE,
QString("SendDTMF"),argsToSend);
if (status){
QString strMessage = strDTMFCode.append(" sent as DTMF code");
qDebug() << strMessage;
- dbusUtility.displayNotification(strMessage);
+ d->dbusUtility->displayNotification(strMessage);
}
else{
qDebug() << "Unable to send DTMF code.";
qDebug() << "Now disconnecting from call status monitors..";
stopCallStatusMonitors();
+ d->strLastDialedNumber.clear();
+ delete d->currentProfile;
+ d->currentProfile = 0;
}
else{
qDebug() << "Audio not yet connected.";
QString strDTMFCode;
if (!strNumber.isEmpty()){
+ int intDTMFDelay = 1;
- //Get the format required by calling card from coniguration
- QString qstrDTMFFormat = gconfUtility->getGconfValueString("dtmf_format");
- int intDTMFDelay = gconfUtility->getGconfValueInteger("dtmf_delay");
+ //Add the prefix p so that there is some delay after the call is picked up by the automated system to send DTMF tones.
+ strDTMFCode = QString("").fill('p',intDTMFDelay);
- if (intDTMFDelay <1 ) intDTMFDelay = 1;
- if (qstrDTMFFormat.isEmpty()) qstrDTMFFormat = "<Country Code><Area Code><Phone Number>";
+ //Now check whether we need a prefix
+ QString strDTMFPrefix = d->currentProfile->dtmfPrefix;
- //Add the prefix p so that there is some delay after the call is picked up by the automated system to send DTMF tones.
- strDTMFCode = QString("").fill('p',intDTMFDelay);
+ if (!strDTMFPrefix.isEmpty()){
+ strDTMFCode = strDTMFCode.append(strDTMFPrefix);
+ }
+
+ //Get the format required by calling card from coniguration
+ QString qstrDTMFFormat = d->currentProfile->dtmfFormat;
+ if (qstrDTMFFormat.isEmpty()) qstrDTMFFormat = "<Country Code><Area Code><Phone Number>";
/* Replace 00 (international dialing code) at the beginning
and also replace any character other than the numbers 0-9 and p.
else if (qstrDTMFFormat.startsWith("011")){
strDTMFCode = strDTMFCode.append("011");
}
- //Default case - we don't need any prefix
strDTMFCode = strDTMFCode.append(strNumber);
//Now check whether we need a suffix
- QString strDTMFSuffix = gconfUtility->getGconfValueString("dtmf_suffix");
- if (!strDTMFSuffix.isEmpty() && !strDTMFSuffix.contains("--None--")){
+ QString strDTMFSuffix = d->currentProfile->dtmfSuffix;
+ if (!strDTMFSuffix.isEmpty()){
strDTMFCode = strDTMFCode.append(strDTMFSuffix);
}
}
return strDTMFCode;
}
-bool CallRouter::isExcludedNumber(QString strInternationalNumber){
+//DBus Method used by external applications to check whether VICaR is enabled and running
+bool CallRouter::isRunning(){
- bool isExcluded = false;
+ return true;
- //Get the list of excluded codes
- QString qstrExcludedNumbers = gconfUtility->getGconfValueString("numbers_to_exclude");
- QStringList strExcludedCodeList = qstrExcludedNumbers.split(",");
- QStringListIterator iterator(strExcludedCodeList);
+ //Verify Whether VICaR telepathy account is online
+ /*
+ if (d->tpUtility->getAccountStatus() == "Connected"){
+ return true;
+ }
+ else{
+ return false;
+ }
+ */
+}
- QRegExp regexp = QRegExp("(^0{2})|[^0-9p]");
+//DBus Method used by external applications to call via VICaR
+QString CallRouter::callInternationalNumber(const QString& strDestinationNumber){
- while (iterator.hasNext()){
- QString strCode = iterator.next();
- strCode = strCode.replace(regexp,"");
- strInternationalNumber = strInternationalNumber.replace(regexp,"");
- if (!strCode.isEmpty() && strInternationalNumber.startsWith(strCode)){
- isExcluded = true;
- }
+ qDebug() << "New call requested by external application. Destination number is " << strDestinationNumber;
+ QString strErrorMessage = this->callViaCallingCard(strDestinationNumber);
+ qDebug() << strErrorMessage;
+
+ if (strErrorMessage.isEmpty()){
+ return QString("Success");
}
- return isExcluded;
-}
+ else{
+ return strErrorMessage;
+ }
+ }