+++ /dev/null
-/*
-@version: 0.6
-@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 <QDBusMessage>
-#include <QStringListIterator>
-
-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;
- QString strLastDTMFCode;
- org::maemo::vicar::Profile *currentProfile;
- CallRouter * const parent;
-};
-
-// ---------------------------------------------------------------------------
-
-CallRouter::CallRouter(QObject *parent) :
- QObject(parent),
- d(new CallRouterPrivate(this))
-{
- Q_ASSERT(0 != d);
- this->registerDBusService();
- qDebug() << "Vicar-Daemon: Registered DBus Service " << APPLICATION_DBUS_SERVICE;
-}
-
-CallRouter::~CallRouter(){
-}
-
-void CallRouter::registerDBusService(){
- //Connect to Session Bus
- QDBusConnection connection = d->dbusUtility->getConnection(false);
-
- if (!connection.interface()->isServiceRegistered(APPLICATION_DBUS_SERVICE)){
-
- if (!connection.registerService(APPLICATION_DBUS_SERVICE)) {
- qDebug() << "Vicar-Daemon: " << d->dbusUtility->getErrorMessage();
- exit(1);
- }
- }
-
- if (!connection.registerObject(APPLICATION_DBUS_PATH, this, QDBusConnection::ExportAdaptors)) {
- qDebug() << "Vicar-Daemon: " << d->dbusUtility->getErrorMessage();
- exit(2);
- }
-
-}
-
-
-void CallRouter::unregisterDBusService(){
-
- //Disconnect from Session bus
- QDBusConnection connection = d->dbusUtility->getConnection(false);
-
- connection.unregisterObject(APPLICATION_DBUS_PATH,QDBusConnection::UnregisterTree);
-
- if (!connection.unregisterService(APPLICATION_DBUS_SERVICE)) {
- qDebug() << "Vicar-Daemon: " << d->dbusUtility->getErrorMessage();
- exit(3);
- }
-
-}
-
-QString CallRouter::callViaCallingCard(QString strDestinationNumber){
-
- d->currentProfile = new org::maemo::vicar::Profile();
- d->currentProfile->profileID = 0;
-
- d->databaseUtility->openDatabase();
- bool result = d->databaseUtility->findProfileByNumber(strDestinationNumber,d->currentProfile);
-
- QString strErrorMessage;
- if (!result){
- strErrorMessage = QString("Vicar-Daemon: Error finding VICaR profile. %1").arg(d->databaseUtility->lastError().text());
- }
- else if (d->currentProfile->profileID == 0){
- bool routeOnDefault = d->gconfUtility->getGconfValueBoolean("route_on_default");
- if (routeOnDefault){
- qDebug() << "Vicar-Daemon: Routing directly as per configuration";
- this->placeCall(strDestinationNumber);
- }
- else{
- qDebug() << "Vicar-Daemon: 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() << "Vicar-Daemon: Initiating call to "<< strCallingCardNumber;
- bool status = this->placeCall(strCallingCardNumber);
- d->strLastDialedNumber = strDestinationNumber;
-
- QString strUserMessage;
-
- if (status){
- qDebug() << "Vicar-Daemon: 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() << "Vicar-Daemon: " << strErrorMessage;
- d->strLastDialedNumber.clear();
- delete d->currentProfile;
- d->currentProfile = 0;
- }
- d->dbusUtility->displayNotification(strUserMessage);
- }
-
- d->databaseUtility->closeDatabase();
- return strErrorMessage;
-}
-
-bool CallRouter::placeCall(QString number){
-
- QList<QVariant> argsToSend;
- argsToSend.append(number);
- argsToSend.append(0);
-
- bool status = d->dbusUtility->sendMethodCall(CSD_SERVICE,
- CSD_CALL_PATH,
- CSD_CALL_INTERFACE,
- QString("CreateWith"),argsToSend);
- return status;
-
-}
-
-void CallRouter::startCallStatusMonitors(){
- /* Declare the slot to be executed when a call is picked up by other party (Audio connection established).
- We need this to confirm whether a call went though successfully.
- */
-
- QDBusConnection connection = d->dbusUtility->getConnection();
-
- bool success = connection.connect(QString(""),
- CSD_CALL_INSTANCE_PATH,
- CSD_CALL_INSTANCE_INTERFACE,
- QString("AudioConnect"),this,
- SLOT(sendNumberAsDTMFCode(const QDBusMessage&)));
-
- if (success){
- qDebug() << "Vicar-Daemon: Successfully connected to Dbus signal AudioConnect in interface "<< CSD_CALL_INSTANCE_INTERFACE;
- }
- else{
- qDebug() << "Vicar-Daemon: Failed to connect to Dbus signal AudioConnect in interface "<< CSD_CALL_INSTANCE_INTERFACE;
- qDebug() <<"Vicar-Daemon: DBus Error: "<< d->dbusUtility->getErrorMessage();
- }
-
-
- /* Declare the slot to be executed when the DTMF code is sent.
- */
-
- success = connection.connect(QString(""),
- CSD_CALL_INSTANCE_PATH,
- CSD_CALL_INSTANCE_INTERFACE,
- QString("StoppedDTMF"),this,
- SLOT(displayDTMFConfirmation()));
-
- if (success){
- qDebug() << "Vicar-Daemon: Successfully connected to Dbus signal StoppedDTMF in interface "<< CSD_CALL_INSTANCE_INTERFACE;
- }
- else{
- qDebug() << "Vicar-Daemon: Failed to connect to Dbus signal StoppedDTMF in interface "<< CSD_CALL_INSTANCE_INTERFACE;
- qDebug() <<"Vicar-Daemon: DBus Error: "<< d->dbusUtility->getErrorMessage();
- }
-
-
- /* Declare the slot to be executed when the call is terminated (due to connection errors etc).
- We need this to avoid sending DTMF code on wrong calls.
- */
-
- success = connection.connect(QString(""),
- CSD_CALL_INSTANCE_PATH,
- CSD_CALL_INSTANCE_INTERFACE,
- QString("Terminated"),this,
- SLOT(stopCallStatusMonitors()));
-
- if (success){
- qDebug() << "Vicar-Daemon: Successfully connected to Dbus signal Terminated in interface "<< CSD_CALL_INSTANCE_INTERFACE;
- }
- else{
- qDebug() << "Vicar-Daemon: Failed to connect to Dbus signal Terminated in interface "<< CSD_CALL_INSTANCE_INTERFACE;
- qDebug() <<"Vicar-Daemon: DBus Error: "<< d->dbusUtility->getErrorMessage();
- }
-
- /* Declare the slot to be executed when a call is received
- (before we can place the call to calling card number).
- It is extremely rare that somebody should get a call within these few seconds.
- In any case, we need this to avoid sending DTMF code on the received call.
-
- Btw - I don't care for the incoming number here. If anyone is calling the user before we can send DTMF code,
- then we stop sending the DTMF code even if user does not respond to the call.
- */
-
- success = connection.connect(QString(""),
- CSD_CALL_PATH,
- CSD_CALL_INTERFACE,
- QString("Coming"),this,
- SLOT(stopCallStatusMonitors()));
-
- if (success){
- qDebug() << "Vicar-Daemon: Successfully connected to Dbus signal Coming in interface" << CSD_CALL_INTERFACE;
- }
- else{
- qDebug() << "Vicar-Daemon: Failed to connect to Dbus signal Coming in interface" << CSD_CALL_INTERFACE;
- qDebug() <<"Vicar-Daemon: DBus Error: "<< d->dbusUtility->getErrorMessage();
- }
-}
-
-void CallRouter::stopCallStatusMonitors(){
-
- d->strLastDTMFCode.clear();
- d->strLastDialedNumber.clear();
- delete d->currentProfile;
- d->currentProfile = 0;
-
- QDBusConnection connection = d->dbusUtility->getConnection();
-
- // Disconnect the slot for audio connection status
- bool status = connection.disconnect(QString(""),
- CSD_CALL_INSTANCE_PATH,
- CSD_CALL_INSTANCE_INTERFACE,
- QString("AudioConnect"),this,
- SLOT(sendNumberAsDTMFCode(const QDBusMessage&)));
-
- if (status){
- qDebug() << "Vicar-Daemon: Successfully disconnected from Dbus signal AudioConnect in interface "<< CSD_CALL_INSTANCE_INTERFACE;
- }
- else{
- qDebug() << "Vicar-Daemon: Failed to disconnect from Dbus signal AudioConnect in interface "<< CSD_CALL_INSTANCE_INTERFACE;
- qDebug() <<"Vicar-Daemon: DBus Error: "<< d->dbusUtility->getErrorMessage();
- }
-
- // Disconnect the slot for monitoring DTMF completion
- status = connection.disconnect(QString(""),
- CSD_CALL_INSTANCE_PATH,
- CSD_CALL_INSTANCE_INTERFACE,
- QString("StoppedDTMF"),this,
- SLOT(displayDTMFConfirmation()));
-
- if (status){
- qDebug() << "Vicar-Daemon: Successfully disconnected from Dbus signal StoppedDTMF in interface "<< CSD_CALL_INSTANCE_INTERFACE;
- }
- else{
- qDebug() << "Vicar-Daemon: Failed to disconnect from Dbus signal StoppedDTMF in interface "<< CSD_CALL_INSTANCE_INTERFACE;
- qDebug() <<"Vicar-Daemon: DBus Error: "<< d->dbusUtility->getErrorMessage();
- }
-
-
- // Disconnect the slot for monitoring terminated calls
- status = connection.disconnect(QString(""),
- CSD_CALL_INSTANCE_PATH,
- CSD_CALL_INSTANCE_INTERFACE,
- QString("Terminated"),this,
- SLOT(stopCallStatusMonitors()));
-
- if (status){
- qDebug() << "Vicar-Daemon: Successfully disconnected from Dbus signal Terminated in interface "<< CSD_CALL_INSTANCE_INTERFACE;
- }
- else{
- qDebug() << "Vicar-Daemon: Failed to disconnect from Dbus signal Terminated in interface "<< CSD_CALL_INSTANCE_INTERFACE;
- qDebug() <<"Vicar-Daemon: DBus Error: "<< d->dbusUtility->getErrorMessage();
- }
-
- // Disconnect the slot for monitoring incoming calls
- status = connection.disconnect(QString(""),
- CSD_CALL_PATH,
- CSD_CALL_INTERFACE,
- QString("Coming"),this,
- SLOT(stopCallStatusMonitors()));
-
- if (status){
- qDebug() << "Vicar-Daemon: Successfully disconnected from Dbus signal Coming in interface" << CSD_CALL_INTERFACE;
- }
- else{
- qDebug() << "Vicar-Daemon: Failed to disconnect from Dbus signal Coming in interface" << CSD_CALL_INTERFACE;
- qDebug() <<"Vicar-Daemon: DBus Error: "<< d->dbusUtility->getErrorMessage();
- }
-}
-
-void CallRouter::sendNumberAsDTMFCode(const QDBusMessage& dbusMessage){
-
- if (!d->strLastDialedNumber.isEmpty() && d->currentProfile != 0){
- //Verify whether we have the last dialed number available
-
- QList<QVariant> listArguments = dbusMessage.arguments();
- bool audioConnected = listArguments.first().toBool();
-
- if (audioConnected){
- // Now that the call to Calling card number is successful. We can send the original number as DTMF tones
- QString strDTMFCode = convertToDTMFCode(d->strLastDialedNumber);
-
- qDebug() << "Vicar-Daemon: Audio connection established. Sending DTMF code "<< strDTMFCode;
-
-
- QList<QVariant> argsToSend;
- argsToSend.append(strDTMFCode);
- bool status = d->dbusUtility->sendMethodCall(CSD_SERVICE,
- CSD_CALL_PATH,
- CSD_CALL_INTERFACE,
- QString("SendDTMF"),argsToSend);
-
- if (status){
- qDebug() << "Vicar-Daemon: Sending " << strDTMFCode << " as DTMF code.";
- d->strLastDTMFCode = strDTMFCode;
- }
- else{
- qDebug() << "Vicar-Daemon: Unable to send DTMF code.";
- }
- }
- else{
- qDebug() << "Vicar-Daemon: Audio not yet connected.";
- }
- }
- else
- {
- qDebug() << "Vicar-Daemon: Last dialed number is empty.";
- }
-}
-
-void CallRouter::displayDTMFConfirmation(){
- //This slot is called when the all the DTMF tones are sent (i.e StoppedDTMF signal is emitted)
- //Just display confirmation message and cleanup
-
-
- if (!d->strLastDTMFCode.isEmpty()){
- QString strMessage = d->strLastDTMFCode.append(" sent as DTMF code");
- d->dbusUtility->displayNotification(strMessage);
- qDebug() << "Vicar-Daemon: "<< d->strLastDTMFCode << " sent as DTMF code.";
- }
-
- /*
- Connecting and Disconnecting from/to DBus signal for each international call
- may not be the most efficient way of handling this. But we need to make sure
- that the DTMF codes are sent only for the calls placed by this app (i.e calls to Calling card number).
- */
-
- qDebug() << "Vicar-Daemon: Now disconnecting from call status monitors..";
- stopCallStatusMonitors();
-}
-
-QString CallRouter::convertToDTMFCode(QString strNumber){
- QString strDTMFCode;
-
- if (!strNumber.isEmpty()){
- //int intDTMFDelay = 1;
-
- //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);
- strDTMFCode = "";
-
- //Now check whether we need a prefix
- QString strDTMFPrefix = d->currentProfile->dtmfPrefix;
-
- 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.
- */
- QRegExp regexp = QRegExp("(^0{2})|[^0-9p]");
- strNumber = strNumber.replace(regexp,"");
-
- /* Now we have a clean number with only country code, area code and phone number,
- lets convert it to the calling card friendly format
- */
- if (qstrDTMFFormat.startsWith("+")){
- strDTMFCode = strDTMFCode.append("+");
- }
- else if (qstrDTMFFormat.startsWith("00")){
- strDTMFCode = strDTMFCode.append("00");
- }
- else if (qstrDTMFFormat.startsWith("011")){
- strDTMFCode = strDTMFCode.append("011");
- }
-
- strDTMFCode = strDTMFCode.append(strNumber);
-
- //Now check whether we need a suffix
- QString strDTMFSuffix = d->currentProfile->dtmfSuffix;
- if (!strDTMFSuffix.isEmpty()){
- strDTMFCode = strDTMFCode.append(strDTMFSuffix);
- }
- }
-
- return strDTMFCode;
-}
-
-//DBus Method used by external applications to check whether VICaR is enabled and running
-bool CallRouter::isRunning(){
-
- return true;
-
- //Verify Whether VICaR telepathy account is online
- /*
- if (d->tpUtility->getAccountStatus() == "Connected"){
- return true;
- }
- else{
- return false;
- }
- */
-}
-
-//DBus Method used by external applications to call via VICaR
-QString CallRouter::callInternationalNumber(const QString& strDestinationNumber){
-
- QString strErrorMessage;
-
- qDebug() << "Vicar-Daemon: New call requested by external application. Destination number is " << strDestinationNumber;
-
- if (isValidPhoneNumber(strDestinationNumber)){
-
- //Remove spaces in the phone number before using
- QString numberWithoutSpaces = QString(strDestinationNumber).remove(" ");
-
- strErrorMessage = this->callViaCallingCard(numberWithoutSpaces);
- }
- else{
- strErrorMessage = QString("Vicar-Daemon: %1 is not a valid number").arg(strDestinationNumber);
- if (strDestinationNumber != "publish" && strDestinationNumber != "subscribe"){
- d->dbusUtility->displayNotification(QString("Vicar: %1 is not a valid number").arg(strDestinationNumber));
- }
- }
-
- qDebug() << strErrorMessage;
-
- if (strErrorMessage.isEmpty()){
- return QString("Success");
- }
- else{
- return strErrorMessage;
- }
- }
-
-//Check whether a string is valid phone number
-bool CallRouter::isValidPhoneNumber(QString strPhoneNumber){
-
-/* Remove all dialble characters and space. The resulting string should be a valid number */
- QRegExp regexp = QRegExp("[p+*# ]");
-
- strPhoneNumber = strPhoneNumber.replace(regexp,"");
-
- qDebug() << "Vicar Daemon: Cleaned up phone number is " << strPhoneNumber;
-
-/* Now remove all digits, the resulting string should be empty, then it is a valid number */
- regexp = QRegExp("[0-9]");
-
- strPhoneNumber = strPhoneNumber.replace(regexp,"");
-
- bool isNumber = strPhoneNumber.isEmpty();
- return isNumber;
-}