diff --git a/fscomm/FSPhone.pro b/fscomm/FSPhone.pro new file mode 100644 index 0000000000..666c7bbd09 --- /dev/null +++ b/fscomm/FSPhone.pro @@ -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 index 0000000000..6d16a3fc73 --- /dev/null +++ b/fscomm/call.cpp @@ -0,0 +1,43 @@ +/* + * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * Copyright (C) 2005-2009, Anthony Minessale II + * + * 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 + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Joao Mesquita + * + */ + +#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 index 0000000000..3cde87416b --- /dev/null +++ b/fscomm/call.h @@ -0,0 +1,73 @@ +/* + * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * Copyright (C) 2005-2009, Anthony Minessale II + * + * 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 + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Joao Mesquita + * + */ +#ifndef CALL_H +#define CALL_H + +#include +#include +#include + +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 index 0000000000..f8a682635f --- /dev/null +++ b/fscomm/conf/accounts/example.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/fscomm/conf/event_socket.conf.xml b/fscomm/conf/event_socket.conf.xml new file mode 100644 index 0000000000..8f780ecf8f --- /dev/null +++ b/fscomm/conf/event_socket.conf.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/fscomm/conf/freeswitch.serial b/fscomm/conf/freeswitch.serial new file mode 100644 index 0000000000..1ed5449607 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 index 0000000000..d7a382b136 --- /dev/null +++ b/fscomm/conf/freeswitch.xml @@ -0,0 +1,267 @@ + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + diff --git a/fscomm/conf/portaudio.conf.xml b/fscomm/conf/portaudio.conf.xml new file mode 100644 index 0000000000..61a1f289d3 --- /dev/null +++ b/fscomm/conf/portaudio.conf.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/fscomm/fshost.cpp b/fscomm/fshost.cpp new file mode 100644 index 0000000000..d592c4485b --- /dev/null +++ b/fscomm/fshost.cpp @@ -0,0 +1,352 @@ +/* + * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * Copyright (C) 2005-2009, Anthony Minessale II + * + * 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 + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Joao Mesquita + * + */ + +#include +#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"); + +} + +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 index 0000000000..c3858cd8ed --- /dev/null +++ b/fscomm/fshost.h @@ -0,0 +1,106 @@ +/* + * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * Copyright (C) 2005-2009, Anthony Minessale II + * + * 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 + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Joao Mesquita + * + */ +#ifndef FSHOST_H +#define FSHOST_H + +#include +#include +#include + +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 _active_calls; + QHash _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 index 0000000000..67154bb036 --- /dev/null +++ b/fscomm/main.cpp @@ -0,0 +1,51 @@ +/* + * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * Copyright (C) 2005-2009, Anthony Minessale II + * + * 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 + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Joao Mesquita + * + */ + +#include +#include +#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 index 0000000000..f460b0db8c --- /dev/null +++ b/fscomm/mainwindow.cpp @@ -0,0 +1,334 @@ +/* + * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * Copyright (C) 2005-2009, Anthony Minessale II + * + * 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 + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Joao Mesquita + * + */ + +#include +#include +#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 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; ilistCalls->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; ilistCalls->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; ilistCalls->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 index 0000000000..a6166642d8 --- /dev/null +++ b/fscomm/mainwindow.h @@ -0,0 +1,80 @@ +/* + * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * Copyright (C) 2005-2009, Anthony Minessale II + * + * 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 + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Joao Mesquita + * + */ + + +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include +#include +#include +#include +#include +#include +#include + +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 index 0000000000..700c09358c --- /dev/null +++ b/fscomm/mainwindow.ui @@ -0,0 +1,350 @@ + + + MainWindow + + + + 0 + 0 + 580 + 563 + + + + FSPhone - A FreeSWITCH softphone + + + + + + + + + false + + + true + + + + + + + + + false + + + New Call + + + + + + + + + + + false + + + Answer + + + + + + + false + + + Hangup + + + + + + + + + + + false + + + 1 + + + + + + + false + + + 2 + + + + + + + false + + + 3 + + + + + + + false + + + 4 + + + + + + + false + + + 5 + + + + + + + false + + + 6 + + + + + + + false + + + 7 + + + + + + + false + + + 8 + + + + + + + false + + + 9 + + + + + + + false + + + * + + + + + + + false + + + 0 + + + + + + + false + + + # + + + + + + + false + + + A + + + + + + + false + + + B + + + + + + + false + + + D + + + + + + + false + + + C + + + + + + + + + + + + + Active Calls + + + + + + + + + + + + Active Accounts + + + + + + QAbstractItemView::NoEditTriggers + + + false + + + QAbstractItemView::NoSelection + + + QAbstractItemView::SelectRows + + + false + + + true + + + 0 + + + true + + + false + + + false + + + false + + + + Account + + + + + Status + + + + + + + + + + + + + + + 0 + 0 + 580 + 22 + + + + + &File + + + + + + + + + + TopToolBarArea + + + false + + + + + + &Preferences + + + + + &Exit + + + + + + + diff --git a/fscomm/mod_qsettings/mod_qsettings.cpp b/fscomm/mod_qsettings/mod_qsettings.cpp new file mode 100644 index 0000000000..b09b305fc4 --- /dev/null +++ b/fscomm/mod_qsettings/mod_qsettings.cpp @@ -0,0 +1,149 @@ +/* + * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * Copyright (C) 2005-2009, Anthony Minessale II + * + * 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 + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Joao Mesquita + * + * + * Description: + * Module to load configurations from Qt preference system QSettings + * + */ +#include +#include +#include +#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 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 index 0000000000..776e3cba02 --- /dev/null +++ b/fscomm/mod_qsettings/mod_qsettings.h @@ -0,0 +1,51 @@ +/* + * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * Copyright (C) 2005-2009, Anthony Minessale II + * + * 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 + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Joao Mesquita + * + */ + +#ifndef MOD_QSETTINGS_H +#define MOD_QSETTINGS_H + +#include +#include +#include + +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 index 0000000000..8f842a5c41 --- /dev/null +++ b/fscomm/prefdialog.cpp @@ -0,0 +1,132 @@ +#include +#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 ."), + 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 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 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 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 index 0000000000..4a73498f11 --- /dev/null +++ b/fscomm/prefdialog.h @@ -0,0 +1,27 @@ +#ifndef PREFDIALOG_H +#define PREFDIALOG_H + +#include +#include +#include + +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 index 0000000000..68c1683647 --- /dev/null +++ b/fscomm/prefdialog.ui @@ -0,0 +1,376 @@ + + + PrefDialog + + + + 0 + 0 + 477 + 356 + + + + Preferences + + + + + + + + + 120 + 0 + + + + + 120 + 16777215 + + + + false + + + QAbstractItemView::NoDragDrop + + + + 96 + 84 + + + + QListView::Static + + + QListView::LeftToRight + + + true + + + 12 + + + QListView::IconMode + + + + Sofia + + + + :/images/pref_sip.png:/images/pref_sip.png + + + + + PortAudio + + + + :/images/pref_audio.gif:/images/pref_audio.gif + + + + + + + + 1 + + + + + + + Global Settings + + + + + + log-level + + + + + + + + + + auto-restart + + + + + + + + + + debug-presence + + + + + + + + + + + + + Softphone Profile + + + + + + user-agent-string + + + + + + + + + + debug + + + + + + + + + + sip-trace + + + + + + + + + + + + + + + + + Devices + + + + + 72 + 34 + 34 + 17 + + + + indev + + + + + + 111 + 32 + 111 + 26 + + + + + + + 63 + 64 + 43 + 17 + + + + outdev + + + + + + 111 + 62 + 111 + 26 + + + + + + + 59 + 94 + 47 + 17 + + + + rindgev + + + + + + 111 + 92 + 111 + 26 + + + + + + + + + Files + + + + + + ring-file + + + + + + + tone_stream://%(2000,4000,440.0,480.0);loops=20 + + + + + + + ring-interval + + + + + + + + + + hold-file + + + + + + + + + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + + + + + buttonBox + accepted() + PrefDialog + accept() + + + 544 + 224 + + + 157 + 246 + + + + + buttonBox + rejected() + PrefDialog + reject() + + + 544 + 230 + + + 286 + 246 + + + + + listSections + currentRowChanged(int) + stackedWidget + setCurrentIndex(int) + + + 180 + 83 + + + 524 + 102 + + + + + diff --git a/fscomm/resources.qrc b/fscomm/resources.qrc new file mode 100644 index 0000000000..992ac3b6ff --- /dev/null +++ b/fscomm/resources.qrc @@ -0,0 +1,13 @@ + + + resources/splash.png + resources/pref_sip.png + resources/pref_audio.gif + + + conf/freeswitch.xml + conf/accounts/example.xml + conf/event_socket.conf.xml + conf/portaudio.conf.xml + + diff --git a/fscomm/resources/pref_audio.gif b/fscomm/resources/pref_audio.gif new file mode 100644 index 0000000000..862963bbe8 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 index 0000000000..7bac856858 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 index 0000000000..47e7acb06d Binary files /dev/null and b/fscomm/resources/splash.png differ