2005-07-04 22:04:47 +00:00
|
|
|
/**
|
|
|
|
* Client.cpp
|
|
|
|
* This file is part of the YATE Project http://YATE.null.ro
|
|
|
|
*
|
|
|
|
* Yet Another Telephony Engine - a fully featured software PBX and IVR
|
2006-05-27 15:08:43 +00:00
|
|
|
* Copyright (C) 2004-2006 Null Team
|
2005-07-04 22:04:47 +00:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
2006-05-27 15:08:43 +00:00
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
2005-07-04 22:04:47 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include "yatecbase.h"
|
2006-06-11 12:51:40 +00:00
|
|
|
#include "yateversn.h"
|
2005-07-04 22:04:47 +00:00
|
|
|
|
2005-07-27 18:31:47 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
|
2005-07-04 22:04:47 +00:00
|
|
|
using namespace TelEngine;
|
|
|
|
|
2005-08-13 02:02:55 +00:00
|
|
|
class ClientThreadProxy
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
enum {
|
|
|
|
setVisible,
|
|
|
|
openPopup,
|
|
|
|
hasElement,
|
|
|
|
setShow,
|
|
|
|
setText,
|
|
|
|
setActive,
|
2006-05-29 13:58:09 +00:00
|
|
|
setFocus,
|
2005-08-13 02:02:55 +00:00
|
|
|
setCheck,
|
|
|
|
setSelect,
|
|
|
|
setUrgent,
|
2006-04-08 18:03:28 +00:00
|
|
|
hasOption,
|
2005-08-13 02:02:55 +00:00
|
|
|
addOption,
|
|
|
|
delOption,
|
2008-08-04 02:06:00 +00:00
|
|
|
getOptions,
|
2006-01-30 20:44:03 +00:00
|
|
|
addTableRow,
|
|
|
|
delTableRow,
|
|
|
|
setTableRow,
|
2006-04-08 18:03:28 +00:00
|
|
|
getTableRow,
|
2008-09-18 10:08:02 +00:00
|
|
|
updateTableRow,
|
|
|
|
updateTableRows,
|
2006-04-08 18:03:28 +00:00
|
|
|
clearTable,
|
2005-08-13 02:02:55 +00:00
|
|
|
getText,
|
|
|
|
getCheck,
|
|
|
|
getSelect,
|
2008-08-04 02:06:00 +00:00
|
|
|
createWindow,
|
|
|
|
closeWindow,
|
|
|
|
setParams,
|
|
|
|
addLines,
|
|
|
|
createObject,
|
|
|
|
setProperty,
|
|
|
|
getProperty
|
2005-08-13 02:02:55 +00:00
|
|
|
};
|
|
|
|
ClientThreadProxy(int func, const String& name, bool show, Window* wnd = 0, Window* skip = 0);
|
2006-01-30 20:44:03 +00:00
|
|
|
ClientThreadProxy(int func, const String& name, const String& text, Window* wnd, Window* skip);
|
2008-08-04 02:06:00 +00:00
|
|
|
ClientThreadProxy(int func, const String& name, const String& text,
|
|
|
|
const String& item, bool show, Window* wnd, Window* skip);
|
|
|
|
ClientThreadProxy(int func, const String& name, String* rtext, bool* rbool,
|
|
|
|
Window* wnd, Window* skip);
|
|
|
|
ClientThreadProxy(int func, const String& name, const NamedList* params,
|
|
|
|
const Window* parent);
|
|
|
|
ClientThreadProxy(int func, const String& name, const String& item, bool start,
|
|
|
|
const NamedList* params, Window* wnd, Window* skip);
|
|
|
|
ClientThreadProxy(int func, const String& name, NamedList* params,
|
|
|
|
Window* wnd, Window* skip);
|
|
|
|
ClientThreadProxy(int func, const String& name, NamedList* params,
|
|
|
|
unsigned int uintVal, bool atStart, Window* wnd, Window* skip);
|
|
|
|
ClientThreadProxy(int func, void** addr, const String& name, const String& text, NamedList* params);
|
2005-08-13 02:02:55 +00:00
|
|
|
void process();
|
|
|
|
bool execute();
|
|
|
|
private:
|
|
|
|
int m_func;
|
|
|
|
bool m_rval;
|
|
|
|
String m_name;
|
|
|
|
String m_text;
|
|
|
|
String m_item;
|
|
|
|
bool m_bool;
|
|
|
|
String* m_rtext;
|
|
|
|
bool* m_rbool;
|
|
|
|
Window* m_wnd;
|
|
|
|
Window* m_skip;
|
|
|
|
const NamedList* m_params;
|
2008-08-04 02:06:00 +00:00
|
|
|
unsigned int m_uint;
|
|
|
|
void** m_pointer;
|
|
|
|
};
|
|
|
|
|
2008-09-08 16:17:00 +00:00
|
|
|
// engine.start message handler used to notify logics
|
|
|
|
class EngineStartHandler : public MessageHandler
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
inline EngineStartHandler(unsigned int prio = 100)
|
|
|
|
: MessageHandler("engine.start",prio)
|
|
|
|
{}
|
|
|
|
virtual bool received(Message& msg);
|
|
|
|
};
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Static classes/function/data
|
|
|
|
*/
|
|
|
|
|
|
|
|
// Struct used to build client relays array
|
|
|
|
struct MsgRelay
|
|
|
|
{
|
|
|
|
const char* name;
|
|
|
|
int id;
|
|
|
|
int prio;
|
|
|
|
};
|
|
|
|
|
|
|
|
// List of window params prefix handled in setParams()
|
|
|
|
static String s_wndParamPrefix[] = {"show:","active:","focus:","check:","select:","display:",""};
|
|
|
|
// Error messages returned by channels
|
|
|
|
static String s_userBusy = "User busy";
|
|
|
|
static String s_rejectReason = "Rejected";
|
|
|
|
static String s_hangupReason = "User hangup";
|
|
|
|
static unsigned int s_eventLen = 0; // Log maximum lines (0: unlimited)
|
|
|
|
static Mutex s_debugMutex;
|
|
|
|
static Mutex s_proxyMutex;
|
|
|
|
static NamedList* s_debugLog = 0;
|
|
|
|
static ClientThreadProxy* s_proxy = 0;
|
|
|
|
static bool s_busy = false;
|
|
|
|
Client* Client::s_client = 0;
|
|
|
|
Configuration Client::s_settings; // Client settings
|
|
|
|
Configuration Client::s_actions; // Logic preferrences
|
|
|
|
Configuration Client::s_accounts; // Accounts
|
|
|
|
Configuration Client::s_contacts; // Contacts
|
|
|
|
Configuration Client::s_providers; // Provider settings
|
|
|
|
Configuration Client::s_history; // Call log
|
|
|
|
Configuration Client::s_calltoHistory; // Dialed destinations history
|
|
|
|
int Client::s_changing = 0;
|
|
|
|
Regexp Client::s_notSelected = "^-\\(.*\\)-$"; // Holds a not selected/set value match
|
|
|
|
ObjList Client::s_logics;
|
|
|
|
String Client::s_skinPath; // Skin path
|
|
|
|
String Client::s_soundPath; // Sounds path
|
|
|
|
String Client::s_ringInName = "defaultringin"; // Ring name for incoming channels
|
|
|
|
String Client::s_ringOutName = "defaultringout"; // Ring name for outgoing channels
|
|
|
|
String Client::s_statusWidget = "status"; // Status widget's name
|
|
|
|
String Client::s_debugWidget = "log_events"; // Default widget displaying the debug text
|
|
|
|
// The list of client's toggles
|
|
|
|
String Client::s_toggles[OptCount] = {
|
|
|
|
"multilines", "autoanswer", "ringincoming", "ringoutgoing",
|
|
|
|
"activatelastoutcall", "activatelastincall", "activatecallonselect",
|
|
|
|
"display_keypad"
|
|
|
|
};
|
|
|
|
bool Client::s_idleLogicsTick = false; // Call logics' timerTick()
|
2008-09-11 15:01:01 +00:00
|
|
|
bool Client::s_exiting = false; // Client exiting flag
|
2008-08-04 02:06:00 +00:00
|
|
|
ClientDriver* ClientDriver::s_driver = 0;
|
|
|
|
String ClientDriver::s_confName = "conf/client"; // The name of the client's conference room
|
|
|
|
bool ClientDriver::s_dropConfPeer = true; // Drop a channel's old peer when terminated while in conference
|
|
|
|
String ClientDriver::s_device; // Currently used audio device
|
|
|
|
ObjList ClientSound::s_sounds; // ClientSound's list
|
|
|
|
Mutex ClientSound::s_soundsMutex(true); // ClientSound's list lock mutex
|
|
|
|
static ClientLogic s_defaultLogic; // The default logic
|
|
|
|
|
|
|
|
// Client relays
|
|
|
|
static MsgRelay s_relays[] = {
|
|
|
|
{"call.cdr", Client::CallCdr, 90},
|
|
|
|
{"ui.action", Client::UiAction, 150},
|
|
|
|
{"user.login", Client::UserLogin, 50},
|
|
|
|
{"user.notify", Client::UserNotify, 50},
|
|
|
|
{"resource.notify", Client::ResourceNotify, 50},
|
|
|
|
{"resource.subscribe", Client::ResourceSubscribe, 50},
|
|
|
|
{"xmpp.iq", Client::XmppIq, 50},
|
|
|
|
{"clientchan.update", Client::ClientChanUpdate, 50},
|
|
|
|
{0,0,0},
|
|
|
|
};
|
|
|
|
|
|
|
|
// Channel notifications
|
|
|
|
TokenDict ClientChannel::s_notification[] = {
|
|
|
|
{"startup", ClientChannel::Startup},
|
|
|
|
{"destroyed", ClientChannel::Destroyed},
|
|
|
|
{"active", ClientChannel::Active},
|
|
|
|
{"onhold", ClientChannel::OnHold},
|
|
|
|
{"noticed", ClientChannel::Noticed},
|
|
|
|
{"addresschanged", ClientChannel::AddrChanged},
|
|
|
|
{"routed", ClientChannel::Routed},
|
|
|
|
{"accepted", ClientChannel::Accepted},
|
|
|
|
{"rejected", ClientChannel::Rejected},
|
|
|
|
{"progressing", ClientChannel::Progressing},
|
|
|
|
{"ringing", ClientChannel::Ringing},
|
|
|
|
{"answered", ClientChannel::Answered},
|
|
|
|
{"transfer", ClientChannel::Transfer},
|
|
|
|
{"conference", ClientChannel::Conference},
|
|
|
|
{0,0}
|
2005-08-13 02:02:55 +00:00
|
|
|
};
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
String ClientContact::s_chatPrefix = "chat"; // Client contact chat window prefix
|
|
|
|
|
|
|
|
|
|
|
|
// Debug output handler
|
|
|
|
static void dbg_client_func(const char* buf, int level)
|
|
|
|
{
|
|
|
|
if (!buf)
|
|
|
|
return;
|
|
|
|
Lock lock(s_debugMutex);
|
|
|
|
if (!s_debugLog)
|
|
|
|
s_debugLog = new NamedList("");
|
|
|
|
s_debugLog->addParam(buf,String(level));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Utility function used in Client::action()
|
|
|
|
// Output a debug message and calls a logic's action method
|
|
|
|
inline bool callLogicAction(ClientLogic* logic, Window* wnd, const String& name, NamedList* params)
|
|
|
|
{
|
|
|
|
if (!logic)
|
|
|
|
return false;
|
|
|
|
DDebug(ClientDriver::self(),DebugAll,
|
|
|
|
"Logic(%s) action='%s' in window (%p,%s) [%p]",
|
2008-09-18 14:41:30 +00:00
|
|
|
logic->toString().c_str(),name.c_str(),wnd,wnd ? wnd->id().c_str() : "",logic);
|
2008-08-04 02:06:00 +00:00
|
|
|
return logic->action(wnd,name,params);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Utility function used in Client::toggle()
|
|
|
|
// Output a debug message and calls a logic's toggle method
|
|
|
|
inline bool callLogicToggle(ClientLogic* logic, Window* wnd, const String& name, bool active)
|
|
|
|
{
|
|
|
|
if (!logic)
|
|
|
|
return false;
|
|
|
|
DDebug(ClientDriver::self(),DebugAll,
|
|
|
|
"Logic(%s) toggle='%s' active=%s in window (%p,%s) [%p]",
|
|
|
|
logic->toString().c_str(),name.c_str(),String::boolText(active),
|
2008-09-18 14:41:30 +00:00
|
|
|
wnd,wnd ? wnd->id().c_str() : "",logic);
|
2008-08-04 02:06:00 +00:00
|
|
|
return logic->toggle(wnd,name,active);
|
|
|
|
}
|
2006-01-30 20:44:03 +00:00
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// Utility function used in Client::select()
|
|
|
|
// Output a debug message and calls a logic's select method
|
|
|
|
inline bool callLogicSelect(ClientLogic* logic, Window* wnd, const String& name,
|
|
|
|
const String& item, const String& text)
|
2006-04-08 18:03:28 +00:00
|
|
|
{
|
2008-08-04 02:06:00 +00:00
|
|
|
if (!logic)
|
|
|
|
return false;
|
|
|
|
DDebug(ClientDriver::self(),DebugAll,
|
|
|
|
"Logic(%s) select='%s' item='%s' in window (%p,%s) [%p]",
|
|
|
|
logic->toString().c_str(),name.c_str(),item.c_str(),
|
2008-09-18 14:41:30 +00:00
|
|
|
wnd,wnd ? wnd->id().c_str() : "",logic);
|
2008-08-04 02:06:00 +00:00
|
|
|
return logic->select(wnd,name,item,text);
|
2006-04-08 18:03:28 +00:00
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// Utility function used to check for action/toggle/select preferences
|
|
|
|
// Check for a substitute
|
|
|
|
// Check if only a logic should process the action
|
|
|
|
// Check for a preffered logic to process the action
|
|
|
|
// Check if a logic should be ignored (not notified)
|
|
|
|
// Otherwise: check if the action should be ignored
|
|
|
|
inline bool hasOverride(const NamedList* params, String& name, String& handle,
|
|
|
|
bool& only, bool& prefer, bool& ignore, bool& bailout)
|
2005-07-12 16:05:29 +00:00
|
|
|
{
|
2008-08-04 02:06:00 +00:00
|
|
|
static String s_ignoreString = "ignore";
|
|
|
|
|
|
|
|
if (!params)
|
|
|
|
return false;
|
|
|
|
handle = params->getValue(name);
|
|
|
|
// Set name if a substitute is found
|
|
|
|
if (handle.startSkip("sameas:",false)) {
|
|
|
|
const char* tmp = params->getValue(handle);
|
|
|
|
if (tmp) {
|
|
|
|
name = handle;
|
|
|
|
handle = tmp;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
handle = "";
|
|
|
|
}
|
|
|
|
// Check logic indications
|
|
|
|
if (!handle)
|
|
|
|
return false;
|
|
|
|
only = handle.startSkip("only:",false);
|
|
|
|
if (only)
|
|
|
|
return true;
|
|
|
|
prefer = handle.startSkip("prefer:",false);
|
|
|
|
ignore = !prefer && handle.startSkip("ignore:",false);
|
|
|
|
bailout = !ignore && handle == s_ignoreString;
|
|
|
|
return true;
|
2005-07-12 16:05:29 +00:00
|
|
|
}
|
2006-04-08 18:03:28 +00:00
|
|
|
|
2006-04-17 19:31:36 +00:00
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
/**
|
|
|
|
* Window
|
|
|
|
*/
|
|
|
|
// Constructor with the specified id
|
2005-07-04 22:04:47 +00:00
|
|
|
Window::Window(const char* id)
|
2008-08-04 02:06:00 +00:00
|
|
|
: m_id(id), m_visible(false), m_master(false), m_popup(false),
|
|
|
|
m_saveOnClose(true), m_populated(false), m_initialized(false)
|
2005-07-04 22:04:47 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// destructor
|
2005-07-04 22:04:47 +00:00
|
|
|
Window::~Window()
|
|
|
|
{
|
|
|
|
if (Client::self())
|
|
|
|
Client::self()->m_windows.remove(this,false);
|
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// retrieve the window id
|
2005-07-04 22:04:47 +00:00
|
|
|
const String& Window::toString() const
|
|
|
|
{
|
|
|
|
return m_id;
|
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// set the window title
|
2005-07-12 20:51:47 +00:00
|
|
|
void Window::title(const String& text)
|
|
|
|
{
|
|
|
|
m_title = text;
|
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// set the window context
|
2006-04-17 21:52:50 +00:00
|
|
|
void Window::context(const String& text)
|
|
|
|
{
|
|
|
|
m_context = text;
|
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// checkes if this window is related to the given window
|
2005-07-04 22:04:47 +00:00
|
|
|
bool Window::related(const Window* wnd) const
|
|
|
|
{
|
|
|
|
if ((wnd == this) || !wnd || wnd->master())
|
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// function for interpreting a set or parameters and take appropiate action
|
|
|
|
// maybe not needed anymore?
|
2005-07-25 22:44:34 +00:00
|
|
|
bool Window::setParams(const NamedList& params)
|
|
|
|
{
|
|
|
|
bool ok = true;
|
|
|
|
unsigned int l = params.length();
|
|
|
|
for (unsigned int i = 0; i < l; i++) {
|
|
|
|
const NamedString* s = params.getParam(i);
|
|
|
|
if (s) {
|
|
|
|
String n(s->name());
|
|
|
|
if (n == "title")
|
|
|
|
title(*s);
|
2006-04-17 21:52:50 +00:00
|
|
|
if (n == "context")
|
|
|
|
context(*s);
|
2008-08-04 02:06:00 +00:00
|
|
|
else if (n.startSkip("show:",false) || n.startSkip("display:",false))
|
2005-07-25 22:44:34 +00:00
|
|
|
ok = setShow(n,s->toBoolean()) && ok;
|
|
|
|
else if (n.startSkip("active:",false))
|
|
|
|
ok = setActive(n,s->toBoolean()) && ok;
|
2006-05-29 13:58:09 +00:00
|
|
|
else if (n.startSkip("focus:",false))
|
|
|
|
ok = setFocus(n,s->toBoolean()) && ok;
|
2005-07-25 22:44:34 +00:00
|
|
|
else if (n.startSkip("check:",false))
|
|
|
|
ok = setCheck(n,s->toBoolean()) && ok;
|
|
|
|
else if (n.startSkip("select:",false))
|
|
|
|
ok = setSelect(n,*s) && ok;
|
2008-08-04 02:06:00 +00:00
|
|
|
else if (n.startSkip("property:",false)) {
|
|
|
|
// Set property: object_name:property_name=value
|
|
|
|
int pos = n.find(':');
|
|
|
|
if (pos > 0)
|
2008-09-18 14:41:30 +00:00
|
|
|
ok = setProperty(n.substr(0,pos),n.substr(pos + 1),*s) && ok;
|
2008-08-04 02:06:00 +00:00
|
|
|
else
|
|
|
|
ok = false;
|
|
|
|
}
|
2005-07-25 22:44:34 +00:00
|
|
|
else if (n.find(':') < 0)
|
|
|
|
ok = setText(n,*s) && ok;
|
|
|
|
else
|
|
|
|
ok = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// Append or insert text lines to a widget
|
|
|
|
bool Window::addLines(const String& name, const NamedList* lines, unsigned int max,
|
|
|
|
bool atStart)
|
|
|
|
{
|
|
|
|
DDebug(ClientDriver::self(),DebugInfo,"stub addLines('%s',%p,%u,%s) [%p]",
|
|
|
|
name.c_str(),lines,max,String::boolText(atStart),this);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// stub function for adding a row to a table
|
2006-01-30 20:44:03 +00:00
|
|
|
bool Window::addTableRow(const String& name, const String& item, const NamedList* data, bool atStart)
|
|
|
|
{
|
|
|
|
DDebug(ClientDriver::self(),DebugInfo,"stub addTableRow('%s','%s',%p,%s) [%p]",
|
|
|
|
name.c_str(),item.c_str(),data,String::boolText(atStart),this);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// stub function for deleting a row from a table
|
2006-01-30 20:44:03 +00:00
|
|
|
bool Window::delTableRow(const String& name, const String& item)
|
|
|
|
{
|
|
|
|
DDebug(ClientDriver::self(),DebugInfo,"stub delTableRow('%s','%s') [%p]",
|
|
|
|
name.c_str(),item.c_str(),this);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// stub function for setting the value for a row
|
2006-01-30 20:44:03 +00:00
|
|
|
bool Window::setTableRow(const String& name, const String& item, const NamedList* data)
|
|
|
|
{
|
|
|
|
DDebug(ClientDriver::self(),DebugInfo,"stub setTableRow('%s','%s',%p) [%p]",
|
|
|
|
name.c_str(),item.c_str(),data,this);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2008-09-18 10:08:02 +00:00
|
|
|
// Set a table row or add a new one if not found
|
|
|
|
bool Window::updateTableRow(const String& name, const String& item,
|
|
|
|
const NamedList* data, bool atStart)
|
|
|
|
{
|
|
|
|
DDebug(ClientDriver::self(),DebugInfo,"stub updateTableRow('%s','%s',%p,%s) [%p]",
|
|
|
|
name.c_str(),item.c_str(),data,String::boolText(atStart),this);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add or set one or more table row(s). Screen update is locked while changing the table.
|
|
|
|
// Each data list element is a NamedPointer carrying a NamedList with item parameters.
|
|
|
|
// The name of an element is the item to update. Set element's value to 'false'
|
|
|
|
// to avoid adding a new item.
|
|
|
|
bool Window::updateTableRows(const String& name, const NamedList* data, bool atStart)
|
|
|
|
{
|
|
|
|
DDebug(ClientDriver::self(),DebugInfo,"stub updateTableRows('%s',%p,%s) [%p]",
|
|
|
|
name.c_str(),data,String::boolText(atStart),this);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// stub function for retrieving the information from a row
|
2006-04-08 18:03:28 +00:00
|
|
|
bool Window::getTableRow(const String& name, const String& item, NamedList* data)
|
|
|
|
{
|
|
|
|
DDebug(ClientDriver::self(),DebugInfo,"stub getTableRow('%s','%s',%p) [%p]",
|
|
|
|
name.c_str(),item.c_str(),data,this);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// stub function for clearing a table
|
2006-01-30 20:44:03 +00:00
|
|
|
bool Window::clearTable(const String& name)
|
|
|
|
{
|
|
|
|
DDebug(ClientDriver::self(),DebugInfo,"stub clearTable('%s') [%p]",
|
|
|
|
name.c_str(),this);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// Check window param prefix
|
|
|
|
bool Window::isValidParamPrefix(const String& prefix)
|
|
|
|
{
|
|
|
|
for (int i = 0; s_wndParamPrefix[i].length(); i++)
|
|
|
|
if (prefix.startsWith(s_wndParamPrefix[i]))
|
|
|
|
return prefix.length() > s_wndParamPrefix[i].length();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* UIFactory
|
|
|
|
*/
|
|
|
|
|
|
|
|
ObjList UIFactory::s_factories;
|
2005-07-04 22:04:47 +00:00
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// Constructor. Append itself to the factories list
|
|
|
|
UIFactory::UIFactory(const char* name)
|
2005-07-04 22:04:47 +00:00
|
|
|
: String(name)
|
|
|
|
{
|
2008-08-04 02:06:00 +00:00
|
|
|
s_factories.append(this)->setDelete(false);
|
|
|
|
Debug(ClientDriver::self(),DebugAll,"Added factory '%s' [%p]",name,this);
|
2005-07-04 22:04:47 +00:00
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// Destructor
|
2005-07-04 22:04:47 +00:00
|
|
|
UIFactory::~UIFactory()
|
|
|
|
{
|
2008-08-04 02:06:00 +00:00
|
|
|
s_factories.remove(this,false);
|
|
|
|
Debug(ClientDriver::self(),DebugAll,"Removed factory '%s' [%p]",c_str(),this);
|
2005-07-04 22:04:47 +00:00
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// Ask all factories to create an object of a given type
|
|
|
|
void* UIFactory::build(const String& type, const char* name, NamedList* params,
|
|
|
|
const char* factory)
|
|
|
|
{
|
|
|
|
for (ObjList* o = s_factories.skipNull(); o; o = o->skipNext()) {
|
|
|
|
UIFactory* f = static_cast<UIFactory*>(o->get());
|
|
|
|
if (!f->canBuild(type) || (factory && *f != factory))
|
|
|
|
continue;
|
|
|
|
DDebug(ClientDriver::self(),DebugAll,
|
|
|
|
"Factory '%s' trying to create type='%s' name='%s' [%p]",
|
|
|
|
f->c_str(),type.c_str(),name,f);
|
|
|
|
void* p = f->create(type,name,params);
|
|
|
|
if (p)
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2005-07-04 22:04:47 +00:00
|
|
|
|
2005-08-13 02:02:55 +00:00
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
/**
|
|
|
|
* ClientThreadProxy
|
|
|
|
*/
|
|
|
|
ClientThreadProxy::ClientThreadProxy(int func, const String& name, bool show,
|
|
|
|
Window* wnd, Window* skip)
|
2005-08-13 02:02:55 +00:00
|
|
|
: m_func(func), m_rval(false),
|
|
|
|
m_name(name), m_bool(show), m_rtext(0), m_rbool(0),
|
2008-08-04 02:06:00 +00:00
|
|
|
m_wnd(wnd), m_skip(skip), m_params(0), m_uint(0), m_pointer(0)
|
2005-08-13 02:02:55 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
ClientThreadProxy::ClientThreadProxy(int func, const String& name, const String& text,
|
|
|
|
Window* wnd, Window* skip)
|
2005-08-13 02:02:55 +00:00
|
|
|
: m_func(func), m_rval(false),
|
2005-08-18 22:46:35 +00:00
|
|
|
m_name(name), m_text(text), m_bool(false), m_rtext(0), m_rbool(0),
|
2008-08-04 02:06:00 +00:00
|
|
|
m_wnd(wnd), m_skip(skip), m_params(0), m_uint(0), m_pointer(0)
|
2005-08-13 02:02:55 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
ClientThreadProxy::ClientThreadProxy(int func, const String& name, const String& text,
|
|
|
|
const String& item, bool show, Window* wnd, Window* skip)
|
2005-08-13 02:02:55 +00:00
|
|
|
: m_func(func), m_rval(false),
|
2005-08-18 22:46:35 +00:00
|
|
|
m_name(name), m_text(text), m_item(item), m_bool(show), m_rtext(0), m_rbool(0),
|
2008-08-04 02:06:00 +00:00
|
|
|
m_wnd(wnd), m_skip(skip), m_params(0), m_uint(0), m_pointer(0)
|
2005-08-13 02:02:55 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
ClientThreadProxy::ClientThreadProxy(int func, const String& name, String* rtext,
|
|
|
|
bool* rbool, Window* wnd, Window* skip)
|
2005-08-13 02:02:55 +00:00
|
|
|
: m_func(func), m_rval(false),
|
2005-08-18 22:46:35 +00:00
|
|
|
m_name(name), m_bool(false), m_rtext(rtext), m_rbool(rbool),
|
2008-08-04 02:06:00 +00:00
|
|
|
m_wnd(wnd), m_skip(skip), m_params(0), m_uint(0), m_pointer(0)
|
2005-08-13 02:02:55 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
ClientThreadProxy::ClientThreadProxy(int func, const String& name, const NamedList* params,
|
|
|
|
const Window* parent)
|
2005-08-13 02:02:55 +00:00
|
|
|
: m_func(func), m_rval(false),
|
2005-08-18 22:46:35 +00:00
|
|
|
m_name(name), m_bool(false), m_rtext(0), m_rbool(0),
|
2008-08-04 02:06:00 +00:00
|
|
|
m_wnd(const_cast<Window*>(parent)), m_skip(0), m_params(params), m_uint(0),
|
|
|
|
m_pointer(0)
|
2005-08-13 02:02:55 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
ClientThreadProxy::ClientThreadProxy(int func, const String& name, const String& item,
|
|
|
|
bool start, const NamedList* params, Window* wnd, Window* skip)
|
2006-01-30 20:44:03 +00:00
|
|
|
: m_func(func), m_rval(false),
|
|
|
|
m_name(name), m_item(item), m_bool(start), m_rtext(0), m_rbool(0),
|
2008-08-04 02:06:00 +00:00
|
|
|
m_wnd(wnd), m_skip(skip), m_params(params), m_uint(0), m_pointer(0)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
ClientThreadProxy::ClientThreadProxy(int func, const String& name, NamedList* params,
|
|
|
|
Window* wnd, Window* skip)
|
|
|
|
: m_func(func), m_rval(false),
|
|
|
|
m_name(name), m_bool(false), m_rtext(0), m_rbool(0),
|
|
|
|
m_wnd(wnd), m_skip(skip), m_params(params), m_uint(0), m_pointer(0)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
ClientThreadProxy::ClientThreadProxy(int func, const String& name, NamedList* params,
|
|
|
|
unsigned int uintVal, bool atStart, Window* wnd, Window* skip)
|
|
|
|
: m_func(func), m_rval(false),
|
|
|
|
m_name(name), m_bool(atStart), m_rtext(0), m_rbool(0),
|
|
|
|
m_wnd(wnd), m_skip(skip), m_params(params), m_uint(uintVal), m_pointer(0)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
ClientThreadProxy::ClientThreadProxy(int func, void** addr, const String& name,
|
|
|
|
const String& text, NamedList* params)
|
|
|
|
: m_func(func), m_rval(false),
|
|
|
|
m_name(name), m_text(text), m_bool(false), m_rtext(0), m_rbool(0),
|
|
|
|
m_wnd(0), m_skip(0), m_params(params), m_uint(0), m_pointer(addr)
|
2006-01-30 20:44:03 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2005-08-13 02:02:55 +00:00
|
|
|
void ClientThreadProxy::process()
|
|
|
|
{
|
2008-08-04 02:06:00 +00:00
|
|
|
XDebug(DebugAll,"ClientThreadProxy::process()"," %d [%p]",m_func,this);
|
2005-08-13 02:02:55 +00:00
|
|
|
Client* client = Client::self();
|
2008-09-11 15:01:01 +00:00
|
|
|
if (!client || Client::exiting()) {
|
2005-08-13 02:02:55 +00:00
|
|
|
s_busy = false;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
switch (m_func) {
|
|
|
|
case setVisible:
|
|
|
|
m_rval = Client::setVisible(m_name,m_bool);
|
|
|
|
break;
|
|
|
|
case openPopup:
|
|
|
|
m_rval = Client::openPopup(m_name,m_params,m_wnd);
|
|
|
|
break;
|
|
|
|
case hasElement:
|
|
|
|
m_rval = client->hasElement(m_name,m_wnd,m_skip);
|
|
|
|
break;
|
|
|
|
case setShow:
|
|
|
|
m_rval = client->setShow(m_name,m_bool,m_wnd,m_skip);
|
|
|
|
break;
|
|
|
|
case setText:
|
2008-08-04 02:06:00 +00:00
|
|
|
m_rval = client->setText(m_name,m_text,m_bool,m_wnd,m_skip);
|
2005-08-13 02:02:55 +00:00
|
|
|
break;
|
|
|
|
case setActive:
|
|
|
|
m_rval = client->setActive(m_name,m_bool,m_wnd,m_skip);
|
|
|
|
break;
|
2006-05-29 13:58:09 +00:00
|
|
|
case setFocus:
|
|
|
|
m_rval = client->setFocus(m_name,m_bool,m_wnd,m_skip);
|
|
|
|
break;
|
2005-08-13 02:02:55 +00:00
|
|
|
case setCheck:
|
|
|
|
m_rval = client->setCheck(m_name,m_bool,m_wnd,m_skip);
|
|
|
|
break;
|
|
|
|
case setSelect:
|
|
|
|
m_rval = client->setSelect(m_name,m_text,m_wnd,m_skip);
|
|
|
|
break;
|
|
|
|
case setUrgent:
|
|
|
|
m_rval = client->setUrgent(m_name,m_bool,m_wnd,m_skip);
|
|
|
|
break;
|
2006-04-08 18:03:28 +00:00
|
|
|
case hasOption:
|
|
|
|
m_rval = client->hasOption(m_name,m_text,m_wnd,m_skip);
|
|
|
|
break;
|
2005-08-13 02:02:55 +00:00
|
|
|
case addOption:
|
|
|
|
m_rval = client->addOption(m_name,m_item,m_bool,m_text,m_wnd,m_skip);
|
|
|
|
break;
|
|
|
|
case delOption:
|
|
|
|
m_rval = client->delOption(m_name,m_text,m_wnd,m_skip);
|
|
|
|
break;
|
2006-01-30 20:44:03 +00:00
|
|
|
case addTableRow:
|
|
|
|
m_rval = client->addTableRow(m_name,m_item,m_params,m_bool,m_wnd,m_skip);
|
|
|
|
break;
|
|
|
|
case delTableRow:
|
|
|
|
m_rval = client->delTableRow(m_name,m_text,m_wnd,m_skip);
|
|
|
|
break;
|
|
|
|
case setTableRow:
|
|
|
|
m_rval = client->setTableRow(m_name,m_item,m_params,m_wnd,m_skip);
|
|
|
|
break;
|
2008-09-18 10:08:02 +00:00
|
|
|
case updateTableRow:
|
|
|
|
m_rval = client->updateTableRow(m_name,m_item,m_params,m_bool,m_wnd,m_skip);
|
|
|
|
break;
|
|
|
|
case updateTableRows:
|
|
|
|
m_rval = client->updateTableRows(m_name,m_params,m_bool,m_wnd,m_skip);
|
|
|
|
break;
|
2006-04-08 18:03:28 +00:00
|
|
|
case getTableRow:
|
|
|
|
m_rval = client->getTableRow(m_name,m_item,const_cast<NamedList*>(m_params),m_wnd,m_skip);
|
|
|
|
break;
|
|
|
|
case clearTable:
|
|
|
|
m_rval = client->clearTable(m_name);
|
|
|
|
break;
|
2005-08-13 02:02:55 +00:00
|
|
|
case getText:
|
2008-09-18 14:41:30 +00:00
|
|
|
m_rval = client->getText(m_name,*m_rtext,m_rbool ? *m_rbool : false,m_wnd,m_skip);
|
2005-08-13 02:02:55 +00:00
|
|
|
break;
|
|
|
|
case getCheck:
|
|
|
|
m_rval = client->getCheck(m_name,*m_rbool,m_wnd,m_skip);
|
|
|
|
break;
|
|
|
|
case getSelect:
|
|
|
|
m_rval = client->getSelect(m_name,*m_rtext,m_wnd,m_skip);
|
|
|
|
break;
|
2008-08-04 02:06:00 +00:00
|
|
|
case getOptions:
|
|
|
|
m_rval = client->getOptions(m_name,const_cast<NamedList*>(m_params),m_wnd,m_skip);
|
|
|
|
break;
|
|
|
|
case createWindow:
|
|
|
|
m_rval = client->createWindowSafe(m_name,m_text);
|
|
|
|
break;
|
|
|
|
case closeWindow:
|
|
|
|
m_rval = client->closeWindow(m_name,m_bool);
|
|
|
|
break;
|
|
|
|
case setParams:
|
|
|
|
m_rval = client->setParams(const_cast<NamedList*>(m_params),m_wnd,m_skip);
|
|
|
|
break;
|
|
|
|
case addLines:
|
|
|
|
m_rval = client->addLines(m_name,const_cast<NamedList*>(m_params),m_uint,
|
|
|
|
m_bool,m_wnd,m_skip);
|
|
|
|
break;
|
|
|
|
case createObject:
|
|
|
|
m_rval = client->createObject(m_pointer,m_name,m_text,const_cast<NamedList*>(m_params));
|
|
|
|
break;
|
|
|
|
case setProperty:
|
|
|
|
m_rval = client->setProperty(m_name,m_item,m_text);
|
|
|
|
break;
|
|
|
|
case getProperty:
|
|
|
|
m_rval = client->getProperty(m_name,m_item,m_text);
|
|
|
|
break;
|
2005-08-13 02:02:55 +00:00
|
|
|
}
|
|
|
|
s_busy = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ClientThreadProxy::execute()
|
|
|
|
{
|
2008-08-04 02:06:00 +00:00
|
|
|
XDebug(DebugAll,"ClientThreadProxy::execute()"," %d in %p [%p]",
|
2005-08-18 22:46:35 +00:00
|
|
|
m_func,Thread::current(),this);
|
2005-08-13 02:02:55 +00:00
|
|
|
s_proxyMutex.lock();
|
|
|
|
s_proxy = this;
|
2005-10-31 18:22:07 +00:00
|
|
|
s_busy = true;
|
2005-08-13 02:02:55 +00:00
|
|
|
while (s_busy)
|
|
|
|
Thread::yield();
|
|
|
|
s_proxyMutex.unlock();
|
|
|
|
return m_rval;
|
|
|
|
}
|
|
|
|
|
2008-09-08 16:17:00 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* EngineStartHandler
|
|
|
|
*/
|
|
|
|
// Notify logics
|
|
|
|
bool EngineStartHandler::received(Message& msg)
|
|
|
|
{
|
|
|
|
if (Client::self())
|
|
|
|
Client::self()->engineStart(msg);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
/**
|
|
|
|
* Client
|
|
|
|
*/
|
|
|
|
// Constructor
|
2005-07-04 22:04:47 +00:00
|
|
|
Client::Client(const char *name)
|
2008-08-04 02:06:00 +00:00
|
|
|
: Thread(name), m_initialized(false), m_line(0), m_oneThread(true)
|
2005-07-04 22:04:47 +00:00
|
|
|
{
|
|
|
|
s_client = this;
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// Set default options
|
|
|
|
for (unsigned int i = 0; i < OptCount; i++)
|
|
|
|
m_toggles[i] = false;
|
|
|
|
m_toggles[OptMultiLines] = true;
|
|
|
|
m_toggles[OptKeypadVisible] = true;
|
|
|
|
|
|
|
|
// Install relays
|
|
|
|
for (int i = 0; s_relays[i].name; i++)
|
|
|
|
installRelay(s_relays[i].name,s_relays[i].id,s_relays[i].prio);
|
|
|
|
|
|
|
|
// Set paths
|
|
|
|
s_skinPath = Engine::config().getValue("client","skinbase");
|
|
|
|
if (!s_skinPath)
|
|
|
|
s_skinPath << Engine::sharedPath() << Engine::pathSeparator() << "skins";
|
|
|
|
s_skinPath << Engine::pathSeparator();
|
|
|
|
String skin(Engine::config().getValue("client","skin","default"));
|
|
|
|
if (skin)
|
|
|
|
s_skinPath << skin;
|
|
|
|
if (!s_skinPath.endsWith(Engine::pathSeparator()))
|
|
|
|
s_skinPath << Engine::pathSeparator();
|
|
|
|
s_soundPath << Engine::sharedPath() << Engine::pathSeparator() << "sounds" <<
|
|
|
|
Engine::pathSeparator();
|
|
|
|
}
|
|
|
|
|
|
|
|
// destructor
|
2005-07-04 22:04:47 +00:00
|
|
|
Client::~Client()
|
2008-01-07 18:36:17 +00:00
|
|
|
{
|
2008-08-04 02:06:00 +00:00
|
|
|
// Halt the engine
|
2008-01-07 18:36:17 +00:00
|
|
|
Engine::halt(0);
|
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// Cleanup before halting
|
2008-01-07 18:36:17 +00:00
|
|
|
void Client::cleanup()
|
2005-07-04 22:04:47 +00:00
|
|
|
{
|
2008-08-04 02:06:00 +00:00
|
|
|
for (ObjList* o = m_relays.skipNull(); o; o = o->skipNext())
|
|
|
|
Engine::uninstall(static_cast<MessageRelay*>(o->get()));
|
|
|
|
m_relays.clear();
|
|
|
|
ClientSound::s_soundsMutex.lock();
|
|
|
|
ClientSound::s_sounds.clear();
|
|
|
|
ClientSound::s_soundsMutex.unlock();
|
2005-07-04 22:04:47 +00:00
|
|
|
m_windows.clear();
|
|
|
|
s_client = 0;
|
2008-01-07 18:36:17 +00:00
|
|
|
m_oneThread = false;
|
|
|
|
do
|
|
|
|
idleActions();
|
|
|
|
while (ClientDriver::self() && !ClientDriver::self()->check(100000));
|
2005-07-04 22:04:47 +00:00
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// Load windows and optionally (re)initialize the client's options
|
|
|
|
void Client::loadUI(const char* file, bool init)
|
2005-07-04 22:04:47 +00:00
|
|
|
{
|
2008-08-04 02:06:00 +00:00
|
|
|
Debug(ClientDriver::self(),DebugAll,"Client::loadUI() [%p]",this);
|
|
|
|
loadWindows(file);
|
|
|
|
for (ObjList* o = s_logics.skipNull(); o; o = o->skipNext()) {
|
|
|
|
ClientLogic* logic = static_cast<ClientLogic*>(o->get());
|
|
|
|
Debug(ClientDriver::self(),DebugAll,"Logic(%s) loadedWindows() [%p]",
|
|
|
|
logic->toString().c_str(),logic);
|
|
|
|
logic->loadedWindows();
|
|
|
|
}
|
2005-07-04 22:04:47 +00:00
|
|
|
initWindows();
|
2008-08-04 02:06:00 +00:00
|
|
|
for (ObjList* o = s_logics.skipNull(); o; o = o->skipNext()) {
|
|
|
|
ClientLogic* logic = static_cast<ClientLogic*>(o->get());
|
|
|
|
Debug(ClientDriver::self(),DebugAll,"Logic(%s) initializedWindows() [%p]",
|
|
|
|
logic->toString().c_str(),logic);
|
|
|
|
logic->initializedWindows();
|
|
|
|
}
|
|
|
|
if (init) {
|
|
|
|
m_initialized = false;
|
|
|
|
initClient();
|
|
|
|
for (ObjList* o = s_logics.skipNull(); o; o = o->skipNext()) {
|
|
|
|
ClientLogic* logic = static_cast<ClientLogic*>(o->get());
|
|
|
|
Debug(ClientDriver::self(),DebugAll,"Logic(%s) initializedClient() [%p]",
|
|
|
|
logic->toString().c_str(),logic);
|
|
|
|
if (logic->initializedClient())
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
setStatus(Engine::config().getValue("client","greeting","Yate " YATE_VERSION " - " YATE_STATUS YATE_RELEASE));
|
|
|
|
m_initialized = true;
|
|
|
|
}
|
|
|
|
// Sanity check: at least one window should be visible
|
|
|
|
ObjList* o = m_windows.skipNull();
|
|
|
|
for (; o && !getVisible(o->get()->toString()); o = o->skipNext())
|
|
|
|
;
|
|
|
|
if (!o)
|
|
|
|
Debug(ClientDriver::self(),DebugWarn,"There is no window visible !!!");
|
|
|
|
}
|
|
|
|
|
|
|
|
// run function for the main thread
|
|
|
|
void Client::run()
|
|
|
|
{
|
|
|
|
Debug(ClientDriver::self(),DebugAll,"Client::run() [%p]",this);
|
2008-09-08 16:17:00 +00:00
|
|
|
Engine::install(new EngineStartHandler);
|
2008-08-04 02:06:00 +00:00
|
|
|
loadUI();
|
|
|
|
// Run
|
2005-07-04 22:04:47 +00:00
|
|
|
main();
|
2008-09-11 15:01:01 +00:00
|
|
|
s_exiting = true;
|
|
|
|
// Drop all calls
|
|
|
|
ClientDriver::dropCalls();
|
2008-08-04 02:06:00 +00:00
|
|
|
// Notify termination to logics
|
|
|
|
for (ObjList* o = s_logics.skipNull(); o; o = o->skipNext()) {
|
|
|
|
ClientLogic* logic = static_cast<ClientLogic*>(o->get());
|
|
|
|
Debug(ClientDriver::self(),DebugAll,"Logic(%s) exitingClient() [%p]",
|
|
|
|
logic->toString().c_str(),logic);
|
|
|
|
logic->exitingClient();
|
|
|
|
}
|
2006-08-16 19:14:01 +00:00
|
|
|
exitClient();
|
2005-07-04 22:04:47 +00:00
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// retrieve the window named by the value of "name" from the client's list of windows
|
2005-07-04 22:04:47 +00:00
|
|
|
Window* Client::getWindow(const String& name)
|
|
|
|
{
|
|
|
|
if (!s_client)
|
|
|
|
return 0;
|
|
|
|
ObjList* l = s_client->m_windows.find(name);
|
|
|
|
return static_cast<Window*>(l ? l->get() : 0);
|
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// function for obtaining a list of all windows that the client uses
|
2005-07-12 20:51:47 +00:00
|
|
|
ObjList* Client::listWindows()
|
|
|
|
{
|
|
|
|
if (!s_client)
|
|
|
|
return 0;
|
|
|
|
ObjList* lst = 0;
|
|
|
|
for (ObjList* l = &s_client->m_windows; l; l = l->next()) {
|
|
|
|
Window* w = static_cast<Window*>(l->get());
|
|
|
|
if (w) {
|
|
|
|
if (!lst)
|
|
|
|
lst = new ObjList;
|
|
|
|
lst->append(new String(w->id()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return lst;
|
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// function for setting the visibility attribute of the "name" window
|
2005-07-04 22:04:47 +00:00
|
|
|
bool Client::setVisible(const String& name, bool show)
|
|
|
|
{
|
2005-08-13 02:02:55 +00:00
|
|
|
if (s_client && s_client->needProxy()) {
|
|
|
|
ClientThreadProxy proxy(ClientThreadProxy::setVisible,name,show);
|
|
|
|
return proxy.execute();
|
|
|
|
}
|
2005-07-04 22:04:47 +00:00
|
|
|
Window* w = getWindow(name);
|
|
|
|
if (!w)
|
|
|
|
return false;
|
|
|
|
w->visible(show);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// function for obtaining the visibility status of the "name" window
|
2005-07-04 22:04:47 +00:00
|
|
|
bool Client::getVisible(const String& name)
|
|
|
|
{
|
|
|
|
Window* w = getWindow(name);
|
|
|
|
return w && w->visible();
|
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// function for initiating the windows
|
2005-07-04 22:04:47 +00:00
|
|
|
void Client::initWindows()
|
|
|
|
{
|
|
|
|
ObjList* l = &m_windows;
|
|
|
|
for (; l; l = l->next()) {
|
|
|
|
Window* w = static_cast<Window*>(l->get());
|
|
|
|
if (w)
|
|
|
|
w->init();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// function for initializing the client
|
2005-07-27 18:31:47 +00:00
|
|
|
void Client::initClient()
|
|
|
|
{
|
2007-08-24 08:44:20 +00:00
|
|
|
s_eventLen = Engine::config().getIntValue("client","eventlen",10240);
|
2006-08-17 17:47:43 +00:00
|
|
|
if (s_eventLen > 65535)
|
|
|
|
s_eventLen = 65535;
|
|
|
|
else if (s_eventLen && (s_eventLen < 1024))
|
|
|
|
s_eventLen = 1024;
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// Load the settings file
|
|
|
|
s_settings = Engine::configFile("client_settings",true);
|
|
|
|
s_settings.load();
|
|
|
|
|
|
|
|
// Load logic actions file
|
|
|
|
s_actions = Engine::configFile("client_actions", false);
|
|
|
|
s_actions.load();
|
|
|
|
|
|
|
|
// Load the accounts file and notify logics
|
2006-06-11 16:50:04 +00:00
|
|
|
s_accounts = Engine::configFile("client_accounts",true);
|
2006-04-17 19:31:36 +00:00
|
|
|
s_accounts.load();
|
|
|
|
unsigned int n = s_accounts.sections();
|
2008-08-04 02:06:00 +00:00
|
|
|
for (unsigned int i = 0; i < n; i++) {
|
2006-04-17 19:31:36 +00:00
|
|
|
NamedList* sect = s_accounts.getSection(i);
|
2008-08-04 02:06:00 +00:00
|
|
|
if (!sect)
|
|
|
|
continue;
|
|
|
|
for (ObjList* o = s_logics.skipNull(); o; o = o->skipNext()) {
|
|
|
|
ClientLogic* logic = static_cast<ClientLogic*>(o->get());
|
|
|
|
if (logic->updateAccount(*sect,sect->getBoolValue("enabled",true),false))
|
|
|
|
break;
|
2006-04-17 19:31:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// Load the contacts file and notify logics
|
2006-06-11 16:50:04 +00:00
|
|
|
s_contacts = Engine::configFile("client_contacts",true);
|
2006-04-17 19:31:36 +00:00
|
|
|
s_contacts.load();
|
|
|
|
n = s_contacts.sections();
|
2008-08-04 02:06:00 +00:00
|
|
|
for (unsigned int i = 0; i < n; i++) {
|
2006-04-17 19:31:36 +00:00
|
|
|
NamedList* sect = s_contacts.getSection(i);
|
2008-08-04 02:06:00 +00:00
|
|
|
if (!sect)
|
|
|
|
continue;
|
|
|
|
// Make sure we have a name
|
|
|
|
if (!sect->getParam("name"))
|
|
|
|
sect->addParam("name",*sect);
|
|
|
|
for (ObjList* o = s_logics.skipNull(); o; o = o->skipNext())
|
|
|
|
if ((static_cast<ClientLogic*>(o->get()))->updateContact(*sect,false,true))
|
|
|
|
break;
|
2006-04-17 19:31:36 +00:00
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// Load the providers file and notify logics
|
2006-04-17 21:52:50 +00:00
|
|
|
s_providers = Engine::configFile("providers");
|
|
|
|
s_providers.load();
|
|
|
|
n = s_providers.sections();
|
2008-08-04 02:06:00 +00:00
|
|
|
for (unsigned int i = 0; i < n; i++) {
|
2006-04-17 21:52:50 +00:00
|
|
|
NamedList* sect = s_providers.getSection(i);
|
2008-08-04 02:06:00 +00:00
|
|
|
if (!sect)
|
|
|
|
continue;
|
|
|
|
for (ObjList* o = s_logics.skipNull(); o; o = o->skipNext())
|
|
|
|
if ((static_cast<ClientLogic*>(o->get()))->updateProviders(*sect,false,true))
|
|
|
|
break;
|
2006-04-17 21:52:50 +00:00
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// Load the log file and notify logics
|
2006-06-11 16:50:04 +00:00
|
|
|
s_history = Engine::configFile("client_history",true);
|
2006-05-08 21:59:42 +00:00
|
|
|
s_history.load();
|
|
|
|
n = s_history.sections();
|
2008-08-04 02:06:00 +00:00
|
|
|
for (unsigned int i = 0; i < n; i++) {
|
2006-05-08 21:59:42 +00:00
|
|
|
NamedList* sect = s_history.getSection(i);
|
2008-08-04 02:06:00 +00:00
|
|
|
if (!sect)
|
|
|
|
continue;
|
|
|
|
for (ObjList* o = s_logics.skipNull(); o; o = o->skipNext())
|
|
|
|
if ((static_cast<ClientLogic*>(o->get()))->callLogUpdate(*sect,false,true))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Load the callto history
|
|
|
|
s_calltoHistory = Engine::configFile("client_calltohistory",true);
|
|
|
|
s_calltoHistory.load();
|
|
|
|
for (ObjList* o = s_logics.skipNull(); o; o = o->skipNext())
|
|
|
|
if ((static_cast<ClientLogic*>(o->get()))->calltoLoaded())
|
|
|
|
break;
|
2006-08-16 19:14:01 +00:00
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// function for moving simultaneously two related windows
|
2005-07-04 22:04:47 +00:00
|
|
|
void Client::moveRelated(const Window* wnd, int dx, int dy)
|
|
|
|
{
|
|
|
|
if (!wnd)
|
|
|
|
return;
|
|
|
|
ObjList* l = &m_windows;
|
|
|
|
for (; l; l = l->next()) {
|
|
|
|
Window* w = static_cast<Window*>(l->get());
|
|
|
|
if (w && (w != wnd) && wnd->related(w))
|
|
|
|
w->moveRel(dx,dy);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// function for opening the pop-up window that has the id "name" with the given parameters
|
2005-07-27 18:31:47 +00:00
|
|
|
bool Client::openPopup(const String& name, const NamedList* params, const Window* parent)
|
2008-08-04 02:06:00 +00:00
|
|
|
{
|
2005-08-13 02:02:55 +00:00
|
|
|
if (s_client && s_client->needProxy()) {
|
|
|
|
ClientThreadProxy proxy(ClientThreadProxy::openPopup,name,params,parent);
|
|
|
|
return proxy.execute();
|
|
|
|
}
|
2005-07-25 22:44:34 +00:00
|
|
|
Window* wnd = getWindow(name);
|
|
|
|
if (!wnd)
|
|
|
|
return false;
|
2006-04-17 21:52:50 +00:00
|
|
|
wnd->context("");
|
2005-07-25 22:44:34 +00:00
|
|
|
if (params)
|
|
|
|
wnd->setParams(*params);
|
2005-07-27 18:31:47 +00:00
|
|
|
if (parent)
|
|
|
|
wnd->setOver(parent);
|
2005-07-25 22:44:34 +00:00
|
|
|
wnd->show();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// function for opening a message type pop-up window with the given text, parent, context
|
2006-05-16 21:53:40 +00:00
|
|
|
bool Client::openMessage(const char* text, const Window* parent, const char* context)
|
2006-01-26 00:00:36 +00:00
|
|
|
{
|
|
|
|
NamedList params("");
|
|
|
|
params.addParam("text",text);
|
2006-04-08 18:03:28 +00:00
|
|
|
params.addParam("modal",String::boolText(parent != 0));
|
2006-05-16 21:53:40 +00:00
|
|
|
if (!null(context))
|
|
|
|
params.addParam("context",context);
|
2006-01-26 00:00:36 +00:00
|
|
|
return openPopup("message",¶ms,parent);
|
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// function for opening a confirm type pop-up window with the given text, parent, context
|
2006-05-16 21:53:40 +00:00
|
|
|
bool Client::openConfirm(const char* text, const Window* parent, const char* context)
|
2006-01-26 00:00:36 +00:00
|
|
|
{
|
|
|
|
NamedList params("");
|
|
|
|
params.addParam("text",text);
|
2006-04-08 18:03:28 +00:00
|
|
|
params.addParam("modal",String::boolText(parent != 0));
|
2006-05-16 21:53:40 +00:00
|
|
|
if (!null(context))
|
|
|
|
params.addParam("context",context);
|
2006-01-26 00:00:36 +00:00
|
|
|
return openPopup("confirm",¶ms,parent);
|
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// check if the window has a widget named "name"
|
2005-07-27 18:31:47 +00:00
|
|
|
bool Client::hasElement(const String& name, Window* wnd, Window* skip)
|
|
|
|
{
|
2005-08-13 02:02:55 +00:00
|
|
|
if (needProxy()) {
|
|
|
|
ClientThreadProxy proxy(ClientThreadProxy::hasElement,name,false,wnd,skip);
|
|
|
|
return proxy.execute();
|
|
|
|
}
|
2005-07-27 18:31:47 +00:00
|
|
|
if (wnd)
|
|
|
|
return wnd->hasElement(name);
|
|
|
|
ObjList* l = &m_windows;
|
|
|
|
for (; l; l = l->next()) {
|
|
|
|
wnd = static_cast<Window*>(l->get());
|
|
|
|
if (wnd && (wnd != skip) && wnd->hasElement(name))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// function for controlling the visibility attribute of the "name" widget from the window given as a parameter
|
|
|
|
// if no window is given, we search for it
|
2005-07-04 22:04:47 +00:00
|
|
|
bool Client::setShow(const String& name, bool visible, Window* wnd, Window* skip)
|
|
|
|
{
|
2005-08-13 02:02:55 +00:00
|
|
|
if (needProxy()) {
|
|
|
|
ClientThreadProxy proxy(ClientThreadProxy::setShow,name,visible,wnd,skip);
|
|
|
|
return proxy.execute();
|
|
|
|
}
|
2005-07-04 22:04:47 +00:00
|
|
|
if (wnd)
|
|
|
|
return wnd->setShow(name,visible);
|
|
|
|
++s_changing;
|
|
|
|
bool ok = false;
|
|
|
|
ObjList* l = &m_windows;
|
|
|
|
for (; l; l = l->next()) {
|
|
|
|
wnd = static_cast<Window*>(l->get());
|
|
|
|
if (wnd && (wnd != skip))
|
|
|
|
ok = wnd->setShow(name,visible) || ok;
|
|
|
|
}
|
|
|
|
--s_changing;
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// function for controlling the enabled attribute of the "name" widget from the "wnd" window
|
2005-07-04 22:04:47 +00:00
|
|
|
bool Client::setActive(const String& name, bool active, Window* wnd, Window* skip)
|
|
|
|
{
|
2005-08-13 02:02:55 +00:00
|
|
|
if (needProxy()) {
|
|
|
|
ClientThreadProxy proxy(ClientThreadProxy::setActive,name,active,wnd,skip);
|
|
|
|
return proxy.execute();
|
|
|
|
}
|
2005-07-04 22:04:47 +00:00
|
|
|
if (wnd)
|
|
|
|
return wnd->setActive(name,active);
|
|
|
|
++s_changing;
|
|
|
|
bool ok = false;
|
|
|
|
ObjList* l = &m_windows;
|
|
|
|
for (; l; l = l->next()) {
|
|
|
|
wnd = static_cast<Window*>(l->get());
|
|
|
|
if (wnd && (wnd != skip))
|
|
|
|
ok = wnd->setActive(name,active) || ok;
|
|
|
|
}
|
|
|
|
--s_changing;
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// function for controlling the focus attribute of the "name" widget from the "wnd" window
|
2006-05-29 13:58:09 +00:00
|
|
|
bool Client::setFocus(const String& name, bool select, Window* wnd, Window* skip)
|
|
|
|
{
|
|
|
|
if (needProxy()) {
|
|
|
|
ClientThreadProxy proxy(ClientThreadProxy::setFocus,name,select,wnd,skip);
|
|
|
|
return proxy.execute();
|
|
|
|
}
|
|
|
|
if (wnd)
|
|
|
|
return wnd->setFocus(name,select);
|
|
|
|
++s_changing;
|
|
|
|
bool ok = false;
|
|
|
|
ObjList* l = &m_windows;
|
|
|
|
for (; l; l = l->next()) {
|
|
|
|
wnd = static_cast<Window*>(l->get());
|
|
|
|
if (wnd && (wnd != skip))
|
|
|
|
ok = wnd->setFocus(name,select) || ok;
|
|
|
|
}
|
|
|
|
--s_changing;
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// function for setting the text of the widget identified by "name"
|
|
|
|
bool Client::setText(const String& name, const String& text, bool richText,
|
|
|
|
Window* wnd, Window* skip)
|
2005-07-04 22:04:47 +00:00
|
|
|
{
|
2005-08-13 02:02:55 +00:00
|
|
|
if (needProxy()) {
|
2008-08-04 02:06:00 +00:00
|
|
|
ClientThreadProxy proxy(ClientThreadProxy::setText,name,text,"",richText,wnd,skip);
|
2005-08-13 02:02:55 +00:00
|
|
|
return proxy.execute();
|
|
|
|
}
|
2005-07-04 22:04:47 +00:00
|
|
|
if (wnd)
|
2008-08-04 02:06:00 +00:00
|
|
|
return wnd->setText(name,text,richText);
|
2005-07-04 22:04:47 +00:00
|
|
|
++s_changing;
|
|
|
|
bool ok = false;
|
2008-08-04 02:06:00 +00:00
|
|
|
for (ObjList* o = m_windows.skipNull(); o; o = o->skipNext()) {
|
|
|
|
wnd = static_cast<Window*>(o->get());
|
|
|
|
if (wnd != skip)
|
|
|
|
ok = wnd->setText(name,text,richText) || ok;
|
2005-07-04 22:04:47 +00:00
|
|
|
}
|
|
|
|
--s_changing;
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// function that controls the checked attribute of checkable widgets
|
2005-07-04 22:04:47 +00:00
|
|
|
bool Client::setCheck(const String& name, bool checked, Window* wnd, Window* skip)
|
|
|
|
{
|
2005-08-13 02:02:55 +00:00
|
|
|
if (needProxy()) {
|
|
|
|
ClientThreadProxy proxy(ClientThreadProxy::setCheck,name,checked,wnd,skip);
|
|
|
|
return proxy.execute();
|
|
|
|
}
|
2005-07-04 22:04:47 +00:00
|
|
|
if (wnd)
|
|
|
|
return wnd->setCheck(name,checked);
|
|
|
|
++s_changing;
|
|
|
|
bool ok = false;
|
|
|
|
ObjList* l = &m_windows;
|
|
|
|
for (; l; l = l->next()) {
|
|
|
|
wnd = static_cast<Window*>(l->get());
|
|
|
|
if (wnd && (wnd != skip))
|
|
|
|
ok = wnd->setCheck(name,checked) || ok;
|
|
|
|
}
|
|
|
|
--s_changing;
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// function for selecting the widget named "name" from the "wnd" window if given, else look for the widget
|
2005-07-04 22:04:47 +00:00
|
|
|
bool Client::setSelect(const String& name, const String& item, Window* wnd, Window* skip)
|
|
|
|
{
|
2005-08-13 02:02:55 +00:00
|
|
|
if (needProxy()) {
|
|
|
|
ClientThreadProxy proxy(ClientThreadProxy::setSelect,name,item,wnd,skip);
|
|
|
|
return proxy.execute();
|
|
|
|
}
|
2005-07-04 22:04:47 +00:00
|
|
|
if (wnd)
|
|
|
|
return wnd->setSelect(name,item);
|
|
|
|
++s_changing;
|
|
|
|
bool ok = false;
|
|
|
|
ObjList* l = &m_windows;
|
|
|
|
for (; l; l = l->next()) {
|
|
|
|
wnd = static_cast<Window*>(l->get());
|
|
|
|
if (wnd && (wnd != skip))
|
|
|
|
ok = wnd->setSelect(name,item) || ok;
|
|
|
|
}
|
|
|
|
--s_changing;
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// function for handling an action that requires immediate action on the "name" widget
|
2005-07-27 18:31:47 +00:00
|
|
|
bool Client::setUrgent(const String& name, bool urgent, Window* wnd, Window* skip)
|
|
|
|
{
|
2005-08-13 02:02:55 +00:00
|
|
|
if (needProxy()) {
|
|
|
|
ClientThreadProxy proxy(ClientThreadProxy::setUrgent,name,urgent,wnd,skip);
|
|
|
|
return proxy.execute();
|
|
|
|
}
|
2005-07-27 18:31:47 +00:00
|
|
|
if (wnd)
|
|
|
|
return wnd->setUrgent(name,urgent);
|
|
|
|
++s_changing;
|
|
|
|
bool ok = false;
|
|
|
|
ObjList* l = &m_windows;
|
|
|
|
for (; l; l = l->next()) {
|
|
|
|
wnd = static_cast<Window*>(l->get());
|
|
|
|
if (wnd && (wnd != skip))
|
|
|
|
ok = wnd->setUrgent(name,urgent) || ok;
|
|
|
|
}
|
|
|
|
--s_changing;
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// function for checking if the "name" widget has the specified item
|
2006-04-08 18:03:28 +00:00
|
|
|
bool Client::hasOption(const String& name, const String& item, Window* wnd, Window* skip)
|
|
|
|
{
|
|
|
|
if (needProxy()) {
|
|
|
|
ClientThreadProxy proxy(ClientThreadProxy::hasOption,name,item,wnd,skip);
|
|
|
|
return proxy.execute();
|
|
|
|
}
|
|
|
|
if (wnd)
|
|
|
|
return wnd->hasOption(name,item);
|
|
|
|
ObjList* l = &m_windows;
|
|
|
|
for (; l; l = l->next()) {
|
|
|
|
wnd = static_cast<Window*>(l->get());
|
|
|
|
if (wnd && (wnd != skip) && wnd->hasOption(name,item))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// function for adding a new option to the "name" widget from the "wnd" window, if given
|
2005-07-25 22:44:34 +00:00
|
|
|
bool Client::addOption(const String& name, const String& item, bool atStart, const String& text, Window* wnd, Window* skip)
|
2005-07-04 22:04:47 +00:00
|
|
|
{
|
2005-08-13 02:02:55 +00:00
|
|
|
if (needProxy()) {
|
|
|
|
ClientThreadProxy proxy(ClientThreadProxy::addOption,name,text,item,atStart,wnd,skip);
|
|
|
|
return proxy.execute();
|
|
|
|
}
|
2005-07-04 22:04:47 +00:00
|
|
|
if (wnd)
|
2005-07-25 22:44:34 +00:00
|
|
|
return wnd->addOption(name,item,atStart,text);
|
2005-07-04 22:04:47 +00:00
|
|
|
++s_changing;
|
|
|
|
bool ok = false;
|
|
|
|
ObjList* l = &m_windows;
|
|
|
|
for (; l; l = l->next()) {
|
|
|
|
wnd = static_cast<Window*>(l->get());
|
|
|
|
if (wnd && (wnd != skip))
|
2005-07-25 22:44:34 +00:00
|
|
|
ok = wnd->addOption(name,item,atStart,text) || ok;
|
2005-07-04 22:04:47 +00:00
|
|
|
}
|
|
|
|
--s_changing;
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// function for deleting an option from the "name" widget from the "wnd" window, if given
|
2005-07-04 22:04:47 +00:00
|
|
|
bool Client::delOption(const String& name, const String& item, Window* wnd, Window* skip)
|
|
|
|
{
|
2005-08-13 02:02:55 +00:00
|
|
|
if (needProxy()) {
|
|
|
|
ClientThreadProxy proxy(ClientThreadProxy::delOption,name,item,wnd,skip);
|
|
|
|
return proxy.execute();
|
|
|
|
}
|
2005-07-04 22:04:47 +00:00
|
|
|
if (wnd)
|
|
|
|
return wnd->delOption(name,item);
|
|
|
|
++s_changing;
|
|
|
|
bool ok = false;
|
|
|
|
ObjList* l = &m_windows;
|
|
|
|
for (; l; l = l->next()) {
|
|
|
|
wnd = static_cast<Window*>(l->get());
|
|
|
|
if (wnd && (wnd != skip))
|
|
|
|
ok = wnd->delOption(name,item) || ok;
|
|
|
|
}
|
|
|
|
--s_changing;
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// Get an element's items
|
|
|
|
bool Client::getOptions(const String& name, NamedList* items,
|
|
|
|
Window* wnd, Window* skip)
|
|
|
|
{
|
|
|
|
if (needProxy()) {
|
|
|
|
ClientThreadProxy proxy(ClientThreadProxy::getOptions,name,items,wnd,skip);
|
|
|
|
return proxy.execute();
|
|
|
|
}
|
|
|
|
if (wnd)
|
|
|
|
return wnd->getOptions(name,items);
|
|
|
|
++s_changing;
|
|
|
|
bool ok = false;
|
|
|
|
ObjList* l = &m_windows;
|
|
|
|
for (; l; l = l->next()) {
|
|
|
|
wnd = static_cast<Window*>(l->get());
|
|
|
|
if (wnd && (wnd != skip))
|
|
|
|
ok = wnd->getOptions(name,items) || ok;
|
|
|
|
}
|
|
|
|
--s_changing;
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Append or insert text lines to a widget
|
|
|
|
bool Client::addLines(const String& name, const NamedList* lines, unsigned int max,
|
|
|
|
bool atStart, Window* wnd, Window* skip)
|
|
|
|
{
|
|
|
|
if (!lines)
|
|
|
|
return false;
|
|
|
|
if (needProxy()) {
|
|
|
|
ClientThreadProxy proxy(ClientThreadProxy::addLines,name,lines,max,atStart,wnd,skip);
|
|
|
|
return proxy.execute();
|
|
|
|
}
|
|
|
|
if (wnd)
|
|
|
|
return wnd->addLines(name,lines,max,atStart);
|
|
|
|
++s_changing;
|
|
|
|
bool ok = false;
|
|
|
|
for (ObjList* o = m_windows.skipNull(); o; o = o->skipNext()) {
|
|
|
|
wnd = static_cast<Window*>(o->get());
|
|
|
|
if (wnd != skip)
|
|
|
|
ok = wnd->addLines(name,lines,max,atStart) || ok;
|
|
|
|
}
|
|
|
|
--s_changing;
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
// function for adding a new row to a table with the "name" id
|
|
|
|
bool Client::addTableRow(const String& name, const String& item, const NamedList* data,
|
|
|
|
bool atStart, Window* wnd, Window* skip)
|
2006-01-30 20:44:03 +00:00
|
|
|
{
|
|
|
|
if (needProxy()) {
|
|
|
|
ClientThreadProxy proxy(ClientThreadProxy::addTableRow,name,item,atStart,data,wnd,skip);
|
|
|
|
return proxy.execute();
|
|
|
|
}
|
|
|
|
if (wnd)
|
|
|
|
return wnd->addTableRow(name,item,data,atStart);
|
|
|
|
++s_changing;
|
|
|
|
bool ok = false;
|
|
|
|
ObjList* l = &m_windows;
|
|
|
|
for (; l; l = l->next()) {
|
|
|
|
wnd = static_cast<Window*>(l->get());
|
|
|
|
if (wnd && (wnd != skip))
|
|
|
|
ok = wnd->addTableRow(name,item,data,atStart) || ok;
|
|
|
|
}
|
|
|
|
--s_changing;
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// function for deleting a row from the "name" table
|
2006-01-30 20:44:03 +00:00
|
|
|
bool Client::delTableRow(const String& name, const String& item, Window* wnd, Window* skip)
|
|
|
|
{
|
|
|
|
if (needProxy()) {
|
|
|
|
ClientThreadProxy proxy(ClientThreadProxy::delTableRow,name,item,wnd,skip);
|
|
|
|
return proxy.execute();
|
|
|
|
}
|
|
|
|
if (wnd)
|
|
|
|
return wnd->delTableRow(name,item);
|
|
|
|
++s_changing;
|
|
|
|
bool ok = false;
|
|
|
|
ObjList* l = &m_windows;
|
|
|
|
for (; l; l = l->next()) {
|
|
|
|
wnd = static_cast<Window*>(l->get());
|
|
|
|
if (wnd && (wnd != skip))
|
|
|
|
ok = wnd->delTableRow(name,item) || ok;
|
|
|
|
}
|
|
|
|
--s_changing;
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// function for changing the value of a row from the "name" table
|
2006-01-30 20:44:03 +00:00
|
|
|
bool Client::setTableRow(const String& name, const String& item, const NamedList* data, Window* wnd, Window* skip)
|
|
|
|
{
|
|
|
|
if (needProxy()) {
|
|
|
|
ClientThreadProxy proxy(ClientThreadProxy::setTableRow,name,item,false,data,wnd,skip);
|
|
|
|
return proxy.execute();
|
|
|
|
}
|
|
|
|
if (wnd)
|
|
|
|
return wnd->setTableRow(name,item,data);
|
|
|
|
++s_changing;
|
|
|
|
bool ok = false;
|
|
|
|
ObjList* l = &m_windows;
|
|
|
|
for (; l; l = l->next()) {
|
|
|
|
wnd = static_cast<Window*>(l->get());
|
|
|
|
if (wnd && (wnd != skip))
|
|
|
|
ok = wnd->setTableRow(name,item,data) || ok;
|
|
|
|
}
|
|
|
|
--s_changing;
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// function for obtaining the information from a specific row from the "name" table
|
2006-04-08 18:03:28 +00:00
|
|
|
bool Client::getTableRow(const String& name, const String& item, NamedList* data, Window* wnd, Window* skip)
|
|
|
|
{
|
|
|
|
if (needProxy()) {
|
|
|
|
ClientThreadProxy proxy(ClientThreadProxy::getTableRow,name,item,false,data,wnd,skip);
|
|
|
|
return proxy.execute();
|
|
|
|
}
|
|
|
|
if (wnd)
|
|
|
|
return wnd->getTableRow(name,item,data);
|
|
|
|
ObjList* l = &m_windows;
|
|
|
|
for (; l; l = l->next()) {
|
|
|
|
wnd = static_cast<Window*>(l->get());
|
|
|
|
if (wnd && (wnd != skip) && wnd->getTableRow(name,item,data))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2008-09-18 10:08:02 +00:00
|
|
|
// Set a table row or add a new one if not found
|
|
|
|
bool Client::updateTableRow(const String& name, const String& item,
|
|
|
|
const NamedList* data, bool atStart, Window* wnd, Window* skip)
|
|
|
|
{
|
|
|
|
if (needProxy()) {
|
|
|
|
ClientThreadProxy proxy(ClientThreadProxy::updateTableRow,name,item,
|
|
|
|
atStart,data,wnd,skip);
|
|
|
|
return proxy.execute();
|
|
|
|
}
|
|
|
|
if (wnd)
|
|
|
|
return wnd->updateTableRow(name,item,data,atStart);
|
|
|
|
++s_changing;
|
|
|
|
bool ok = false;
|
|
|
|
for (ObjList* l = m_windows.skipNull(); l; l = l->skipNext()) {
|
|
|
|
wnd = static_cast<Window*>(l->get());
|
|
|
|
if (wnd && (wnd != skip))
|
|
|
|
ok = wnd->updateTableRow(name,item,data,atStart) || ok;
|
|
|
|
}
|
|
|
|
--s_changing;
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add or set one or more table row(s)
|
|
|
|
bool Client::updateTableRows(const String& name, const NamedList* data, bool atStart,
|
|
|
|
Window* wnd, Window* skip)
|
|
|
|
{
|
|
|
|
if (needProxy()) {
|
|
|
|
ClientThreadProxy proxy(ClientThreadProxy::updateTableRows,name,String::empty(),
|
|
|
|
atStart,data,wnd,skip);
|
|
|
|
return proxy.execute();
|
|
|
|
}
|
|
|
|
if (wnd)
|
|
|
|
return wnd->updateTableRows(name,data,atStart);
|
|
|
|
++s_changing;
|
|
|
|
bool ok = false;
|
|
|
|
for (ObjList* l = m_windows.skipNull(); l; l = l->skipNext()) {
|
|
|
|
wnd = static_cast<Window*>(l->get());
|
|
|
|
if (wnd && (wnd != skip))
|
|
|
|
ok = wnd->updateTableRows(name,data,atStart) || ok;
|
|
|
|
}
|
|
|
|
--s_changing;
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// function for deleting all row from a table given by the name parameter
|
2006-04-08 18:03:28 +00:00
|
|
|
bool Client::clearTable(const String& name, Window* wnd, Window* skip)
|
|
|
|
{
|
|
|
|
if (needProxy()) {
|
|
|
|
ClientThreadProxy proxy(ClientThreadProxy::clearTable,name,false,wnd,skip);
|
|
|
|
return proxy.execute();
|
|
|
|
}
|
|
|
|
if (wnd)
|
|
|
|
return wnd->clearTable(name);
|
|
|
|
++s_changing;
|
|
|
|
bool ok = false;
|
|
|
|
ObjList* l = &m_windows;
|
|
|
|
for (; l; l = l->next()) {
|
|
|
|
wnd = static_cast<Window*>(l->get());
|
|
|
|
if (wnd && (wnd != skip))
|
|
|
|
ok = wnd->clearTable(name) || ok;
|
|
|
|
}
|
|
|
|
--s_changing;
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// function for obtaining the text from the "name" widget
|
2008-08-14 15:04:55 +00:00
|
|
|
bool Client::getText(const String& name, String& text, bool richText, Window* wnd, Window* skip)
|
2005-07-04 22:04:47 +00:00
|
|
|
{
|
2005-08-13 02:02:55 +00:00
|
|
|
if (needProxy()) {
|
2008-08-14 15:04:55 +00:00
|
|
|
ClientThreadProxy proxy(ClientThreadProxy::getText,name,&text,&richText,wnd,skip);
|
2005-08-13 02:02:55 +00:00
|
|
|
return proxy.execute();
|
|
|
|
}
|
2005-07-04 22:04:47 +00:00
|
|
|
if (wnd)
|
2008-08-14 15:04:55 +00:00
|
|
|
return wnd->getText(name,text,richText);
|
2005-07-04 22:04:47 +00:00
|
|
|
ObjList* l = &m_windows;
|
|
|
|
for (; l; l = l->next()) {
|
|
|
|
wnd = static_cast<Window*>(l->get());
|
2008-08-14 15:04:55 +00:00
|
|
|
if (wnd && (wnd != skip) && wnd->getText(name,text,richText))
|
2005-07-04 22:04:47 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// function for obtaining the status of the checked attribute for the "name" checkable attribute
|
2005-07-04 22:04:47 +00:00
|
|
|
bool Client::getCheck(const String& name, bool& checked, Window* wnd, Window* skip)
|
|
|
|
{
|
2005-08-13 02:02:55 +00:00
|
|
|
if (needProxy()) {
|
|
|
|
ClientThreadProxy proxy(ClientThreadProxy::getCheck,name,0,&checked,wnd,skip);
|
|
|
|
return proxy.execute();
|
|
|
|
}
|
2005-07-04 22:04:47 +00:00
|
|
|
if (wnd)
|
|
|
|
return wnd->getCheck(name,checked);
|
|
|
|
ObjList* l = &m_windows;
|
|
|
|
for (; l; l = l->next()) {
|
|
|
|
wnd = static_cast<Window*>(l->get());
|
|
|
|
if (wnd && (wnd != skip) && wnd->getCheck(name,checked))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// get the iten currently selected from the "name" widget
|
2005-07-04 22:04:47 +00:00
|
|
|
bool Client::getSelect(const String& name, String& item, Window* wnd, Window* skip)
|
|
|
|
{
|
2005-08-13 02:02:55 +00:00
|
|
|
if (needProxy()) {
|
|
|
|
ClientThreadProxy proxy(ClientThreadProxy::getSelect,name,&item,0,wnd,skip);
|
|
|
|
return proxy.execute();
|
|
|
|
}
|
2005-07-25 22:44:34 +00:00
|
|
|
if (wnd)
|
|
|
|
return wnd->getSelect(name,item);
|
|
|
|
ObjList* l = &m_windows;
|
|
|
|
for (; l; l = l->next()) {
|
|
|
|
wnd = static_cast<Window*>(l->get());
|
|
|
|
if (wnd && (wnd != skip) && wnd->getSelect(name,item))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2005-07-04 22:04:47 +00:00
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// Set a property
|
|
|
|
bool Client::setProperty(const String& name, const String& item, const String& value,
|
|
|
|
Window* wnd, Window* skip)
|
2005-07-04 22:04:47 +00:00
|
|
|
{
|
2008-08-04 02:06:00 +00:00
|
|
|
if (needProxy()) {
|
|
|
|
ClientThreadProxy proxy(ClientThreadProxy::setProperty,name,value,item,false,wnd,skip);
|
|
|
|
return proxy.execute();
|
2006-08-17 17:47:43 +00:00
|
|
|
}
|
2008-08-04 02:06:00 +00:00
|
|
|
if (wnd)
|
|
|
|
return wnd->setProperty(name,item,value);
|
|
|
|
++s_changing;
|
|
|
|
bool ok = false;
|
|
|
|
for (ObjList* o = m_windows.skipNull(); o; o = o->skipNext()) {
|
|
|
|
wnd = static_cast<Window*>(o->get());
|
|
|
|
if (wnd != skip)
|
|
|
|
ok = wnd->setProperty(name,item,value) || ok;
|
|
|
|
}
|
|
|
|
--s_changing;
|
|
|
|
return ok;
|
2006-09-17 23:19:05 +00:00
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// Get a property
|
|
|
|
bool Client::getProperty(const String& name, const String& item, String& value,
|
|
|
|
Window* wnd, Window* skip)
|
2006-09-17 23:19:05 +00:00
|
|
|
{
|
2008-08-04 02:06:00 +00:00
|
|
|
if (needProxy()) {
|
|
|
|
ClientThreadProxy proxy(ClientThreadProxy::getProperty,name,value,item,false,wnd,skip);
|
|
|
|
return proxy.execute();
|
|
|
|
}
|
|
|
|
if (wnd)
|
|
|
|
return wnd->getProperty(name,item,value);
|
|
|
|
++s_changing;
|
|
|
|
bool ok = false;
|
|
|
|
for (ObjList* o = m_windows.skipNull(); o; o = o->skipNext()) {
|
|
|
|
wnd = static_cast<Window*>(o->get());
|
|
|
|
if (wnd != skip)
|
|
|
|
ok = wnd->getProperty(name,item,value) || ok;
|
|
|
|
}
|
|
|
|
--s_changing;
|
|
|
|
return ok;
|
2006-09-17 23:19:05 +00:00
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// Create a window with a given name
|
|
|
|
bool Client::createWindowSafe(const String& name, const String& alias)
|
2006-09-17 23:19:05 +00:00
|
|
|
{
|
2008-08-04 02:06:00 +00:00
|
|
|
if (needProxy()) {
|
|
|
|
ClientThreadProxy proxy(ClientThreadProxy::createWindow,name,alias,0,0);
|
|
|
|
return proxy.execute();
|
|
|
|
}
|
|
|
|
if (!createWindow(name,alias))
|
|
|
|
return false;
|
|
|
|
ObjList* obj = m_windows.find(alias);
|
|
|
|
if (!obj)
|
|
|
|
return false;
|
|
|
|
(static_cast<Window*>(obj->get()))->init();
|
|
|
|
return true;
|
2005-07-04 22:04:47 +00:00
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// Ask to an UI factory to create an object in the UI's thread
|
|
|
|
bool Client::createObject(void** dest, const String& type, const char* name,
|
|
|
|
NamedList* params)
|
2005-07-04 22:04:47 +00:00
|
|
|
{
|
2008-08-04 02:06:00 +00:00
|
|
|
if (!dest)
|
|
|
|
return false;
|
|
|
|
if (needProxy()) {
|
|
|
|
ClientThreadProxy proxy(ClientThreadProxy::createObject,dest,type,name,params);
|
|
|
|
return proxy.execute();
|
|
|
|
}
|
|
|
|
*dest = UIFactory::build(type,name,params);
|
|
|
|
return (0 != *dest);
|
2005-07-04 22:04:47 +00:00
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// Hide/close a window with a given name
|
|
|
|
bool Client::closeWindow(const String& name, bool hide)
|
2005-07-04 22:04:47 +00:00
|
|
|
{
|
2008-08-04 02:06:00 +00:00
|
|
|
if (needProxy()) {
|
|
|
|
ClientThreadProxy proxy(ClientThreadProxy::closeWindow,name,hide);
|
|
|
|
return proxy.execute();
|
2006-05-17 15:14:43 +00:00
|
|
|
}
|
2008-08-04 02:06:00 +00:00
|
|
|
Window* wnd = getWindow(name);
|
|
|
|
if (!wnd)
|
|
|
|
return false;
|
|
|
|
if (hide)
|
|
|
|
wnd->hide();
|
|
|
|
else if (wnd->canClose())
|
|
|
|
TelEngine::destruct(wnd);
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
return true;
|
2005-07-04 22:04:47 +00:00
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// Set multiple window parameters
|
|
|
|
bool Client::setParams(const NamedList* params, Window* wnd, Window* skip)
|
2005-07-04 22:04:47 +00:00
|
|
|
{
|
2008-08-04 02:06:00 +00:00
|
|
|
if (!params)
|
|
|
|
return false;
|
|
|
|
if (needProxy()) {
|
|
|
|
ClientThreadProxy proxy(ClientThreadProxy::setParams,String::empty(),
|
|
|
|
(NamedList*)params,wnd,skip);
|
|
|
|
return proxy.execute();
|
2007-05-25 17:08:13 +00:00
|
|
|
}
|
2005-07-12 20:51:47 +00:00
|
|
|
if (wnd)
|
2008-08-04 02:06:00 +00:00
|
|
|
return wnd->setParams(*params);
|
|
|
|
++s_changing;
|
|
|
|
bool ok = false;
|
|
|
|
for (ObjList* o = m_windows.skipNull(); o; o = o->skipNext()) {
|
|
|
|
wnd = static_cast<Window*>(o->get());
|
|
|
|
if (wnd && (wnd != skip))
|
|
|
|
ok = wnd->setParams(*params) || ok;
|
2006-04-08 18:03:28 +00:00
|
|
|
}
|
2008-08-04 02:06:00 +00:00
|
|
|
--s_changing;
|
|
|
|
return ok;
|
2005-07-04 22:04:47 +00:00
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
bool Client::addToLog(const String& text)
|
2005-07-04 22:04:47 +00:00
|
|
|
{
|
2008-08-04 02:06:00 +00:00
|
|
|
dbg_client_func(text,-1);
|
|
|
|
return true;
|
2005-07-04 22:04:47 +00:00
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// set the status of the client
|
|
|
|
bool Client::setStatus(const String& text, Window* wnd)
|
2005-07-04 22:04:47 +00:00
|
|
|
{
|
2008-08-04 02:06:00 +00:00
|
|
|
Debug(ClientDriver::self(),DebugInfo,"Status '%s' in window %p",text.c_str(),wnd);
|
|
|
|
addToLog(text);
|
|
|
|
return setText(s_statusWidget,text,false,wnd);
|
2005-07-04 22:04:47 +00:00
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
bool Client::setStatusLocked(const String& text, Window* wnd)
|
2005-07-04 22:04:47 +00:00
|
|
|
{
|
2008-08-04 02:06:00 +00:00
|
|
|
lockOther();
|
|
|
|
bool ok = setStatus(text,wnd);
|
|
|
|
unlockOther();
|
|
|
|
return ok;
|
2005-07-04 22:04:47 +00:00
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// Change debug output
|
|
|
|
bool Client::debugHook(bool active)
|
2005-07-04 22:04:47 +00:00
|
|
|
{
|
2008-08-04 02:06:00 +00:00
|
|
|
if (ClientDriver::self())
|
|
|
|
ClientDriver::self()->debugEnabled(!active);
|
|
|
|
Debugger::setOutput(active ? dbg_client_func : 0);
|
2006-05-07 15:11:31 +00:00
|
|
|
return true;
|
2005-07-04 22:04:47 +00:00
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// Process received messages
|
|
|
|
bool Client::received(Message& msg, int id)
|
2005-07-04 22:04:47 +00:00
|
|
|
{
|
2008-08-04 02:06:00 +00:00
|
|
|
bool processed = false;
|
|
|
|
bool stop = false;
|
|
|
|
for (ObjList* o = s_logics.skipNull(); !stop && o; o = o->skipNext()) {
|
|
|
|
ClientLogic* logic = static_cast<ClientLogic*>(o->get());
|
|
|
|
Debug(ClientDriver::self(),DebugAll,"Logic(%s) processing %s [%p]",
|
|
|
|
logic->toString().c_str(),msg.c_str(),logic);
|
|
|
|
switch (id) {
|
|
|
|
case CallCdr:
|
|
|
|
processed = logic->handleCallCdr(msg,stop) || processed;
|
|
|
|
break;
|
|
|
|
case UiAction:
|
|
|
|
processed = logic->handleUiAction(msg,stop) || processed;
|
|
|
|
break;
|
|
|
|
case UserLogin:
|
|
|
|
processed = logic->handleUserLogin(msg,stop) || processed;
|
|
|
|
break;
|
|
|
|
case UserNotify:
|
|
|
|
processed = logic->handleUserNotify(msg,stop) || processed;
|
|
|
|
break;
|
|
|
|
case ResourceNotify:
|
|
|
|
processed = logic->handleResourceNotify(msg,stop) || processed;
|
|
|
|
break;
|
|
|
|
case ResourceSubscribe:
|
|
|
|
processed = logic->handleResourceSubscribe(msg,stop) || processed;
|
|
|
|
break;
|
|
|
|
case XmppIq:
|
|
|
|
processed = logic->handleXmppIq(msg,stop) || processed;
|
|
|
|
break;
|
|
|
|
case ClientChanUpdate:
|
|
|
|
processed = logic->handleClientChanUpdate(msg,stop) || processed;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
processed = logic->defaultMsgHandler(msg,id,stop) || processed;
|
2005-07-04 22:04:47 +00:00
|
|
|
}
|
|
|
|
}
|
2008-08-04 02:06:00 +00:00
|
|
|
return processed;
|
2005-07-04 22:04:47 +00:00
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// Handle actions from user interface
|
|
|
|
bool Client::action(Window* wnd, const String& name, NamedList* params)
|
2006-01-23 15:57:47 +00:00
|
|
|
{
|
2008-08-04 02:06:00 +00:00
|
|
|
static String sect = "action";
|
2006-01-23 15:57:47 +00:00
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
XDebug(ClientDriver::self(),DebugAll,"Action '%s' in window (%p,%s)",
|
2008-09-18 14:41:30 +00:00
|
|
|
name.c_str(),wnd,wnd ? wnd->id().c_str() : "");
|
2008-08-04 02:06:00 +00:00
|
|
|
|
|
|
|
String substitute = name;
|
|
|
|
String handle;
|
|
|
|
bool only = false, prefer = false, ignore = false, bailout = false;
|
|
|
|
bool ok = false;
|
|
|
|
if (hasOverride(s_actions.getSection(sect),substitute,handle,only,prefer,ignore,bailout) &&
|
|
|
|
(only || prefer)) {
|
|
|
|
ok = callLogicAction(findLogic(handle),wnd,substitute,params);
|
|
|
|
bailout = only || ok;
|
2006-05-08 21:59:42 +00:00
|
|
|
}
|
2008-08-04 02:06:00 +00:00
|
|
|
if (bailout)
|
|
|
|
return ok;
|
|
|
|
for(ObjList* o = s_logics.skipNull(); o; o = o->skipNext()) {
|
|
|
|
ClientLogic* logic = static_cast<ClientLogic*>(o->get());
|
|
|
|
if (ignore && handle == logic->toString())
|
2006-05-08 21:59:42 +00:00
|
|
|
continue;
|
2008-08-04 02:06:00 +00:00
|
|
|
if (callLogicAction(logic,wnd,substitute,params))
|
|
|
|
return true;
|
2006-05-08 21:59:42 +00:00
|
|
|
}
|
2008-08-04 02:06:00 +00:00
|
|
|
// Not processed: enqueue event
|
|
|
|
Engine::enqueue(eventMessage("action",wnd,substitute,params));
|
|
|
|
return false;
|
2005-07-04 22:04:47 +00:00
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// Deal with toggle widget events
|
|
|
|
bool Client::toggle(Window* wnd, const String& name, bool active)
|
2005-07-14 21:41:32 +00:00
|
|
|
{
|
2008-08-04 02:06:00 +00:00
|
|
|
static String sect = "toggle";
|
2005-07-25 22:44:34 +00:00
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
XDebug(ClientDriver::self(),DebugAll,
|
|
|
|
"Toggle name='%s' active='%s' in window (%p,%s)",
|
2008-09-18 14:41:30 +00:00
|
|
|
name.c_str(),String::boolText(active),wnd,wnd ? wnd->id().c_str() : "");
|
2005-07-25 22:44:34 +00:00
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
String substitute = name;
|
|
|
|
String handle;
|
|
|
|
bool only = false, prefer = false, ignore = false, bailout = false;
|
|
|
|
bool ok = false;
|
|
|
|
if (hasOverride(s_actions.getSection(sect),substitute,handle,only,prefer,ignore,bailout) &&
|
|
|
|
(only || prefer)) {
|
|
|
|
ok = callLogicToggle(findLogic(handle),wnd,substitute,active);
|
|
|
|
bailout = only || ok;
|
2006-01-30 20:44:03 +00:00
|
|
|
}
|
2008-08-04 02:06:00 +00:00
|
|
|
if (bailout)
|
|
|
|
return ok;
|
|
|
|
for(ObjList* o = s_logics.skipNull(); o; o = o->skipNext()) {
|
|
|
|
ClientLogic* logic = static_cast<ClientLogic*>(o->get());
|
|
|
|
if (ignore && handle == logic->toString())
|
|
|
|
continue;
|
|
|
|
if (callLogicToggle(logic,wnd,substitute,active))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
// Not processed: enqueue event
|
|
|
|
Message* m = eventMessage("toggle",wnd,substitute);
|
|
|
|
m->addParam("active",String::boolText(active));
|
|
|
|
Engine::enqueue(m);
|
|
|
|
return false;
|
2006-01-30 20:44:03 +00:00
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// Handle selection changes (list selection changes, focus changes ...)
|
|
|
|
bool Client::select(Window* wnd, const String& name, const String& item, const String& text)
|
2005-07-25 22:44:34 +00:00
|
|
|
{
|
2008-08-04 02:06:00 +00:00
|
|
|
static String sect = "select";
|
2005-07-14 21:41:32 +00:00
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
XDebug(ClientDriver::self(),DebugAll,
|
|
|
|
"Select name='%s' item='%s' in window (%p,%s)",
|
2008-09-18 14:41:30 +00:00
|
|
|
name.c_str(),item.c_str(),wnd,wnd ? wnd->id().c_str() : "");
|
2005-07-14 21:41:32 +00:00
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
String substitute = name;
|
|
|
|
String handle;
|
|
|
|
bool only = false, prefer = false, ignore = false, bailout = false;
|
|
|
|
bool ok = false;
|
|
|
|
if (hasOverride(s_actions.getSection(sect),substitute,handle,only,prefer,ignore,bailout) &&
|
|
|
|
(only || prefer)) {
|
|
|
|
ok = callLogicSelect(findLogic(handle),wnd,substitute,item,text);
|
|
|
|
bailout = only || ok;
|
2006-05-31 14:50:37 +00:00
|
|
|
}
|
2008-08-04 02:06:00 +00:00
|
|
|
if (bailout)
|
|
|
|
return ok;
|
|
|
|
for(ObjList* o = s_logics.skipNull(); o; o = o->skipNext()) {
|
|
|
|
ClientLogic* logic = static_cast<ClientLogic*>(o->get());
|
|
|
|
if (ignore && handle == logic->toString())
|
|
|
|
continue;
|
|
|
|
if (callLogicSelect(logic,wnd,substitute,item,text))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
// Not processed: enqueue event
|
|
|
|
Message* m = eventMessage("select",wnd,substitute);
|
|
|
|
m->addParam("item",item);
|
|
|
|
if (text)
|
|
|
|
m->addParam("text",text);
|
|
|
|
Engine::enqueue(m);
|
|
|
|
return false;
|
2006-05-31 14:50:37 +00:00
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// function for setting the current line
|
|
|
|
void Client::line(int newLine)
|
2005-07-25 22:44:34 +00:00
|
|
|
{
|
2008-08-04 02:06:00 +00:00
|
|
|
Debug(ClientDriver::self(),DebugInfo,"line(%d)",newLine);
|
|
|
|
m_line = newLine;
|
2005-07-25 22:44:34 +00:00
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// actions taken when the client is idle, has nothing to do
|
2005-08-13 02:02:55 +00:00
|
|
|
void Client::idleActions()
|
|
|
|
{
|
2007-05-25 17:08:13 +00:00
|
|
|
s_debugMutex.lock();
|
2008-08-04 02:06:00 +00:00
|
|
|
NamedList* log = s_debugLog;
|
2007-05-25 17:08:13 +00:00
|
|
|
s_debugLog = 0;
|
|
|
|
s_debugMutex.unlock();
|
2008-08-04 02:06:00 +00:00
|
|
|
// add to the debug log new information
|
2007-05-25 17:08:13 +00:00
|
|
|
if (log) {
|
2008-08-04 02:06:00 +00:00
|
|
|
addLines(s_debugWidget,log,s_eventLen);
|
|
|
|
TelEngine::destruct(log);
|
|
|
|
}
|
|
|
|
// Tick the logics
|
|
|
|
if (s_idleLogicsTick) {
|
|
|
|
s_idleLogicsTick = false;
|
|
|
|
Time time;
|
|
|
|
for (ObjList* o = s_logics.skipNull(); o; o = o->skipNext())
|
|
|
|
(static_cast<ClientLogic*>(o->get()))->idleTimerTick(time);
|
2007-05-25 17:08:13 +00:00
|
|
|
}
|
2006-06-09 16:51:57 +00:00
|
|
|
// arbitrary limit to let other threads run too
|
|
|
|
for (int i = 0; i < 4; i++) {
|
|
|
|
if (!s_busy)
|
|
|
|
return;
|
|
|
|
ClientThreadProxy* tmp = s_proxy;
|
|
|
|
s_proxy = 0;
|
|
|
|
if (!tmp)
|
|
|
|
return;
|
2005-08-13 02:02:55 +00:00
|
|
|
tmp->process();
|
2006-06-09 16:51:57 +00:00
|
|
|
}
|
2005-08-13 02:02:55 +00:00
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// Request to a logic to set a client's parameter. Save the settings file
|
|
|
|
// and/or update interface
|
|
|
|
bool Client::setClientParam(const String& param, const String& value,
|
|
|
|
bool save, bool update)
|
|
|
|
{
|
|
|
|
for (ObjList* o = s_logics.skipNull(); o; o = o->skipNext()) {
|
|
|
|
ClientLogic* logic = static_cast<ClientLogic*>(o->get());
|
|
|
|
if (logic->setClientParam(param,value,save,update))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Called when the user pressed the backspace key
|
|
|
|
bool Client::backspace(const String& name, Window* wnd)
|
|
|
|
{
|
|
|
|
for (ObjList* o = s_logics.skipNull(); o; o = o->skipNext()) {
|
|
|
|
ClientLogic* logic = static_cast<ClientLogic*>(o->get());
|
|
|
|
if (logic->backspace(name,wnd))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2005-08-19 23:21:31 +00:00
|
|
|
bool Client::driverLock(long maxwait)
|
|
|
|
{
|
|
|
|
if (maxwait < 0)
|
|
|
|
maxwait = 0;
|
|
|
|
return ClientDriver::self() && ClientDriver::self()->lock(maxwait);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Client::driverLockLoop()
|
|
|
|
{
|
|
|
|
if (!(isCurrent() && ClientDriver::self()))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
while (!driverLock()) {
|
|
|
|
if (Engine::exiting() || !ClientDriver::self())
|
|
|
|
return false;
|
|
|
|
idleActions();
|
|
|
|
yield();
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Client::driverUnlock()
|
|
|
|
{
|
|
|
|
if (ClientDriver::self())
|
|
|
|
ClientDriver::self()->unlock();
|
|
|
|
}
|
|
|
|
|
2005-08-13 02:02:55 +00:00
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// Create and install a message relay owned by this client.
|
|
|
|
void Client::installRelay(const char* name, int id, int prio)
|
|
|
|
{
|
|
|
|
if (!(name && *name))
|
|
|
|
return;
|
|
|
|
Debug(ClientDriver::self(),DebugAll,"installRelay(%s,%d,%d)",name,id,prio);
|
|
|
|
MessageRelay* relay = new MessageRelay(name,this,id,prio);
|
|
|
|
if (Engine::install(relay))
|
|
|
|
m_relays.append(relay);
|
|
|
|
else
|
|
|
|
TelEngine::destruct(relay);
|
|
|
|
}
|
|
|
|
|
2008-08-14 09:58:19 +00:00
|
|
|
// Process an IM message
|
|
|
|
bool Client::imExecute(Message& msg)
|
|
|
|
{
|
2008-09-18 14:53:42 +00:00
|
|
|
static String sect = "miscellaneous";
|
2008-08-14 09:58:19 +00:00
|
|
|
|
|
|
|
XDebug(ClientDriver::self(),DebugAll,"Client::imExecute [%p]",this);
|
|
|
|
// Check for a preferred or only logic
|
|
|
|
String name = "imincoming";
|
|
|
|
String handle;
|
|
|
|
bool only = false, prefer = false, ignore = false, bailout = false;
|
|
|
|
bool ok = false;
|
|
|
|
if (hasOverride(s_actions.getSection(sect),name,handle,only,prefer,ignore,bailout) &&
|
|
|
|
(only || prefer)) {
|
|
|
|
ClientLogic* logic = findLogic(handle);
|
|
|
|
if (logic)
|
|
|
|
ok = logic->imIncoming(msg);
|
|
|
|
bailout = only || ok;
|
|
|
|
}
|
|
|
|
if (bailout)
|
|
|
|
return ok;
|
|
|
|
// Ask the logics to create a channel
|
|
|
|
for (ObjList* o = s_logics.skipNull(); o; o = o->skipNext()) {
|
|
|
|
ClientLogic* logic = static_cast<ClientLogic*>(o->get());
|
|
|
|
if (ignore && handle == logic->toString())
|
|
|
|
continue;
|
|
|
|
Debug(ClientDriver::self(),DebugAll,"Logic(%s) imIncoming [%p]",
|
|
|
|
logic->toString().c_str(),logic);
|
|
|
|
if (logic->imIncoming(msg))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// Build an incoming channel
|
|
|
|
bool Client::buildIncomingChannel(Message& msg, const String& dest)
|
2006-01-30 20:44:03 +00:00
|
|
|
{
|
2008-08-04 02:06:00 +00:00
|
|
|
Debug(ClientDriver::self(),DebugAll,"Client::buildIncomingChannel() [%p]",this);
|
|
|
|
if (!(msg.userData() && ClientDriver::self()))
|
2006-01-30 20:44:03 +00:00
|
|
|
return false;
|
2008-08-04 02:06:00 +00:00
|
|
|
CallEndpoint* peer = static_cast<CallEndpoint*>(msg.userData());
|
|
|
|
if (!peer)
|
|
|
|
return false;
|
|
|
|
ClientDriver::self()->lock();
|
|
|
|
ClientChannel* chan = new ClientChannel(msg,peer->id());
|
|
|
|
ClientDriver::self()->unlock();
|
|
|
|
bool ok = chan->connect(peer,msg.getValue("reason"));
|
|
|
|
// Activate or answer
|
|
|
|
if (ok) {
|
|
|
|
msg.setParam("targetid",chan->id());
|
|
|
|
if (!getBoolOpt(OptAutoAnswer)) {
|
|
|
|
if (getBoolOpt(OptActivateLastInCall) && !ClientDriver::self()->activeId())
|
|
|
|
ClientDriver::self()->setActive(chan->id());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
chan->callAnswer();
|
|
|
|
}
|
|
|
|
TelEngine::destruct(chan);
|
|
|
|
return ok;
|
|
|
|
}
|
2006-04-08 18:03:28 +00:00
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// Build an outgoing channel
|
|
|
|
bool Client::buildOutgoingChannel(NamedList& params)
|
|
|
|
{
|
|
|
|
Debug(ClientDriver::self(),DebugAll,"Client::buildOutgoingChannel() [%p]",this);
|
|
|
|
// get the target of the call
|
|
|
|
NamedString* target = params.getParam("target");
|
|
|
|
if (!target || target->null())
|
2006-05-08 21:59:42 +00:00
|
|
|
return false;
|
2008-08-04 02:06:00 +00:00
|
|
|
// Create the channel. Release driver's mutex as soon as possible
|
|
|
|
if (!driverLockLoop())
|
|
|
|
return false;
|
|
|
|
ClientChannel* chan = new ClientChannel(target,params);
|
|
|
|
if (!chan->ref())
|
|
|
|
TelEngine::destruct(chan);
|
|
|
|
driverUnlock();
|
|
|
|
if (!chan)
|
2006-05-08 21:59:42 +00:00
|
|
|
return false;
|
2008-08-04 02:06:00 +00:00
|
|
|
params.addParam("channelid",chan->id());
|
|
|
|
if (getBoolOpt(OptActivateLastOutCall) || !ClientDriver::self()->activeId())
|
|
|
|
ClientDriver::self()->setActive(chan->id());
|
|
|
|
TelEngine::destruct(chan);
|
|
|
|
return true;
|
|
|
|
}
|
2006-05-08 21:59:42 +00:00
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// Call execute handler called by the driver
|
|
|
|
bool Client::callIncoming(Message& msg, const String& dest)
|
|
|
|
{
|
2008-09-18 14:53:42 +00:00
|
|
|
static String sect = "miscellaneous";
|
2006-04-08 18:03:28 +00:00
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
XDebug(ClientDriver::self(),DebugAll,"Client::callIncoming [%p]",this);
|
|
|
|
// if we are in single line mode and we have already a channel, reject the call
|
|
|
|
if (ClientDriver::self() && ClientDriver::self()->isBusy() && !getBoolOpt(OptMultiLines)) {
|
|
|
|
msg.setParam("error","busy");
|
|
|
|
msg.setParam("reason",s_userBusy);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// Check for a preferred or only logic
|
|
|
|
String name = "callincoming";
|
|
|
|
String handle;
|
|
|
|
bool only = false, prefer = false, ignore = false, bailout = false;
|
|
|
|
bool ok = false;
|
|
|
|
if (hasOverride(s_actions.getSection(sect),name,handle,only,prefer,ignore,bailout) &&
|
|
|
|
(only || prefer)) {
|
|
|
|
ClientLogic* logic = findLogic(handle);
|
|
|
|
if (logic)
|
|
|
|
ok = logic->callIncoming(msg,dest);
|
|
|
|
bailout = only || ok;
|
|
|
|
}
|
|
|
|
if (bailout)
|
|
|
|
return ok;
|
|
|
|
// Ask the logics to create a channel
|
|
|
|
for (ObjList* o = s_logics.skipNull(); o; o = o->skipNext()) {
|
|
|
|
ClientLogic* logic = static_cast<ClientLogic*>(o->get());
|
|
|
|
if (ignore && handle == logic->toString())
|
|
|
|
continue;
|
|
|
|
Debug(ClientDriver::self(),DebugAll,"Logic(%s) callIncoming [%p]",
|
|
|
|
logic->toString().c_str(),logic);
|
|
|
|
if (logic->callIncoming(msg,dest))
|
|
|
|
return true;
|
|
|
|
}
|
2006-01-30 20:44:03 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// Accept an incoming call
|
|
|
|
void Client::callAnswer(const String& id)
|
|
|
|
{
|
|
|
|
Debug(ClientDriver::self(),DebugInfo,"callAccept('%s')",id.c_str());
|
|
|
|
if (!driverLockLoop())
|
|
|
|
return;
|
|
|
|
ClientChannel* chan = static_cast<ClientChannel*>(ClientDriver::self()->find(id));
|
|
|
|
if (chan) {
|
|
|
|
chan->callAnswer();
|
|
|
|
ClientDriver::self()->setActive(chan->id());
|
|
|
|
}
|
|
|
|
driverUnlock();
|
|
|
|
}
|
2006-01-30 20:44:03 +00:00
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// Terminate a call
|
|
|
|
void Client::callTerminate(const String& id, const char* reason, const char* error)
|
2005-07-04 22:04:47 +00:00
|
|
|
{
|
2008-08-04 02:06:00 +00:00
|
|
|
Debug(ClientDriver::self(),DebugInfo,"callTerminate(%s)",id.c_str());
|
|
|
|
// Check if the channel exists
|
|
|
|
Lock lock(ClientDriver::self());
|
|
|
|
if (!ClientDriver::self())
|
|
|
|
return;
|
|
|
|
Channel* chan = ClientDriver::self()->find(id);
|
|
|
|
if (!chan)
|
|
|
|
return;
|
|
|
|
bool hangup = chan->isAnswered();
|
|
|
|
lock.drop();
|
|
|
|
// Drop the call
|
|
|
|
Message* m = new Message("call.drop");
|
|
|
|
m->addParam("id",id);
|
|
|
|
if (hangup)
|
|
|
|
m->addParam("reason",reason ? reason : s_hangupReason.c_str());
|
|
|
|
else {
|
|
|
|
m->addParam("error",error ? error : "rejected");
|
|
|
|
m->addParam("reason",reason ? reason : s_rejectReason.c_str());
|
|
|
|
}
|
|
|
|
Engine::enqueue(m);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the active channel if any
|
|
|
|
ClientChannel* Client::getActiveChannel()
|
|
|
|
{
|
|
|
|
return ClientDriver::self() ? ClientDriver::self()->findActiveChan() : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Start/stop ringer
|
|
|
|
bool Client::ringer(bool in, bool on)
|
|
|
|
{
|
|
|
|
String* what = in ? &s_ringInName : &s_ringOutName;
|
|
|
|
bool ok = in ? getBoolOpt(OptRingIn) : getBoolOpt(OptRingOut);
|
|
|
|
Lock lock(ClientSound::s_soundsMutex);
|
|
|
|
DDebug(ClientDriver::self(),DebugAll,"Ringer in=%s on=%s",
|
|
|
|
String::boolText(in),String::boolText(on));
|
|
|
|
if (!on)
|
|
|
|
ClientSound::stop(*what);
|
|
|
|
else if (*what)
|
|
|
|
return ok && ClientSound::start(*what,-1,false);
|
|
|
|
else
|
2005-07-04 22:04:47 +00:00
|
|
|
return false;
|
2008-08-04 02:06:00 +00:00
|
|
|
return true;
|
|
|
|
}
|
2006-04-08 18:03:28 +00:00
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// Send DTMFs on selected channel
|
|
|
|
bool Client::emitDigits(const char* digits, const String& id)
|
|
|
|
{
|
|
|
|
Debug(ClientDriver::self(),DebugInfo,"emitDigit(%s,%s)",digits,id.c_str());
|
|
|
|
if (!driverLockLoop())
|
2005-07-04 22:04:47 +00:00
|
|
|
return false;
|
2008-08-04 02:06:00 +00:00
|
|
|
ClientChannel* chan = static_cast<ClientChannel*>(ClientDriver::self()->find(id));
|
|
|
|
bool ok = (0 != chan);
|
|
|
|
if (ok) {
|
|
|
|
Message* m = chan->message("chan.dtmf");
|
|
|
|
m->addParam("text",digits);
|
|
|
|
Engine::enqueue(m);
|
2005-07-04 22:04:47 +00:00
|
|
|
}
|
2008-08-04 02:06:00 +00:00
|
|
|
driverUnlock();
|
2005-07-04 22:04:47 +00:00
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// Set a boolean option of this client
|
|
|
|
bool Client::setBoolOpt(ClientToggle toggle, bool value, bool updateUi)
|
2006-04-08 18:03:28 +00:00
|
|
|
{
|
2008-08-04 02:06:00 +00:00
|
|
|
if (toggle >= OptCount)
|
2006-04-08 18:03:28 +00:00
|
|
|
return false;
|
2008-08-04 02:06:00 +00:00
|
|
|
|
|
|
|
if (m_toggles[toggle] == value && !updateUi)
|
2006-04-08 18:03:28 +00:00
|
|
|
return false;
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
m_toggles[toggle] = value;
|
|
|
|
if (updateUi)
|
|
|
|
setCheck(s_toggles[toggle],value);
|
2006-04-08 18:03:28 +00:00
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// Special options
|
|
|
|
switch (toggle) {
|
|
|
|
case OptRingIn:
|
|
|
|
if (!value)
|
|
|
|
ringer(true,false);
|
|
|
|
break;
|
|
|
|
case OptRingOut:
|
|
|
|
if (!value)
|
|
|
|
ringer(false,false);
|
|
|
|
break;
|
|
|
|
default: ;
|
2006-04-08 18:03:28 +00:00
|
|
|
}
|
2008-08-04 02:06:00 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2008-09-08 16:17:00 +00:00
|
|
|
// Engine start notification. Notify all registered logics
|
|
|
|
void Client::engineStart(Message& msg)
|
|
|
|
{
|
|
|
|
// Wait for init
|
|
|
|
while (!initialized())
|
|
|
|
Thread::yield();
|
|
|
|
for(ObjList* o = s_logics.skipNull(); o; o = o->skipNext()) {
|
|
|
|
ClientLogic* logic = static_cast<ClientLogic*>(o->get());
|
|
|
|
DDebug(ClientDriver::self(),DebugAll,"Logic(%s) processing engine.start [%p]",
|
|
|
|
logic->toString().c_str(),logic);
|
|
|
|
logic->engineStart(msg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// Add a new module for handling actions
|
|
|
|
bool Client::addLogic(ClientLogic* logic)
|
|
|
|
{
|
|
|
|
if (!logic || s_logics.find(logic))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
bool dup = (0 != s_logics.find(logic->toString()));
|
2008-09-18 14:41:30 +00:00
|
|
|
Debug(ClientDriver::self(),dup ? DebugGoOn : DebugInfo,
|
2008-08-04 02:06:00 +00:00
|
|
|
"Adding logic%s %p name=%s prio=%d",
|
2008-09-18 14:41:30 +00:00
|
|
|
dup ? " [DUPLICATE]" : "",logic,logic->toString().c_str(),logic->priority());
|
2008-08-04 02:06:00 +00:00
|
|
|
|
|
|
|
for (ObjList* l = s_logics.skipNull(); l; l = l->skipNext()) {
|
|
|
|
ClientLogic* obj = static_cast<ClientLogic*>(l->get());
|
|
|
|
if (logic->priority() <= obj->priority()) {
|
|
|
|
l->insert(logic)->setDelete(false);
|
|
|
|
return true;
|
|
|
|
}
|
2006-04-08 18:03:28 +00:00
|
|
|
}
|
2008-08-04 02:06:00 +00:00
|
|
|
s_logics.append(logic)->setDelete(false);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Remove a logic from the list
|
|
|
|
void Client::removeLogic(ClientLogic* logic)
|
|
|
|
{
|
|
|
|
if (!(logic && s_logics.find(logic)))
|
|
|
|
return;
|
|
|
|
Debug(ClientDriver::self(),DebugInfo,"Removing logic %p name=%s",
|
|
|
|
logic,logic->toString().c_str());
|
|
|
|
s_logics.remove(logic,false);
|
2006-04-08 18:03:28 +00:00
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// Convenience method to retrieve a logic
|
|
|
|
inline ClientLogic* Client::findLogic(const String& name)
|
|
|
|
{
|
|
|
|
ObjList* o = s_logics.find(name);
|
|
|
|
return o ? static_cast<ClientLogic*>(o->get()) : 0;
|
|
|
|
}
|
2006-04-08 18:03:28 +00:00
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// Save a configuration file. Call openMessage() on failure
|
|
|
|
bool Client::save(Configuration& cfg, Window* parent, bool showErr)
|
2006-09-17 23:19:05 +00:00
|
|
|
{
|
2008-08-04 02:06:00 +00:00
|
|
|
DDebug(ClientDriver::self(),DebugAll,"Saving '%s'",cfg.c_str());
|
|
|
|
if (cfg.save())
|
|
|
|
return true;
|
|
|
|
String s = "Failed to save configuration file " + cfg;
|
|
|
|
if (!(showErr && self() && self()->openMessage(s,parent)))
|
|
|
|
Debug(ClientDriver::self(),DebugWarn,"%s",s.c_str());
|
2006-09-17 23:19:05 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// Check if a string names a client's boolean option
|
|
|
|
Client::ClientToggle Client::getBoolOpt(const String& name)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < OptCount; i++)
|
|
|
|
if (s_toggles[i] == name)
|
|
|
|
return (ClientToggle)i;
|
|
|
|
return OptCount;
|
|
|
|
}
|
2006-09-17 23:19:05 +00:00
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// Build an 'ui.event' message
|
|
|
|
Message* Client::eventMessage(const String& event, Window* wnd, const char* name,
|
|
|
|
NamedList* params)
|
2005-07-04 22:04:47 +00:00
|
|
|
{
|
2008-08-04 02:06:00 +00:00
|
|
|
Message* m = new Message("ui.event");
|
|
|
|
if (wnd)
|
|
|
|
m->addParam("window",wnd->id());
|
|
|
|
m->addParam("event",event);
|
|
|
|
if (name && *name)
|
|
|
|
m->addParam("name",name);
|
|
|
|
if (params) {
|
|
|
|
unsigned int n = params->count();
|
|
|
|
for (unsigned int i = 0; i < n; i++) {
|
|
|
|
NamedString* p = params->getParam(i);
|
|
|
|
if (p)
|
|
|
|
m->addParam(p->name(),*p);
|
|
|
|
}
|
2005-07-27 18:31:47 +00:00
|
|
|
}
|
2008-08-04 02:06:00 +00:00
|
|
|
return m;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Incoming (from engine) constructor
|
|
|
|
ClientChannel::ClientChannel(const Message& msg, const String& peerid)
|
|
|
|
: Channel(ClientDriver::self(),0,true),
|
|
|
|
m_party(msg.getValue("caller")), m_noticed(false),
|
|
|
|
m_line(0), m_active(false), m_silence(false), m_conference(false),
|
|
|
|
m_clientData(0)
|
|
|
|
{
|
|
|
|
Debug(this,DebugCall,"Created incoming from=%s peer=%s [%p]",
|
|
|
|
m_party.c_str(),peerid.c_str(),this);
|
|
|
|
m_targetid = peerid;
|
|
|
|
m_peerId = peerid;
|
|
|
|
Message* s = message("chan.startup");
|
|
|
|
s->setParam("caller",msg.getValue("caller"));
|
|
|
|
s->setParam("called",msg.getValue("called"));
|
|
|
|
s->setParam("billid",msg.getValue("billid"));
|
|
|
|
Engine::enqueue(s);
|
|
|
|
update(Startup,true,true,"call.ringing",false,true);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Outgoing (to engine) constructor
|
|
|
|
ClientChannel::ClientChannel(const String& target, const NamedList& params)
|
|
|
|
: Channel(ClientDriver::self(),0,false),
|
|
|
|
m_party(target), m_noticed(true), m_line(0), m_active(false),
|
|
|
|
m_silence(true), m_conference(false), m_clientData(0)
|
|
|
|
{
|
|
|
|
Debug(this,DebugCall,"Created outgoing to=%s [%p]",
|
|
|
|
m_party.c_str(),this);
|
|
|
|
// Build the call.route and chan.startup messages
|
|
|
|
Message* m = message("call.route");
|
2006-05-08 21:59:42 +00:00
|
|
|
Message* s = message("chan.startup");
|
2008-08-04 02:06:00 +00:00
|
|
|
// Make sure we set the target's protocol if we have one
|
|
|
|
Regexp r("^[a-z0-9]\\+/");
|
|
|
|
String to = target;
|
|
|
|
const char* param = "callto";
|
|
|
|
if (!r.matches(target.safe())) {
|
|
|
|
const char* proto = params.getValue("protocol");
|
|
|
|
if (proto)
|
|
|
|
to = String(proto) + "/" + target;
|
|
|
|
else
|
|
|
|
param = "called";
|
2006-05-08 21:59:42 +00:00
|
|
|
}
|
2008-08-04 02:06:00 +00:00
|
|
|
m->setParam(param,to);
|
|
|
|
s->setParam("called",to);
|
2008-08-21 14:47:55 +00:00
|
|
|
m->copyParams(params,"line,protocol,account,caller,callername,domain");
|
|
|
|
s->copyParams(params,"line,protocol,account,caller,callername,domain");
|
2006-05-08 21:59:42 +00:00
|
|
|
Engine::enqueue(s);
|
2008-08-04 02:06:00 +00:00
|
|
|
if (startRouter(m))
|
|
|
|
update(Startup);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Destructor
|
|
|
|
ClientChannel::~ClientChannel()
|
|
|
|
{
|
|
|
|
XDebug(this,DebugInfo,"ClientChannel::~ClientChannel() [%p]",this);
|
2005-07-04 22:04:47 +00:00
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
void ClientChannel::destroyed()
|
2005-07-04 22:04:47 +00:00
|
|
|
{
|
2008-08-04 02:06:00 +00:00
|
|
|
Debug(this,DebugCall,"Destroyed [%p]",this);
|
|
|
|
Lock lock(m_mutex);
|
|
|
|
setClientData();
|
|
|
|
if (m_conference) {
|
|
|
|
// Drop old peer if conference
|
|
|
|
if (ClientDriver::s_dropConfPeer) {
|
|
|
|
Message* m = new Message("call.drop");
|
|
|
|
m->addParam("id",m_peerId);
|
|
|
|
m->addParam("reason","Conference terminated");
|
|
|
|
Engine::enqueue(m);
|
|
|
|
}
|
2005-07-04 22:04:47 +00:00
|
|
|
}
|
2008-08-04 02:06:00 +00:00
|
|
|
else if (m_transferId)
|
|
|
|
ClientDriver::setAudioTransfer(id());
|
|
|
|
// Reset driver's active id
|
|
|
|
ClientDriver* drv = static_cast<ClientDriver*>(driver());
|
|
|
|
if (drv && id() == drv->activeId())
|
|
|
|
drv->setActive();
|
|
|
|
setMedia();
|
|
|
|
update(Destroyed,false,false,"chan.hangup");
|
|
|
|
lock.drop();
|
|
|
|
Channel::destroyed();
|
2005-07-04 22:04:47 +00:00
|
|
|
}
|
|
|
|
|
2007-01-17 02:09:24 +00:00
|
|
|
void ClientChannel::disconnected(bool final, const char* reason)
|
|
|
|
{
|
2008-08-04 02:06:00 +00:00
|
|
|
Debug(this,DebugCall,"Disconnected reason=%s [%p]",reason,this);
|
2007-01-17 02:09:24 +00:00
|
|
|
Channel::disconnected(final,reason);
|
2008-08-04 02:06:00 +00:00
|
|
|
if (!m_reason)
|
2007-01-17 02:09:24 +00:00
|
|
|
m_reason = reason;
|
2008-08-04 02:06:00 +00:00
|
|
|
setActive(false);
|
|
|
|
// Reset transfer
|
|
|
|
if (m_transferId && !m_conference)
|
|
|
|
ClientDriver::setAudioTransfer(id());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if our consumer's source sent any data
|
|
|
|
// Don't set the silence flag is already reset
|
|
|
|
void ClientChannel::checkSilence()
|
|
|
|
{
|
|
|
|
if (!m_silence)
|
|
|
|
return;
|
|
|
|
m_silence = !(getConsumer() && getConsumer()->getConnSource() &&
|
|
|
|
DataNode::invalidStamp() != getConsumer()->getConnSource()->timeStamp());
|
|
|
|
if (!m_silence)
|
|
|
|
DDebug(this,DebugInfo,"Got audio data [%p]",this);
|
2007-01-17 02:09:24 +00:00
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// Open/close media
|
|
|
|
bool ClientChannel::setMedia(bool open, bool replace)
|
2005-07-04 22:04:47 +00:00
|
|
|
{
|
2008-08-04 02:06:00 +00:00
|
|
|
Lock lock(m_mutex);
|
|
|
|
|
|
|
|
// Check silence (we might already have a consumer)
|
|
|
|
checkSilence();
|
|
|
|
|
|
|
|
// Remove source/consumer if replacing
|
|
|
|
if (!open) {
|
|
|
|
if (getSource() || getConsumer()) {
|
|
|
|
Debug(this,DebugInfo,"Closing media channels [%p]",this);
|
|
|
|
setSource();
|
|
|
|
setConsumer();
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2005-07-04 22:04:47 +00:00
|
|
|
String dev = ClientDriver::device();
|
|
|
|
if (dev.null())
|
|
|
|
return false;
|
2008-08-04 02:06:00 +00:00
|
|
|
if (!replace && getSource() && getConsumer())
|
2005-07-12 16:05:29 +00:00
|
|
|
return true;
|
2007-01-28 17:57:31 +00:00
|
|
|
Debug(this,DebugAll,"Opening media channels [%p]",this);
|
2005-07-04 22:04:47 +00:00
|
|
|
Message m("chan.attach");
|
|
|
|
complete(m,true);
|
|
|
|
m.userData(this);
|
2008-08-04 02:06:00 +00:00
|
|
|
m.setParam("consumer",dev);
|
|
|
|
m.setParam("source",dev);
|
|
|
|
Engine::dispatch(m);
|
|
|
|
if (getConsumer())
|
|
|
|
checkSilence();
|
|
|
|
else
|
|
|
|
Debug(this,DebugNote,"Failed to set data consumer [%p]",this);
|
|
|
|
if (!getSource())
|
|
|
|
Debug(this,DebugNote,"Failed to set data source [%p]",this);
|
|
|
|
bool ok = (getSource() && getConsumer());
|
|
|
|
if (!ok && Client::self()) {
|
|
|
|
String tmp = "Failed to open media channel(s)";
|
|
|
|
Client::self()->setStatusLocked(tmp);
|
|
|
|
}
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set/reset this channel's data source/consumer
|
|
|
|
bool ClientChannel::setActive(bool active, bool upd)
|
|
|
|
{
|
|
|
|
Lock lock(m_mutex);
|
|
|
|
// Don't activate it if envolved in a transfer
|
|
|
|
noticed();
|
|
|
|
if (active && m_transferId && !m_conference)
|
|
|
|
return false;
|
|
|
|
if (isAnswered())
|
|
|
|
setMedia(active);
|
|
|
|
// Don't notify if nothing changed
|
|
|
|
if (m_active == active)
|
|
|
|
return true;
|
|
|
|
Debug(this,DebugInfo,"Set active=%s [%p]",String::boolText(active),this);
|
|
|
|
m_active = active;
|
|
|
|
if (!upd)
|
|
|
|
return true;
|
|
|
|
update(active ? Active : OnHold);
|
|
|
|
// TODO: notify the peer if answered
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set/reset the transferred peer's id. Enqueue clientchan.update if changed
|
|
|
|
void ClientChannel::setTransfer(const String& target)
|
|
|
|
{
|
|
|
|
Lock lock(m_mutex);
|
|
|
|
if (m_conference || m_transferId == target)
|
|
|
|
return;
|
|
|
|
if (target)
|
|
|
|
Debug(this,DebugCall,"Transferred to '%s' [%p]",target.c_str(),this);
|
|
|
|
else
|
|
|
|
Debug(this,DebugCall,"Transfer released [%p]",this);
|
|
|
|
m_transferId = target;
|
|
|
|
setMedia(!m_transferId && m_active && isAnswered());
|
|
|
|
update(Transfer);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set/reset the conference data. Enqueue clientchan.update if changed.
|
|
|
|
void ClientChannel::setConference(const String& target)
|
|
|
|
{
|
|
|
|
Lock lock(m_mutex);
|
|
|
|
if (m_transferId == target && !m_transferId)
|
|
|
|
return;
|
|
|
|
Debug(this,DebugCall,"%sing conference room '%s' [%p]",
|
2008-09-18 14:41:30 +00:00
|
|
|
target ? "Enter" : "Exit",target ? target.c_str() : m_transferId.c_str(),this);
|
2008-08-04 02:06:00 +00:00
|
|
|
m_transferId = target;
|
|
|
|
m_conference = (0 != m_transferId);
|
|
|
|
setMedia(m_active && isAnswered());
|
|
|
|
update(Conference);
|
2005-07-04 22:04:47 +00:00
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// Notice this channel. Enqueue a clientchan.update message
|
|
|
|
void ClientChannel::noticed()
|
2005-07-04 22:04:47 +00:00
|
|
|
{
|
2008-08-04 02:06:00 +00:00
|
|
|
Lock lock(m_mutex);
|
|
|
|
if (m_noticed)
|
|
|
|
return;
|
|
|
|
m_noticed = true;
|
|
|
|
update(Noticed);
|
2005-07-04 22:04:47 +00:00
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// Set the channel's line (address)
|
2005-07-04 22:04:47 +00:00
|
|
|
void ClientChannel::line(int newLine)
|
|
|
|
{
|
2008-08-04 02:06:00 +00:00
|
|
|
Lock lock(m_mutex);
|
2005-07-04 22:04:47 +00:00
|
|
|
m_line = newLine;
|
|
|
|
m_address.clear();
|
2008-08-04 02:06:00 +00:00
|
|
|
if (m_line > 0) {
|
2005-07-04 22:04:47 +00:00
|
|
|
m_address << "line/" << m_line;
|
2008-08-04 02:06:00 +00:00
|
|
|
update(AddrChanged);
|
|
|
|
}
|
2005-07-04 22:04:47 +00:00
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// Outgoing call routed: enqueue update message
|
2005-07-04 22:04:47 +00:00
|
|
|
bool ClientChannel::callRouted(Message& msg)
|
|
|
|
{
|
2008-08-04 02:06:00 +00:00
|
|
|
Lock lock(m_mutex);
|
|
|
|
update(Routed,true,false);
|
2005-07-04 22:04:47 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// Outgoing call accepted: enqueue update message
|
2005-07-04 22:04:47 +00:00
|
|
|
void ClientChannel::callAccept(Message& msg)
|
|
|
|
{
|
2008-08-04 02:06:00 +00:00
|
|
|
Debug(this,DebugCall,"callAccept() [%p]",this);
|
2005-07-04 22:04:47 +00:00
|
|
|
Channel::callAccept(msg);
|
2008-08-04 02:06:00 +00:00
|
|
|
Lock lock(m_mutex);
|
|
|
|
m_peerId = getPeerId();
|
|
|
|
Debug(this,DebugInfo,"Peer id set to %s",m_peerId.c_str());
|
|
|
|
update(Accepted);
|
2005-07-04 22:04:47 +00:00
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// Outgoing call rejected: reset and and enqueue update message
|
2005-07-12 16:05:29 +00:00
|
|
|
void ClientChannel::callRejected(const char* error, const char* reason, const Message* msg)
|
2005-07-04 22:04:47 +00:00
|
|
|
{
|
2008-08-04 02:06:00 +00:00
|
|
|
Debug(this,DebugCall,"callRejected('%s','%s',%p) [%p]",
|
2005-07-12 16:05:29 +00:00
|
|
|
error,reason,msg,this);
|
2008-08-04 02:06:00 +00:00
|
|
|
setMedia();
|
2005-07-04 22:04:47 +00:00
|
|
|
if (!reason)
|
|
|
|
reason = error;
|
|
|
|
if (!reason)
|
|
|
|
reason = "Unknown reason";
|
2005-07-12 16:05:29 +00:00
|
|
|
Channel::callRejected(error,reason,msg);
|
2008-08-04 02:06:00 +00:00
|
|
|
setActive(false);
|
|
|
|
m_reason = reason;
|
|
|
|
update(Rejected,true,false);
|
2005-07-12 16:05:29 +00:00
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// Outgoing call progress
|
|
|
|
// Check for early media: start ringing tone if missing and the channel is active
|
|
|
|
// Enqueue update message
|
2005-07-12 16:05:29 +00:00
|
|
|
bool ClientChannel::msgProgress(Message& msg)
|
|
|
|
{
|
2008-08-04 02:06:00 +00:00
|
|
|
Debug(this,DebugCall,"msgProgress() [%p]",this);
|
|
|
|
if (active() && peerHasSource(msg))
|
|
|
|
setMedia(true);
|
2005-07-25 22:44:34 +00:00
|
|
|
bool ret = Channel::msgProgress(msg);
|
2008-08-04 02:06:00 +00:00
|
|
|
update(Progressing);
|
2005-07-25 22:44:34 +00:00
|
|
|
return ret;
|
2005-07-04 22:04:47 +00:00
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// Outgoing call ringing
|
|
|
|
// Check for early media: start ringing tone if missing and the channel is active
|
|
|
|
// Enqueue update message
|
2005-07-04 22:04:47 +00:00
|
|
|
bool ClientChannel::msgRinging(Message& msg)
|
|
|
|
{
|
2008-08-04 02:06:00 +00:00
|
|
|
Debug(this,DebugCall,"msgRinging() [%p]",this);
|
|
|
|
if (active() && peerHasSource(msg))
|
|
|
|
setMedia(true);
|
2005-07-25 22:44:34 +00:00
|
|
|
bool ret = Channel::msgRinging(msg);
|
2008-08-04 02:06:00 +00:00
|
|
|
update(Ringing);
|
2005-07-25 22:44:34 +00:00
|
|
|
return ret;
|
2005-07-04 22:04:47 +00:00
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// set status for when a call was answered, set the flags for different actions
|
|
|
|
// accordingly, and attach media channels
|
2005-07-04 22:04:47 +00:00
|
|
|
bool ClientChannel::msgAnswered(Message& msg)
|
|
|
|
{
|
2008-08-04 02:06:00 +00:00
|
|
|
Lock lock(m_mutex);
|
|
|
|
Debug(this,DebugCall,"msgAnswered() [%p]",this);
|
2007-01-17 02:09:24 +00:00
|
|
|
m_reason.clear();
|
2008-08-04 02:06:00 +00:00
|
|
|
// Active: Open media if the peer has a source
|
|
|
|
if (active() && peerHasSource(msg))
|
|
|
|
setMedia(true);
|
|
|
|
m_silence = false;
|
2005-07-25 22:44:34 +00:00
|
|
|
bool ret = Channel::msgAnswered(msg);
|
2008-08-04 02:06:00 +00:00
|
|
|
update(Answered);
|
2005-07-25 22:44:34 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// Dropped notification
|
|
|
|
bool ClientChannel::msgDrop(Message& msg, const char* reason)
|
2005-07-25 22:44:34 +00:00
|
|
|
{
|
2008-08-04 02:06:00 +00:00
|
|
|
Lock lock(m_mutex);
|
|
|
|
noticed();
|
|
|
|
Debug(this,DebugCall,"msgDrop() reason=%s [%p]",reason,this);
|
|
|
|
if (!m_reason)
|
|
|
|
m_reason = reason;
|
|
|
|
// Reset transfer
|
|
|
|
if (m_transferId && !m_conference)
|
|
|
|
ClientDriver::setAudioTransfer(id());
|
|
|
|
setActive(false,!Engine::exiting());
|
|
|
|
lock.drop();
|
|
|
|
return Channel::msgDrop(msg,reason);
|
2005-07-04 22:04:47 +00:00
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// Answer the call if not answered
|
|
|
|
// Activate the channel
|
|
|
|
void ClientChannel::callAnswer()
|
|
|
|
{
|
|
|
|
Lock lock(m_mutex);
|
|
|
|
noticed();
|
|
|
|
if (!isAnswered()) {
|
|
|
|
Debug(this,DebugCall,"callAnswer() [%p]",this);
|
|
|
|
m_reason.clear();
|
|
|
|
status("answered");
|
|
|
|
update(Answered,true,true,"call.answered",false,true);
|
|
|
|
}
|
|
|
|
// Activating channel will set the media
|
|
|
|
if (ClientDriver::self())
|
|
|
|
ClientDriver::self()->setActive(id());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Enqueue clientchan.update message
|
|
|
|
void ClientChannel::update(int notif, bool chan, bool updatePeer,
|
|
|
|
const char* engineMsg, bool minimal, bool data)
|
|
|
|
{
|
|
|
|
if (engineMsg)
|
|
|
|
Engine::enqueue(message(engineMsg,minimal,data));
|
|
|
|
if (updatePeer) {
|
|
|
|
CallEndpoint* peer = getPeer();
|
|
|
|
if (peer && peer->ref()) {
|
|
|
|
if (peer->getConsumer())
|
|
|
|
m_peerOutFormat = peer->getConsumer()->getFormat();
|
|
|
|
if (peer->getSource())
|
|
|
|
m_peerInFormat = peer->getSource()->getFormat();
|
|
|
|
TelEngine::destruct(peer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const char* op = lookup(notif);
|
|
|
|
if (!op)
|
|
|
|
return;
|
|
|
|
Message* m = new Message("clientchan.update");
|
|
|
|
m->addParam("notify",op);
|
|
|
|
// Add extended params only if we don't set the channel
|
|
|
|
if (chan)
|
|
|
|
m->userData(this);
|
|
|
|
else {
|
|
|
|
m->addParam("id",id());
|
|
|
|
m->addParam("direction",isOutgoing() ? "incoming" : "outgoing");
|
|
|
|
if (m_address)
|
|
|
|
m->addParam("address",m_address);
|
|
|
|
if (notif != Noticed && m_noticed)
|
|
|
|
m->addParam("noticed",String::boolText(true));
|
|
|
|
if (m_active)
|
|
|
|
m->addParam("active",String::boolText(true));
|
|
|
|
if (m_transferId)
|
|
|
|
m->addParam("transferid",m_transferId);
|
|
|
|
if (m_conference)
|
|
|
|
m->addParam("conference",String::boolText(m_conference));
|
|
|
|
}
|
|
|
|
if (m_silence)
|
|
|
|
m->addParam("silence",String::boolText(true));
|
|
|
|
Engine::enqueue(m);
|
|
|
|
}
|
2005-07-04 22:04:47 +00:00
|
|
|
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
/**
|
|
|
|
* ClientDriver
|
|
|
|
*/
|
2005-07-04 22:04:47 +00:00
|
|
|
ClientDriver::ClientDriver()
|
|
|
|
: Driver("client","misc")
|
|
|
|
{
|
|
|
|
s_driver = this;
|
|
|
|
}
|
|
|
|
|
|
|
|
ClientDriver::~ClientDriver()
|
|
|
|
{
|
|
|
|
s_driver = 0;
|
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// install relays
|
2005-07-25 22:44:34 +00:00
|
|
|
void ClientDriver::setup()
|
|
|
|
{
|
|
|
|
Driver::setup();
|
|
|
|
installRelay(Halt);
|
|
|
|
installRelay(Progress);
|
2006-01-23 15:57:47 +00:00
|
|
|
installRelay(Route,200);
|
2008-08-14 09:58:19 +00:00
|
|
|
installRelay(Text);
|
|
|
|
installRelay(ImRoute);
|
|
|
|
installRelay(ImExecute);
|
2005-07-25 22:44:34 +00:00
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// if we receive a message for an incoming call, we pass the message on
|
|
|
|
// to the callIncoming function to handle it
|
2005-07-04 22:04:47 +00:00
|
|
|
bool ClientDriver::msgExecute(Message& msg, String& dest)
|
|
|
|
{
|
|
|
|
Debug(this,DebugInfo,"msgExecute() '%s'",dest.c_str());
|
2008-08-04 02:06:00 +00:00
|
|
|
return Client::self() && Client::self()->callIncoming(msg,dest);
|
2005-07-04 22:04:47 +00:00
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// Timer notification
|
2005-07-27 18:31:47 +00:00
|
|
|
void ClientDriver::msgTimer(Message& msg)
|
|
|
|
{
|
|
|
|
Driver::msgTimer(msg);
|
2008-08-04 02:06:00 +00:00
|
|
|
// Tell the client to tick the logigs if busy
|
|
|
|
if (isBusy())
|
|
|
|
Client::setLogicsTick();
|
2005-07-27 18:31:47 +00:00
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// Routing handler
|
2006-01-23 15:57:47 +00:00
|
|
|
bool ClientDriver::msgRoute(Message& msg)
|
|
|
|
{
|
|
|
|
// don't route here our own calls
|
|
|
|
if (name() == msg.getValue("module"))
|
|
|
|
return false;
|
2008-08-04 02:06:00 +00:00
|
|
|
if (Client::self() && Client::self()->callRouting(msg)) {
|
2006-01-23 15:57:47 +00:00
|
|
|
msg.retValue() = name() + "/*";
|
|
|
|
return true;
|
|
|
|
}
|
2008-07-16 09:48:49 +00:00
|
|
|
return Driver::msgRoute(msg);
|
2006-01-23 15:57:47 +00:00
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
bool ClientDriver::received(Message& msg, int id)
|
|
|
|
{
|
2008-08-14 09:58:19 +00:00
|
|
|
if (id == ImRoute) {
|
|
|
|
// don't route here our own messages
|
|
|
|
if (name() == msg.getValue("module"))
|
|
|
|
return false;
|
|
|
|
if (!(Client::self() && Client::self()->imRouting(msg)))
|
|
|
|
return false;
|
|
|
|
msg.retValue() = name() + "/*";
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (id == ImExecute || id == Text) {
|
|
|
|
if (name() == msg.getValue("module"))
|
|
|
|
return false;
|
|
|
|
return Client::self() && Client::self()->imExecute(msg);
|
|
|
|
}
|
2008-09-11 15:01:01 +00:00
|
|
|
if (id == Halt) {
|
|
|
|
dropCalls();
|
|
|
|
if (Client::self())
|
|
|
|
Client::self()->quit();
|
2008-08-04 02:06:00 +00:00
|
|
|
}
|
|
|
|
return Driver::received(msg,id);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set/reset the active channel.
|
|
|
|
bool ClientDriver::setActive(const String& id)
|
|
|
|
{
|
|
|
|
Lock lock(this);
|
|
|
|
bool ok = false;
|
|
|
|
// Hold the old one
|
|
|
|
if (m_activeId && m_activeId != id) {
|
|
|
|
ClientChannel* chan = findChan(m_activeId);
|
|
|
|
ok = chan && chan->setActive(false);
|
|
|
|
TelEngine::destruct(chan);
|
|
|
|
}
|
|
|
|
m_activeId = "";
|
|
|
|
// Select the new one
|
|
|
|
if (!id)
|
|
|
|
return ok;
|
|
|
|
ClientChannel* chan = findChan(id);
|
|
|
|
ok = chan && chan->setActive(true);
|
|
|
|
TelEngine::destruct(chan);
|
|
|
|
if (ok)
|
|
|
|
m_activeId = id;
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
// find a channel with the specified line
|
2005-07-04 22:04:47 +00:00
|
|
|
ClientChannel* ClientDriver::findLine(int line)
|
|
|
|
{
|
|
|
|
if (line < 1)
|
|
|
|
return 0;
|
|
|
|
Lock mylock(this);
|
|
|
|
ObjList* l = &channels();
|
|
|
|
for (; l; l = l->next()) {
|
|
|
|
ClientChannel* cc = static_cast<ClientChannel*>(l->get());
|
|
|
|
if (cc && (cc->line() == line))
|
|
|
|
return cc;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-09-11 15:01:01 +00:00
|
|
|
// Drop all calls belonging to the active driver
|
|
|
|
void ClientDriver::dropCalls(const char* reason)
|
|
|
|
{
|
|
|
|
Message m("call.drop");
|
|
|
|
if (!reason && Engine::exiting())
|
|
|
|
reason = "shutdown";
|
|
|
|
if (reason)
|
|
|
|
m.addParam("reason",reason);
|
|
|
|
if (self())
|
|
|
|
self()->dropAll(m);
|
|
|
|
}
|
|
|
|
|
2008-08-04 02:06:00 +00:00
|
|
|
// Attach/detach client channels peers' source/consumer
|
|
|
|
bool ClientDriver::setAudioTransfer(const String& id, const String& target)
|
|
|
|
{
|
|
|
|
DDebug(s_driver,DebugInfo,"setAudioTransfer(%s,%s)",id.c_str(),target.safe());
|
|
|
|
|
|
|
|
// Get master (id) and its peer
|
|
|
|
ClientChannel* master = findChan(id);
|
|
|
|
if (!master)
|
|
|
|
return false;
|
|
|
|
CallEndpoint* masterPeer = master->getPeer();
|
|
|
|
if (!(masterPeer && masterPeer->ref()))
|
|
|
|
masterPeer = 0;
|
|
|
|
|
|
|
|
// Release conference or transfer
|
|
|
|
String tmp = master->transferId();
|
|
|
|
if (master->conference())
|
|
|
|
setConference(id,false);
|
|
|
|
else if (master->transferId())
|
|
|
|
master->setTransfer();
|
|
|
|
|
|
|
|
// First remove any slave's transfer
|
|
|
|
ClientChannel* slave = findChan(tmp);
|
|
|
|
if (slave && !slave->conference()) {
|
|
|
|
setAudioTransfer(slave->id());
|
|
|
|
if (masterPeer) {
|
|
|
|
CallEndpoint* slavePeer = slave->getPeer();
|
|
|
|
if (slavePeer && slavePeer->ref()) {
|
|
|
|
DDebug(s_driver,DebugAll,"setAudioTransfer detaching peers for %s - %s",
|
|
|
|
master->id().c_str(),slave->id().c_str());
|
|
|
|
DataTranslator::detachChain(masterPeer->getSource(),slavePeer->getConsumer());
|
|
|
|
DataTranslator::detachChain(slavePeer->getSource(),masterPeer->getConsumer());
|
|
|
|
TelEngine::destruct(slavePeer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
TelEngine::destruct(slave);
|
|
|
|
|
|
|
|
// Set new transfer: we must have a valid target
|
|
|
|
bool ok = true;
|
|
|
|
CallEndpoint* slavePeer = 0;
|
|
|
|
while (target) {
|
|
|
|
ok = false;
|
|
|
|
if (!masterPeer)
|
|
|
|
break;
|
|
|
|
slave = findChan(target);
|
|
|
|
if (!slave)
|
|
|
|
break;
|
|
|
|
if (slave->conference())
|
|
|
|
break;
|
|
|
|
slavePeer = slave->getPeer();
|
|
|
|
if (!(slavePeer && slavePeer->ref())) {
|
|
|
|
slavePeer = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// The new target may be involved in a transfer
|
|
|
|
if (slave->transferId())
|
|
|
|
setAudioTransfer(target);
|
|
|
|
DDebug(s_driver,DebugAll,"setAudioTransfer attaching peers for %s - %s",
|
|
|
|
master->id().c_str(),slave->id().c_str());
|
|
|
|
ok = DataTranslator::attachChain(masterPeer->getSource(),slavePeer->getConsumer()) &&
|
|
|
|
DataTranslator::attachChain(slavePeer->getSource(),masterPeer->getConsumer());
|
|
|
|
// Fallback on failure
|
|
|
|
if (!ok) {
|
|
|
|
DataTranslator::detachChain(masterPeer->getSource(),slavePeer->getConsumer());
|
|
|
|
DataTranslator::detachChain(slavePeer->getSource(),masterPeer->getConsumer());
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set channels on success
|
|
|
|
if (target)
|
|
|
|
if (ok) {
|
|
|
|
master->setTransfer(slave->id());
|
|
|
|
slave->setTransfer(master->id());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
Debug(s_driver,DebugNote,
|
|
|
|
"setAudioTransfer failed to attach peers for %s - %s",
|
|
|
|
master->id().c_str(),target.c_str());
|
|
|
|
|
|
|
|
// Release references
|
|
|
|
TelEngine::destruct(slavePeer);
|
|
|
|
TelEngine::destruct(slave);
|
|
|
|
TelEngine::destruct(masterPeer);
|
|
|
|
TelEngine::destruct(master);
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Attach/detach a client channel to/from a conference room
|
|
|
|
bool ClientDriver::setConference(const String& id, bool in, const String* confName)
|
|
|
|
{
|
|
|
|
Lock lock(s_driver);
|
|
|
|
if (!s_driver)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!confName)
|
|
|
|
confName = &s_confName;
|
|
|
|
|
|
|
|
DDebug(s_driver,DebugInfo,"setConference id=%s in=%s conf=%s",
|
|
|
|
id.c_str(),String::boolText(in),confName->c_str());
|
|
|
|
ClientChannel* chan = findChan(id);
|
|
|
|
if (!chan)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
bool ok = false;
|
|
|
|
if (in) {
|
|
|
|
// Check if already in conference (or if the conference room is the same)
|
|
|
|
// Remove transfer
|
|
|
|
if (chan->conference()) {
|
|
|
|
if (chan->transferId() == *confName) {
|
|
|
|
TelEngine::destruct(chan);
|
|
|
|
return true;;
|
|
|
|
}
|
|
|
|
setConference(id,false);
|
|
|
|
}
|
|
|
|
else if (chan->transferId())
|
|
|
|
setAudioTransfer(id);
|
|
|
|
Message m("call.conference");
|
|
|
|
m.addParam("room",*confName);
|
|
|
|
m.addParam("notify",*confName);
|
|
|
|
m.userData(chan);
|
|
|
|
ok = Engine::dispatch(m);
|
|
|
|
if (ok)
|
|
|
|
chan->setConference(*confName);
|
|
|
|
else
|
|
|
|
Debug(s_driver,DebugNote,"setConference failed for '%s'",id.c_str());
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
Message m("chan.locate");
|
|
|
|
m.addParam("id",chan->m_peerId);
|
|
|
|
Engine::dispatch(m);
|
|
|
|
CallEndpoint* cp = 0;
|
|
|
|
if (m.userData())
|
|
|
|
cp = static_cast<CallEndpoint*>(m.userData()->getObject("CallEndpoint"));
|
|
|
|
const char* reason = "Unable to locate peer";
|
|
|
|
if (cp) {
|
|
|
|
ok = chan->connect(cp,"Conference terminated");
|
|
|
|
if (ok)
|
|
|
|
chan->setConference();
|
|
|
|
else
|
|
|
|
reason = "Connect failed";
|
|
|
|
}
|
|
|
|
if (!ok)
|
|
|
|
Debug(s_driver,DebugNote,"setConference failed to re-connect '%s'. %s",
|
|
|
|
id.c_str(),reason);
|
|
|
|
}
|
|
|
|
TelEngine::destruct(chan);
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Find a channel with the specified id
|
|
|
|
ClientChannel* ClientDriver::findChan(const String& id)
|
|
|
|
{
|
|
|
|
Lock lock(s_driver);
|
|
|
|
if (!s_driver)
|
|
|
|
return 0;
|
|
|
|
Channel* chan = s_driver->find(id);
|
|
|
|
return (chan && chan->ref()) ? static_cast<ClientChannel*>(chan) : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get a referenced channel whose stored peer is the given one
|
|
|
|
ClientChannel* ClientDriver::findChanByPeer(const String& peer)
|
|
|
|
{
|
|
|
|
Lock lock(s_driver);
|
|
|
|
if (!s_driver)
|
|
|
|
return 0;
|
|
|
|
for (ObjList* o = s_driver->channels().skipNull(); o; o = o->skipNext()) {
|
|
|
|
ClientChannel* c = static_cast<ClientChannel*>(o->get());
|
|
|
|
if (c && c->m_peerId == peer)
|
|
|
|
return c->ref() ? c : 0;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* ClientAccount
|
|
|
|
*/
|
|
|
|
// Constructor
|
|
|
|
ClientAccount::ClientAccount(const char* proto, const char* user,
|
|
|
|
const char* host, bool startup)
|
|
|
|
: Mutex(true),
|
|
|
|
m_port(0), m_startup(startup), m_expires(-1), m_connected(false),
|
|
|
|
m_resource(0)
|
|
|
|
{
|
|
|
|
setIdUri(proto,user,host);
|
|
|
|
DDebug(ClientDriver::self(),DebugAll,"Created client account=%s [%p]",
|
|
|
|
m_uri.c_str(),this);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Constructor. Build an account from a list of parameters.
|
|
|
|
ClientAccount::ClientAccount(const NamedList& params)
|
|
|
|
: Mutex(true),
|
|
|
|
m_port(0), m_startup(false), m_expires(-1), m_connected(false),
|
|
|
|
m_resource(0)
|
|
|
|
{
|
|
|
|
setIdUri(params.getValue("protocol"),params.getValue("username"),params.getValue("domain"));
|
|
|
|
m_startup = params.getBoolValue("enable");
|
|
|
|
m_password = params.getValue("password");
|
|
|
|
const char* res = params.getValue("resource");
|
|
|
|
if (res)
|
|
|
|
setResource(new ClientResource(res));
|
|
|
|
m_server = params.getValue("server");
|
|
|
|
m_options = params.getValue("options");
|
|
|
|
m_port = params.getIntValue("port",m_port);
|
|
|
|
m_outbound = params.getValue("outbound");
|
|
|
|
m_expires = params.getIntValue("expires",m_expires);
|
|
|
|
DDebug(ClientDriver::self(),DebugAll,"Created client account=%s [%p]",
|
|
|
|
m_uri.c_str(),this);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get this account's resource
|
|
|
|
ClientResource* ClientAccount::resource(bool ref)
|
|
|
|
{
|
|
|
|
Lock lock(this);
|
|
|
|
if (!m_resource)
|
|
|
|
return 0;
|
|
|
|
return (!ref || m_resource->ref()) ? m_resource : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set/reset this account's resource
|
|
|
|
void ClientAccount::setResource(ClientResource* res)
|
|
|
|
{
|
|
|
|
Lock lock(this);
|
|
|
|
TelEngine::destruct(m_resource);
|
|
|
|
m_resource = res;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Find a contact by its id
|
|
|
|
ClientContact* ClientAccount::findContact(const String& id, bool ref)
|
|
|
|
{
|
|
|
|
Lock lock(this);
|
|
|
|
ObjList* obj = m_contacts.find(id);
|
|
|
|
if (!obj)
|
|
|
|
return 0;
|
|
|
|
ClientContact* c = static_cast<ClientContact*>(obj->get());
|
|
|
|
return (!ref || c->ref()) ? c : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Find a contact having a given id and resource
|
|
|
|
ClientContact* ClientAccount::findContact(const String& id, const String& resid,
|
|
|
|
bool ref)
|
|
|
|
{
|
|
|
|
Lock lock(this);
|
|
|
|
ClientContact* c = findContact(id,false);
|
|
|
|
if (!(c && c->findResource(resid)))
|
|
|
|
return 0;
|
|
|
|
return (!ref || c->ref()) ? c : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Build a contact and append it to the list
|
|
|
|
ClientContact* ClientAccount::appendContact(const String& id, const char* name)
|
|
|
|
{
|
|
|
|
Lock lock(this);
|
|
|
|
if (!id || findContact(id))
|
|
|
|
return 0;
|
|
|
|
ClientContact* c = new ClientContact(this,id,name);
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Build a contact and append it to the list
|
|
|
|
ClientContact* ClientAccount::appendContact(const NamedList& params)
|
|
|
|
{
|
|
|
|
Lock lock(this);
|
|
|
|
if (params.null() || findContact(params))
|
|
|
|
return 0;
|
|
|
|
ClientContact* c = new ClientContact(this,params);
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Remove a contact from list. Reset contact's owner
|
|
|
|
ClientContact* ClientAccount::removeContact(const String& id, bool delObj)
|
|
|
|
{
|
|
|
|
Lock lock(this);
|
|
|
|
ClientContact* c = findContact(id);
|
|
|
|
if (!c)
|
|
|
|
return 0;
|
|
|
|
m_contacts.remove(c,false);
|
|
|
|
c->m_owner = 0;
|
|
|
|
lock.drop();
|
|
|
|
Debug(ClientDriver::self(),DebugAll,
|
|
|
|
"Account(%s) removed contact '%s' delObj=%u [%p]",
|
|
|
|
m_uri.c_str(),c->uri().c_str(),delObj,this);
|
|
|
|
if (delObj)
|
|
|
|
TelEngine::destruct(c);
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Build a login/logout message from account's data
|
|
|
|
Message* ClientAccount::userlogin(bool login, const char* msg)
|
|
|
|
{
|
|
|
|
#define SAFE_FILL(param,value) { if(value) m->addParam(param,value); }
|
|
|
|
Message* m = new Message(msg);
|
|
|
|
m->addParam("account",m_id);
|
|
|
|
m->addParam("operation",login ? "create" : "delete");
|
|
|
|
// Fill login data
|
|
|
|
if (login) {
|
|
|
|
SAFE_FILL("username",m_uri.getUser());
|
|
|
|
SAFE_FILL("password",m_password);
|
|
|
|
SAFE_FILL("domain",m_uri.getHost());
|
|
|
|
lock();
|
|
|
|
if (m_resource)
|
|
|
|
SAFE_FILL("resource",m_resource->toString());
|
|
|
|
unlock();
|
|
|
|
SAFE_FILL("server",m_server);
|
|
|
|
SAFE_FILL("options",m_options);
|
|
|
|
if (m_port)
|
|
|
|
m->addParam("port",String(m_port));
|
|
|
|
SAFE_FILL("outbound",m_outbound);
|
|
|
|
if (m_expires >= 0)
|
|
|
|
m->addParam("expires",String(m_expires));
|
|
|
|
}
|
|
|
|
SAFE_FILL("protocol",m_id.getProtocol());
|
|
|
|
#undef SAFE_FILL
|
|
|
|
return m;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Remove from owner. Release data
|
|
|
|
void ClientAccount::destroyed()
|
|
|
|
{
|
|
|
|
lock();
|
|
|
|
setResource();
|
|
|
|
// Clear contacts. Remove their owner before
|
|
|
|
for (ObjList* o = m_contacts.skipNull(); o; o = o->skipNext())
|
|
|
|
(static_cast<ClientContact*>(o->get()))->m_owner = 0;
|
|
|
|
m_contacts.clear();
|
|
|
|
unlock();
|
|
|
|
DDebug(ClientDriver::self(),DebugAll,"Destroyed client account=%s [%p]",
|
|
|
|
m_uri.c_str(),this);
|
|
|
|
RefObject::destroyed();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Method used by the contact to append itself to this account's list
|
|
|
|
void ClientAccount::appendContact(ClientContact* contact)
|
|
|
|
{
|
|
|
|
if (!contact)
|
|
|
|
return;
|
|
|
|
Lock lock(this);
|
|
|
|
m_contacts.append(contact);
|
|
|
|
Debug(ClientDriver::self(),DebugAll,
|
|
|
|
"Account(%s) added contact '%s' [%p]",
|
|
|
|
m_uri.c_str(),contact->uri().c_str(),this);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* ClientAccountList
|
|
|
|
*/
|
|
|
|
// Find an account
|
|
|
|
ClientAccount* ClientAccountList::findAccount(const String& id, bool ref)
|
|
|
|
{
|
|
|
|
Lock lock(this);
|
|
|
|
ObjList* obj = m_accounts.find(id);
|
|
|
|
if (!obj)
|
|
|
|
return 0;
|
|
|
|
ClientAccount* a = static_cast<ClientAccount*>(obj->get());
|
|
|
|
return (!ref || a->ref()) ? a : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Find an account's contact
|
|
|
|
ClientContact* ClientAccountList::findContact(const String& account, const String& id, bool ref)
|
|
|
|
{
|
|
|
|
Lock lock(this);
|
|
|
|
ClientAccount* acc = findAccount(account,false);
|
|
|
|
return acc ? acc->findContact(id,ref) : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Find an account's contact from a built id
|
|
|
|
ClientContact* ClientAccountList::findContact(const String& builtId, bool ref)
|
|
|
|
{
|
|
|
|
String account, contact;
|
|
|
|
ClientContact::splitContactId(builtId,account,contact);
|
|
|
|
return findContact(account,contact,ref);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Append a new account
|
|
|
|
bool ClientAccountList::appendAccount(ClientAccount* account)
|
|
|
|
{
|
|
|
|
if (!account || findAccount(account->toString()) || !account->ref())
|
|
|
|
return false;
|
|
|
|
m_accounts.append(account);
|
|
|
|
DDebug(ClientDriver::self(),DebugAll,"List(%s) added account '%s'",
|
|
|
|
c_str(),account->uri().c_str());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Remove an account
|
|
|
|
void ClientAccountList::removeAccount(const String& id)
|
|
|
|
{
|
|
|
|
Lock lock(this);
|
|
|
|
ObjList* obj = m_accounts.find(id);
|
|
|
|
if (!obj)
|
|
|
|
return;
|
|
|
|
DDebug(ClientDriver::self(),DebugAll,"List(%s) removed account '%s'",
|
|
|
|
c_str(),(static_cast<ClientAccount*>(obj->get()))->uri().c_str());
|
|
|
|
obj->remove();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* ClientContact
|
|
|
|
*/
|
|
|
|
// Constructor. Append itself to the owner's list
|
|
|
|
ClientContact::ClientContact(ClientAccount* owner, const char* id, const char* name,
|
|
|
|
bool chat)
|
|
|
|
: m_name(name ? name : id), m_owner(owner), m_uri(id)
|
|
|
|
{
|
|
|
|
m_id = m_uri;
|
|
|
|
m_id.toLower();
|
|
|
|
XDebug(ClientDriver::self(),DebugAll,"ClientContact(%p,%s) [%p]",
|
|
|
|
owner,m_uri.c_str(),this);
|
|
|
|
if (m_owner)
|
|
|
|
m_owner->appendContact(this);
|
|
|
|
if (chat)
|
|
|
|
createChatWindow();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Constructor. Build a contact from a list of parameters.
|
|
|
|
ClientContact::ClientContact(ClientAccount* owner, NamedList& params, bool chat)
|
|
|
|
: m_name(params.getValue("name",params)), m_owner(owner), m_uri(params)
|
|
|
|
{
|
|
|
|
m_id = m_uri;
|
|
|
|
m_id.toLower();
|
|
|
|
XDebug(ClientDriver::self(),DebugAll,"ClientContact(%p,%s) [%p]",
|
|
|
|
owner,m_uri.c_str(),this);
|
|
|
|
if (m_owner)
|
|
|
|
m_owner->appendContact(this);
|
|
|
|
if (chat)
|
|
|
|
createChatWindow();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create the chat window
|
|
|
|
void ClientContact::createChatWindow(bool force, const char* name)
|
|
|
|
{
|
|
|
|
if (force)
|
|
|
|
destroyChatWindow();
|
|
|
|
if (hasChat())
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Generate chat window name and create the window
|
|
|
|
MD5 md5(m_id);
|
|
|
|
m_chatWndName = s_chatPrefix + md5.hexDigest();
|
|
|
|
if (Client::self())
|
|
|
|
Client::self()->createWindowSafe(name,m_chatWndName);
|
|
|
|
Window* w = Client::self()->getWindow(m_chatWndName);
|
|
|
|
if (!w)
|
|
|
|
return;
|
|
|
|
String id;
|
|
|
|
buildContactId(id);
|
|
|
|
w->context(id);
|
|
|
|
NamedList tmp("");
|
|
|
|
tmp.addParam("contactname",m_name);
|
|
|
|
Client::self()->setParams(&tmp,w);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Find a group this contact might belong to
|
|
|
|
String* ClientContact::findGroup(const String& group)
|
|
|
|
{
|
|
|
|
Lock lock(m_owner);
|
|
|
|
ObjList* obj = m_groups.find(group);
|
|
|
|
return obj ? static_cast<String*>(obj->get()) : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Append a group to this contact
|
|
|
|
bool ClientContact::appendGroup(const String& group)
|
|
|
|
{
|
|
|
|
Lock lock(m_owner);
|
|
|
|
if (findGroup(group))
|
|
|
|
return false;
|
|
|
|
m_groups.append(new String(group));
|
|
|
|
DDebug(ClientDriver::self(),DebugAll,
|
|
|
|
"Account(%s) contact='%s' added group '%s' [%p]",
|
2008-09-18 14:41:30 +00:00
|
|
|
m_owner ? m_owner->uri().c_str() : "",m_uri.c_str(),group.c_str(),this);
|
2008-08-04 02:06:00 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Remove a contact's group
|
|
|
|
bool ClientContact::removeGroup(const String& group)
|
|
|
|
{
|
|
|
|
Lock lock(m_owner);
|
|
|
|
ObjList* obj = m_groups.find(group);
|
|
|
|
if (!obj)
|
|
|
|
return false;
|
|
|
|
obj->remove();
|
|
|
|
DDebug(ClientDriver::self(),DebugAll,
|
|
|
|
"Account(%s) contact='%s' removed group '%s' [%p]",
|
2008-09-18 14:41:30 +00:00
|
|
|
m_owner ? m_owner->uri().c_str() : "",m_uri.c_str(),group.c_str(),this);
|
2008-08-04 02:06:00 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Find a resource having a given id
|
|
|
|
ClientResource* ClientContact::findResource(const String& id, bool ref)
|
|
|
|
{
|
|
|
|
Lock lock(m_owner);
|
|
|
|
ObjList* obj = m_resources.find(id);
|
|
|
|
if (!obj)
|
|
|
|
return 0;
|
|
|
|
ClientResource* r = static_cast<ClientResource*>(obj->get());
|
|
|
|
return (!ref || r->ref()) ? r : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the first resource with audio capability
|
|
|
|
ClientResource* ClientContact::findAudioResource(bool ref)
|
|
|
|
{
|
|
|
|
Lock lock(m_owner);
|
|
|
|
ObjList* o = m_resources.skipNull();
|
|
|
|
for (; o; o = o->skipNext())
|
|
|
|
if ((static_cast<ClientResource*>(o->get()))->m_audio)
|
|
|
|
break;
|
|
|
|
if (!o)
|
|
|
|
return 0;
|
|
|
|
ClientResource* r = static_cast<ClientResource*>(o->get());
|
|
|
|
return (!ref || r->ref()) ? r : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Append a resource having a given id
|
|
|
|
ClientResource* ClientContact::appendResource(const String& id)
|
|
|
|
{
|
|
|
|
Lock lock(m_owner);
|
|
|
|
if (findResource(id))
|
|
|
|
return 0;
|
|
|
|
ClientResource* r = new ClientResource(id);
|
|
|
|
m_resources.append(r);
|
|
|
|
DDebug(ClientDriver::self(),DebugAll,
|
|
|
|
"Account(%s) contact='%s' added resource '%s' [%p]",
|
2008-09-18 14:41:30 +00:00
|
|
|
m_owner ? m_owner->uri().c_str() : "",m_uri.c_str(),id.c_str(),this);
|
2008-08-04 02:06:00 +00:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Remove a resource having a given id
|
|
|
|
bool ClientContact::removeResource(const String& id)
|
|
|
|
{
|
|
|
|
Lock lock(m_owner);
|
|
|
|
ObjList* obj = m_resources.find(id);
|
|
|
|
if (!obj)
|
|
|
|
return false;
|
|
|
|
obj->remove();
|
|
|
|
DDebug(ClientDriver::self(),DebugAll,
|
|
|
|
"Account(%s) contact='%s' removed resource '%s' [%p]",
|
2008-09-18 14:41:30 +00:00
|
|
|
m_owner ? m_owner->uri().c_str() : "",m_uri.c_str(),id.c_str(),this);
|
2008-08-04 02:06:00 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Remove from owner. Release data
|
|
|
|
void ClientContact::destroyed()
|
|
|
|
{
|
|
|
|
destroyChatWindow();
|
|
|
|
if (m_owner) {
|
|
|
|
Lock lock(m_owner);
|
|
|
|
m_owner->removeContact(m_id,false);
|
|
|
|
m_owner = 0;
|
|
|
|
}
|
|
|
|
RefObject::destroyed();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* ClientSound
|
|
|
|
*/
|
|
|
|
// Start playing the file
|
|
|
|
bool ClientSound::start(int repeat, bool force)
|
|
|
|
{
|
|
|
|
if (m_started && !force)
|
|
|
|
return true;
|
|
|
|
stop();
|
|
|
|
DDebug(ClientDriver::self(),DebugInfo,"Starting sound %s",c_str());
|
|
|
|
m_repeat = (repeat > 0 ? repeat : -1);
|
|
|
|
m_started = doStart();
|
|
|
|
return m_started;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Stop playing the file
|
|
|
|
void ClientSound::stop()
|
|
|
|
{
|
|
|
|
if (!m_started)
|
|
|
|
return;
|
|
|
|
DDebug(ClientDriver::self(),DebugInfo,"Stopping sound %s",c_str());
|
|
|
|
doStop();
|
|
|
|
m_started = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if a sound is started
|
|
|
|
bool ClientSound::started(const String& name)
|
|
|
|
{
|
|
|
|
if (!name)
|
|
|
|
return false;
|
|
|
|
Lock lock(s_soundsMutex);
|
|
|
|
ObjList* obj = s_sounds.find(name);
|
|
|
|
return obj ? (static_cast<ClientSound*>(obj->get()))->started() : false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Start playing a given sound
|
|
|
|
bool ClientSound::start(const String& name, int repeat, bool force)
|
|
|
|
{
|
|
|
|
if (!name)
|
|
|
|
return false;
|
|
|
|
Lock lock(s_soundsMutex);
|
|
|
|
ObjList* obj = s_sounds.find(name);
|
|
|
|
if (!obj)
|
|
|
|
return false;
|
|
|
|
return (static_cast<ClientSound*>(obj->get()))->start(repeat,force);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Stop playing a given sound
|
|
|
|
void ClientSound::stop(const String& name)
|
|
|
|
{
|
|
|
|
if (!name)
|
|
|
|
return;
|
|
|
|
Lock lock(s_soundsMutex);
|
|
|
|
ObjList* obj = s_sounds.find(name);
|
|
|
|
if (!obj)
|
|
|
|
return;
|
|
|
|
(static_cast<ClientSound*>(obj->get()))->stop();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Find a sound object
|
|
|
|
ClientSound* ClientSound::find(const String& token, bool byName)
|
|
|
|
{
|
|
|
|
if (!token)
|
|
|
|
return 0;
|
|
|
|
Lock lock(s_soundsMutex);
|
|
|
|
if (byName) {
|
|
|
|
ObjList* obj = s_sounds.find(token);
|
|
|
|
return obj ? static_cast<ClientSound*>(obj->get()) : 0;
|
|
|
|
}
|
|
|
|
// Find by file
|
|
|
|
for (ObjList* o = s_sounds.skipNull(); o; o = o->skipNext()) {
|
|
|
|
ClientSound* sound = static_cast<ClientSound*>(o->get());
|
|
|
|
if (token == sound->file())
|
|
|
|
return sound;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-07-04 22:04:47 +00:00
|
|
|
/* vi: set ts=8 sw=4 sts=4 noet: */
|