]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
Let there be PHONE CALLS!
authorBrian West <brian@freeswitch.org>
Mon, 4 Jan 2010 20:49:22 +0000 (20:49 +0000)
committerBrian West <brian@freeswitch.org>
Mon, 4 Jan 2010 20:49:22 +0000 (20:49 +0000)
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@16142 d0543943-73ff-0310-b7d9-9358b9ac24b2

23 files changed:
fscomm/FSPhone.pro [new file with mode: 0644]
fscomm/call.cpp [new file with mode: 0644]
fscomm/call.h [new file with mode: 0644]
fscomm/conf/accounts/example.xml [new file with mode: 0644]
fscomm/conf/event_socket.conf.xml [new file with mode: 0644]
fscomm/conf/freeswitch.serial [new file with mode: 0644]
fscomm/conf/freeswitch.xml [new file with mode: 0644]
fscomm/conf/portaudio.conf.xml [new file with mode: 0644]
fscomm/fshost.cpp [new file with mode: 0644]
fscomm/fshost.h [new file with mode: 0644]
fscomm/main.cpp [new file with mode: 0644]
fscomm/mainwindow.cpp [new file with mode: 0644]
fscomm/mainwindow.h [new file with mode: 0644]
fscomm/mainwindow.ui [new file with mode: 0644]
fscomm/mod_qsettings/mod_qsettings.cpp [new file with mode: 0644]
fscomm/mod_qsettings/mod_qsettings.h [new file with mode: 0644]
fscomm/prefdialog.cpp [new file with mode: 0644]
fscomm/prefdialog.h [new file with mode: 0644]
fscomm/prefdialog.ui [new file with mode: 0644]
fscomm/resources.qrc [new file with mode: 0644]
fscomm/resources/pref_audio.gif [new file with mode: 0644]
fscomm/resources/pref_sip.png [new file with mode: 0644]
fscomm/resources/splash.png [new file with mode: 0644]

diff --git a/fscomm/FSPhone.pro b/fscomm/FSPhone.pro
new file mode 100644 (file)
index 0000000..666c7bb
--- /dev/null
@@ -0,0 +1,40 @@
+# #####################################
+# 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
diff --git a/fscomm/call.cpp b/fscomm/call.cpp
new file mode 100644 (file)
index 0000000..6d16a3f
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * 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)
+{
+}
diff --git a/fscomm/call.h b/fscomm/call.h
new file mode 100644 (file)
index 0000000..3cde874
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * 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
diff --git a/fscomm/conf/accounts/example.xml b/fscomm/conf/accounts/example.xml
new file mode 100644 (file)
index 0000000..f8a6826
--- /dev/null
@@ -0,0 +1,34 @@
+<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>
diff --git a/fscomm/conf/event_socket.conf.xml b/fscomm/conf/event_socket.conf.xml
new file mode 100644 (file)
index 0000000..8f780ec
--- /dev/null
@@ -0,0 +1,8 @@
+<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>
diff --git a/fscomm/conf/freeswitch.serial b/fscomm/conf/freeswitch.serial
new file mode 100644 (file)
index 0000000..1ed5449
Binary files /dev/null and b/fscomm/conf/freeswitch.serial differ
diff --git a/fscomm/conf/freeswitch.xml b/fscomm/conf/freeswitch.xml
new file mode 100644 (file)
index 0000000..d7a382b
--- /dev/null
@@ -0,0 +1,267 @@
+<?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>
+
+
diff --git a/fscomm/conf/portaudio.conf.xml b/fscomm/conf/portaudio.conf.xml
new file mode 100644 (file)
index 0000000..61a1f28
--- /dev/null
@@ -0,0 +1,17 @@
+<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>
diff --git a/fscomm/fshost.cpp b/fscomm/fshost.cpp
new file mode 100644 (file)
index 0000000..d592c44
--- /dev/null
@@ -0,0 +1,352 @@
+/*
+ * 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");
+}
diff --git a/fscomm/fshost.h b/fscomm/fshost.h
new file mode 100644 (file)
index 0000000..c3858cd
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * 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
diff --git a/fscomm/main.cpp b/fscomm/main.cpp
new file mode 100644 (file)
index 0000000..67154bb
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * 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();
+}
diff --git a/fscomm/mainwindow.cpp b/fscomm/mainwindow.cpp
new file mode 100644 (file)
index 0000000..f460b0d
--- /dev/null
@@ -0,0 +1,334 @@
+/*
+ * 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;
+    }
+}
diff --git a/fscomm/mainwindow.h b/fscomm/mainwindow.h
new file mode 100644 (file)
index 0000000..a616664
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * 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
diff --git a/fscomm/mainwindow.ui b/fscomm/mainwindow.ui
new file mode 100644 (file)
index 0000000..700c093
--- /dev/null
@@ -0,0 +1,350 @@
+<?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>&amp;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>&amp;Preferences</string>
+   </property>
+  </action>
+  <action name="action_Exit">
+   <property name="text">
+    <string>&amp;Exit</string>
+   </property>
+  </action>
+ </widget>
+ <layoutdefault spacing="6" margin="11"/>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/fscomm/mod_qsettings/mod_qsettings.cpp b/fscomm/mod_qsettings/mod_qsettings.cpp
new file mode 100644 (file)
index 0000000..b09b305
--- /dev/null
@@ -0,0 +1,149 @@
+/* 
+ * 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;
+}
diff --git a/fscomm/mod_qsettings/mod_qsettings.h b/fscomm/mod_qsettings/mod_qsettings.h
new file mode 100644 (file)
index 0000000..776e3cb
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * 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
diff --git a/fscomm/prefdialog.cpp b/fscomm/prefdialog.cpp
new file mode 100644 (file)
index 0000000..8f842a5
--- /dev/null
@@ -0,0 +1,132 @@
+#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;
+    }
+}
diff --git a/fscomm/prefdialog.h b/fscomm/prefdialog.h
new file mode 100644 (file)
index 0000000..4a73498
--- /dev/null
@@ -0,0 +1,27 @@
+#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
diff --git a/fscomm/prefdialog.ui b/fscomm/prefdialog.ui
new file mode 100644 (file)
index 0000000..68c1683
--- /dev/null
@@ -0,0 +1,376 @@
+<?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>
diff --git a/fscomm/resources.qrc b/fscomm/resources.qrc
new file mode 100644 (file)
index 0000000..992ac3b
--- /dev/null
@@ -0,0 +1,13 @@
+<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>
diff --git a/fscomm/resources/pref_audio.gif b/fscomm/resources/pref_audio.gif
new file mode 100644 (file)
index 0000000..862963b
Binary files /dev/null and b/fscomm/resources/pref_audio.gif differ
diff --git a/fscomm/resources/pref_sip.png b/fscomm/resources/pref_sip.png
new file mode 100644 (file)
index 0000000..7bac856
Binary files /dev/null and b/fscomm/resources/pref_sip.png differ
diff --git a/fscomm/resources/splash.png b/fscomm/resources/splash.png
new file mode 100644 (file)
index 0000000..47e7acb
Binary files /dev/null and b/fscomm/resources/splash.png differ