--- /dev/null
+vicar (0.2-1) unstable; urgency=low
+
+ * Fixed a bug that does not allow Country Codes to Exclude to be blank
+ * Save button now displays a success notification
+ * Settings will be automatically saved on close
+ * Save and Reset buttons moved to Hildon application menu
+ * Calling Card Number and Country Codes to Exclude fields accept numbers by default for hardware keyboard
+ * Merged basic and advanced settings into one screen
+ * Code cleanup
+
+ -- Sudheer K. <scifi.guy@hotmail.com> Sat, 8 May 2010 13:57:08 -0700
+
--- /dev/null
+Source: vicar
+Section: user/network
+Priority: extra
+Maintainer: Sudheer K. <scifi.guy@hotmail.com>
+Build-Depends: debhelper (>= 5), libqt4-dev, libgconf2-dev
+Standards-Version: 3.7.2
+Homepage: vicar.garage.maemo.org
+XSBC-Bugtracker: https://garage.maemo.org/tracker/?atid=5673&group_id=1586
+XB-Maemo-Display-Name: VICaR - Value International Call Router
+
+Package: vicar
+Architecture: any
+Depends: ${shlibs:Depends}
+Description: Automatically routes international GSM calls through a calling card number.
+ * Calling card number and other options can be configured by launching VICaR from applications menu.
+ * Make sure to update all your international numbers to start with the appropriate dialing code and a prefix of + or 00.
+ * To avoid routing local calls through VICaR, add the local country codes to the list of country codes to exclude.
--- /dev/null
+This package was debianized by Sudheer K. <scifi.guy@hotmail.com> on
+Sat, 8 May 2010 13:57:08 -0700.
+
+It was downloaded from https://garage.maemo.org/projects/vicar
+
+Upstream Author: Sudheer K. <scifi.guy@hotmail.com>
+
+Copyright: 2010, Sudheer K.
+
+License:
+
+ This package 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 package 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 package; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+On Debian systems, the complete text of the GNU General
+Public License can be found in `/usr/share/common-licenses/GPL'.
+
+The Debian packaging is (C) 2010, Sudheer K. <scifi.guy@hotmail.com> and
+is licensed under the GPL, see above.
+
+
+# Please also look if there are files or directories which have a
+# different copyright/license attached and list them here.
--- /dev/null
+usr/bin
+usr/sbin
--- /dev/null
+vicar_0.2-1_armel.deb user/network extra
--- /dev/null
+#!/bin/sh
+# postinst script for vicar
+#
+# see: dh_installdeb(1)
+
+set -e
+
+# summary of how this script can be called:
+# * <postinst> `configure' <most-recently-configured-version>
+# * <old-postinst> `abort-upgrade' <new version>
+# * <conflictor's-postinst> `abort-remove' `in-favour' <package>
+# <new-version>
+# * <postinst> `abort-remove'
+# * <deconfigured's-postinst> `abort-deconfigure' `in-favour'
+# <failed-install-package> <version> `removing'
+# <conflicting-package> <version>
+# for details, see http://www.debian.org/doc/debian-policy/ or
+# the debian-policy package
+
+
+case "$1" in
+ configure)
+
+ # Kill any running instances of the daemon (only used on Linux based systems)
+ killall -q vicar-daemon || true
+
+ echo "Sarting VICaR daemon ..."
+ [[ -x /opt/vicar/vicar-daemon ]] && exec /opt/vicar/vicar-daemon& >/dev/null
+ ;;
+
+ abort-upgrade|abort-remove|abort-deconfigure)
+ ;;
+
+ *)
+ echo "postinst called with unknown argument \`$1'" >&2
+ exit 1
+ ;;
+esac
+
+# dh_installdeb will replace this with shell code automatically
+# generated by other debhelper scripts.
+
+#DEBHELPER#
+
+exit 0
+
+
--- /dev/null
+#!/bin/sh
+# postrm script for vicar
+#
+# see: dh_installdeb(1)
+
+set -e
+
+# summary of how this script can be called:
+# * <postrm> `remove'
+# * <postrm> `purge'
+# * <old-postrm> `upgrade' <new-version>
+# * <new-postrm> `failed-upgrade' <old-version>
+# * <new-postrm> `abort-install'
+# * <new-postrm> `abort-install' <old-version>
+# * <new-postrm> `abort-upgrade' <old-version>
+# * <disappearer's-postrm> `disappear' <overwriter>
+# <overwriter-version>
+# for details, see http://www.debian.org/doc/debian-policy/ or
+# the debian-policy package
+
+
+case "$1" in
+ purge)
+ echo "Deleting configuration from GConf ..."
+ gconftool-2 --recursive-unset /apps/Maemo/vicar
+ echo "Removing logs ..."
+ [[ -x /var/log/vicar.log ]] && rm -f /var/log/vicar.log
+ killall -q vicar-daemon || true
+ ;;
+
+ remove|abort-install)
+ echo "Removing unused scripts ..."
+ [[ -x /etc/event.d/launch-vicar ]] && rm -f /etc/event.d/launch-vicar
+ killall -q vicar-daemon || true
+ ;;
+
+ upgrade|failed-upgrade|abort-upgrade|disappear)
+ ;;
+
+ *)
+ echo "postrm called with unknown argument \`$1'" >&2
+ exit 1
+ ;;
+esac
+
+# dh_installdeb will replace this with shell code automatically
+# generated by other debhelper scripts.
+
+#DEBHELPER#
+
+exit 0
+
+
--- /dev/null
+#!/usr/bin/make -f
+# -*- makefile -*-
+# Sample debian/rules that uses debhelper.
+# This file was originally written by Joey Hess and Craig Small.
+# As a special exception, when this file is copied by dh-make into a
+# dh-make output file, you may use that output file without restriction.
+# This special exception was added by Craig Small in version 0.37 of dh-make.
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+
+APPNAME := vicar
+builddir:
+ mkdir -p builddir
+
+builddir/Makefile: builddir
+ cd builddir && /opt/qt4-maemo5/bin/qmake ../$(APPNAME).pro
+
+build: build-stamp
+
+build-stamp: builddir/Makefile
+ dh_testdir
+
+ # Add here commands to compile the package.
+ cd builddir && $(MAKE)
+ #docbook-to-man debian/$(APPNAME).sgml > $(APPNAME).1
+
+ touch $@
+
+clean:
+ dh_testdir
+ dh_testroot
+ rm -f build-stamp
+
+ # Add here commands to clean up after the build process.
+ rm -rf builddir
+
+ dh_clean
+
+install: build
+ dh_testdir
+ dh_testroot
+ dh_clean -k
+ dh_installdirs
+
+ # Add here commands to install the package into debian/arora.
+ cd builddir && $(MAKE) INSTALL_ROOT=$(CURDIR)/debian/$(APPNAME) install
+
+
+# Build architecture-independent files here.
+binary-indep: build install
+# We have nothing to do by default.
+
+# Build architecture-dependent files here.
+binary-arch: build install
+ dh_testdir
+ dh_testroot
+ dh_installdocs
+ dh_installexamples
+ dh_installman
+ dh_link
+ dh_strip
+ dh_compress
+ dh_fixperms
+ dh_installdeb
+ dh_shlibdeps
+ dh_gencontrol
+ dh_md5sums
+ dh_builddeb
+
+binary: binary-indep binary-arch
+.PHONY: build clean binary-indep binary-arch binary install configure
--- /dev/null
+shlibs:Depends=libc6 (>= 2.5.0-1), libgcc1 (>= 1:4.2.1), libgconf2-6 (>= 2.13.5), libglib2.0-0 (>= 2.20.0), libqt4-maemo5-core (>= 4.6.2~git20100212), libqt4-maemo5-dbus (>= 4.6.2~git20100212), libqt4-maemo5-gui (>= 4.6.2~git20100212), libqt4-maemo5-xml (>= 4.6.2~git20100212), libstdc++6 (>= 4.2.1)
--- /dev/null
+description "Starting VICaR daemon to route international calls"
+author "Sudheer K."
+
+start on started hildon-desktop
+stop on starting shutdown
+
+console none
+
+script
+
+ if [ -x "/opt/vicar/vicar-daemon" ]; then
+ exec /opt/vicar/vicar-daemon
+ fi
+
+end script
+
+normal exit 1
--- /dev/null
+# Author: Sudheer K.
+# Service description file
+[D-BUS Service]
+Name=org.maemo.vicar
+Exec=/opt/vicar/vicar-daemon
--- /dev/null
+# Author: Sudheer K.
+[Desktop Entry]
+Encoding=UTF-8
+Version=1.0
+Type=Application
+Name=Vicar
+Exec=/opt/vicar/vicar-config
+Icon=qgn_list_gene_default_app
--- /dev/null
+TEMPLATE = subdirs\r
+CONFIG += ordered\r
+SUBDIRS += vicar-lib\r
+SUBDIRS += vicar-daemon\r
+SUBDIRS += vicar-config\r
+\r
+#MAKE INSTALL\r
+\r
+INSTALLS += desktop service vicar-up\r
+\r
+desktop.path = /usr/share/applications/hildon\r
+desktop.files += data/vicar-config.desktop\r
+\r
+service.path = /usr/share/dbus-1/services\r
+service.files = data/org.maemo.vicar.service\r
+\r
+vicar-up.path = /etc/event.d/\r
+vicar-up.files = data/event.d/launch-vicar\r
--- /dev/null
+/*
+@version: 0.2
+@author: Sudheer K. <scifi.guy@hotmail.com>
+@license: GNU General Public License
+*/
+
+#include "configwindow.h"
+#include "ui_configwindow.h"
+#include "gconfutility.h"
+#include "dbusutility.h"
+#include <QDebug>
+#include <QMessageBox>
+
+ConfigWindow::ConfigWindow(QWidget *parent) :
+ QMainWindow(parent),
+ ui(new Ui::ConfigWindow)
+{
+ ui->setupUi(this);
+ gconfUtility = new GConfUtility();
+ loadValues();
+}
+
+ConfigWindow::~ConfigWindow()
+{
+ delete ui;
+ delete gconfUtility;
+ gconfUtility = 0;
+}
+
+void ConfigWindow::changeEvent(QEvent *e)
+{
+ QMainWindow::changeEvent(e);
+ switch (e->type()) {
+ case QEvent::LanguageChange:
+ ui->retranslateUi(this);
+ break;
+ default:
+ break;
+ }
+}
+
+void ConfigWindow::closeEvent(QCloseEvent *e)
+{
+ if (verifyConfigData()){
+ qDebug() << "Verification successful. Saving data to gconf";
+ saveConfigData();
+ e->accept();
+ }
+ else{
+ e->ignore();
+ }
+}
+
+void ConfigWindow::on_actionSave_triggered()
+{
+ if (verifyConfigData()){
+ qDebug() << "Verification successful. Saving data to gconf";
+ saveConfigData();
+ }
+
+}
+
+void ConfigWindow::on_actionReset_triggered()
+{
+ ui->checkBoxIntlCallRedirEnabled->setChecked(false);
+ ui->lineEditCallingCardNumber->clear();
+ ui->lineEditCountryCodesToExclude->clear();
+ ui->comboBoxDTMFFormat->clear();
+ ui->comboBoxDTMFSuffix->clear();
+ ui->spinBoxDTMFDelay->setValue(1);
+}
+
+void ConfigWindow::loadValues(){
+
+ bool isRoutingEnabled = gconfUtility->getGconfValueBoolean("routing_enabled");
+ QString strCallingCardNumber = gconfUtility->getGconfValueString("calling_card_number");
+ QString strNumbersToExclude = gconfUtility->getGconfValueString("numbers_to_exclude");
+ QString strDTMFFormat = gconfUtility->getGconfValueString("dtmf_format");
+ QString strDTMFSuffix = gconfUtility->getGconfValueString("dtmf_suffix");
+ int intDTMFDelay = gconfUtility->getGconfValueInteger("dtmf_delay");
+
+ ui->checkBoxIntlCallRedirEnabled->setChecked(isRoutingEnabled);
+ ui->lineEditCallingCardNumber->setText(strCallingCardNumber);
+ ui->lineEditCountryCodesToExclude->setText(strNumbersToExclude);
+ int intIndex = ui->comboBoxDTMFFormat->findText(strDTMFFormat);
+ ui->comboBoxDTMFFormat->setCurrentIndex(intIndex);
+ intIndex = ui->comboBoxDTMFSuffix->findText(strDTMFSuffix);
+ ui->comboBoxDTMFSuffix->setCurrentIndex(intIndex);
+ ui->spinBoxDTMFDelay->setValue(intDTMFDelay);
+
+ //Accept numbers only for Calling Card Number field
+ ui->lineEditCallingCardNumber->setValidator(new QRegExpValidator( QRegExp( "^-?\\d\\d*$"), this));
+
+ qDebug() << "Values loaded from GConf";
+
+}
+
+bool ConfigWindow::verifyConfigData(){
+ //Verify whether user-input matches application requirements
+ bool isRoutingEnabled = ui->checkBoxIntlCallRedirEnabled->isChecked();
+ QString strCallingCardNumber = ui->lineEditCallingCardNumber->text();
+ QString strNumbersToExclude = ui->lineEditCountryCodesToExclude->text();
+
+
+ QString strMessage = QString("");
+
+ if (isRoutingEnabled){
+ //Call Routing is checked. Now validate other values
+ if (strCallingCardNumber.isEmpty()){
+ strMessage.append("Enter a calling card number\n");
+ ui->lineEditCallingCardNumber->setFocus();
+ }
+
+ if (strCallingCardNumber.startsWith("+")||strCallingCardNumber.startsWith("00")){
+ strMessage.append("Calling card number must be a local number. \nPlease remove the international dialing code.\n");
+ ui->lineEditCallingCardNumber->setFocus();
+ }
+
+ }
+
+ if (!strMessage.isEmpty()){
+ QMessageBox::warning(this,"Invalid Data",strMessage);
+ return false;
+ }
+ else{
+ return true;
+ }
+}
+
+void ConfigWindow::saveConfigData(){
+
+ bool isRoutingEnabled = ui->checkBoxIntlCallRedirEnabled->isChecked();
+ QString strCallingCardNumber = ui->lineEditCallingCardNumber->text();
+ QString strNumbersToExclude = ui->lineEditCountryCodesToExclude->text();
+
+ QString strDTMFFormat = ui->comboBoxDTMFFormat->currentText();
+ QString strDTMFSuffix = ui->comboBoxDTMFSuffix->currentText();
+ int intDTMFDelay = ui->spinBoxDTMFDelay->value();
+
+
+ gconfUtility->setGconfValueBoolean("routing_enabled",isRoutingEnabled);
+
+ if (!strCallingCardNumber.isEmpty()){
+ gconfUtility->setGconfValueString("calling_card_number",strCallingCardNumber);
+ }
+
+ if (!strNumbersToExclude.isEmpty()){
+ strNumbersToExclude = strNumbersToExclude.remove(" ");
+ strNumbersToExclude = strNumbersToExclude.remove("\t");
+ strNumbersToExclude = strNumbersToExclude.replace("\n",",");
+ }
+
+ gconfUtility->setGconfValueString("numbers_to_exclude",strNumbersToExclude);
+ gconfUtility->setGconfValueInteger("dtmf_delay",intDTMFDelay);
+ gconfUtility->setGconfValueString("dtmf_format",strDTMFFormat);
+ gconfUtility->setGconfValueString("dtmf_suffix",strDTMFSuffix);
+
+ DbusUtility dbusUtility = DbusUtility();
+
+ qDebug() << "Settings updated";
+ dbusUtility.displayNotification("VICaR: Settings Updated.");
+
+ if (isRoutingEnabled){
+ qDebug() << "Enable call routing immediately";
+ dbusUtility.sendSignal(APPLICATION_DBUS_PATH,APPLICATION_DBUS_INTERFACE,"startOutgoingCallMonitor");
+ }
+ else{
+ qDebug() << "Disable call routing immediately";
+ dbusUtility.sendSignal(APPLICATION_DBUS_PATH,APPLICATION_DBUS_INTERFACE,"stopOutgoingCallMonitor");
+ }
+}
+
--- /dev/null
+/*
+@version: 0.2
+@author: Sudheer K. <scifi.guy@hotmail.com>
+@license: GNU General Public License
+*/
+
+#ifndef CONFIGWINDOW_H
+#define CONFIGWINDOW_H
+
+#include <QMainWindow>
+#include <QCloseEvent>
+#include "gconfutility.h"
+
+#define APPLICATION_DBUS_PATH "/org/maemo/vicar"
+#define APPLICATION_DBUS_INTERFACE "org.maemo.vicar"
+
+namespace Ui {
+ class ConfigWindow;
+}
+
+class ConfigWindow : public QMainWindow {
+ Q_OBJECT
+public:
+ ConfigWindow(QWidget *parent = 0);
+ ~ConfigWindow();
+ void loadValues();
+ bool verifyConfigData();
+ void saveConfigData();
+
+protected:
+ void changeEvent(QEvent *e);
+ void closeEvent(QCloseEvent *e);
+
+private:
+ Ui::ConfigWindow *ui;
+ GConfUtility *gconfUtility;
+
+private slots:
+ void on_actionReset_triggered();
+ void on_actionSave_triggered();
+};
+
+#endif // CONFIGWINDOW_H
--- /dev/null
+/*
+@version: 0.2
+@author: Sudheer K. <scifi.guy@hotmail.com>
+@license: GNU General Public License
+*/
+
+#include <QtGui/QApplication>
+#include "configwindow.h"
+int main(int argc, char *argv[])
+{
+
+ QApplication a(argc, argv);
+ ConfigWindow w;
+ w.show();
+ return a.exec();
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ConfigWindow</class>
+ <widget class="QMainWindow" name="ConfigWindow">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>800</width>
+ <height>480</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>VICaR - Settings</string>
+ </property>
+ <widget class="QWidget" name="centralwidget">
+ <widget class="QScrollArea" name="scrollArea">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>9</y>
+ <width>800</width>
+ <height>478</height>
+ </rect>
+ </property>
+ <property name="widgetResizable">
+ <bool>true</bool>
+ </property>
+ <widget class="QWidget" name="scrollAreaWidgetContents">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>798</width>
+ <height>476</height>
+ </rect>
+ </property>
+ <widget class="QGroupBox" name="groupBoxBasic">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>789</width>
+ <height>231</height>
+ </rect>
+ </property>
+ <property name="title">
+ <string>Basic</string>
+ </property>
+ <widget class="QWidget" name="formLayoutWidget">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>20</y>
+ <width>751</width>
+ <height>201</height>
+ </rect>
+ </property>
+ <layout class="QFormLayout" name="formLayoutBasic">
+ <property name="fieldGrowthPolicy">
+ <enum>QFormLayout::AllNonFixedFieldsGrow</enum>
+ </property>
+ <property name="leftMargin">
+ <number>10</number>
+ </property>
+ <item row="0" column="0">
+ <widget class="QLabel" name="labelCallRedirection">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>300</width>
+ <height>25</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>300</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>International Call Routing:</string>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QCheckBox" name="checkBoxIntlCallRedirEnabled">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>175</width>
+ <height>60</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Enabled</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="labelCallingCardNumber">
+ <property name="text">
+ <string>Calling Card Number:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="lineEditCallingCardNumber">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>60</height>
+ </size>
+ </property>
+ <property name="inputMethodHints">
+ <set>Qt::ImhDigitsOnly</set>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="labelCountryCodesToExclude">
+ <property name="text">
+ <string>Country Codes to Exclude:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLineEdit" name="lineEditCountryCodesToExclude">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>60</height>
+ </size>
+ </property>
+ <property name="inputMethodHints">
+ <set>Qt::ImhDigitsOnly</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ <widget class="QGroupBox" name="groupBoxAdvanced">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>240</y>
+ <width>789</width>
+ <height>271</height>
+ </rect>
+ </property>
+ <property name="title">
+ <string>Advanced</string>
+ </property>
+ <widget class="QWidget" name="formLayoutWidget_2">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>30</y>
+ <width>771</width>
+ <height>171</height>
+ </rect>
+ </property>
+ <layout class="QFormLayout" name="formLayoutAdvanced">
+ <property name="sizeConstraint">
+ <enum>QLayout::SetDefaultConstraint</enum>
+ </property>
+ <property name="fieldGrowthPolicy">
+ <enum>QFormLayout::AllNonFixedFieldsGrow</enum>
+ </property>
+ <property name="leftMargin">
+ <number>10</number>
+ </property>
+ <property name="bottomMargin">
+ <number>9</number>
+ </property>
+ <item row="0" column="0">
+ <widget class="QLabel" name="labelDTMFFormat">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>300</width>
+ <height>25</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>300</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Format required for DTMF tone:</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QComboBox" name="comboBoxDTMFFormat">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>50</width>
+ <height>60</height>
+ </size>
+ </property>
+ <item>
+ <property name="text">
+ <string><Country Code><Area Code><Phone Number></string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>+<Country Code><Area Code><Phone Number></string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>00<Country Code><Area Code><Phone Number></string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>011<Country Code><Area Code><Phone Number></string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QSpinBox" name="spinBoxDTMFDelay">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Minimum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>100</width>
+ <height>60</height>
+ </size>
+ </property>
+ <property name="layoutDirection">
+ <enum>Qt::LeftToRight</enum>
+ </property>
+ <property name="minimum">
+ <number>1</number>
+ </property>
+ <property name="maximum">
+ <number>10</number>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="labelDTMFDelay">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>300</width>
+ <height>25</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>300</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Delay before sending DTMF (no of pauses):</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="labelDTMFSuffix">
+ <property name="text">
+ <string>Suffix after DTMF tone</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QComboBox" name="comboBoxDTMFSuffix">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>50</width>
+ <height>0</height>
+ </size>
+ </property>
+ <item>
+ <property name="text">
+ <string>--None--</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>#</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>*</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </widget>
+ </widget>
+ </widget>
+ <widget class="QMenuBar" name="menubar">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>800</width>
+ <height>23</height>
+ </rect>
+ </property>
+ <widget class="QMenu" name="menuVicarConfiguration">
+ <property name="title">
+ <string>VICaR - Configuration</string>
+ </property>
+ <addaction name="actionSave"/>
+ <addaction name="actionReset"/>
+ </widget>
+ <addaction name="menuVicarConfiguration"/>
+ </widget>
+ <action name="actionSave">
+ <property name="text">
+ <string>Save</string>
+ </property>
+ <property name="toolTip">
+ <string>Save Settings</string>
+ </property>
+ <property name="font">
+ <font/>
+ </property>
+ </action>
+ <action name="actionReset">
+ <property name="text">
+ <string>Reset</string>
+ </property>
+ <property name="toolTip">
+ <string>Reset Settings</string>
+ </property>
+ </action>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
--- /dev/null
+/********************************************************************************
+** Form generated from reading UI file 'configwindow.ui'
+**
+** Created: Sun Jun 6 09:52:22 2010
+** by: Qt User Interface Compiler version 4.6.2
+**
+** WARNING! All changes made in this file will be lost when recompiling UI file!
+********************************************************************************/
+
+#ifndef UI_CONFIGWINDOW_H
+#define UI_CONFIGWINDOW_H
+
+#include <QtCore/QVariant>
+#include <QtGui/QAction>
+#include <QtGui/QApplication>
+#include <QtGui/QButtonGroup>
+#include <QtGui/QCheckBox>
+#include <QtGui/QComboBox>
+#include <QtGui/QFormLayout>
+#include <QtGui/QGroupBox>
+#include <QtGui/QHeaderView>
+#include <QtGui/QLabel>
+#include <QtGui/QLineEdit>
+#include <QtGui/QMainWindow>
+#include <QtGui/QMenu>
+#include <QtGui/QMenuBar>
+#include <QtGui/QScrollArea>
+#include <QtGui/QSpinBox>
+#include <QtGui/QWidget>
+
+QT_BEGIN_NAMESPACE
+
+class Ui_ConfigWindow
+{
+public:
+ QAction *actionSave;
+ QAction *actionReset;
+ QWidget *centralwidget;
+ QScrollArea *scrollArea;
+ QWidget *scrollAreaWidgetContents;
+ QGroupBox *groupBoxBasic;
+ QWidget *formLayoutWidget;
+ QFormLayout *formLayoutBasic;
+ QLabel *labelCallRedirection;
+ QCheckBox *checkBoxIntlCallRedirEnabled;
+ QLabel *labelCallingCardNumber;
+ QLineEdit *lineEditCallingCardNumber;
+ QLabel *labelCountryCodesToExclude;
+ QLineEdit *lineEditCountryCodesToExclude;
+ QGroupBox *groupBoxAdvanced;
+ QWidget *formLayoutWidget_2;
+ QFormLayout *formLayoutAdvanced;
+ QLabel *labelDTMFFormat;
+ QComboBox *comboBoxDTMFFormat;
+ QSpinBox *spinBoxDTMFDelay;
+ QLabel *labelDTMFDelay;
+ QLabel *labelDTMFSuffix;
+ QComboBox *comboBoxDTMFSuffix;
+ QMenuBar *menubar;
+ QMenu *menuVicarConfiguration;
+
+ void setupUi(QMainWindow *ConfigWindow)
+ {
+ if (ConfigWindow->objectName().isEmpty())
+ ConfigWindow->setObjectName(QString::fromUtf8("ConfigWindow"));
+ ConfigWindow->resize(800, 480);
+ actionSave = new QAction(ConfigWindow);
+ actionSave->setObjectName(QString::fromUtf8("actionSave"));
+ QFont font;
+ actionSave->setFont(font);
+ actionReset = new QAction(ConfigWindow);
+ actionReset->setObjectName(QString::fromUtf8("actionReset"));
+ centralwidget = new QWidget(ConfigWindow);
+ centralwidget->setObjectName(QString::fromUtf8("centralwidget"));
+ scrollArea = new QScrollArea(centralwidget);
+ scrollArea->setObjectName(QString::fromUtf8("scrollArea"));
+ scrollArea->setGeometry(QRect(0, 9, 800, 478));
+ scrollArea->setWidgetResizable(true);
+ scrollAreaWidgetContents = new QWidget();
+ scrollAreaWidgetContents->setObjectName(QString::fromUtf8("scrollAreaWidgetContents"));
+ scrollAreaWidgetContents->setGeometry(QRect(0, 0, 798, 476));
+ groupBoxBasic = new QGroupBox(scrollAreaWidgetContents);
+ groupBoxBasic->setObjectName(QString::fromUtf8("groupBoxBasic"));
+ groupBoxBasic->setGeometry(QRect(0, 0, 789, 231));
+ formLayoutWidget = new QWidget(groupBoxBasic);
+ formLayoutWidget->setObjectName(QString::fromUtf8("formLayoutWidget"));
+ formLayoutWidget->setGeometry(QRect(10, 20, 751, 201));
+ formLayoutBasic = new QFormLayout(formLayoutWidget);
+ formLayoutBasic->setObjectName(QString::fromUtf8("formLayoutBasic"));
+ formLayoutBasic->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow);
+ formLayoutBasic->setContentsMargins(10, 0, 0, 0);
+ labelCallRedirection = new QLabel(formLayoutWidget);
+ labelCallRedirection->setObjectName(QString::fromUtf8("labelCallRedirection"));
+ QSizePolicy sizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);
+ sizePolicy.setHorizontalStretch(0);
+ sizePolicy.setVerticalStretch(0);
+ sizePolicy.setHeightForWidth(labelCallRedirection->sizePolicy().hasHeightForWidth());
+ labelCallRedirection->setSizePolicy(sizePolicy);
+ labelCallRedirection->setMinimumSize(QSize(300, 25));
+ labelCallRedirection->setMaximumSize(QSize(300, 16777215));
+ labelCallRedirection->setMargin(0);
+
+ formLayoutBasic->setWidget(0, QFormLayout::LabelRole, labelCallRedirection);
+
+ checkBoxIntlCallRedirEnabled = new QCheckBox(formLayoutWidget);
+ checkBoxIntlCallRedirEnabled->setObjectName(QString::fromUtf8("checkBoxIntlCallRedirEnabled"));
+ QSizePolicy sizePolicy1(QSizePolicy::Fixed, QSizePolicy::Fixed);
+ sizePolicy1.setHorizontalStretch(0);
+ sizePolicy1.setVerticalStretch(0);
+ sizePolicy1.setHeightForWidth(checkBoxIntlCallRedirEnabled->sizePolicy().hasHeightForWidth());
+ checkBoxIntlCallRedirEnabled->setSizePolicy(sizePolicy1);
+ checkBoxIntlCallRedirEnabled->setMinimumSize(QSize(175, 60));
+
+ formLayoutBasic->setWidget(0, QFormLayout::FieldRole, checkBoxIntlCallRedirEnabled);
+
+ labelCallingCardNumber = new QLabel(formLayoutWidget);
+ labelCallingCardNumber->setObjectName(QString::fromUtf8("labelCallingCardNumber"));
+
+ formLayoutBasic->setWidget(1, QFormLayout::LabelRole, labelCallingCardNumber);
+
+ lineEditCallingCardNumber = new QLineEdit(formLayoutWidget);
+ lineEditCallingCardNumber->setObjectName(QString::fromUtf8("lineEditCallingCardNumber"));
+ QSizePolicy sizePolicy2(QSizePolicy::Expanding, QSizePolicy::Fixed);
+ sizePolicy2.setHorizontalStretch(0);
+ sizePolicy2.setVerticalStretch(0);
+ sizePolicy2.setHeightForWidth(lineEditCallingCardNumber->sizePolicy().hasHeightForWidth());
+ lineEditCallingCardNumber->setSizePolicy(sizePolicy2);
+ lineEditCallingCardNumber->setMinimumSize(QSize(0, 60));
+ lineEditCallingCardNumber->setInputMethodHints(Qt::ImhDigitsOnly);
+
+ formLayoutBasic->setWidget(1, QFormLayout::FieldRole, lineEditCallingCardNumber);
+
+ labelCountryCodesToExclude = new QLabel(formLayoutWidget);
+ labelCountryCodesToExclude->setObjectName(QString::fromUtf8("labelCountryCodesToExclude"));
+
+ formLayoutBasic->setWidget(2, QFormLayout::LabelRole, labelCountryCodesToExclude);
+
+ lineEditCountryCodesToExclude = new QLineEdit(formLayoutWidget);
+ lineEditCountryCodesToExclude->setObjectName(QString::fromUtf8("lineEditCountryCodesToExclude"));
+ sizePolicy2.setHeightForWidth(lineEditCountryCodesToExclude->sizePolicy().hasHeightForWidth());
+ lineEditCountryCodesToExclude->setSizePolicy(sizePolicy2);
+ lineEditCountryCodesToExclude->setMinimumSize(QSize(0, 60));
+ lineEditCountryCodesToExclude->setInputMethodHints(Qt::ImhDigitsOnly);
+
+ formLayoutBasic->setWidget(2, QFormLayout::FieldRole, lineEditCountryCodesToExclude);
+
+ groupBoxAdvanced = new QGroupBox(scrollAreaWidgetContents);
+ groupBoxAdvanced->setObjectName(QString::fromUtf8("groupBoxAdvanced"));
+ groupBoxAdvanced->setGeometry(QRect(0, 240, 789, 271));
+ formLayoutWidget_2 = new QWidget(groupBoxAdvanced);
+ formLayoutWidget_2->setObjectName(QString::fromUtf8("formLayoutWidget_2"));
+ formLayoutWidget_2->setGeometry(QRect(10, 30, 771, 171));
+ formLayoutAdvanced = new QFormLayout(formLayoutWidget_2);
+ formLayoutAdvanced->setObjectName(QString::fromUtf8("formLayoutAdvanced"));
+ formLayoutAdvanced->setSizeConstraint(QLayout::SetDefaultConstraint);
+ formLayoutAdvanced->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow);
+ formLayoutAdvanced->setContentsMargins(10, 0, 0, 9);
+ labelDTMFFormat = new QLabel(formLayoutWidget_2);
+ labelDTMFFormat->setObjectName(QString::fromUtf8("labelDTMFFormat"));
+ sizePolicy.setHeightForWidth(labelDTMFFormat->sizePolicy().hasHeightForWidth());
+ labelDTMFFormat->setSizePolicy(sizePolicy);
+ labelDTMFFormat->setMinimumSize(QSize(300, 25));
+ labelDTMFFormat->setMaximumSize(QSize(300, 16777215));
+ labelDTMFFormat->setWordWrap(true);
+
+ formLayoutAdvanced->setWidget(0, QFormLayout::LabelRole, labelDTMFFormat);
+
+ comboBoxDTMFFormat = new QComboBox(formLayoutWidget_2);
+ comboBoxDTMFFormat->setObjectName(QString::fromUtf8("comboBoxDTMFFormat"));
+ QSizePolicy sizePolicy3(QSizePolicy::Minimum, QSizePolicy::Minimum);
+ sizePolicy3.setHorizontalStretch(0);
+ sizePolicy3.setVerticalStretch(0);
+ sizePolicy3.setHeightForWidth(comboBoxDTMFFormat->sizePolicy().hasHeightForWidth());
+ comboBoxDTMFFormat->setSizePolicy(sizePolicy3);
+ comboBoxDTMFFormat->setMinimumSize(QSize(50, 60));
+
+ formLayoutAdvanced->setWidget(0, QFormLayout::FieldRole, comboBoxDTMFFormat);
+
+ spinBoxDTMFDelay = new QSpinBox(formLayoutWidget_2);
+ spinBoxDTMFDelay->setObjectName(QString::fromUtf8("spinBoxDTMFDelay"));
+ QSizePolicy sizePolicy4(QSizePolicy::Fixed, QSizePolicy::Minimum);
+ sizePolicy4.setHorizontalStretch(0);
+ sizePolicy4.setVerticalStretch(0);
+ sizePolicy4.setHeightForWidth(spinBoxDTMFDelay->sizePolicy().hasHeightForWidth());
+ spinBoxDTMFDelay->setSizePolicy(sizePolicy4);
+ spinBoxDTMFDelay->setMinimumSize(QSize(100, 60));
+ spinBoxDTMFDelay->setLayoutDirection(Qt::LeftToRight);
+ spinBoxDTMFDelay->setMinimum(1);
+ spinBoxDTMFDelay->setMaximum(10);
+
+ formLayoutAdvanced->setWidget(2, QFormLayout::FieldRole, spinBoxDTMFDelay);
+
+ labelDTMFDelay = new QLabel(formLayoutWidget_2);
+ labelDTMFDelay->setObjectName(QString::fromUtf8("labelDTMFDelay"));
+ sizePolicy.setHeightForWidth(labelDTMFDelay->sizePolicy().hasHeightForWidth());
+ labelDTMFDelay->setSizePolicy(sizePolicy);
+ labelDTMFDelay->setMinimumSize(QSize(300, 25));
+ labelDTMFDelay->setMaximumSize(QSize(300, 16777215));
+ labelDTMFDelay->setWordWrap(true);
+
+ formLayoutAdvanced->setWidget(2, QFormLayout::LabelRole, labelDTMFDelay);
+
+ labelDTMFSuffix = new QLabel(formLayoutWidget_2);
+ labelDTMFSuffix->setObjectName(QString::fromUtf8("labelDTMFSuffix"));
+
+ formLayoutAdvanced->setWidget(1, QFormLayout::LabelRole, labelDTMFSuffix);
+
+ comboBoxDTMFSuffix = new QComboBox(formLayoutWidget_2);
+ comboBoxDTMFSuffix->setObjectName(QString::fromUtf8("comboBoxDTMFSuffix"));
+ sizePolicy1.setHeightForWidth(comboBoxDTMFSuffix->sizePolicy().hasHeightForWidth());
+ comboBoxDTMFSuffix->setSizePolicy(sizePolicy1);
+ comboBoxDTMFSuffix->setMinimumSize(QSize(50, 0));
+
+ formLayoutAdvanced->setWidget(1, QFormLayout::FieldRole, comboBoxDTMFSuffix);
+
+ scrollArea->setWidget(scrollAreaWidgetContents);
+ ConfigWindow->setCentralWidget(centralwidget);
+ menubar = new QMenuBar(ConfigWindow);
+ menubar->setObjectName(QString::fromUtf8("menubar"));
+ menubar->setGeometry(QRect(0, 0, 800, 23));
+ menuVicarConfiguration = new QMenu(menubar);
+ menuVicarConfiguration->setObjectName(QString::fromUtf8("menuVicarConfiguration"));
+ ConfigWindow->setMenuBar(menubar);
+
+ menubar->addAction(menuVicarConfiguration->menuAction());
+ menuVicarConfiguration->addAction(actionSave);
+ menuVicarConfiguration->addAction(actionReset);
+
+ retranslateUi(ConfigWindow);
+
+ QMetaObject::connectSlotsByName(ConfigWindow);
+ } // setupUi
+
+ void retranslateUi(QMainWindow *ConfigWindow)
+ {
+ ConfigWindow->setWindowTitle(QApplication::translate("ConfigWindow", "VICaR - Settings", 0, QApplication::UnicodeUTF8));
+ actionSave->setText(QApplication::translate("ConfigWindow", "Save", 0, QApplication::UnicodeUTF8));
+#ifndef QT_NO_TOOLTIP
+ actionSave->setToolTip(QApplication::translate("ConfigWindow", "Save Settings", 0, QApplication::UnicodeUTF8));
+#endif // QT_NO_TOOLTIP
+ actionReset->setText(QApplication::translate("ConfigWindow", "Reset", 0, QApplication::UnicodeUTF8));
+#ifndef QT_NO_TOOLTIP
+ actionReset->setToolTip(QApplication::translate("ConfigWindow", "Reset Settings", 0, QApplication::UnicodeUTF8));
+#endif // QT_NO_TOOLTIP
+ groupBoxBasic->setTitle(QApplication::translate("ConfigWindow", "Basic", 0, QApplication::UnicodeUTF8));
+ labelCallRedirection->setText(QApplication::translate("ConfigWindow", "International Call Routing:", 0, QApplication::UnicodeUTF8));
+ checkBoxIntlCallRedirEnabled->setText(QApplication::translate("ConfigWindow", "Enabled", 0, QApplication::UnicodeUTF8));
+ labelCallingCardNumber->setText(QApplication::translate("ConfigWindow", "Calling Card Number:", 0, QApplication::UnicodeUTF8));
+ labelCountryCodesToExclude->setText(QApplication::translate("ConfigWindow", "Country Codes to Exclude:", 0, QApplication::UnicodeUTF8));
+ groupBoxAdvanced->setTitle(QApplication::translate("ConfigWindow", "Advanced", 0, QApplication::UnicodeUTF8));
+ labelDTMFFormat->setText(QApplication::translate("ConfigWindow", "Format required for DTMF tone:", 0, QApplication::UnicodeUTF8));
+ comboBoxDTMFFormat->clear();
+ comboBoxDTMFFormat->insertItems(0, QStringList()
+ << QApplication::translate("ConfigWindow", "<Country Code><Area Code><Phone Number>", 0, QApplication::UnicodeUTF8)
+ << QApplication::translate("ConfigWindow", "+<Country Code><Area Code><Phone Number>", 0, QApplication::UnicodeUTF8)
+ << QApplication::translate("ConfigWindow", "00<Country Code><Area Code><Phone Number>", 0, QApplication::UnicodeUTF8)
+ << QApplication::translate("ConfigWindow", "011<Country Code><Area Code><Phone Number>", 0, QApplication::UnicodeUTF8)
+ );
+ labelDTMFDelay->setText(QApplication::translate("ConfigWindow", "Delay before sending DTMF (no of pauses):", 0, QApplication::UnicodeUTF8));
+ labelDTMFSuffix->setText(QApplication::translate("ConfigWindow", "Suffix after DTMF tone", 0, QApplication::UnicodeUTF8));
+ comboBoxDTMFSuffix->clear();
+ comboBoxDTMFSuffix->insertItems(0, QStringList()
+ << QApplication::translate("ConfigWindow", "--None--", 0, QApplication::UnicodeUTF8)
+ << QApplication::translate("ConfigWindow", "#", 0, QApplication::UnicodeUTF8)
+ << QApplication::translate("ConfigWindow", "*", 0, QApplication::UnicodeUTF8)
+ );
+ menuVicarConfiguration->setTitle(QApplication::translate("ConfigWindow", "VICaR - Configuration", 0, QApplication::UnicodeUTF8));
+ } // retranslateUi
+
+};
+
+namespace Ui {
+ class ConfigWindow: public Ui_ConfigWindow {};
+} // namespace Ui
+
+QT_END_NAMESPACE
+
+#endif // UI_CONFIGWINDOW_H
--- /dev/null
+/********************************************************************************
+** Form generated from reading UI file 'configwindow.ui'
+**
+** Created: Sun Jun 6 09:41:25 2010
+** by: Qt User Interface Compiler version 4.6.2
+**
+** WARNING! All changes made in this file will be lost when recompiling UI file!
+********************************************************************************/
+
+#ifndef UI_CONFIGWINDOW_H
+#define UI_CONFIGWINDOW_H
+
+#include <QtCore/QVariant>
+#include <QtGui/QAction>
+#include <QtGui/QApplication>
+#include <QtGui/QButtonGroup>
+#include <QtGui/QCheckBox>
+#include <QtGui/QComboBox>
+#include <QtGui/QFormLayout>
+#include <QtGui/QGroupBox>
+#include <QtGui/QHeaderView>
+#include <QtGui/QLabel>
+#include <QtGui/QLineEdit>
+#include <QtGui/QMainWindow>
+#include <QtGui/QMenu>
+#include <QtGui/QMenuBar>
+#include <QtGui/QScrollArea>
+#include <QtGui/QSpinBox>
+#include <QtGui/QWidget>
+
+QT_BEGIN_NAMESPACE
+
+class Ui_ConfigWindow
+{
+public:
+ QAction *actionSave;
+ QAction *actionReset;
+ QWidget *centralwidget;
+ QScrollArea *scrollArea;
+ QWidget *scrollAreaWidgetContents;
+ QGroupBox *groupBoxBasic;
+ QWidget *formLayoutWidget;
+ QFormLayout *formLayoutBasic;
+ QLabel *labelCallRedirection;
+ QCheckBox *checkBoxIntlCallRedirEnabled;
+ QLabel *labelCallingCardNumber;
+ QLineEdit *lineEditCallingCardNumber;
+ QLabel *labelCountryCodesToExclude;
+ QLineEdit *lineEditCountryCodesToExclude;
+ QGroupBox *groupBoxAdvanced;
+ QWidget *formLayoutWidget_2;
+ QFormLayout *formLayoutAdvanced;
+ QLabel *labelDTMFFormat;
+ QComboBox *comboBoxDTMFFormat;
+ QSpinBox *spinBoxDTMFDelay;
+ QLabel *labelDTMFDelay;
+ QLabel *labelDTMFSuffix;
+ QComboBox *comboBoxDTMFSuffix;
+ QMenuBar *menubar;
+ QMenu *menuVicarConfiguration;
+
+ void setupUi(QMainWindow *ConfigWindow)
+ {
+ if (ConfigWindow->objectName().isEmpty())
+ ConfigWindow->setObjectName(QString::fromUtf8("ConfigWindow"));
+ ConfigWindow->resize(800, 480);
+ actionSave = new QAction(ConfigWindow);
+ actionSave->setObjectName(QString::fromUtf8("actionSave"));
+ QFont font;
+ actionSave->setFont(font);
+ actionReset = new QAction(ConfigWindow);
+ actionReset->setObjectName(QString::fromUtf8("actionReset"));
+ centralwidget = new QWidget(ConfigWindow);
+ centralwidget->setObjectName(QString::fromUtf8("centralwidget"));
+ scrollArea = new QScrollArea(centralwidget);
+ scrollArea->setObjectName(QString::fromUtf8("scrollArea"));
+ scrollArea->setGeometry(QRect(0, 20, 800, 470));
+ scrollArea->setWidgetResizable(true);
+ scrollAreaWidgetContents = new QWidget();
+ scrollAreaWidgetContents->setObjectName(QString::fromUtf8("scrollAreaWidgetContents"));
+ scrollAreaWidgetContents->setGeometry(QRect(0, 0, 798, 600));
+ groupBoxBasic = new QGroupBox(scrollAreaWidgetContents);
+ groupBoxBasic->setObjectName(QString::fromUtf8("groupBoxBasic"));
+ groupBoxBasic->setGeometry(QRect(0, 0, 789, 231));
+ formLayoutWidget = new QWidget(groupBoxBasic);
+ formLayoutWidget->setObjectName(QString::fromUtf8("formLayoutWidget"));
+ formLayoutWidget->setGeometry(QRect(10, 20, 751, 201));
+ formLayoutBasic = new QFormLayout(formLayoutWidget);
+ formLayoutBasic->setObjectName(QString::fromUtf8("formLayoutBasic"));
+ formLayoutBasic->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow);
+ formLayoutBasic->setContentsMargins(10, 0, 0, 0);
+ labelCallRedirection = new QLabel(formLayoutWidget);
+ labelCallRedirection->setObjectName(QString::fromUtf8("labelCallRedirection"));
+ QSizePolicy sizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);
+ sizePolicy.setHorizontalStretch(0);
+ sizePolicy.setVerticalStretch(0);
+ sizePolicy.setHeightForWidth(labelCallRedirection->sizePolicy().hasHeightForWidth());
+ labelCallRedirection->setSizePolicy(sizePolicy);
+ labelCallRedirection->setMinimumSize(QSize(300, 25));
+ labelCallRedirection->setMaximumSize(QSize(300, 16777215));
+ labelCallRedirection->setMargin(0);
+
+ formLayoutBasic->setWidget(0, QFormLayout::LabelRole, labelCallRedirection);
+
+ checkBoxIntlCallRedirEnabled = new QCheckBox(formLayoutWidget);
+ checkBoxIntlCallRedirEnabled->setObjectName(QString::fromUtf8("checkBoxIntlCallRedirEnabled"));
+ QSizePolicy sizePolicy1(QSizePolicy::Fixed, QSizePolicy::Fixed);
+ sizePolicy1.setHorizontalStretch(0);
+ sizePolicy1.setVerticalStretch(0);
+ sizePolicy1.setHeightForWidth(checkBoxIntlCallRedirEnabled->sizePolicy().hasHeightForWidth());
+ checkBoxIntlCallRedirEnabled->setSizePolicy(sizePolicy1);
+ checkBoxIntlCallRedirEnabled->setMinimumSize(QSize(175, 60));
+
+ formLayoutBasic->setWidget(0, QFormLayout::FieldRole, checkBoxIntlCallRedirEnabled);
+
+ labelCallingCardNumber = new QLabel(formLayoutWidget);
+ labelCallingCardNumber->setObjectName(QString::fromUtf8("labelCallingCardNumber"));
+
+ formLayoutBasic->setWidget(1, QFormLayout::LabelRole, labelCallingCardNumber);
+
+ lineEditCallingCardNumber = new QLineEdit(formLayoutWidget);
+ lineEditCallingCardNumber->setObjectName(QString::fromUtf8("lineEditCallingCardNumber"));
+ QSizePolicy sizePolicy2(QSizePolicy::Expanding, QSizePolicy::Fixed);
+ sizePolicy2.setHorizontalStretch(0);
+ sizePolicy2.setVerticalStretch(0);
+ sizePolicy2.setHeightForWidth(lineEditCallingCardNumber->sizePolicy().hasHeightForWidth());
+ lineEditCallingCardNumber->setSizePolicy(sizePolicy2);
+ lineEditCallingCardNumber->setMinimumSize(QSize(0, 60));
+ lineEditCallingCardNumber->setInputMethodHints(Qt::ImhDigitsOnly);
+
+ formLayoutBasic->setWidget(1, QFormLayout::FieldRole, lineEditCallingCardNumber);
+
+ labelCountryCodesToExclude = new QLabel(formLayoutWidget);
+ labelCountryCodesToExclude->setObjectName(QString::fromUtf8("labelCountryCodesToExclude"));
+
+ formLayoutBasic->setWidget(2, QFormLayout::LabelRole, labelCountryCodesToExclude);
+
+ lineEditCountryCodesToExclude = new QLineEdit(formLayoutWidget);
+ lineEditCountryCodesToExclude->setObjectName(QString::fromUtf8("lineEditCountryCodesToExclude"));
+ sizePolicy2.setHeightForWidth(lineEditCountryCodesToExclude->sizePolicy().hasHeightForWidth());
+ lineEditCountryCodesToExclude->setSizePolicy(sizePolicy2);
+ lineEditCountryCodesToExclude->setMinimumSize(QSize(0, 60));
+ lineEditCountryCodesToExclude->setInputMethodHints(Qt::ImhDigitsOnly);
+
+ formLayoutBasic->setWidget(2, QFormLayout::FieldRole, lineEditCountryCodesToExclude);
+
+ groupBoxAdvanced = new QGroupBox(scrollAreaWidgetContents);
+ groupBoxAdvanced->setObjectName(QString::fromUtf8("groupBoxAdvanced"));
+ groupBoxAdvanced->setGeometry(QRect(0, 240, 789, 400));
+ formLayoutWidget_2 = new QWidget(groupBoxAdvanced);
+ formLayoutWidget_2->setObjectName(QString::fromUtf8("formLayoutWidget_2"));
+ formLayoutWidget_2->setGeometry(QRect(10, 30, 771, 171));
+ formLayoutAdvanced = new QFormLayout(formLayoutWidget_2);
+ formLayoutAdvanced->setObjectName(QString::fromUtf8("formLayoutAdvanced"));
+ formLayoutAdvanced->setSizeConstraint(QLayout::SetDefaultConstraint);
+ formLayoutAdvanced->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow);
+ formLayoutAdvanced->setContentsMargins(10, 0, 0, 9);
+ labelDTMFFormat = new QLabel(formLayoutWidget_2);
+ labelDTMFFormat->setObjectName(QString::fromUtf8("labelDTMFFormat"));
+ sizePolicy.setHeightForWidth(labelDTMFFormat->sizePolicy().hasHeightForWidth());
+ labelDTMFFormat->setSizePolicy(sizePolicy);
+ labelDTMFFormat->setMinimumSize(QSize(300, 25));
+ labelDTMFFormat->setMaximumSize(QSize(300, 16777215));
+ labelDTMFFormat->setWordWrap(true);
+
+ formLayoutAdvanced->setWidget(0, QFormLayout::LabelRole, labelDTMFFormat);
+
+ comboBoxDTMFFormat = new QComboBox(formLayoutWidget_2);
+ comboBoxDTMFFormat->setObjectName(QString::fromUtf8("comboBoxDTMFFormat"));
+ QSizePolicy sizePolicy3(QSizePolicy::Minimum, QSizePolicy::Minimum);
+ sizePolicy3.setHorizontalStretch(0);
+ sizePolicy3.setVerticalStretch(0);
+ sizePolicy3.setHeightForWidth(comboBoxDTMFFormat->sizePolicy().hasHeightForWidth());
+ comboBoxDTMFFormat->setSizePolicy(sizePolicy3);
+ comboBoxDTMFFormat->setMinimumSize(QSize(50, 60));
+
+ formLayoutAdvanced->setWidget(0, QFormLayout::FieldRole, comboBoxDTMFFormat);
+
+ spinBoxDTMFDelay = new QSpinBox(formLayoutWidget_2);
+ spinBoxDTMFDelay->setObjectName(QString::fromUtf8("spinBoxDTMFDelay"));
+ QSizePolicy sizePolicy4(QSizePolicy::Fixed, QSizePolicy::Minimum);
+ sizePolicy4.setHorizontalStretch(0);
+ sizePolicy4.setVerticalStretch(0);
+ sizePolicy4.setHeightForWidth(spinBoxDTMFDelay->sizePolicy().hasHeightForWidth());
+ spinBoxDTMFDelay->setSizePolicy(sizePolicy4);
+ spinBoxDTMFDelay->setMinimumSize(QSize(100, 60));
+ spinBoxDTMFDelay->setLayoutDirection(Qt::LeftToRight);
+ spinBoxDTMFDelay->setMinimum(1);
+ spinBoxDTMFDelay->setMaximum(10);
+
+ formLayoutAdvanced->setWidget(2, QFormLayout::FieldRole, spinBoxDTMFDelay);
+
+ labelDTMFDelay = new QLabel(formLayoutWidget_2);
+ labelDTMFDelay->setObjectName(QString::fromUtf8("labelDTMFDelay"));
+ sizePolicy.setHeightForWidth(labelDTMFDelay->sizePolicy().hasHeightForWidth());
+ labelDTMFDelay->setSizePolicy(sizePolicy);
+ labelDTMFDelay->setMinimumSize(QSize(300, 25));
+ labelDTMFDelay->setMaximumSize(QSize(300, 16777215));
+ labelDTMFDelay->setWordWrap(true);
+
+ formLayoutAdvanced->setWidget(2, QFormLayout::LabelRole, labelDTMFDelay);
+
+ labelDTMFSuffix = new QLabel(formLayoutWidget_2);
+ labelDTMFSuffix->setObjectName(QString::fromUtf8("labelDTMFSuffix"));
+
+ formLayoutAdvanced->setWidget(1, QFormLayout::LabelRole, labelDTMFSuffix);
+
+ comboBoxDTMFSuffix = new QComboBox(formLayoutWidget_2);
+ comboBoxDTMFSuffix->setObjectName(QString::fromUtf8("comboBoxDTMFSuffix"));
+ sizePolicy1.setHeightForWidth(comboBoxDTMFSuffix->sizePolicy().hasHeightForWidth());
+ comboBoxDTMFSuffix->setSizePolicy(sizePolicy1);
+ comboBoxDTMFSuffix->setMinimumSize(QSize(50, 0));
+
+ formLayoutAdvanced->setWidget(1, QFormLayout::FieldRole, comboBoxDTMFSuffix);
+
+ scrollArea->setWidget(scrollAreaWidgetContents);
+ ConfigWindow->setCentralWidget(centralwidget);
+ menubar = new QMenuBar(ConfigWindow);
+ menubar->setObjectName(QString::fromUtf8("menubar"));
+ menubar->setGeometry(QRect(0, 0, 800, 23));
+ menuVicarConfiguration = new QMenu(menubar);
+ menuVicarConfiguration->setObjectName(QString::fromUtf8("menuVicarConfiguration"));
+ ConfigWindow->setMenuBar(menubar);
+
+ menubar->addAction(menuVicarConfiguration->menuAction());
+ menuVicarConfiguration->addAction(actionSave);
+ menuVicarConfiguration->addAction(actionReset);
+
+ retranslateUi(ConfigWindow);
+
+ QMetaObject::connectSlotsByName(ConfigWindow);
+ } // setupUi
+
+ void retranslateUi(QMainWindow *ConfigWindow)
+ {
+ ConfigWindow->setWindowTitle(QApplication::translate("ConfigWindow", "VICaR - Settings", 0, QApplication::UnicodeUTF8));
+ actionSave->setText(QApplication::translate("ConfigWindow", "Save", 0, QApplication::UnicodeUTF8));
+#ifndef QT_NO_TOOLTIP
+ actionSave->setToolTip(QApplication::translate("ConfigWindow", "Save Settings", 0, QApplication::UnicodeUTF8));
+#endif // QT_NO_TOOLTIP
+ actionReset->setText(QApplication::translate("ConfigWindow", "Reset", 0, QApplication::UnicodeUTF8));
+#ifndef QT_NO_TOOLTIP
+ actionReset->setToolTip(QApplication::translate("ConfigWindow", "Reset Settings", 0, QApplication::UnicodeUTF8));
+#endif // QT_NO_TOOLTIP
+ groupBoxBasic->setTitle(QApplication::translate("ConfigWindow", "Basic", 0, QApplication::UnicodeUTF8));
+ labelCallRedirection->setText(QApplication::translate("ConfigWindow", "International Call Routing:", 0, QApplication::UnicodeUTF8));
+ checkBoxIntlCallRedirEnabled->setText(QApplication::translate("ConfigWindow", "Enabled", 0, QApplication::UnicodeUTF8));
+ labelCallingCardNumber->setText(QApplication::translate("ConfigWindow", "Calling Card Number:", 0, QApplication::UnicodeUTF8));
+ labelCountryCodesToExclude->setText(QApplication::translate("ConfigWindow", "Country Codes to Exclude:", 0, QApplication::UnicodeUTF8));
+ groupBoxAdvanced->setTitle(QApplication::translate("ConfigWindow", "Advanced", 0, QApplication::UnicodeUTF8));
+ labelDTMFFormat->setText(QApplication::translate("ConfigWindow", "Format required for DTMF tone:", 0, QApplication::UnicodeUTF8));
+ comboBoxDTMFFormat->clear();
+ comboBoxDTMFFormat->insertItems(0, QStringList()
+ << QApplication::translate("ConfigWindow", "<Country Code><Area Code><Phone Number>", 0, QApplication::UnicodeUTF8)
+ << QApplication::translate("ConfigWindow", "+<Country Code><Area Code><Phone Number>", 0, QApplication::UnicodeUTF8)
+ << QApplication::translate("ConfigWindow", "00<Country Code><Area Code><Phone Number>", 0, QApplication::UnicodeUTF8)
+ << QApplication::translate("ConfigWindow", "011<Country Code><Area Code><Phone Number>", 0, QApplication::UnicodeUTF8)
+ );
+ labelDTMFDelay->setText(QApplication::translate("ConfigWindow", "Delay before sending DTMF (no of pauses):", 0, QApplication::UnicodeUTF8));
+ labelDTMFSuffix->setText(QApplication::translate("ConfigWindow", "Suffix after DTMF tone", 0, QApplication::UnicodeUTF8));
+ comboBoxDTMFSuffix->clear();
+ comboBoxDTMFSuffix->insertItems(0, QStringList()
+ << QApplication::translate("ConfigWindow", "--None--", 0, QApplication::UnicodeUTF8)
+ << QApplication::translate("ConfigWindow", "#", 0, QApplication::UnicodeUTF8)
+ << QApplication::translate("ConfigWindow", "*", 0, QApplication::UnicodeUTF8)
+ );
+ menuVicarConfiguration->setTitle(QApplication::translate("ConfigWindow", "VICaR - Configuration", 0, QApplication::UnicodeUTF8));
+ } // retranslateUi
+
+};
+
+namespace Ui {
+ class ConfigWindow: public Ui_ConfigWindow {};
+} // namespace Ui
+
+QT_END_NAMESPACE
+
+#endif // UI_CONFIGWINDOW_H
--- /dev/null
+INCLUDEPATH += .
+INCLUDEPATH += /usr/include/gconf/2 \
+ /usr/include/glib-2.0 \
+ /usr/lib/glib-2.0/include
+INCLUDEPATH += ../vicar-lib/src
+LIBS += /usr/lib/libgconf-2.so
+LIBS += ../lib/libvicar.a
+CONFIG += qt \
+ debug
+QT += dbus
+TEMPLATE = app
+TARGET = vicar-config
+VPATH += src \
+ uis
+UI_DIR = uis
+MOC_DIR = mocs
+OBJECTS_DIR = objs
+
+# Input
+HEADERS += configwindow.h
+FORMS += configwindow.ui
+SOURCES += src/main.cpp \
+ configwindow.cpp
+
+# MAKE INSTALL
+INSTALLDIR = /../../debian/vicar
+INSTALLS += target
+target.path = $$INSTALLDIR/opt/vicar
--- /dev/null
+/*
+@version: 0.2
+@author: Sudheer K. <scifi.guy@hotmail.com>
+@license: GNU General Public License
+*/
+
+#include "callrouter.h"
+#include <dbusutility.h>
+#include <gconfutility.h>
+#include <QDebug>
+#include <QRegExp>
+#include <QDBusConnection>
+#include <QTimer>
+#include <QStringListIterator>
+
+//Create a statis Dbus utility object that will be shared across all member functions
+static DbusUtility dbusUtility = DbusUtility();
+static QString strLastDialedNumber = QString();
+
+CallRouter::CallRouter(QObject *parent) :
+ QObject(parent)
+{
+ gconfUtility = new GConfUtility();
+}
+
+CallRouter::~CallRouter(){
+ delete gconfUtility;
+ gconfUtility = 0;
+}
+
+void CallRouter::registerDBusService(){
+ QDBusConnection connection = dbusUtility.getConnection();
+
+ if (!connection.registerService(APPLICATION_DBUS_SERVICE)) {
+ qDebug() << dbusUtility.getErrorMessage();
+ exit(1);
+ }
+
+ if (!connection.registerObject(APPLICATION_DBUS_PATH, this,
+ QDBusConnection::ExportScriptableSlots)) {
+ qDebug() << dbusUtility.getErrorMessage();
+ exit(2);
+ }
+
+ this->connectToDBusSignals();
+
+}
+
+
+void CallRouter::unregisterDBusService(){
+
+ this->disconnectFromDBusSignals();
+
+ QDBusConnection connection = dbusUtility.getConnection();
+
+ connection.unregisterObject(APPLICATION_DBUS_PATH,QDBusConnection::UnregisterTree);
+
+ if (!connection.unregisterService(APPLICATION_DBUS_SERVICE)) {
+ qDebug() << dbusUtility.getErrorMessage();
+ exit(3);
+ }
+
+}
+
+void CallRouter::connectToDBusSignals(){
+
+ QDBusConnection connection = dbusUtility.getConnection();
+
+ // 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());
+ }
+
+}
+
+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);
+ }
+ }
+ }
+}
+
+void CallRouter::callViaCallingCard(){
+ //Now call the calling card number. This is generally a local and/or tollfree number
+
+ QString strCallingCardNumber = gconfUtility->getGconfValueString("calling_card_number");
+
+ qDebug() << "Wait time elapsed. Initiating call to "<< strCallingCardNumber;
+
+ QList<QVariant> argsToSend;
+ argsToSend.append(strCallingCardNumber);
+ argsToSend.append(0);
+
+ bool status = dbusUtility.sendMethodCall(CSD_SERVICE,
+ CSD_CALL_PATH,
+ CSD_CALL_INTERFACE,
+ QString("CreateWith"),argsToSend);
+
+ 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();
+ }
+
+ dbusUtility.displayNotification(strUserMessage);
+
+}
+
+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 = 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() << "Successfully connected to Dbus signal AudioConnect in interface "<< CSD_CALL_INSTANCE_INTERFACE;
+ }
+ else{
+ qDebug() << "Failed to connect to Dbus signal AudioConnect in interface "<< CSD_CALL_INSTANCE_INTERFACE;
+ qDebug() <<"DBus Error: "<< 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() << "Successfully connected to Dbus signal Terminated in interface "<< CSD_CALL_INSTANCE_INTERFACE;
+ }
+ else{
+ qDebug() << "Failed to connect to Dbus signal Terminated in interface "<< CSD_CALL_INSTANCE_INTERFACE;
+ qDebug() <<"DBus Error: "<< 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() << "Successfully connected to Dbus signal Coming in interface" << CSD_CALL_INTERFACE;
+ }
+ else{
+ qDebug() << "Failed to connect to Dbus signal Coming in interface" << CSD_CALL_INTERFACE;
+ qDebug() <<"DBus Error: "<< dbusUtility.getErrorMessage();
+ }
+}
+
+void CallRouter::stopCallStatusMonitors(){
+
+ strLastDialedNumber.clear();
+
+ QDBusConnection connection = 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() << "Successfully disconnected from Dbus signal AudioConnect in interface "<< CSD_CALL_INSTANCE_INTERFACE;
+ }
+ else{
+ qDebug() << "Failed to disconnect from Dbus signal AudioConnect in interface "<< CSD_CALL_INSTANCE_INTERFACE;
+ qDebug() <<"DBus Error: "<< 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() << "Successfully disconnected from Dbus signal Terminated in interface "<< CSD_CALL_INSTANCE_INTERFACE;
+ }
+ else{
+ qDebug() << "Failed to disconnect from Dbus signal Terminated in interface "<< CSD_CALL_INSTANCE_INTERFACE;
+ qDebug() <<"DBus Error: "<< 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() << "Successfully disconnected from Dbus signal Coming in interface" << CSD_CALL_INTERFACE;
+ }
+ else{
+ qDebug() << "Failed to disconnect from Dbus signal Coming in interface" << CSD_CALL_INTERFACE;
+ qDebug() <<"DBus Error: "<< dbusUtility.getErrorMessage();
+ }
+}
+
+void CallRouter::sendNumberAsDTMFCode(const QDBusMessage& dbusMessage){
+
+ if (!strLastDialedNumber.isEmpty()){
+ //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(strLastDialedNumber);
+
+ qDebug() << "Audio connection established. Sending DTMF code "<< strDTMFCode;
+
+ QList<QVariant> argsToSend;
+ argsToSend.append(strDTMFCode);
+
+ bool status = 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);
+ }
+ else{
+ qDebug() << "Unable to send 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() << "Now disconnecting from call status monitors..";
+ stopCallStatusMonitors();
+
+ }
+ else{
+ qDebug() << "Audio not yet connected.";
+ }
+ }
+ else
+ {
+ qDebug() << "Last dialed number is empty.";
+ }
+}
+
+QString CallRouter::convertToDTMFCode(QString strNumber){
+ QString strDTMFCode;
+
+ if (!strNumber.isEmpty()){
+
+ //Get the format required by calling card from coniguration
+ QString qstrDTMFFormat = gconfUtility->getGconfValueString("dtmf_format");
+ int intDTMFDelay = gconfUtility->getGconfValueInteger("dtmf_delay");
+
+ if (intDTMFDelay <1 ) intDTMFDelay = 1;
+ if (qstrDTMFFormat.isEmpty()) qstrDTMFFormat = "<Country Code><Area Code><Phone Number>";
+
+ //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);
+
+ /* 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");
+ }
+ //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--")){
+ strDTMFCode = strDTMFCode.append(strDTMFSuffix);
+ }
+ }
+
+ return strDTMFCode;
+}
+
+bool CallRouter::isExcludedNumber(QString strInternationalNumber){
+
+ bool isExcluded = false;
+
+ //Get the list of excluded codes
+ QString qstrExcludedNumbers = gconfUtility->getGconfValueString("numbers_to_exclude");
+ QStringList strExcludedCodeList = qstrExcludedNumbers.split(",");
+ QStringListIterator iterator(strExcludedCodeList);
+
+ QRegExp regexp = QRegExp("(^0{2})|[^0-9p]");
+
+ while (iterator.hasNext()){
+ QString strCode = iterator.next();
+ strCode = strCode.replace(regexp,"");
+ strInternationalNumber = strInternationalNumber.replace(regexp,"");
+ if (!strCode.isEmpty() && strInternationalNumber.startsWith(strCode)){
+ isExcluded = true;
+ }
+ }
+ return isExcluded;
+}
--- /dev/null
+/*
+@version: 0.2
+@author: Sudheer K. <scifi.guy@hotmail.com>
+@license: GNU General Public License
+*/
+
+#ifndef CALLROUTER_H
+#define CALLROUTER_H
+
+#include <QObject>
+#include <QDBusMessage>
+#include <gconfutility.h>
+
+#define APPLICATION_DBUS_PATH "/org/maemo/vicar"
+#define APPLICATION_DBUS_INTERFACE "org.maemo.vicar"
+#define APPLICATION_DBUS_SERVICE "org.maemo.vicar"
+#define APPLICATION_FRIENDLY_NAME "VICaR"
+
+/* CSD CALL plugin D-Bus definitions */
+#define CSD_CALL_BUS_NAME "com.nokia.csd.Call"
+#define CSD_CALL_INTERFACE "com.nokia.csd.Call"
+#define CSD_CALL_INSTANCE_INTERFACE "com.nokia.csd.Call.Instance"
+#define CSD_CALL_CONFERENCE "com.nokia.csd.Call.Conference"
+#define CSD_CALL_PATH "/com/nokia/csd/call"
+#define CSD_CALL_INSTANCE_PATH "/com/nokia/csd/call/1"
+#define CSD_CALL_SERVICE "com.nokia.csd.Call"
+#define CSD_SERVICE "com.nokia.csd"
+
+class CallRouter : public QObject
+{
+Q_OBJECT
+Q_CLASSINFO("D-Bus Interface", "org.maemo.vicar")
+
+public:
+ CallRouter(QObject *parent = 0);
+ ~CallRouter();
+ void registerDBusService();
+ void unregisterDBusService();
+
+ void startCallStatusMonitors();
+ QString convertToDTMFCode(QString);
+ void connectToDBusSignals();
+ void disconnectFromDBusSignals();
+ bool isExcludedNumber(QString);
+
+public slots:
+ Q_SCRIPTABLE void startOutgoingCallMonitor();
+ Q_SCRIPTABLE void stopOutgoingCallMonitor();
+ Q_SCRIPTABLE void processOutgoingCall(const QDBusMessage& dbusMessage);
+ Q_SCRIPTABLE void callViaCallingCard();
+ Q_SCRIPTABLE void sendNumberAsDTMFCode(const QDBusMessage& dbusMessage);
+ Q_SCRIPTABLE void stopCallStatusMonitors();
+
+
+
+private:
+ GConfUtility *gconfUtility;
+};
+
+#endif // CALLROUTER_H
--- /dev/null
+/*
+@version: 0.2
+@author: Sudheer K. <scifi.guy@hotmail.com>
+@license: GNU General Public License
+*/
+
+#include <QtCore/QCoreApplication>
+#include <QDBusConnection>
+#include <QDebug>
+#include "callrouter.h"
+#include "gconfutility.h"
+
+int main(int argc, char *argv[])
+{
+ QCoreApplication a(argc, argv);
+
+ CallRouter callRouter(&a);
+ callRouter.registerDBusService();
+ qDebug() << "Registered DBus Service " << APPLICATION_DBUS_SERVICE;
+
+ GConfUtility *gconfUtility = new GConfUtility();
+ //If International call routing is already enabled, start monitoring calls
+ //Otherwise wait for the signal from the configuration app
+ if (gconfUtility->getGconfValueBoolean((char *)"routing_enabled")){
+ qDebug() << "Call routing enabled. Starting call monitor..";
+ callRouter.startOutgoingCallMonitor();
+ }
+
+ delete gconfUtility;
+ gconfUtility = 0;
+
+ return a.exec();
+}
--- /dev/null
+INCLUDEPATH += /usr/include/gconf/2 \
+ /usr/include/glib-2.0 \
+ /usr/lib/glib-2.0/include
+INCLUDEPATH += ../vicar-lib/src
+
+LIBS += /usr/lib/libgconf-2.so
+LIBS += ../lib/libvicar.a
+
+CONFIG += qt debug
+QT += dbus
+QT -= gui
+TEMPLATE = app
+TARGET = vicar-daemon
+CONFIG += console
+CONFIG -= app_bundle
+
+VPATH += src
+MOC_DIR = mocs
+OBJECTS_DIR = objs
+
+SOURCES += src/main.cpp \
+ src/callrouter.cpp
+HEADERS += src/callrouter.h
+
+#MAKE INSTALL
+INSTALLDIR = /../../debian/vicar
+
+INSTALLS += target
+
+target.path =$$INSTALLDIR/opt/vicar
+
--- /dev/null
+/*
+@version: 0.2
+@author: Sudheer K. <scifi.guy@hotmail.com>
+@license: GNU General Public License
+*/
+
+#include "dbusutility.h"
+#include <QDBusMessage>
+#include <QDebug>
+
+
+//Construction is available in the header file due to a peculiar issue with systemBus() function.
+
+
+//Destructor for Dbus Utility object.
+DbusUtility::~DbusUtility(){
+ this->connection.disconnectFromBus(this->connection.baseService());
+ qDebug() << "Disconnected from system bus";
+}
+
+QDBusConnection DbusUtility::getConnection(){
+ if (!this->connection.isConnected()){
+ qDebug() << "Not connected to Dbus";
+ }
+ return this->connection;
+}
+
+void DbusUtility::setConnection(QDBusConnection connection){
+ this->connection = connection;
+}
+
+//Utility method to send a dbus signal.
+bool DbusUtility::sendSignal(QString strPath,QString strInterface,QString strName){
+ QDBusMessage dbusSignal = QDBusMessage::createSignal(strPath,strInterface,strName);
+ bool status = DbusUtility::connection.send(dbusSignal);
+ return status;
+}
+
+//Utility method to call a dbus method with parameters
+bool DbusUtility::sendMethodCall(QString strService,QString strPath,
+ QString strInterface,QString strMethodName,
+ QList<QVariant> & arguments){
+ QDBusMessage dbusMethodCall = QDBusMessage::createMethodCall(strService,strPath,strInterface,strMethodName);
+ dbusMethodCall.setArguments(arguments);
+ bool status = DbusUtility::connection.send(dbusMethodCall);
+ return status;
+}
+
+//Utility method to display a notification (Orange sliding banner in Maemo) with custom message
+bool DbusUtility::displayNotification(QString strMessage){
+ QList <QVariant> arguments;
+ arguments.append(strMessage);
+
+ bool status = this->sendMethodCall(NOTIFICATION_SERVICE,
+ NOTIFICATION_PATH,
+ NOTIFICATION_INTERFACE,
+ QString("SystemNoteInfoprint"),
+ arguments);
+ return status;
+}
+
+
+//Utility method to retrieve the last dbus error
+QString DbusUtility::getErrorMessage(){
+ QString strErrorMessage;
+ QDBusError dbusError = this->connection.lastError();
+ if (dbusError.isValid()){
+ strErrorMessage = qPrintable(dbusError.message());
+ }
+ return strErrorMessage;
+}
--- /dev/null
+/*
+@version: 0.2
+@author: Sudheer K. <scifi.guy@hotmail.com>
+@license: GNU General Public License
+*/
+
+#ifndef DBUSUTILITY_H
+#define DBUSUTILITY_H
+
+#include <QDBusMessage>
+#include <QDBusConnection>
+
+#define NOTIFICATION_SERVICE "org.freedesktop.Notifications"
+#define NOTIFICATION_PATH "/org/freedesktop/Notifications"
+#define NOTIFICATION_INTERFACE "org.freedesktop.Notifications"
+
+class DbusUtility
+{
+protected:
+ QDBusConnection connection;
+public:
+ DbusUtility():connection(QDBusConnection::systemBus())
+ {}
+ ~DbusUtility();
+ QDBusConnection getConnection();
+ void setConnection(QDBusConnection connection);
+ bool sendSignal(QString strPath,QString strInterface,QString strName);
+ bool sendMethodCall(QString strService,QString strPath,
+ QString strInterface,QString strMethodName,
+ QList<QVariant> & arguments);
+ bool displayNotification(QString strMessage);
+ QString getErrorMessage();
+};
+
+#endif // DBUSUTILITY_H
--- /dev/null
+/*
+@version: 0.2
+@author: Sudheer K. <scifi.guy@hotmail.com>
+@license: GNU General Public License
+*/
+
+#include "gconfutility.h"
+#include <gconf/gconf-client.h>
+#include <QDebug>
+
+GConfUtility::GConfUtility(QObject *parent) :
+ QObject(parent)
+{
+ /* Get a GConf client */
+ gconfClient = gconf_client_get_default();
+ g_assert(GCONF_IS_CLIENT(gconfClient));
+}
+
+GConfUtility::~GConfUtility(){
+ /* release GConf client */
+ g_object_unref(gconfClient);
+ gconfClient = 0;
+}
+
+QString GConfUtility::getGconfValueString(QString strKey){
+
+ char* strValue = NULL;
+
+ if (!strKey.isEmpty()) {
+ strKey.prepend(GCONF_DIR);
+
+ strValue = gconf_client_get_string(gconfClient, strKey.toAscii().constData(), NULL);
+ qDebug() << "Gconf: "<<strKey.toAscii().constData()<< " is "<<strValue;
+ }
+
+ return QString(strValue);
+}
+
+void GConfUtility::setGconfValueString(QString strKey,QString strValue){
+
+ if (!strKey.isEmpty()){
+
+ strKey.prepend(GCONF_DIR);
+
+ if (!strValue.isEmpty()){
+ gconf_client_set_string(gconfClient, strKey.toAscii().constData(), strValue.toAscii().constData(),NULL);
+ qDebug() << "Assigned "<<strKey.toAscii().constData()<< " to "<<strValue.toAscii().constData();
+ }
+ else{
+ gconf_client_unset(gconfClient, strKey.toAscii().constData(),NULL);
+ qDebug() << "Assigned "<<strKey.toAscii().constData()<< " to NULL";
+ }
+
+ }
+}
+
+bool GConfUtility::getGconfValueBoolean(QString strKey){
+
+ bool boolValue = false;
+
+ if (!strKey.isEmpty()) {
+ strKey.prepend(GCONF_DIR);
+
+ boolValue = gconf_client_get_bool(gconfClient, strKey.toAscii().constData(), NULL);
+ qDebug() << "Gconf: "<<strKey.toAscii().constData()<< " is "<<boolValue;
+ }
+
+ return boolValue;
+}
+
+void GConfUtility::setGconfValueBoolean(QString strKey,bool boolValue){
+
+ if (!strKey.isEmpty()){
+
+ strKey.prepend(GCONF_DIR);
+
+ gconf_client_set_bool(gconfClient, strKey.toAscii().constData(),boolValue,NULL);
+ qDebug() << "Assigned "<<strKey.toAscii().constData()<< " to "<<boolValue;
+ }
+}
+
+int GConfUtility::getGconfValueInteger(QString strKey){
+
+ int intValue = 0;
+
+ if (!strKey.isEmpty()) {
+ strKey.prepend(GCONF_DIR);
+
+ intValue = gconf_client_get_int(gconfClient, strKey.toAscii().constData(), NULL);
+ qDebug() << "Gconf: "<<strKey.toAscii().constData()<< " is "<<intValue;
+ }
+
+ return intValue;
+}
+
+void GConfUtility::setGconfValueInteger(QString strKey,int intValue){
+
+ if (!strKey.isEmpty()){
+
+ strKey.prepend(GCONF_DIR);
+
+ gconf_client_set_int(gconfClient, strKey.toAscii().constData(),intValue,NULL);
+ qDebug() << "Assigned "<<strKey.toAscii().constData()<< " to "<<intValue;
+ }
+}
--- /dev/null
+/*
+@version: 0.2
+@author: Sudheer K. <scifi.guy@hotmail.com>
+@license: GNU General Public License
+*/
+
+#ifndef GCONFUTILITY_H
+#define GCONFUTILITY_H
+
+#include <QObject>
+#include <gconf/gconf-client.h>
+
+#define APPLICATION_NAME "vicar"
+#define GCONF_DIR "/apps/Maemo/" APPLICATION_NAME "/"
+
+class GConfUtility : public QObject
+ {
+Q_OBJECT
+public:
+ GConfUtility(QObject *parent = 0);
+ ~GConfUtility();
+ void setGconfValueString(QString strKey,QString strValue);
+ QString getGconfValueString(QString strKey);
+
+ void setGconfValueBoolean(QString strKey,bool boolValue);
+ bool getGconfValueBoolean(QString strKey);
+
+ void setGconfValueInteger(QString strKey,int intValue);
+ int getGconfValueInteger(QString strKey);
+
+private:
+ GConfClient *gconfClient;
+};
+
+#endif // GCONFUTILITY_H
--- /dev/null
+INCLUDEPATH += /usr/include/gconf/2 \
+ /usr/include/glib-2.0 \
+ /usr/lib/glib-2.0/include
+#QMAKE_LIBDIR=./
+LIBS += /usr/lib/libgconf-2.so
+CONFIG += qt debug staticlib
+CONFIG -= gui
+QT += dbus
+QT -= gui
+TARGET = vicar
+TEMPLATE = lib
+VPATH += src
+MOC_DIR = mocs
+OBJECTS_DIR = objs
+DESTDIR = ../lib
+
+SOURCES += src/dbusutility.cpp \
+ src/gconfutility.cpp
+HEADERS += src/dbusutility.h \
+ src/gconfutility.h
+
+#MAKE INSTALL
+INSTALLDIR = /../../debian/vicar
+
+INSTALLS += target
+
+target.path =$$INSTALLDIR/opt/lib
--- /dev/null
+QMAKEVERSION = $$[QMAKE_VERSION]
+ISQT4 = $$find(QMAKEVERSION, ^[2-9])
+isEmpty( ISQT4 ) {
+error("Use the qmake include with Qt4.4 or greater, on Debian that is qmake-qt4");
+}
+
+TEMPLATE = subdirs
+SUBDIRS = src
+