--- /dev/null
+# #####################################
+# version check qt
+# #####################################
+contains(QT_VERSION, ^4\.[0-5]\..*) {
+ message("Cannot build FsGui with Qt version $$QT_VERSION.")
+ error("Use at least Qt 4.6.")
+}
+QT += xml
+TARGET = fsphone
+macx:TARGET = FSPhone
+TEMPLATE = app
+INCLUDEPATH = ../../../src/include \
+ ../../../libs/apr/include \
+ ../../../libs/libteletone/src
+LIBS = -L../../../.libs \
+ -lfreeswitch \
+ -lm
+!win32:!macx {
+ # This is here to comply with the default freeswitch installation
+ QMAKE_LFLAGS += -Wl,-rpath,/usr/local/freeswitch/lib
+ LIBS += -lcrypt \
+ -lrt
+}
+SOURCES += main.cpp \
+ mainwindow.cpp \
+ fshost.cpp \
+ call.cpp \
+ mod_qsettings/mod_qsettings.cpp \
+ prefdialog.cpp
+HEADERS += mainwindow.h \
+ fshost.h \
+ call.h \
+ mod_qsettings/mod_qsettings.h \
+ prefdialog.h
+FORMS += mainwindow.ui \
+ prefdialog.ui
+RESOURCES += resources.qrc
+OTHER_FILES += conf/portaudio.conf.xml \
+ conf/event_socket.conf.xml \
+ conf/freeswitch.xml
--- /dev/null
+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005-2009, Anthony Minessale II <anthm@freeswitch.org>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthm@freeswitch.org>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Joao Mesquita <jmesquita@freeswitch.org>
+ *
+ */
+
+#include "call.h"
+
+Call::Call()
+{
+}
+
+Call::Call(int call_id, QString cid_name, QString cid_number, fsphone_call_direction_t direction, QString uuid) :
+ _call_id(call_id),
+ _cid_name(cid_name),
+ _cid_number(cid_number),
+ _direction(direction),
+ _uuid (uuid)
+{
+}
--- /dev/null
+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005-2009, Anthony Minessale II <anthm@freeswitch.org>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthm@freeswitch.org>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Joao Mesquita <jmesquita@freeswitch.org>
+ *
+ */
+#ifndef CALL_H
+#define CALL_H
+
+#include <QtCore>
+#include <QString>
+#include <fshost.h>
+
+typedef enum {
+ FSPHONE_CALL_STATE_RINGING = 0,
+ FSPHONE_CALL_STATE_TRYING = 1,
+ FSPHONE_CALL_STATE_ANSWERED = 2
+} fsphone_call_state_t;
+
+typedef enum {
+ FSPHONE_CALL_DIRECTION_INBOUND = 0,
+ FSPHONE_CALL_DIRECTION_OUTBOUND = 1
+} fsphone_call_direction_t;
+
+class Call
+{
+public:
+ Call(void);
+ Call(int call_id, QString cid_name, QString cid_number, fsphone_call_direction_t direction, QString uuid);
+ QString getCidName(void) { return _cid_name; }
+ QString getCidNumber(void) { return _cid_number; }
+ int getCallID(void) { return _call_id; }
+ QString getUUID(void) { return _uuid; }
+ void setbUUID(QString uuid) { _buuid = uuid; }
+ fsphone_call_direction_t getDirection() { return _direction; }
+ fsphone_call_state_t getState() { return _state; }
+ void setState(fsphone_call_state_t state) { _state = state; }
+
+private:
+ int _call_id;
+ QString _cid_name;
+ QString _cid_number;
+ fsphone_call_direction_t _direction;
+ QString _uuid;
+ QString _buuid;
+ fsphone_call_state_t _state;
+};
+
+Q_DECLARE_METATYPE(Call)
+
+#endif // CALL_H
--- /dev/null
+<include>
+ <!--<gateway name="default">-->
+ <!--/// account username *required* ///-->
+ <!--<param name="username" value="cluecon"/>-->
+ <!--/// auth realm: *optional* same as gateway name, if blank ///-->
+ <!--<param name="realm" value="asterlink.com"/>-->
+ <!--/// username to use in from: *optional* same as username, if blank ///-->
+ <!--<param name="from-user" value="cluecon"/>-->
+ <!--/// domain to use in from: *optional* same as realm, if blank ///-->
+ <!--<param name="from-domain" value="asterlink.com"/>-->
+ <!--/// account password *required* ///-->
+ <!--<param name="password" value="cluecon"/>-->
+ <!--/// extension for inbound calls: *optional* same as username, if blank ///-->
+ <!--<param name="extension" value="cluecon"/>-->
+ <!--/// proxy host: *optional* same as realm, if blank ///-->
+ <!--<param name="proxy" value="asterlink.com"/>-->
+ <!--/// send register to this proxy: *optional* same as proxy, if blank ///-->
+ <!--<param name="register-proxy" value="mysbc.com"/>-->
+ <!--/// expire in seconds: *optional* 3600, if blank ///-->
+ <!--<param name="expire-seconds" value="60"/>-->
+ <!--/// do not register ///-->
+ <!--<param name="register" value="false"/>-->
+ <!-- which transport to use for register -->
+ <!--<param name="register-transport" value="udp"/>-->
+ <!--How many seconds before a retry when a failure or timeout occurs -->
+ <!--<param name="retry-seconds" value="30"/>-->
+ <!--Use the callerid of an inbound call in the from field on outbound calls via this gateway -->
+ <!--<param name="caller-id-in-from" value="false"/>-->
+ <!--extra sip params to send in the contact-->
+ <!--<param name="contact-params" value="tport=tcp"/>-->
+ <!--send an options ping every x seconds, failure will unregister and/or mark it down-->
+ <!--<param name="ping" value="25"/>-->
+ <!--</gateway>-->
+</include>
--- /dev/null
+<configuration name="event_socket.conf" description="Socket Client">
+ <settings>
+ <param name="nat-map" value="false"/>
+ <param name="listen-ip" value="127.0.0.1"/>
+ <param name="listen-port" value="8021"/>
+ <param name="password" value="ClueCon"/>
+ </settings>
+</configuration>
--- /dev/null
+<?xml version="1.0"?>
+<document type="freeswitch/xml">
+ <X-PRE-PROCESS cmd="set" data="auto_answer=false"/>
+ <X-PRE-PROCESS cmd="set" data="domain=$${local_ip_v4}"/>
+ <X-PRE-PROCESS cmd="set" data="hold_music=local_stream://moh"/>
+ <X-PRE-PROCESS cmd="set" data="codec_prefs=CELT@48000h,G7221@32000h,G7221@16000h,G722,PCMU,PCMA,GSM"/>
+ <X-PRE-PROCESS cmd="set" data="external_rtp_ip=stun:stun.freeswitch.org"/>
+ <X-PRE-PROCESS cmd="set" data="external_sip_ip=stun:stun.freeswitch.org"/>
+ <X-PRE-PROCESS cmd="set" data="outbound_caller_name=FreeSWITCH"/>
+ <X-PRE-PROCESS cmd="set" data="outbound_caller_id=0000000000"/>
+ <X-PRE-PROCESS cmd="set" data="console_loglevel=info"/>
+ <X-PRE-PROCESS cmd="set" data="default_gateway=default"/>
+ <X-PRE-PROCESS cmd="set" data="us-ring=%(2000, 4000, 440.0, 480.0)"/>
+ <X-PRE-PROCESS cmd="set" data="bong-ring=v=-7;%(100,0,941.0,1477.0);v=-7;>=2;+=.1;%(1400,0,350,440)"/>
+ <X-PRE-PROCESS cmd="set" data="sit=%(274,0,913.8);%(274,0,1370.6);%(380,0,1776.7)"/>
+
+ <section name="configuration" description="Various Configuration">
+ <configuration name="cdr_csv.conf" description="CDR CSV Format">
+ <settings>
+ <param name="default-template" value="example"/>
+ <param name="rotate-on-hup" value="true"/>
+ <param name="legs" value="a"/>
+ </settings>
+ <templates>
+ <template name="example">"${caller_id_name}","${caller_id_number}","${destination_number}","${context}","${start_stamp}","${answer_stamp}","${end_stamp}","${duration}","${billsec}","${hangup_cause}","${uuid}","${bleg_uuid}","${accountcode}","${read_codec}","${write_codec}"</template>
+ </templates>
+ </configuration>
+
+ <configuration name="console.conf" description="Console Logger">
+ <mappings>
+ <map name="all" value="console,debug,info,notice,warning,err,crit,alert"/>
+ </mappings>
+ <settings>
+ <param name="colorize" value="true"/>
+ <param name="loglevel" value="$${console_loglevel}"/>
+ </settings>
+ </configuration>
+
+ <configuration name="enum.conf" description="ENUM Module">
+ <settings>
+ <param name="default-root" value="e164.org"/>
+ <param name="default-isn-root" value="freenum.org"/>
+ <param name="query-timeout" value="10"/>
+ <param name="auto-reload" value="true"/>
+ </settings>
+ <routes>
+ <route service="E2U+SIP" regex="sip:(.*)" replace="sofia/softphone/$1"/>
+ </routes>
+ </configuration>
+
+ <configuration name="qsettings.conf" description="configures our mod_qsettings">
+ <bindings value="dialplan" />
+ </configuration>
+
+ <configuration name="local_stream.conf" description="stream files from local dir">
+ <directory name="moh/48000" path="$${base_dir}/sounds/music/48000">
+ <param name="rate" value="48000"/>
+ <param name="shuffle" value="true"/>
+ <param name="channels" value="1"/>
+ <param name="interval" value="10"/>
+ <param name="timer-name" value="soft"/>
+ </directory>
+ </configuration>
+
+ <configuration name="logfile.conf" description="File Logging">
+ <settings>
+ <param name="rotate-on-hup" value="true"/>
+ </settings>
+ <profiles>
+ <profile name="default">
+ <settings>
+ </settings>
+ <mappings>
+ <map name="all" value="debug,info,notice,warning,err,crit,alert"/>
+ </mappings>
+ </profile>
+ </profiles>
+ </configuration>
+
+ <configuration name="modules.conf" description="Modules">
+ <modules>
+ <load module="mod_console"/>
+ <load module="mod_logfile"/>
+ <load module="mod_enum"/>
+ <load module="mod_cdr_csv"/>
+ <load module="mod_portaudio"/>
+ <load module="mod_sofia"/>
+ <load module="mod_loopback"/>
+ <load module="mod_commands"/>
+ <load module="mod_dptools"/>
+ <load module="mod_dialplan_xml"/>
+ <load module="mod_voipcodecs"/>
+ <load module="mod_ilbc"/>
+ <load module="mod_speex"/>
+ <load module="mod_celt"/>
+ <load module="mod_siren"/>
+ <load module="mod_sndfile"/>
+ <load module="mod_tone_stream"/>
+ <load module="mod_local_stream"/>
+ </modules>
+ </configuration>
+
+ <configuration name="post_load_modules.conf" description="Modules">
+ <modules>
+ </modules>
+ </configuration>
+
+ <configuration name="sofia.conf" description="sofia Endpoint">
+ <global_settings>
+ <param name="log-level" value="0"/>
+ <param name="auto-restart" value="true"/>
+ <param name="debug-presence" value="0"/>
+ </global_settings>
+ <profiles>
+ <profile name="softphone">
+ <gateways>
+ <X-PRE-PROCESS cmd="include" data="accounts/*.xml"/>
+ </gateways>
+ <settings>
+ <!--<param name="media-option" value="bypass-media-after-att-xfer"/>-->
+ <param name="user-agent-string" value="FreeSWITCH/FSPhone"/>
+ <!-- <param name="user-agent-string" value="FreeSWITCH Rocks!"/> -->
+ <param name="debug" value="0"/>
+ <param name="sip-trace" value="no"/>
+ <param name="context" value="public"/>
+ <param name="rfc2833-pt" value="101"/>
+ <!-- port to bind to for sip traffic -->
+ <param name="sip-port" value="12345"/>
+ <param name="dialplan" value="XML"/>
+ <param name="dtmf-duration" value="100"/>
+ <param name="codec-prefs" value="$${codec_prefs}"/>
+ <param name="use-rtp-timer" value="true"/>
+ <param name="rtp-timer-name" value="soft"/>
+ <!-- ip address to use for rtp, DO NOT USE HOSTNAMES ONLY IP ADDRESSES -->
+ <param name="rtp-ip" value="$${local_ip_v4}"/>
+ <!-- ip address to bind to, DO NOT USE HOSTNAMES ONLY IP ADDRESSES -->
+ <param name="sip-ip" value="$${local_ip_v4}"/>
+ <param name="hold-music" value="$${hold_music}"/>
+ <param name="apply-nat-acl" value="rfc1918"/>
+ <!--<param name="enable-timer" value="false"/>-->
+ <!--<param name="enable-100rel" value="true"/>-->
+ <!--<param name="minimum-session-expires" value="120"/>-->
+ <!--<param name="dtmf-type" value="info"/>-->
+ <param name="manage-presence" value="false"/>
+ <!--<param name="bitpacking" value="aal2"/> -->
+ <param name="max-proceeding" value="3"/>
+ <!--<param name="session-timeout" value="120"/>-->
+ <!--set to 'greedy' if you want your codec list to take precedence -->
+ <param name="inbound-codec-negotiation" value="generous"/>
+ <!-- if you want to send any special bind params of your own -->
+ <!--<param name="bind-params" value="transport=udp"/>-->
+ <!--Uncomment to let calls hit the dialplan *before* you decide if the codec is ok-->
+ <!--<param name="inbound-late-negotiation" value="true"/>-->
+ <!--<param name="accept-blind-reg" value="true"/> -->
+ <!--<param name="accept-blind-auth" value="true"/> -->
+ <!--<param name="suppress-cng" value="true"/> -->
+ <param name="nonce-ttl" value="60"/>
+ <!--<param name="NDLB-broken-auth-hash" value="true"/>-->
+ <!--<param name="NDLB-received-in-nat-reg-contact" value="true"/>-->
+ <param name="auth-calls" value="false"/>
+ <param name="auth-all-packets" value="false"/>
+ <param name="ext-rtp-ip" value="$${external_rtp_ip}"/>
+ <param name="ext-sip-ip" value="$${external_sip_ip}"/>
+ <!-- rtp inactivity timeout -->
+ <param name="rtp-timeout-sec" value="300"/>
+ <param name="rtp-hold-timeout-sec" value="1800"/>
+ <!-- VAD choose one (out is a good choice); -->
+ <!-- <param name="vad" value="in"/> -->
+ <!-- <param name="vad" value="out"/> -->
+ <!-- <param name="vad" value="both"/> -->
+ <param name="disable-register" value="true"/>
+ <!--<param name="NDLB-force-rport" value="true"/>-->
+ <param name="challenge-realm" value="auto_from"/>
+ <!--<param name="disable-rtp-auto-adjust" value="true"/>-->
+ <!--<param name="inbound-use-callid-as-uuid" value="true"/>-->
+ <!--<param name="outbound-use-uuid-as-callid" value="true"/>-->
+ <!--<param name="auto-rtp-bugs" data="clear"/>-->
+ </settings>
+ </profile>
+ </profiles>
+ </configuration>
+
+ <configuration name="switch.conf" description="Core Configuration">
+ <cli-keybindings>
+ <key name="1" value="help"/>
+ <key name="2" value="status"/>
+ <key name="3" value="pa answer"/>
+ <key name="4" value="pa hangup"/>
+ <key name="5" value="sofia status"/>
+ <key name="6" value="reloadxml"/>
+ <key name="7" value="console loglevel 0"/>
+ <key name="8" value="console loglevel 7"/>
+ <key name="9" value="sofia status profile softphone"/>
+ <key name="10" value="fsctl pause"/>
+ <key name="11" value="fsctl resume"/>
+ <key name="12" value="version"/>
+ </cli-keybindings>
+ <settings>
+ <param name="colorize-console" value="true"/>
+ <param name="max-sessions" value="20"/>
+ <param name="sessions-per-second" value="5"/>
+ <param name="loglevel" value="debug"/>
+ <param name="crash-protection" value="false"/>
+ <param name="dump-cores" value="yes"/>
+ <param name="rtp-start-port" value="16384"/>
+ <param name="rtp-end-port" value="16484"/>
+ </settings>
+ </configuration>
+ </section>
+
+ <section name="dialplan" description="Regex/XML Dialplan">
+ <context name="default">
+ <extension name="codec_and_sip_uri">
+ <condition field="destination_number" expression="^sip:(.*):(.*)$">
+ <action application="bridge" data="{absolute_codec_string=$1}sofia/softphone/$2"/>
+ </condition>
+ </extension>
+ <extension name="sip_uri">
+ <condition field="destination_number" expression="^sip:(.*)$">
+ <action application="bridge" data="sofia/softphone/$1"/>
+ </condition>
+ </extension>
+ <extension name="codec_and_number">
+ <condition field="destination_number" expression="^(.*):(.*)@(.*)$">
+ <action application="bridge" data="{absolute_codec_string=$1}sofia/gateway/$3/$2"/>
+ </condition>
+ </extension>
+ <extension name="number">
+ <condition field="destination_number" expression="^(.*)@(.*)$">
+ <action application="bridge" data="sofia/gateway/$2/$1"/>
+ </condition>
+ </extension>
+ <extension name="number">
+ <condition field="destination_number" expression="^(.*)$">
+ <action application="bridge" data="sofia/gateway/${default_gateway}/$1"/>
+ </condition>
+ </extension>
+ </context>
+ <context name="public">
+ <extension name="public_extensions">
+ <condition field="$${auto_answer}" expression="^true$"/>
+ <condition field="destination_number" expression="^(.*)$">
+ <action application="info"/>
+ <action application="bridge" data="portaudio/auto_answer"/>
+ </condition>
+ </extension>
+ <extension name="public_extensions">
+ <condition field="${sip_to_params}" expression="intercom=true"/>
+ <condition field="${alert_info}" expression="Ring;Answer"/>
+ <condition field="destination_number" expression="^(.*)$">
+ <action application="info"/>
+ <action application="bridge" data="portaudio/auto_answer"/>
+ </condition>
+ </extension>
+ <extension name="public_extensions">
+ <condition field="destination_number" expression="^(.*)$">
+ <action application="info"/>
+ <action application="set" data="ringback=${us-ring}"/>
+ <action application="pre_answer"/>
+ <action application="bridge" data="portaudio"/>
+ </condition>
+ </extension>
+ </context>
+ </section>
+</document>
+
+
--- /dev/null
+<configuration name="portaudio.conf" description="Soundcard Endpoint">
+ <settings>
+ <param name="indev" value="${indev}"/>
+ <!-- device to use for output -->
+ <param name="outdev" value="${outdev}"/>
+ <!--<param name="ringdev" value="${ringdev}"/>-->
+ <param name="ring-file" value="${ring-file}"/>
+ <param name="ring-interval" value="${ring-interval}"/>
+ <param name="hold-file" value="$${hold_music}"/>
+ <!--<param name="timer-name" value="soft"/>-->
+ <param name="dialplan" value="XML"/>
+ <param name="cid-name" value="$${outbound_caller_name}"/>
+ <param name="cid-num" value="$${outbound_caller_number}"/>
+ <param name="sample-rate" value="48000"/>
+ <param name="codec-ms" value="10"/>
+ </settings>
+</configuration>
--- /dev/null
+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005-2009, Anthony Minessale II <anthm@freeswitch.org>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthm@freeswitch.org>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Joao Mesquita <jmesquita@freeswitch.org>
+ *
+ */
+
+#include <QtGui>
+#include "fshost.h"
+#include "call.h"
+#include "mod_qsettings/mod_qsettings.h"
+
+/* Declare it globally */
+FSHost g_FSHost;
+
+FSHost::FSHost(QObject *parent) :
+ QThread(parent)
+{
+ /* Initialize libs & globals */
+ printf("Initializing globals...\n");
+ switch_core_setrlimits();
+ switch_core_set_globals();
+
+ qRegisterMetaType<Call>("Call");
+
+}
+
+void FSHost::run(void)
+{
+ switch_core_flag_t flags = SCF_USE_SQL | SCF_USE_AUTO_NAT;
+ const char *err = NULL;
+ switch_bool_t console = SWITCH_FALSE;
+ switch_status_t destroy_status;
+
+ /* Create directory structure for softphone with default configs */
+ QDir conf_dir = QDir(QDir::home());
+ if (!conf_dir.exists(".fsphone"))
+ {
+ conf_dir.mkpath(".fsphone/conf/accounts");
+ conf_dir.mkpath(".fsphone/templates");
+ QFile rootXML(":/confs/freeswitch.xml");
+ QString dest = QString("%1/.fsphone/conf/freeswitch.xml").arg(conf_dir.absolutePath());
+ rootXML.copy(dest);
+
+ QFile defaultAccount(":/confs/example.xml");
+ dest = QString("%1/.fsphone/conf/accounts/example.xml").arg(conf_dir.absolutePath());
+ defaultAccount.copy(dest);
+ }
+
+ /* Set all directories to the home user directory */
+ if (conf_dir.cd(".fsphone"))
+ {
+ SWITCH_GLOBAL_dirs.conf_dir = (char *) malloc(strlen(QString("%1/conf").arg(conf_dir.absolutePath()).toAscii().constData()) + 1);
+ if (!SWITCH_GLOBAL_dirs.conf_dir) {
+ emit coreLoadingError("Cannot allocate memory for conf_dir.");
+ }
+ strcpy(SWITCH_GLOBAL_dirs.conf_dir, QString("%1/conf").arg(conf_dir.absolutePath()).toAscii().constData());
+
+ SWITCH_GLOBAL_dirs.log_dir = (char *) malloc(strlen(QString("%1/log").arg(conf_dir.absolutePath()).toAscii().constData()) + 1);
+ if (!SWITCH_GLOBAL_dirs.log_dir) {
+ emit coreLoadingError("Cannot allocate memory for log_dir.");
+ }
+ strcpy(SWITCH_GLOBAL_dirs.log_dir, QString("%1/log").arg(conf_dir.absolutePath()).toAscii().constData());
+
+ SWITCH_GLOBAL_dirs.run_dir = (char *) malloc(strlen(QString("%1/run").arg(conf_dir.absolutePath()).toAscii().constData()) + 1);
+ if (!SWITCH_GLOBAL_dirs.run_dir) {
+ emit coreLoadingError("Cannot allocate memory for run_dir.");
+ }
+ strcpy(SWITCH_GLOBAL_dirs.run_dir, QString("%1/run").arg(conf_dir.absolutePath()).toAscii().constData());
+
+ SWITCH_GLOBAL_dirs.db_dir = (char *) malloc(strlen(QString("%1/db").arg(conf_dir.absolutePath()).toAscii().constData()) + 1);
+ if (!SWITCH_GLOBAL_dirs.db_dir) {
+ emit coreLoadingError("Cannot allocate memory for db_dir.");
+ }
+ strcpy(SWITCH_GLOBAL_dirs.db_dir, QString("%1/db").arg(conf_dir.absolutePath()).toAscii().constData());
+
+ SWITCH_GLOBAL_dirs.script_dir = (char *) malloc(strlen(QString("%1/script").arg(conf_dir.absolutePath()).toAscii().constData()) + 1);
+ if (!SWITCH_GLOBAL_dirs.script_dir) {
+ emit coreLoadingError("Cannot allocate memory for script_dir.");
+ }
+ strcpy(SWITCH_GLOBAL_dirs.script_dir, QString("%1/script").arg(conf_dir.absolutePath()).toAscii().constData());
+
+ SWITCH_GLOBAL_dirs.htdocs_dir = (char *) malloc(strlen(QString("%1/htdocs").arg(conf_dir.absolutePath()).toAscii().constData()) + 1);
+ if (!SWITCH_GLOBAL_dirs.htdocs_dir) {
+ emit coreLoadingError("Cannot allocate memory for htdocs_dir.");
+ }
+ strcpy(SWITCH_GLOBAL_dirs.htdocs_dir, QString("%1/htdocs").arg(conf_dir.absolutePath()).toAscii().constData());
+ }
+
+ /* If you need to override configuration directories, you need to change them in the SWITCH_GLOBAL_dirs global structure */
+ printf("Initializing core...\n");
+ /* Initialize the core and load modules, that will startup FS completely */
+ if (switch_core_init_and_modload(flags, console, &err) != SWITCH_STATUS_SUCCESS) {
+ fprintf(stderr, "Failed to initialize FreeSWITCH's core: %s\n", err);
+ emit coreLoadingError(err);
+ }
+
+ printf("Everything OK, Entering runtime loop.\n");
+
+ if (switch_event_bind("FSHost", SWITCH_EVENT_ALL, SWITCH_EVENT_SUBCLASS_ANY, eventHandlerCallback, NULL) != SWITCH_STATUS_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n");
+ }
+
+ /* Load our QSettings module */
+ if (switch_loadable_module_build_dynamic("mod_qsettings",mod_qsettings_load,NULL,mod_qsettings_shutdown,SWITCH_FALSE) != SWITCH_STATUS_SUCCESS)
+ {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't load mod_qsettings\n");
+ }
+ QString res;
+ sendCmd("load", "mod_event_socket", &res);
+ emit ready();
+ /* Go into the runtime loop. If the argument is true, this basically sets runtime.running = 1 and loops while that is set
+ * If its false, it initializes the libedit for the console, then does the same thing
+ */
+ switch_core_runtime_loop(!console);
+ fflush(stdout);
+
+
+ switch_event_unbind_callback(eventHandlerCallback);
+ /* When the runtime loop exits, its time to shutdown */
+ destroy_status = switch_core_destroy();
+ if (destroy_status == SWITCH_STATUS_SUCCESS)
+ {
+ printf("We have properly shutdown the core.\n");
+ }
+}
+
+switch_status_t FSHost::processAlegEvent(switch_event_t * event, QString uuid)
+{
+ switch_status_t status = SWITCH_STATUS_SUCCESS;
+ Call * call = _active_calls.value(uuid);
+ /* Inbound call */
+ if (call->getDirection() == FSPHONE_CALL_DIRECTION_INBOUND)
+ {
+ switch(event->event_id) {
+ case SWITCH_EVENT_CHANNEL_ANSWER:
+ {
+ call->setbUUID(switch_event_get_header_nil(event, "Other-Leg-Unique-ID"));
+ _bleg_uuids.insert(switch_event_get_header_nil(event, "Other-Leg-Unique-ID"), uuid);
+ call->setState(FSPHONE_CALL_STATE_ANSWERED);
+ emit answered(uuid);
+ break;
+ }
+ case SWITCH_EVENT_CHANNEL_HANGUP_COMPLETE:
+ {
+ emit hungup(_active_calls.take(uuid));
+ break;
+ }
+ case SWITCH_EVENT_CHANNEL_STATE:
+ {
+ printf("CHANNEL_STATE Answer-State: %s | Channel-State: %s | %s | %s\n", switch_event_get_header_nil(event, "Answer-State"),switch_event_get_header_nil(event, "Channel-State"), uuid.toAscii().constData(), switch_event_get_header_nil(event, "Other-Leg-Unique-ID"));
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+ /* Outbound call */
+ else
+ {
+ switch(event->event_id)
+ {
+ case SWITCH_EVENT_CHANNEL_BRIDGE:
+ {
+ _active_calls.value(uuid)->setbUUID(switch_event_get_header_nil(event, "Other-Leg-Unique-ID"));
+ _bleg_uuids.insert(switch_event_get_header_nil(event, "Other-Leg-Unique-ID"), uuid);
+ break;
+ }
+ case SWITCH_EVENT_CHANNEL_HANGUP_COMPLETE:
+ {
+ if (call->getState() == FSPHONE_CALL_STATE_TRYING)
+ {
+ emit callFailed(uuid);
+ _active_calls.take(uuid);
+ }
+ break;
+ }
+ default:
+ printf("A leg: %s(%s)\n",switch_event_name(event->event_id), switch_event_get_header_nil(event, "Event-Subclass"));
+ break;
+ }
+ }
+ return status;
+}
+
+switch_status_t FSHost::processBlegEvent(switch_event_t * event, QString buuid)
+{
+ QString uuid = _bleg_uuids.value(buuid);
+ switch_status_t status = SWITCH_STATUS_SUCCESS;
+ Call * call = _active_calls.value(uuid);
+ /* Inbound call */
+ if (call->getDirection() == FSPHONE_CALL_DIRECTION_INBOUND)
+ {
+ qDebug() << " Inbound call";
+ }
+ /* Outbound call */
+ else
+ {
+ switch(event->event_id)
+ {
+ case SWITCH_EVENT_CHANNEL_ANSWER:
+ {
+ emit answered(uuid);
+ break;
+ }
+ case SWITCH_EVENT_CHANNEL_HANGUP_COMPLETE:
+ {
+ emit hungup(_active_calls.take(uuid));
+ _bleg_uuids.take(buuid);
+ break;
+ }
+ case SWITCH_EVENT_CHANNEL_STATE:
+ {
+ if (QString(switch_event_get_header_nil(event, "Answer-State")) == "early")
+ {
+ call->setState(FSPHONE_CALL_STATE_RINGING);
+ emit ringing(uuid);
+ }
+ //printEventHeaders(event);
+ break;
+ }
+
+ default:
+ printf("B leg: %s(%s)\n",switch_event_name(event->event_id), switch_event_get_header_nil(event, "Event-Subclass"));
+ break;
+ }
+ }
+ return status;
+}
+
+void FSHost::generalEventHandler(switch_event_t *event)
+{
+ QString uuid = switch_event_get_header_nil(event, "Unique-ID");
+
+ if (_bleg_uuids.contains(uuid))
+ {
+ if (processBlegEvent(event, uuid) == SWITCH_STATUS_SUCCESS)
+ {
+ return;
+ }
+ }
+ if (_active_calls.contains(uuid))
+ {
+ if (processAlegEvent(event, uuid) == SWITCH_STATUS_SUCCESS)
+ {
+ return;
+ }
+ }
+
+ /* This is how we identify new calls, inbound and outbound */
+ switch(event->event_id) {
+ case SWITCH_EVENT_CUSTOM:
+ {
+ if (strcmp(event->subclass_name, "portaudio::ringing") == 0 && !_active_calls.contains(uuid))
+ {
+ Call *call = new Call(atoi(switch_event_get_header_nil(event, "call_id")),
+ switch_event_get_header_nil(event, "Caller-Caller-ID-Name"),
+ switch_event_get_header_nil(event, "Caller-Caller-ID-Number"),
+ FSPHONE_CALL_DIRECTION_INBOUND,
+ uuid);
+ _active_calls.insert(uuid, call);
+ call->setState(FSPHONE_CALL_STATE_RINGING);
+ emit ringing(uuid);
+ }
+ else if (strcmp(event->subclass_name, "portaudio::makecall") == 0)
+ {
+ Call *call = new Call(atoi(switch_event_get_header_nil(event, "call_id")),NULL,
+ switch_event_get_header_nil(event, "Caller-Destination-Number"),
+ FSPHONE_CALL_DIRECTION_OUTBOUND,
+ uuid);
+ _active_calls.insert(uuid, call);
+ call->setState(FSPHONE_CALL_STATE_TRYING);
+ emit newOutgoingCall(uuid);
+ }
+ else if (strcmp(event->subclass_name, "sofia::gateway_state") == 0)
+ {
+ QString state = switch_event_get_header_nil(event, "State");
+ QString gw = switch_event_get_header_nil(event, "Gateway");
+ if (state == "TRYING")
+ emit gwStateChange(gw, FSPHONE_GW_STATE_TRYING);
+ else if (state == "REGISTER")
+ emit gwStateChange(gw, FSPHONE_GW_STATE_REGISTER);
+ else if (state == "REGED")
+ emit gwStateChange(gw, FSPHONE_GW_STATE_REGED);
+ else if (state == "UNREGED")
+ emit gwStateChange(gw, FSPHONE_GW_STATE_UNREGED);
+ else if (state == "UNREGISTER")
+ emit gwStateChange(gw, FSPHONE_GW_STATE_UNREGISTER);
+ else if (state =="FAILED")
+ emit gwStateChange(gw, FSPHONE_GW_STATE_FAILED);
+ else if (state == "FAIL_WAIT")
+ emit gwStateChange(gw, FSPHONE_GW_STATE_FAIL_WAIT);
+ else if (state == "EXPIRED")
+ emit gwStateChange(gw, FSPHONE_GW_STATE_EXPIRED);
+ else if (state == "NOREG")
+ emit gwStateChange(gw, FSPHONE_GW_STATE_NOREG);
+ }
+ else
+ {
+ //printf("We got a not treated custom event: %s\n", (!zstr(event->subclass_name) ? event->subclass_name : "NULL"));
+ }
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+switch_status_t FSHost::sendCmd(const char *cmd, const char *args, QString *res)
+{
+ switch_status_t status = SWITCH_STATUS_FALSE;
+ switch_stream_handle_t stream = { 0 };
+ SWITCH_STANDARD_STREAM(stream);
+ status = switch_api_execute(cmd, args, NULL, &stream);
+ *res = switch_str_nil((char *) stream.data);
+
+ return status;
+}
+
+void FSHost::printEventHeaders(switch_event_t *event)
+{
+ switch_event_header_t *hp;
+ printf("Received event: %s(%s)\n", switch_event_name(event->event_id), switch_event_get_header_nil(event, "Event-Subclass"));
+ for (hp = event->headers; hp; hp = hp->next) {
+ printf("%s=%s\n", hp->name, hp->value);
+ }
+ printf("\n\n");
+}
--- /dev/null
+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005-2009, Anthony Minessale II <anthm@freeswitch.org>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthm@freeswitch.org>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Joao Mesquita <jmesquita@freeswitch.org>
+ *
+ */
+#ifndef FSHOST_H
+#define FSHOST_H
+
+#include <QThread>
+#include <QHash>
+#include <switch.h>
+
+class Call;
+
+#define FSPHONE_GW_STATE_TRYING 0
+#define FSPHONE_GW_STATE_REGISTER 1
+#define FSPHONE_GW_STATE_REGED 2
+#define FSPHONE_GW_STATE_UNREGED 3
+#define FSPHONE_GW_STATE_UNREGISTER 4
+#define FSPHONE_GW_STATE_FAILED 5
+#define FSPHONE_GW_STATE_FAIL_WAIT 6
+#define FSPHONE_GW_STATE_EXPIRED 7
+#define FSPHONE_GW_STATE_NOREG 8
+
+static const char *fsphone_gw_state_names[] = {
+ "TRYING",
+ "REGISTER",
+ "REGED",
+ "UNREGED",
+ "UNREGISTER",
+ "FAILED",
+ "FAIL_WAIT",
+ "EXPIRED",
+ "NOREG"
+};
+
+class FSHost : public QThread
+{
+Q_OBJECT
+public:
+ explicit FSHost(QObject *parent = 0);
+ switch_status_t sendCmd(const char *cmd, const char *args, QString *res);
+ void generalEventHandler(switch_event_t *event);
+ Call * getCallByUUID(QString uuid) { return _active_calls.value(uuid, NULL); }
+ QString getGwStateName(int id) { return fsphone_gw_state_names[id]; }
+
+protected:
+ void run(void);
+
+signals:
+ void coreLoadingError(QString);
+ void ready(void);
+ void ringing(QString);
+ void answered(QString);
+ void newOutgoingCall(QString);
+ void callFailed(QString);
+ void hungup(Call*);
+ void gwStateChange(QString, int);
+
+private:
+ switch_status_t processBlegEvent(switch_event_t *, QString);
+ switch_status_t processAlegEvent(switch_event_t *, QString);
+ void printEventHeaders(switch_event_t *event);
+ QHash<QString, Call*> _active_calls;
+ QHash<QString, QString> _bleg_uuids;
+};
+
+extern FSHost g_FSHost;
+
+/*
+ Used to match callback from fs core. We dup the event and call the class
+ method callback to make use of the signal/slot infrastructure.
+*/
+static void eventHandlerCallback(switch_event_t *event)
+{
+ switch_event_t *clone = NULL;
+ if (switch_event_dup(&clone, event) == SWITCH_STATUS_SUCCESS) {
+ g_FSHost.generalEventHandler(clone);
+ }
+ switch_safe_free(clone);
+}
+
+#endif // FSHOST_H
--- /dev/null
+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005-2009, Anthony Minessale II <anthm@freeswitch.org>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthm@freeswitch.org>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Joao Mesquita <jmesquita@freeswitch.org>
+ *
+ */
+
+#include <QtGui/QApplication>
+#include <QSplashScreen>
+#include "mainwindow.h"
+
+int main(int argc, char *argv[])
+{
+ QApplication a(argc, argv);
+ QCoreApplication::setOrganizationName("FreeSWITCH");
+ QCoreApplication::setOrganizationDomain("freeswitch.org");
+ QCoreApplication::setApplicationName("FSPhone");
+
+ QPixmap image(":/images/splash.png");
+ QSplashScreen *splash = new QSplashScreen(image);
+ splash->show();
+ splash->showMessage("Loading, please wait...", Qt::AlignRight|Qt::AlignBottom, Qt::blue);
+
+ QObject::connect(&g_FSHost, SIGNAL(ready()), splash, SLOT(close()));
+ MainWindow w;
+ QObject::connect(&g_FSHost, SIGNAL(ready()), &w, SLOT(show()));
+ g_FSHost.start();
+ return a.exec();
+}
--- /dev/null
+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005-2009, Anthony Minessale II <anthm@freeswitch.org>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthm@freeswitch.org>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Joao Mesquita <jmesquita@freeswitch.org>
+ *
+ */
+
+#include <QInputDialog>
+#include <QMessageBox>
+#include "mainwindow.h"
+#include "ui_mainwindow.h"
+
+MainWindow::MainWindow(QWidget *parent) :
+ QMainWindow(parent),
+ ui(new Ui::MainWindow),
+ preferences(NULL)
+{
+ ui->setupUi(this);
+
+ dialpadMapper = new QSignalMapper(this);
+ connect(ui->dtmf0Btn, SIGNAL(clicked()), dialpadMapper, SLOT(map()));
+ connect(ui->dtmf1Btn, SIGNAL(clicked()), dialpadMapper, SLOT(map()));
+ connect(ui->dtmf2Btn, SIGNAL(clicked()), dialpadMapper, SLOT(map()));
+ connect(ui->dtmf3Btn, SIGNAL(clicked()), dialpadMapper, SLOT(map()));
+ connect(ui->dtmf4Btn, SIGNAL(clicked()), dialpadMapper, SLOT(map()));
+ connect(ui->dtmf5Btn, SIGNAL(clicked()), dialpadMapper, SLOT(map()));
+ connect(ui->dtmf6Btn, SIGNAL(clicked()), dialpadMapper, SLOT(map()));
+ connect(ui->dtmf7Btn, SIGNAL(clicked()), dialpadMapper, SLOT(map()));
+ connect(ui->dtmf8Btn, SIGNAL(clicked()), dialpadMapper, SLOT(map()));
+ connect(ui->dtmf9Btn, SIGNAL(clicked()), dialpadMapper, SLOT(map()));
+ connect(ui->dtmfABtn, SIGNAL(clicked()), dialpadMapper, SLOT(map()));
+ connect(ui->dtmfBBtn, SIGNAL(clicked()), dialpadMapper, SLOT(map()));
+ connect(ui->dtmfCBtn, SIGNAL(clicked()), dialpadMapper, SLOT(map()));
+ connect(ui->dtmfDBtn, SIGNAL(clicked()), dialpadMapper, SLOT(map()));
+ connect(ui->dtmfAstBtn, SIGNAL(clicked()), dialpadMapper, SLOT(map()));
+ connect(ui->dtmfPoundBtn, SIGNAL(clicked()), dialpadMapper, SLOT(map()));
+ dialpadMapper->setMapping(ui->dtmf0Btn, QString("0"));
+ dialpadMapper->setMapping(ui->dtmf1Btn, QString("1"));
+ dialpadMapper->setMapping(ui->dtmf2Btn, QString("2"));
+ dialpadMapper->setMapping(ui->dtmf3Btn, QString("3"));
+ dialpadMapper->setMapping(ui->dtmf4Btn, QString("4"));
+ dialpadMapper->setMapping(ui->dtmf5Btn, QString("5"));
+ dialpadMapper->setMapping(ui->dtmf6Btn, QString("6"));
+ dialpadMapper->setMapping(ui->dtmf7Btn, QString("7"));
+ dialpadMapper->setMapping(ui->dtmf8Btn, QString("8"));
+ dialpadMapper->setMapping(ui->dtmf9Btn, QString("9"));
+ dialpadMapper->setMapping(ui->dtmfABtn, QString("A"));
+ dialpadMapper->setMapping(ui->dtmfBBtn, QString("B"));
+ dialpadMapper->setMapping(ui->dtmfCBtn, QString("C"));
+ dialpadMapper->setMapping(ui->dtmfDBtn, QString("D"));
+ dialpadMapper->setMapping(ui->dtmfAstBtn, QString("*"));
+ dialpadMapper->setMapping(ui->dtmfPoundBtn, QString("#"));
+ connect(dialpadMapper, SIGNAL(mapped(QString)), this, SLOT(dialDTMF(QString)));
+
+ connect(&g_FSHost, SIGNAL(ready()),this, SLOT(fshostReady()));
+ connect(&g_FSHost, SIGNAL(ringing(QString)), this, SLOT(ringing(QString)));
+ connect(&g_FSHost, SIGNAL(answered(QString)), this, SLOT(answered(QString)));
+ connect(&g_FSHost, SIGNAL(hungup(Call*)), this, SLOT(hungup(Call*)));
+ connect(&g_FSHost, SIGNAL(newOutgoingCall(QString)), this, SLOT(newOutgoingCall(QString)));
+ connect(&g_FSHost, SIGNAL(gwStateChange(QString,int)), this, SLOT(gwStateChanged(QString,int)));
+ /*connect(&g_FSHost, SIGNAL(coreLoadingError(QString)), this, SLOT(coreLoadingError(QString)));*/
+
+ connect(ui->newCallBtn, SIGNAL(clicked()), this, SLOT(makeCall()));
+ connect(ui->answerBtn, SIGNAL(clicked()), this, SLOT(paAnswer()));
+ connect(ui->hangupBtn, SIGNAL(clicked()), this, SLOT(paHangup()));
+ connect(ui->listCalls, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(callListDoubleClick(QListWidgetItem*)));
+ connect(ui->action_Preferences, SIGNAL(triggered()), this, SLOT(prefTriggered()));
+ connect(ui->action_Exit, SIGNAL(triggered()), this, SLOT(close()));
+}
+
+MainWindow::~MainWindow()
+{
+ delete ui;
+ QString res;
+ g_FSHost.sendCmd("fsctl", "shutdown", &res);
+ g_FSHost.wait();
+}
+
+void MainWindow::prefTriggered()
+{
+ if (!preferences)
+ preferences = new PrefDialog();
+
+ preferences->raise();
+ preferences->show();
+ preferences->activateWindow();
+}
+
+void MainWindow::coreLoadingError(QString err)
+{
+ QMessageBox::warning(this, "Error Loading Core...", err, QMessageBox::Ok);
+ QApplication::exit(255);
+}
+
+void MainWindow::gwStateChanged(QString gw, int state)
+{
+ ui->statusBar->showMessage(tr("Account %1 is %2").arg(gw, g_FSHost.getGwStateName(state)));
+
+ /* TODO: This should be placed somewhere else when the config handler is here... */
+ QList<QTableWidgetItem *> match = ui->tableAccounts->findItems(gw, Qt::MatchExactly);
+ if (match.isEmpty())
+ {
+ /* Create the damn thing */
+ ui->tableAccounts->setRowCount(ui->tableAccounts->rowCount()+1);
+ QTableWidgetItem *gwField = new QTableWidgetItem(gw);
+ QTableWidgetItem *stField = new QTableWidgetItem(g_FSHost.getGwStateName(state));
+ ui->tableAccounts->setItem(0,0,gwField);
+ ui->tableAccounts->setItem(0,1,stField);
+ ui->tableAccounts->resizeColumnsToContents();
+ return;
+ }
+
+ QTableWidgetItem *gwField = match.at(0);
+ QTableWidgetItem *stField = ui->tableAccounts->item(gwField->row(),1);
+ stField->setText(g_FSHost.getGwStateName(state));
+ ui->tableAccounts->resizeColumnsToContents();
+
+}
+
+void MainWindow::dialDTMF(QString dtmf)
+{
+ QString result;
+ QString dtmf_string = QString("dtmf %1").arg(dtmf);
+ if (g_FSHost.sendCmd("pa", dtmf_string.toAscii(), &result) == SWITCH_STATUS_FALSE) {
+ ui->textEdit->setText("Error sending that command");
+ }
+}
+
+void MainWindow::callListDoubleClick(QListWidgetItem *item)
+{
+ Call *call = g_FSHost.getCallByUUID(item->data(Qt::UserRole).toString());
+ QString switch_str = QString("switch %1").arg(call->getCallID());
+ QString result;
+ if (g_FSHost.sendCmd("pa", switch_str.toAscii(), &result) == SWITCH_STATUS_FALSE) {
+ ui->textEdit->setText(QString("Error switching to call %1").arg(call->getCallID()));
+ return;
+ }
+ ui->hangupBtn->setEnabled(true);
+}
+
+void MainWindow::makeCall()
+{
+ bool ok;
+ QString dialstring = QInputDialog::getText(this, tr("Make new call"),
+ tr("Number to dial:"), QLineEdit::Normal, NULL,&ok);
+
+ if (ok && !dialstring.isEmpty())
+ {
+ paCall(dialstring);
+ }
+}
+
+void MainWindow::fshostReady()
+{
+ ui->statusBar->showMessage("Ready");
+ ui->newCallBtn->setEnabled(true);
+ ui->textEdit->setEnabled(true);
+ ui->textEdit->setText("Ready to dial and receive calls!");
+}
+
+void MainWindow::paAnswer()
+{
+ QString result;
+ if (g_FSHost.sendCmd("pa", "answer", &result) == SWITCH_STATUS_FALSE) {
+ ui->textEdit->setText("Error sending that command");
+ }
+
+ ui->textEdit->setText("Talking...");
+ ui->hangupBtn->setEnabled(true);
+ ui->answerBtn->setEnabled(false);
+}
+
+void MainWindow::paCall(QString dialstring)
+{
+ QString result;
+
+ QString callstring = QString("call %1").arg(dialstring);
+
+ if (g_FSHost.sendCmd("pa", callstring.toAscii(), &result) == SWITCH_STATUS_FALSE) {
+ ui->textEdit->setText("Error sending that command");
+ }
+
+ ui->hangupBtn->setEnabled(true);
+}
+
+void MainWindow::paHangup()
+{
+ QString result;
+ if (g_FSHost.sendCmd("pa", "hangup", &result) == SWITCH_STATUS_FALSE) {
+ ui->textEdit->setText("Error sending that command");
+ }
+
+ ui->textEdit->setText("Click to dial number...");
+ ui->statusBar->showMessage("Call hungup");
+ ui->hangupBtn->setEnabled(false);
+}
+
+void MainWindow::newOutgoingCall(QString uuid)
+{
+ Call *call = g_FSHost.getCallByUUID(uuid);
+ ui->textEdit->setText(QString("Calling %1 (%2)").arg(call->getCidName(), call->getCidNumber()));
+ QListWidgetItem *item = new QListWidgetItem(tr("%1 (%2) - Calling").arg(call->getCidName(), call->getCidNumber()));
+ item->setData(Qt::UserRole, uuid);
+ ui->listCalls->addItem(item);
+ ui->hangupBtn->setEnabled(true);
+}
+
+void MainWindow::ringing(QString uuid)
+{
+
+ Call *call = g_FSHost.getCallByUUID(uuid);
+ for (int i=0; i<ui->listCalls->count(); i++)
+ {
+ QListWidgetItem *item = ui->listCalls->item(i);
+ if (item->data(Qt::UserRole).toString() == uuid)
+ {
+ item->setText(tr("%1 - Ringing").arg(call->getCidNumber()));
+ ui->textEdit->setText(QString("Call from %1 (%2)").arg(call->getCidName(), call->getCidNumber()));
+ return;
+ }
+ }
+
+ ui->textEdit->setText(QString("Call from %1 (%2)").arg(call->getCidName(), call->getCidNumber()));
+ QListWidgetItem *item = new QListWidgetItem(tr("%1 (%2) - Ringing").arg(call->getCidName(), call->getCidNumber()));
+ item->setData(Qt::UserRole, uuid);
+ ui->listCalls->addItem(item);
+ ui->answerBtn->setEnabled(true);
+}
+
+void MainWindow::answered(QString uuid)
+{
+ Call *call = g_FSHost.getCallByUUID(uuid);
+ for (int i=0; i<ui->listCalls->count(); i++)
+ {
+ QListWidgetItem *item = ui->listCalls->item(i);
+ if (item->data(Qt::UserRole).toString() == uuid)
+ {
+ if (call->getDirection() == FSPHONE_CALL_DIRECTION_INBOUND)
+ {
+ item->setText(tr("%1 (%2) - Active").arg(call->getCidName(), call->getCidNumber()));
+ break;
+ }
+ else
+ {
+ item->setText(tr("%1 - Active").arg(call->getCidNumber()));
+ break;
+ }
+ }
+ }
+ ui->dtmf0Btn->setEnabled(true);
+ ui->dtmf1Btn->setEnabled(true);
+ ui->dtmf2Btn->setEnabled(true);
+ ui->dtmf3Btn->setEnabled(true);
+ ui->dtmf4Btn->setEnabled(true);
+ ui->dtmf5Btn->setEnabled(true);
+ ui->dtmf6Btn->setEnabled(true);
+ ui->dtmf7Btn->setEnabled(true);
+ ui->dtmf8Btn->setEnabled(true);
+ ui->dtmf9Btn->setEnabled(true);
+ ui->dtmfABtn->setEnabled(true);
+ ui->dtmfBBtn->setEnabled(true);
+ ui->dtmfCBtn->setEnabled(true);
+ ui->dtmfDBtn->setEnabled(true);
+ ui->dtmfAstBtn->setEnabled(true);
+ ui->dtmfPoundBtn->setEnabled(true);
+}
+
+void MainWindow::hungup(Call* call)
+{
+ for (int i=0; i<ui->listCalls->count(); i++)
+ {
+ QListWidgetItem *item = ui->listCalls->item(i);
+ if (item->data(Qt::UserRole).toString() == call->getUUID())
+ {
+ delete ui->listCalls->takeItem(i);
+ break;
+ }
+ }
+ ui->textEdit->setText(tr("Call with %1 (%2) hungup.").arg(call->getCidName(), call->getCidNumber()));
+ /* TODO: Will cause problems if 2 calls are received at the same time */
+ ui->answerBtn->setEnabled(false);
+ ui->hangupBtn->setEnabled(false);
+ ui->dtmf0Btn->setEnabled(false);
+ ui->dtmf1Btn->setEnabled(false);
+ ui->dtmf2Btn->setEnabled(false);
+ ui->dtmf3Btn->setEnabled(false);
+ ui->dtmf4Btn->setEnabled(false);
+ ui->dtmf5Btn->setEnabled(false);
+ ui->dtmf6Btn->setEnabled(false);
+ ui->dtmf7Btn->setEnabled(false);
+ ui->dtmf8Btn->setEnabled(false);
+ ui->dtmf9Btn->setEnabled(false);
+ ui->dtmfABtn->setEnabled(false);
+ ui->dtmfBBtn->setEnabled(false);
+ ui->dtmfCBtn->setEnabled(false);
+ ui->dtmfDBtn->setEnabled(false);
+ ui->dtmfAstBtn->setEnabled(false);
+ ui->dtmfPoundBtn->setEnabled(false);
+ delete call;
+}
+
+void MainWindow::changeEvent(QEvent *e)
+{
+ QMainWindow::changeEvent(e);
+ switch (e->type()) {
+ case QEvent::LanguageChange:
+ ui->retranslateUi(this);
+ break;
+ default:
+ break;
+ }
+}
--- /dev/null
+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005-2009, Anthony Minessale II <anthm@freeswitch.org>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthm@freeswitch.org>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Joao Mesquita <jmesquita@freeswitch.org>
+ *
+ */
+
+
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include <QMainWindow>
+#include <QListWidgetItem>
+#include <QSignalMapper>
+#include <switch.h>
+#include <fshost.h>
+#include <call.h>
+#include <prefdialog.h>
+
+namespace Ui {
+ class MainWindow;
+}
+
+class MainWindow : public QMainWindow {
+ Q_OBJECT
+public:
+ MainWindow(QWidget *parent = 0);
+ ~MainWindow();
+
+protected:
+ void changeEvent(QEvent *e);
+
+signals:
+ void dtmfDialed(QString);
+
+private slots:
+ void prefTriggered();
+ void coreLoadingError(QString);
+ void gwStateChanged(QString, int);
+ void dialDTMF(QString);
+ void callListDoubleClick(QListWidgetItem *);
+ void makeCall();
+ void fshostReady();
+ void paAnswer();
+ void paCall(QString);
+ void paHangup();
+ void newOutgoingCall(QString);
+ void ringing(QString);
+ void answered(QString);
+ void hungup(Call*);
+
+private:
+ Ui::MainWindow *ui;
+ QSignalMapper *dialpadMapper;
+ PrefDialog *preferences;
+};
+
+#endif // MAINWINDOW_H
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>580</width>
+ <height>563</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>FSPhone - A FreeSWITCH softphone</string>
+ </property>
+ <widget class="QWidget" name="centralWidget">
+ <layout class="QHBoxLayout" name="horizontalLayout_4">
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QTextEdit" name="textEdit">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QPushButton" name="newCallBtn">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>New Call</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QGridLayout" name="gridLayout_2">
+ <item row="0" column="0">
+ <widget class="QPushButton" name="answerBtn">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Answer</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QPushButton" name="hangupBtn">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Hangup</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <widget class="QPushButton" name="dtmf1Btn">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QPushButton" name="dtmf2Btn">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>2</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="2">
+ <widget class="QPushButton" name="dtmf3Btn">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>3</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QPushButton" name="dtmf4Btn">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>4</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QPushButton" name="dtmf5Btn">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>5</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="2">
+ <widget class="QPushButton" name="dtmf6Btn">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>6</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QPushButton" name="dtmf7Btn">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>7</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QPushButton" name="dtmf8Btn">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>8</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="2">
+ <widget class="QPushButton" name="dtmf9Btn">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>9</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QPushButton" name="dtmfAstBtn">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>*</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QPushButton" name="dtmf0Btn">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>0</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="2">
+ <widget class="QPushButton" name="dtmfPoundBtn">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>#</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="3">
+ <widget class="QPushButton" name="dtmfABtn">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>A</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="3">
+ <widget class="QPushButton" name="dtmfBBtn">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>B</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="3">
+ <widget class="QPushButton" name="dtmfDBtn">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>D</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="3">
+ <widget class="QPushButton" name="dtmfCBtn">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>C</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="title">
+ <string>Active Calls</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <widget class="QListWidget" name="listCalls"/>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox_2">
+ <property name="title">
+ <string>Active Accounts</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QTableWidget" name="tableAccounts">
+ <property name="editTriggers">
+ <set>QAbstractItemView::NoEditTriggers</set>
+ </property>
+ <property name="alternatingRowColors">
+ <bool>false</bool>
+ </property>
+ <property name="selectionMode">
+ <enum>QAbstractItemView::NoSelection</enum>
+ </property>
+ <property name="selectionBehavior">
+ <enum>QAbstractItemView::SelectRows</enum>
+ </property>
+ <property name="showGrid">
+ <bool>false</bool>
+ </property>
+ <property name="cornerButtonEnabled">
+ <bool>true</bool>
+ </property>
+ <property name="rowCount">
+ <number>0</number>
+ </property>
+ <attribute name="horizontalHeaderVisible">
+ <bool>true</bool>
+ </attribute>
+ <attribute name="horizontalHeaderCascadingSectionResizes">
+ <bool>false</bool>
+ </attribute>
+ <attribute name="verticalHeaderVisible">
+ <bool>false</bool>
+ </attribute>
+ <attribute name="verticalHeaderHighlightSections">
+ <bool>false</bool>
+ </attribute>
+ <column>
+ <property name="text">
+ <string>Account</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Status</string>
+ </property>
+ </column>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QMenuBar" name="menuBar">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>580</width>
+ <height>22</height>
+ </rect>
+ </property>
+ <widget class="QMenu" name="menu_File">
+ <property name="title">
+ <string>&File</string>
+ </property>
+ <addaction name="action_Preferences"/>
+ <addaction name="separator"/>
+ <addaction name="action_Exit"/>
+ </widget>
+ <addaction name="menu_File"/>
+ </widget>
+ <widget class="QToolBar" name="mainToolBar">
+ <attribute name="toolBarArea">
+ <enum>TopToolBarArea</enum>
+ </attribute>
+ <attribute name="toolBarBreak">
+ <bool>false</bool>
+ </attribute>
+ </widget>
+ <widget class="QStatusBar" name="statusBar"/>
+ <action name="action_Preferences">
+ <property name="text">
+ <string>&Preferences</string>
+ </property>
+ </action>
+ <action name="action_Exit">
+ <property name="text">
+ <string>&Exit</string>
+ </property>
+ </action>
+ </widget>
+ <layoutdefault spacing="6" margin="11"/>
+ <resources/>
+ <connections/>
+</ui>
--- /dev/null
+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005-2009, Anthony Minessale II <anthm@freeswitch.org>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthm@freeswitch.org>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Joao Mesquita <jmesquita@freeswitch.org>
+ *
+ *
+ * Description:
+ * Module to load configurations from Qt preference system QSettings
+ *
+ */
+#include <QString>
+#include <QtGui>
+#include <QDir>
+#include "mod_qsettings/mod_qsettings.h"
+
+static struct {
+ switch_memory_pool_t* pool;
+} globals;
+
+switch_xml_t XMLBinding::getConfigXML(QString tmpl)
+{
+ switch_event_t *e;
+ switch_event_create_plain(&e, SWITCH_EVENT_REQUEST_PARAMS);
+ switch_assert(e);
+
+ QFile tmplFile(QString("%1/templates/%2.xml").arg(QApplication::applicationDirPath(),tmpl));
+
+ if (!tmplFile.exists()) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,
+ "Template %s.xml, doesn't exist on directory, falling back to embedded template.\n",
+ tmpl.toAscii().constData());
+ tmplFile.setFileName(QString(":/confs/%1.xml").arg(tmpl));
+ return NULL;
+ }
+
+ if (tmplFile.open(QIODevice::ReadOnly | QIODevice::Text))
+ {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Template %s could not be read.!\n", tmpl.toAscii().constData());
+ return NULL;
+ }
+
+ /* Open template file and expand all strings based on QSettings */
+ QString tmplContents(tmplFile.readAll());
+ tmplFile.close();
+ _settings->beginGroup("FreeSIWTCH/conf");
+ _settings->beginGroup(tmpl);
+ foreach(QString k, _settings->childKeys())
+ {
+ switch_event_add_header_string(e, SWITCH_STACK_BOTTOM, k.toAscii().constData(), _settings->value(k).toByteArray().constData());
+ }
+
+ char *res = switch_event_expand_headers(e, tmplContents.toAscii().constData());
+ switch_safe_free(e);
+ return switch_xml_parse_str(res, strlen(res));
+}
+
+static switch_xml_t xml_url_fetch(const char *section, const char *tag_name, const char *key_name, const char *key_value, switch_event_t *params,
+ void *user_data)
+{
+ XMLBinding *binding = (XMLBinding *) user_data;
+
+ if (!binding) {
+ return NULL;
+ }
+
+ return binding->getConfigXML(key_value);
+}
+
+static switch_status_t do_config(void)
+{
+ char *cf = "qsettings.conf";
+ switch_xml_t cfg, xml, bindings_tag;
+ XMLBinding *binding = NULL;
+
+ if (!(xml = switch_xml_open_cfg(cf, &cfg, NULL))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "open of %s failed\n", cf);
+ return SWITCH_STATUS_TERM;
+ }
+
+ if (!(bindings_tag = switch_xml_child(cfg, "bindings"))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing <bindings> tag!\n");
+ switch_xml_free(xml);
+ return SWITCH_STATUS_FALSE;
+ }
+
+ QString bind_mask = switch_xml_attr_soft(bindings_tag, "value");
+ if (!bind_mask.isEmpty())
+ {
+ binding = new XMLBinding(bind_mask);
+ }
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Binding XML Fetch Function [%s]\n",
+ binding->getBinding().isEmpty() ? "all" : binding->getBinding().toAscii().constData());
+ switch_xml_bind_search_function(xml_url_fetch, switch_xml_parse_section_string(binding->getBinding().toAscii().constData()), binding);
+ binding = NULL;
+
+ switch_xml_free(xml);
+ return SWITCH_STATUS_SUCCESS;
+}
+
+SWITCH_MODULE_LOAD_FUNCTION(mod_qsettings_load)
+{
+ /*switch_api_interface_t *qsettings_api_interface;*/
+
+ /* connect my internal structure to the blank pointer passed to me */
+ *module_interface = switch_loadable_module_create_module_interface(pool, "mod_qsettings");
+
+ memset(&globals,0,sizeof(globals));
+ globals.pool = pool;
+
+ if (do_config() == SWITCH_STATUS_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Sucessfully configured.\n");
+ } else {
+ return SWITCH_STATUS_FALSE;
+ }
+
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "We loaded mod_qsettings.\n");
+ /* indicate that the module should continue to be loaded */
+ return SWITCH_STATUS_SUCCESS;
+}
+
+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_qsettings_shutdown)
+{
+ switch_xml_unbind_search_function_ptr(xml_url_fetch);
+ return SWITCH_STATUS_SUCCESS;
+}
--- /dev/null
+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005-2009, Anthony Minessale II <anthm@freeswitch.org>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthm@freeswitch.org>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Joao Mesquita <jmesquita@freeswitch.org>
+ *
+ */
+
+#ifndef MOD_QSETTINGS_H
+#define MOD_QSETTINGS_H
+
+#include <QString>
+#include <QSettings>
+#include <switch.h>
+
+SWITCH_MODULE_LOAD_FUNCTION(mod_qsettings_load);
+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_qsettings_shutdown);
+
+class XMLBinding
+{
+public:
+ XMLBinding(QString binding) : _binding(binding), _settings(new QSettings) {}
+ QString getBinding(void) { return _binding; }
+ switch_xml_t getConfigXML(QString);
+private:
+ QString _binding;
+ QSettings* _settings;
+};
+
+#endif // MOD_QSETTINGS_H
--- /dev/null
+#include <QtGui>
+#include "prefdialog.h"
+#include "ui_prefdialog.h"
+
+PrefDialog::PrefDialog(QWidget *parent) :
+ QDialog(parent),
+ ui(new Ui::PrefDialog)
+{
+ ui->setupUi(this);
+ getPaDevlist();
+}
+
+PrefDialog::~PrefDialog()
+{
+ delete ui;
+}
+
+void PrefDialog::getPaDevlist()
+{
+ QString result;
+ int errorLine, errorColumn;
+ QString errorMsg;
+
+ if (g_FSHost.sendCmd("pa", "devlist xml", &result) != SWITCH_STATUS_SUCCESS)
+ {
+ QMessageBox::critical(this, tr("PortAudio error" ),
+ tr("Error querying audio devices."),
+ QMessageBox::Ok);
+ return;
+ }
+
+ if (!_xmlPaDevList.setContent(result, &errorMsg, &errorLine, &errorColumn))
+ {
+ QMessageBox::critical(this, tr("PortAudio error" ),
+ tr("Error parsing output xml from pa devlist.\n%1 (Line:%2, Col:%3).").arg(errorMsg,
+ errorLine,
+ errorColumn),
+ QMessageBox::Ok);
+ return;
+ }
+ QDomElement root = _xmlPaDevList.documentElement();
+ if (root.tagName() != "xml")
+ {
+ QMessageBox::critical(this, tr("PortAudio error" ),
+ tr("Error parsing output xml from pa devlist. Root tag is not <xml>."),
+ QMessageBox::Ok);
+ return;
+ }
+ QDomElement devices = root.firstChildElement("devices");
+ if (devices.isNull())
+ {
+ QMessageBox::critical(this, tr("PortAudio error" ),
+ tr("Error parsing output xml from pa devlist. There is no <devices> tag."),
+ QMessageBox::Ok);
+ return;
+ }
+
+ QDomElement child = devices.firstChildElement();
+ if (child.isNull())
+ {
+ QMessageBox::critical(this, tr("PortAudio error" ),
+ tr("Error parsing output xml from pa devlist. There is no <device> tag."),
+ QMessageBox::Ok);
+ return;
+ }
+
+ while (!child.isNull())
+ {
+ if (child.tagName() == "device")
+ {
+ QString id, name, inputs, outputs;
+ id = child.attribute("id","-1");
+ name = child.attribute("name","Null");
+ inputs = child.attribute("inputs","0");
+ outputs = child.attribute("outputs","0");
+ if (inputs.toInt() != 0)
+ ui->PaIndevCombo->addItem(name,inputs.toInt());
+ if (outputs.toInt() != 0)
+ {
+ ui->PaOutdevCombo->addItem(name,inputs.toInt());
+ ui->PaRingdevCombo->addItem(name,inputs.toInt());
+ }
+ }
+ child = child.nextSiblingElement();
+ }
+
+ QDomElement bindings = root.firstChildElement("bindings");
+ if (bindings.isNull())
+ {
+ QMessageBox::critical(this, tr("PortAudio error" ),
+ tr("Error parsing output xml from pa devlist. There is no <bindings> tag."),
+ QMessageBox::Ok);
+ return;
+ }
+
+ child = devices.firstChildElement();
+ if (child.isNull())
+ {
+ QMessageBox::critical(this, tr("PortAudio error" ),
+ tr("Error parsing output xml from pa devlist. There are no bindings."),
+ QMessageBox::Ok);
+ return;
+ }
+
+ while (!child.isNull())
+ {
+ QString id;
+ id = child.attribute("device","-1");
+
+ if (child.tagName() == "ring")
+ ui->PaRingdevCombo->setCurrentIndex(id.toInt());
+ else if (child.tagName() == "input")
+ ui->PaIndevCombo->setCurrentIndex(id.toInt());
+ else if (child.tagName() == "ring")
+ ui->PaOutdevCombo->setCurrentIndex(id.toInt());
+
+ child = child.nextSiblingElement();
+ }
+
+}
+
+void PrefDialog::changeEvent(QEvent *e)
+{
+ QDialog::changeEvent(e);
+ switch (e->type()) {
+ case QEvent::LanguageChange:
+ ui->retranslateUi(this);
+ break;
+ default:
+ break;
+ }
+}
--- /dev/null
+#ifndef PREFDIALOG_H
+#define PREFDIALOG_H
+
+#include <QDialog>
+#include <QDomDocument>
+#include <fshost.h>
+
+namespace Ui {
+ class PrefDialog;
+}
+
+class PrefDialog : public QDialog {
+ Q_OBJECT
+public:
+ PrefDialog(QWidget *parent = 0);
+ ~PrefDialog();
+
+protected:
+ void changeEvent(QEvent *e);
+
+private:
+ void getPaDevlist(void);
+ Ui::PrefDialog *ui;
+ QDomDocument _xmlPaDevList;
+};
+
+#endif // PREFDIALOG_H
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>PrefDialog</class>
+ <widget class="QDialog" name="PrefDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>477</width>
+ <height>356</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Preferences</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QListWidget" name="listSections">
+ <property name="minimumSize">
+ <size>
+ <width>120</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>120</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="showDropIndicator" stdset="0">
+ <bool>false</bool>
+ </property>
+ <property name="dragDropMode">
+ <enum>QAbstractItemView::NoDragDrop</enum>
+ </property>
+ <property name="iconSize">
+ <size>
+ <width>96</width>
+ <height>84</height>
+ </size>
+ </property>
+ <property name="movement">
+ <enum>QListView::Static</enum>
+ </property>
+ <property name="flow">
+ <enum>QListView::LeftToRight</enum>
+ </property>
+ <property name="isWrapping" stdset="0">
+ <bool>true</bool>
+ </property>
+ <property name="spacing">
+ <number>12</number>
+ </property>
+ <property name="viewMode">
+ <enum>QListView::IconMode</enum>
+ </property>
+ <item>
+ <property name="text">
+ <string>Sofia</string>
+ </property>
+ <property name="icon">
+ <iconset resource="resources.qrc">
+ <normaloff>:/images/pref_sip.png</normaloff>:/images/pref_sip.png</iconset>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>PortAudio</string>
+ </property>
+ <property name="icon">
+ <iconset resource="resources.qrc">
+ <normaloff>:/images/pref_audio.gif</normaloff>:/images/pref_audio.gif</iconset>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item>
+ <widget class="QStackedWidget" name="stackedWidget">
+ <property name="currentIndex">
+ <number>1</number>
+ </property>
+ <widget class="QWidget" name="page">
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="title">
+ <string>Global Settings</string>
+ </property>
+ <layout class="QFormLayout" name="formLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>log-level</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QSpinBox" name="spinBox"/>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>auto-restart</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QComboBox" name="comboBox"/>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>debug-presence</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QSpinBox" name="spinBox_2"/>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox_2">
+ <property name="title">
+ <string>Softphone Profile</string>
+ </property>
+ <layout class="QFormLayout" name="formLayout_2">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_4">
+ <property name="text">
+ <string>user-agent-string</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="lineEdit"/>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_5">
+ <property name="text">
+ <string>debug</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QSpinBox" name="spinBox_3"/>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_6">
+ <property name="text">
+ <string>sip-trace</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QComboBox" name="comboBox_2"/>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="page_2">
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QGroupBox" name="groupBox_3">
+ <property name="title">
+ <string>Devices</string>
+ </property>
+ <widget class="QLabel" name="label_7">
+ <property name="geometry">
+ <rect>
+ <x>72</x>
+ <y>34</y>
+ <width>34</width>
+ <height>17</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>indev</string>
+ </property>
+ </widget>
+ <widget class="QComboBox" name="PaIndevCombo">
+ <property name="geometry">
+ <rect>
+ <x>111</x>
+ <y>32</y>
+ <width>111</width>
+ <height>26</height>
+ </rect>
+ </property>
+ </widget>
+ <widget class="QLabel" name="label_8">
+ <property name="geometry">
+ <rect>
+ <x>63</x>
+ <y>64</y>
+ <width>43</width>
+ <height>17</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>outdev</string>
+ </property>
+ </widget>
+ <widget class="QComboBox" name="PaOutdevCombo">
+ <property name="geometry">
+ <rect>
+ <x>111</x>
+ <y>62</y>
+ <width>111</width>
+ <height>26</height>
+ </rect>
+ </property>
+ </widget>
+ <widget class="QLabel" name="label_9">
+ <property name="geometry">
+ <rect>
+ <x>59</x>
+ <y>94</y>
+ <width>47</width>
+ <height>17</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>rindgev</string>
+ </property>
+ </widget>
+ <widget class="QComboBox" name="PaRingdevCombo">
+ <property name="geometry">
+ <rect>
+ <x>111</x>
+ <y>92</y>
+ <width>111</width>
+ <height>26</height>
+ </rect>
+ </property>
+ </widget>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox_4">
+ <property name="title">
+ <string>Files</string>
+ </property>
+ <layout class="QFormLayout" name="formLayout_3">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_10">
+ <property name="text">
+ <string>ring-file</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="lineEdit_2">
+ <property name="text">
+ <string>tone_stream://%(2000,4000,440.0,480.0);loops=20</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_12">
+ <property name="text">
+ <string>ring-interval</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QSpinBox" name="spinBox_4"/>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_11">
+ <property name="text">
+ <string>hold-file</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLineEdit" name="lineEdit_3"/>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources>
+ <include location="resources.qrc"/>
+ </resources>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>PrefDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>544</x>
+ <y>224</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>246</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>PrefDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>544</x>
+ <y>230</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>246</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>listSections</sender>
+ <signal>currentRowChanged(int)</signal>
+ <receiver>stackedWidget</receiver>
+ <slot>setCurrentIndex(int)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>180</x>
+ <y>83</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>524</x>
+ <y>102</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
--- /dev/null
+<RCC>
+ <qresource prefix="/images">
+ <file alias="splash.png">resources/splash.png</file>
+ <file alias="pref_sip.png">resources/pref_sip.png</file>
+ <file alias="pref_audio.gif">resources/pref_audio.gif</file>
+ </qresource>
+ <qresource prefix="/confs">
+ <file alias="freeswitch.xml">conf/freeswitch.xml</file>
+ <file alias="example.xml">conf/accounts/example.xml</file>
+ <file alias="event_socket.conf.xml">conf/event_socket.conf.xml</file>
+ <file alias="portaudio.conf.xml">conf/portaudio.conf.xml</file>
+ </qresource>
+</RCC>