/* * yatecbase.h * This file is part of the YATE Project http://YATE.null.ro * * Common base classes for all telephony clients * * Yet Another Telephony Engine - a fully featured software PBX and IVR * Copyright (C) 2004-2006 Null Team * * 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 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef __YATECBASE_H #define __YATECBASE_H #ifndef __cplusplus #error C++ is required #endif #include /** * Holds all Telephony Engine related classes. */ namespace TelEngine { class Window; // A generic window class UIWidget; // A custom widget class UIFactory; // Base factory used to build custom widgets class Client; // The client class ClientChannel; // A client telephony channel class ClientDriver; // The client telephony driver class ClientLogic; // The client's default logic class ClientAccount; // A client account class ClientAccountList; // A client account list class ClientContact; // A client contact class ClientResource; // A client contact's resource class DurationUpdate; // Class used to update UI durations class ClientSound; // A sound file /** * A window is the basic user interface element. * Everything inside is implementation specific functionality. * @short An abstract user interface window */ class YATE_API Window : public GenObject { friend class Client; public: /** * Constructor, creates a new windows with an ID * @param id String identifier of the new window */ Window(const char* id = 0); /** * Destructor */ virtual ~Window(); /** * Retrive the standard name of this Window, used to search in lists * @return Identifier of this window */ virtual const String& toString() const; /* * Get the window's title (may not be displayed on screen) * @return Title of this window */ virtual void title(const String& text); /** * Set the contextual information previously associated with this window * @param text New contextual information */ virtual void context(const String& text); /** * Set window parameters or widget contents * @param params List of parameters to set in the window and its widgets * @return True if all parameters could be set */ virtual bool setParams(const NamedList& params); /** * Force this window on top of another one which becomes its parent * @param parent Window to force as parent of this one */ virtual void setOver(const Window* parent) = 0; /** * Check if this window has an element by name * @param name Name of the element to search for * @return True if one element with the given name exists */ virtual bool hasElement(const String& name) = 0; /** * Set an element as interactive in the window * @param name Name of the element * @param active True to make interactive, false to disallow interaction * @return True if the operation was successfull */ virtual bool setActive(const String& name, bool active) = 0; /** * Set an element as receiving input in the window * @param name Name of the element * @param select Also select the content of the focused element * @return True if the operation was successfull */ virtual bool setFocus(const String& name, bool select = false) = 0; /** * Set the visibility of an element in the window * @param name Name of the element * @param visible True to make element visible, false to hide it * @return True if the operation was successfull */ virtual bool setShow(const String& name, bool visible) = 0; /** * Set the displayed text of an element in the window * @param name Name of the element * @param text Text value to set in the element * @param richText True if the text contains format data * @return True if the operation was successfull */ virtual bool setText(const String& name, const String& text, bool richText = false) = 0; /** * Set the checked or toggled status of an element in the window * @param name Name of the element * @param checked True to make element checked or toggled * @return True if the operation was successfull */ virtual bool setCheck(const String& name, bool checked) = 0; /** * Set the selection of an item in an element in the window * @param name Name of the element * @param item Name of the item that should be selected * @return True if the operation was successfull */ virtual bool setSelect(const String& name, const String& item) = 0; /** * Flag an element as requiring immediate attention * @param name Name of the element * @param urgent True if the element requires immediate attention * @return True if the operation was successfull */ virtual bool setUrgent(const String& name, bool urgent) = 0; /** * Check if an element has an item by its name * @param name Name of the element to search for * @param item Name of the item that should be searched * @return True if one item with the given name exists in the element */ virtual bool hasOption(const String& name, const String& item) = 0; /** * Add an item to an element that supports such an operation (list) * @param name Name of the element * @param item Name of the item to add * @param atStart True to insert item on the first position, false to append * @param text Displayed text to associate with the item (not all lists support it) * @return True if the operation was successfull */ virtual bool addOption(const String& name, const String& item, bool atStart = false, const String& text = String::empty()) = 0; /** * Get an element's items * @param name Name of the element to search for * @param items List to fill with element's items * @return True if the element exists */ virtual bool getOptions(const String& name, NamedList* items) = 0; /** * Remove an item from an element (list) * @param name Name of the element * @param item Name of the item to remove * @return True if the operation was successfull */ virtual bool delOption(const String& name, const String& item) = 0; /** * Append or insert text lines to a widget * @param name The name of the widget * @param lines List containing the lines * @param max The maximum number of lines allowed to be displayed. Set to 0 to ignore * @param atStart True to insert, false to append * @return True on success */ virtual bool addLines(const String& name, const NamedList* lines, unsigned int max, bool atStart = false); /** * Add a row to a table owned by this window * @param name Name of the element * @param item Name of the item to add * @param data Table's columns to set * @param atStart True to insert, false to append * @return True if the operation was successfull */ virtual bool addTableRow(const String& name, const String& item, const NamedList* data = 0, bool atStart = false); /** * Append or update several table rows at once * @param name Name of the element * @param data Parameters to initialize the rows with * @param prefix Prefix to match (and remove) in parameter names * @return True if all the operations were successfull */ virtual bool setMultipleRows(const String& name, const NamedList& data, const String& prefix = String::empty()); /** * Insert a row into a table owned by this window * @param name Name of the element * @param item Name of the item to insert * @param before Name of the item to insert before * @param data Table's columns to set * @return True if the operation was successfull */ virtual bool insertTableRow(const String& name, const String& item, const String& before, const NamedList* data = 0); /** * Delete a row from a table owned by this window * @param name Name of the element * @param item Name of the item to remove * @return True if the operation was successfull */ virtual bool delTableRow(const String& name, const String& item); /** * Update a row from a table owned by this window * @param name Name of the element * @param item Name of the item to update * @param data Data to update * @return True if the operation was successfull */ virtual bool setTableRow(const String& name, const String& item, const NamedList* data); /** * Set a table row or add a new one if not found * @param name Name of the element * @param item Table item to set/add * @param data Optional list of parameters used to set row data * @param atStart True to add item at start, false to add them to the end * @return True if the operation was successfull */ virtual bool updateTableRow(const String& name, const String& item, const NamedList* data = 0, bool atStart = 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 boolean value 'true' to add a new item if not found * or 'false' to set an existing one. Set it to empty string to delete the item * @param name Name of the table * @param data The list of items to add/set/delete * @param atStart True to add new items at start, false to add them to the end * @return True if the operation was successfull */ virtual bool updateTableRows(const String& name, const NamedList* data, bool atStart = false); /** * Retrieve a row from a table owned by this window * @param name Name of the element * @param item Name of the item to retrieve * @param data List to fill with table's columns contents * @return True if the operation was successfull */ virtual bool getTableRow(const String& name, const String& item, NamedList* data = 0); /** * Clear (delete all rows) a table owned by this window * @param name Name of the element * @return True if the operation was successfull */ virtual bool clearTable(const String& name); /** * Get an element's text * @param name Name of the element * @param text The destination string * @param richText True to get the element's roch text if supported. * @return True if the operation was successfull */ virtual bool getText(const String& name, String& text, bool richText = false) = 0; /** * Get the checked state of a checkable control * @param name Name of the element * @param checked The checked state of the control * @return True if the operation was successfull */ virtual bool getCheck(const String& name, bool& checked) = 0; /** * Retrieve an element's selection * @param name Name of the element * @param item String to fill with selection's contents * @return True if the operation was successfull */ virtual bool getSelect(const String& name, String& item) = 0; /** * Set a property for this window or for a widget owned by it * @param name Name of the element * @param item Property's name * @param value Property's value * @return True on success */ virtual bool setProperty(const String& name, const String& item, const String& value) { return false; } /** * Get a property from this window or from a widget owned by it * @param name Name of the element * @param item Property's name * @param value Property's value * @return True on success */ virtual bool getProperty(const String& name, const String& item, String& value) { return false; } /** * Populate the window if not already done */ inline void populate() { if (m_populated) return; doPopulate(); m_populated = true; } /** * Initialize the window if not already done */ inline void init() { if (m_initialized) return; doInit(); m_initialized = true; } /** * Show this window */ virtual void show() = 0; /** * Hide this window */ virtual void hide() = 0; /** * Resize this window * @param width The new width * @param height The new width */ virtual void size(int width, int height) = 0; /** * Move this window * @param x The x coordinate of the upper left corner * @param y The y coordinate of the upper left corner */ virtual void move(int x, int y) = 0; /** * Move this window related to its current position * @param dx The value to be added to the current x coordinate of the upper left corner * @param dy The value to be added to the current y coordinate of the upper left corner */ virtual void moveRel(int dx, int dy) = 0; /** * Checkes if this window is related to the given window * @param wnd The window to check for any relation * @return False if wnd is this window or a master one */ virtual bool related(const Window* wnd) const; virtual void menu(int x, int y) = 0; /** * Check if this window can be closed * @return True if this window can be closed, false to prevent hiding it */ virtual bool canClose() { return true; } /** * Retrive the standard name of this Window * @return Identifier of this window */ inline const String& id() const { return m_id; } /* * Get the window's title (may not be displayed on screen) * @return Title of this window */ inline const String& title() const { return m_title; } /** * Get the contextual information previously associated with this window * @return String contextual information */ inline const String& context() const { return m_context; } /** * Get the visibility status of this window * @return True if window is visible, false if it's hidden */ inline bool visible() const { return m_visible; } /** * Set the visibility status of this window * @param yes True if window should be visible */ inline void visible(bool yes) { if (yes) show(); else hide(); } /** * Check if this window is a master (topmost) window * @return True if this window is topmost */ inline bool master() const { return m_master; } /** * Check if this window is a popup window * @return True if this window is initially hidden */ inline bool popup() const { return m_popup; } /** * Check if a string is a parameter prefix handled by setParams(). * Exact prefix match is not a valid one * @param prefix String to check * @return True if the given prefix is a valid one */ static bool isValidParamPrefix(const String& prefix); protected: virtual void doPopulate() = 0; virtual void doInit() = 0; String m_id; String m_title; String m_context; bool m_visible; bool m_master; bool m_popup; bool m_saveOnClose; // Save window's data when destroyed private: bool m_populated; // Already populated flag bool m_initialized; // Already initialized flag }; class YATE_API UIWidget : public String { public: /** * Constructor, creates a new widget * @param name The widget's name */ inline UIWidget(const char* name = 0) : String(name) {} /** * Destructor */ virtual ~UIWidget() {} /** * Retrive the standard name of this Window * @return Identifier of this window */ inline const String& name() const { return toString(); } /** * Set widget's parameters * @param params List of parameters * @return True if all parameters could be set */ virtual bool setParams(const NamedList& params) { return false; } /** * Get widget's items * @param items List to fill with widget's items * @return False on failure (e.g. not initialized) */ virtual bool getOptions(NamedList& items) { return false; } /** * Add a row to a table * @param item Name of the item to add * @param data Table's columns to set * @param atStart True to insert, false to append * @return True if the operation was successfull */ virtual bool addTableRow(const String& item, const NamedList* data = 0, bool atStart = false) { return false; } /** Append or update several table rows at once * @param data Parameters to initialize the rows with * @param prefix Prefix to match (and remove) in parameter names * @return True if all the operations were successfull */ virtual bool setMultipleRows(const NamedList& data, const String& prefix = String::empty()) { 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 boolean value 'true' to add a new item if not found * or 'false' to set an existing one. Set it to empty string to delete the item * @param data The list of items to add/set/delete * @param atStart True to add new items at start, false to add them to the end * @return True if the operation was successfull */ virtual bool updateTableRows(const NamedList* data, bool atStart = false) { return false; } /** * Insert a row into a table * @param item Name of the item to insert * @param before Name of the item to insert before * @param data Table's columns to set * @return True if the operation was successfull */ virtual bool insertTableRow(const String& item, const String& before, const NamedList* data = 0) { return false; } /** * Delete a row from a table * @param item Name of the item to remove * @return True if the operation was successfull */ virtual bool delTableRow(const String& item) { return false; } /** * Update a table's row * @param item Name of the item to update * @param data Data to update * @return True if the operation was successfull */ virtual bool setTableRow(const String& item, const NamedList* data) { return false; } /** * Retrieve a row from a table * @param item Name of the item to retrieve * @param data List to fill with table's columns contents * @return True if the operation was successfull */ virtual bool getTableRow(const String& item, NamedList* data = 0) { return false; } /** * Clear (delete all rows) a table * @return True if the operation was successfull */ virtual bool clearTable() { return false; } /** * Retrieve the widget's selection * @param item String to fill with selection's contents * @return True if the operation was successfull */ virtual bool getSelect(String& item) { return false; } }; /** * Each instance of UIFactory creates special user interface elements by type. * Keeps a global list with all factories. The list doesn't own the facotries * @short A static user interface creator */ class YATE_API UIFactory : public String { public: /** * Constructor. Append itself to the factories list */ UIFactory(const char* name); /** * Destructor. Remove itself from list */ virtual ~UIFactory(); /** * Check if this factory can build an object of a given type * @param type Object type to check * @return True if this factory can build the object */ inline bool canBuild(const String& type) { return 0 != m_types.find(type); } /** * Ask this factory to create an object of a given type * @param type Object's type * @param name Object' name * @param params Optional object parameters * @return Valid pointer or 0 if failed to build it */ virtual void* create(const String& type, const char* name, NamedList* params = 0) = 0; /** * Ask all factories to create an object of a given type * @param type Object's type * @param name Object' name * @param params Optional object parameters * @param factory Optional factory name used to create the requested object. If non 0, * this will be the only factory asked to create the object * @return Valid pointer or 0 if failed to build it */ static void* build(const String& type, const char* name, NamedList* params = 0, const char* factory = 0); protected: ObjList m_types; // List of object types this factory can build private: static ObjList s_factories; // Registered factories list }; /** * Singleton class that holds the User Interface's main thread and methods * @short Thread that runs the User Interface */ class YATE_API Client : public Thread, public MessageReceiver { friend class Window; friend class ClientChannel; friend class ClientDriver; friend class ClientLogic; public: /** * Message relays installed by this receiver. */ enum MsgID { CallCdr = 0, UiAction = 1, UserLogin = 2, UserNotify = 3, ResourceNotify = 4, ResourceSubscribe = 5, ClientChanUpdate = 7, // Handlers not automatically installed ChanNotify = 8, // NOTE: Keep the MsgIdCount in sync: it can be used by other parties to install // other relays MsgIdCount = 9 }; /** * Client boolean options mapped to UI toggles */ enum ClientToggle { OptMultiLines = 0, // Accept incoming calls OptAutoAnswer = 1, // Auto answer incoming calls OptRingIn = 2, // Enable/disable incoming ringer OptRingOut = 3, // Enable/disable outgoing ringer OptActivateLastOutCall = 4, // Set the last outgoing call active OptActivateLastInCall = 5, // Set the last incoming call active OptActivateCallOnSelect = 6, // Set the active call when selected in channel list (don't require double click) OptKeypadVisible = 7, // Show/hide keypad OptCount = 8 }; /** * Constructor * @param name The client's name */ Client(const char *name = 0); /** * Destructor */ virtual ~Client(); /** * Run the client's thread */ virtual void run(); /** * Cleanup when thread terminates */ virtual void cleanup(); /** * Execute the client */ virtual void main() = 0; /** * Lock the client */ virtual void lock() = 0; /** * Unlock the client */ virtual void unlock() = 0; /** * Lock the client only if we are using more then 1 thread */ inline void lockOther() { if (!m_oneThread) lock(); } /** * Unlock the client only if we are using more then 1 thread */ inline void unlockOther() { if (!m_oneThread) unlock(); } /** * Handle all windows closed event from UI */ virtual void allHidden() = 0; /** * Load windows and optionally (re)initialize the client's options. * @param file The resource file describing the windows. Set to 0 to use the default one * @param init True to (re)initialize the client */ void loadUI(const char* file = 0, bool init = true); /** * Terminate application */ virtual void quit() = 0; /** * Process a received message. Check for a logic to process it * @param msg Received message * @param id Message id * @return True if a logic processed the message (stop dispatching it) */ virtual bool received(Message& msg, int id); /** * Create a window with a given name * @param name The window's name * @param alias Window name alias after succesfully loaded. * Set to empty string to use the given name * @return True on success */ virtual bool createWindowSafe(const String& name, const String& alias = String::empty()); /** * Ask to an UI factory to create an object in the UI's thread * @param dest Destination to be filled with the newly create object's address * @param type Object's type * @param name Object's name * @param params Optional object parameters * @return True on success */ virtual bool createObject(void** dest, const String& type, const char* name, NamedList* params = 0); /** * Hide/destroy a window with a given name * @param name The window's name * @param hide True to hide, false to close * @return True on success */ virtual bool closeWindow(const String& name, bool hide = true); /** * Install/uninstall a debugger output hook * @param active True to install, false to uninstall the hook * @return True on success */ virtual bool debugHook(bool active); /** * Add a log line * @param text Text to add * @return True on success */ virtual bool addToLog(const String& text); /** * Set the status text * @param text Status text * @param wnd Optional window owning the status control * @return True on success */ virtual bool setStatus(const String& text, Window* wnd = 0); /** * Set the status text safely * @param text Status text * @param wnd Optional window owning the status control * @return True on success */ bool setStatusLocked(const String& text, Window* wnd = 0); /** * Set multiple window parameters * @param params The parameter list * @param wnd Optional window whose params are to be set * @param skip Optional window to skip if wnd is 0 * @return True on success */ bool setParams(const NamedList* params, Window* wnd = 0, Window* skip = 0); /** * Handle actions from user interface. Enqueue an ui.event message if * the action is not handled by a client logic * @param wnd The window in which the user did something * @param name The action's name * @param params Optional action parameters * @return True if the action was handled by a client logic */ virtual bool action(Window* wnd, const String& name, NamedList* params = 0); /** * Handle actions from checkable widgets. Enqueue an ui.event message if * the action is not handled by a client logic * @param wnd The window in which the user did something * @param name The object's name * @param active Object's state * @return True if the action was handled by a client logic */ virtual bool toggle(Window* wnd, const String& name, bool active); /** * Handle 'select' actions from user interface. Enqueue an ui.event message if * the action is not handled by a client logic * @param wnd The window in which the user selected the object * @param name The action's name * @param item Item identifying the selection * @param text Selection's text * @return True if the action was handled by a client logic */ virtual bool select(Window* wnd, const String& name, const String& item, const String& text = String::empty()); /** * Check if the client is using more then 1 thread * @return True if the client is using more then 1 thread */ inline bool oneThread() const { return m_oneThread; } /** * Get the currently selected line * @return The selected line */ inline int line() const { return m_line; } /** * Set the selected line * @param newLine The selected line */ void line(int newLine); bool hasElement(const String& name, Window* wnd = 0, Window* skip = 0); bool setActive(const String& name, bool active, Window* wnd = 0, Window* skip = 0); bool setFocus(const String& name, bool select = false, Window* wnd = 0, Window* skip = 0); bool setShow(const String& name, bool visible, Window* wnd = 0, Window* skip = 0); bool setText(const String& name, const String& text, bool richText = false, Window* wnd = 0, Window* skip = 0); bool setCheck(const String& name, bool checked, Window* wnd = 0, Window* skip = 0); bool setSelect(const String& name, const String& item, Window* wnd = 0, Window* skip = 0); bool setUrgent(const String& name, bool urgent, Window* wnd = 0, Window* skip = 0); bool hasOption(const String& name, const String& item, Window* wnd = 0, Window* skip = 0); /** * Get an element's items * @param name Name of the element to search for * @param items List to fill with element's items * @param wnd Optional window owning the element * @param skip Optional window to skip when searching for the element * @return True if the element exists */ virtual bool getOptions(const String& name, NamedList* items, Window* wnd = 0, Window* skip = 0); bool addOption(const String& name, const String& item, bool atStart, const String& text = String::empty(), Window* wnd = 0, Window* skip = 0); bool delOption(const String& name, const String& item, Window* wnd = 0, Window* skip = 0); /** * Append or insert text lines to a widget * @param name The name of the widget * @param lines List containing the lines * @param max The maximum number of lines allowed to be displayed. Set to 0 to ignore * @param atStart True to insert, false to append * @param wnd Optional window owning the widget * @param skip Optional window to skip if wnd is 0 * @return True on success */ bool addLines(const String& name, const NamedList* lines, unsigned int max, bool atStart = false, Window* wnd = 0, Window* skip = 0); bool addTableRow(const String& name, const String& item, const NamedList* data = 0, bool atStart = false, Window* wnd = 0, Window* skip = 0); /** Append or update several table rows at once * @param name Name of the element * @param data Parameters to initialize the rows with * @param prefix Prefix to match (and remove) in parameter names * @param wnd Optional window owning the element * @param skip Optional window to skip if wnd is 0 * @return True if all the operations were successfull */ bool setMultipleRows(const String& name, const NamedList& data, const String& prefix = String::empty(), Window* wnd = 0, Window* skip = 0); /** * Insert a row into a table owned by this window * @param name Name of the element * @param item Name of the item to insert * @param before Name of the item to insert before * @param data Table's columns to set * @param wnd Optional window owning the element * @param skip Optional window to skip if wnd is 0 * @return True if the operation was successfull */ bool insertTableRow(const String& name, const String& item, const String& before, const NamedList* data = 0, Window* wnd = 0, Window* skip = 0); bool delTableRow(const String& name, const String& item, Window* wnd = 0, Window* skip = 0); bool setTableRow(const String& name, const String& item, const NamedList* data, Window* wnd = 0, Window* skip = 0); bool getTableRow(const String& name, const String& item, NamedList* data = 0, Window* wnd = 0, Window* skip = 0); bool clearTable(const String& name, Window* wnd = 0, Window* skip = 0); /** * Set a table row or add a new one if not found * @param name Name of the element * @param item Table item to set/add * @param data Optional list of parameters used to set row data * @param atStart True to add item at start, false to add them to the end * @param wnd Optional window owning the element * @param skip Optional window to skip if wnd is 0 * @return True if the operation was successfull */ bool updateTableRow(const String& name, const String& item, const NamedList* data = 0, bool atStart = false, Window* wnd = 0, Window* skip = 0); /** * 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 boolean value 'true' to add a new item if not found * or 'false' to set an existing one. Set it to empty string to delete the item * @param name Name of the table * @param data The list of items to add/set/delete * @param atStart True to add new items at start, false to add them to the end * @param wnd Optional window owning the element * @param skip Optional window to skip if wnd is 0 * @return True if the operation was successfull */ bool updateTableRows(const String& name, const NamedList* data, bool atStart = false, Window* wnd = 0, Window* skip = 0); /** * Get an element's text * @param name Name of the element * @param text The destination string * @param richText True to get the element's roch text if supported. * @param wnd Optional window owning the element * @param skip Optional window to skip if wnd is 0 * @return True if the operation was successfull */ bool getText(const String& name, String& text, bool richText = false, Window* wnd = 0, Window* skip = 0); bool getCheck(const String& name, bool& checked, Window* wnd = 0, Window* skip = 0); bool getSelect(const String& name, String& item, Window* wnd = 0, Window* skip = 0); /** * Set a property * @param name Name of the element * @param item Property's name * @param value Property's value * @param wnd Optional target window * @param skip Optional window to skip if wnd is 0 * @return True on success */ virtual bool setProperty(const String& name, const String& item, const String& value, Window* wnd = 0, Window* skip = 0); /** * Get a property * @param name Name of the element * @param item Property's name * @param value Property's value * @param wnd Optional target window * @param skip Optional window to skip if wnd is 0 * @return True on success */ virtual bool getProperty(const String& name, const String& item, String& value, Window* wnd = 0, Window* skip = 0); void moveRelated(const Window* wnd, int dx, int dy); inline bool initialized() const { return m_initialized; } inline static Client* self() { return s_client; } inline static bool changing() { return (s_changing > 0); } static Window* getWindow(const String& name); static bool setVisible(const String& name, bool show = true); static bool getVisible(const String& name); static bool openPopup(const String& name, const NamedList* params = 0, const Window* parent = 0); static bool openMessage(const char* text, const Window* parent = 0, const char* context = 0); static bool openConfirm(const char* text, const Window* parent = 0, const char* context = 0); static ObjList* listWindows(); void idleActions(); /** * Postpone a copy of a message to be dispatched from the UI thread * @param msg Message to be postponed * @param id Identifier of the message to be used on dispatch * @return True if the UI thread was not current so the message was postponed */ bool postpone(const Message& msg, int id); /** * Show a file open dialog window * This method isn't using the proxy thread since it's usually called on UI action * @param parent Dialog window's parent * @param params Dialog window's params. Parameters that can be specified include 'caption', * 'dir', 'filters', 'selectedfilter', 'confirmoverwrite', 'choosedir'. * The parameter 'filters' may be a pipe ('|') separated list of filters * @param files List of selected file(s). Allow multiple file selection if non 0 * @param file The selected file if multiple file selection is disabled * @return True on success */ virtual bool chooseFile(Window* parent, const NamedList& params, NamedList* files, String* file) { return false; } /** * Request to a logic to set a client's parameter. Save the settings file * and/or update interface * @param param Parameter's name * @param value The value of the parameter * @param save True to save the configuration file * @param update True to update the interface * @return True on success, false if the parameter doesn't exist, the value * is incorrect or failed to save the file */ virtual bool setClientParam(const String& param, const String& value, bool save, bool update); /** * Called when the user pressed the backspace key * @param name The active widget (it might be the window itself) * @param wnd Optional window containing the widget that triggered the action * @return True on success */ virtual bool backspace(const String& name, Window* wnd = 0); /** * Create and install a message relay owned by this client. * The new relay will be unistalled when the client is terminated * @param name Message name * @param id Relay id * @param prio Message priority */ void installRelay(const char* name, int id, int prio); /** * Call routing handler called by the driver * @param msg The call.route message */ virtual bool callRouting(Message& msg) { return true;} /** * IM message routing handler called by the driver * @param msg The im.route message */ virtual bool imRouting(Message& msg) { return true;} /** * Process an IM message * @param msg The im.execute of chan.text message */ virtual bool imExecute(Message& msg); /** * Build an incoming channel. * Answer it if succesfully connected and auto answer is set. * Reject it if multiline is false and the driver is busy. * Set the active one if requested by config and there is no active channel. * Start the ringer if there is no active channel * @param msg The call.execute message * @param dest The destination (target) * @return True if a channel was created and connected */ virtual bool buildIncomingChannel(Message& msg, const String& dest); /** * Build an outgoing channel * @param params Call parameters * @return True if a channel was created its router started */ virtual bool buildOutgoingChannel(NamedList& params); /** * Call execute handler called by the driver. * Ask the logics to create the channel * @param msg The call.execute message * @param dest The destination (target) * @return True if a channel was created and connected */ bool callIncoming(Message& msg, const String& dest); /** * Answer an incoming call * @param id The accepted channel's id * @return True on success */ void callAnswer(const String& id); /** * Terminate a call * @param id The channel's id * @param reason Optional termination reason * @param error Optional termination error * @return True on success */ void callTerminate(const String& id, const char* reason = 0, const char* error = 0); /** * Get the active channel if any * @return Referenced pointer to the active channel or 0 */ ClientChannel* getActiveChannel(); /** * Start/stop ringer. The ringer is started only if not disabled * @param in True if the request is for the incoming call alert, false if it * is for the outgoing call ringing alert * @param on True to start, false to stop the sound * @return True on success */ virtual bool ringer(bool in, bool on); /** * Create a sound object. Append it to the global list * @param name The name of sound object * @param file The file to play (should contain the whole path and the file name) * @param device Optional device used to play the file. Set to 0 to use the default one * @return True on success, false if a sound with the given name already exists */ virtual bool createSound(const char* name, const char* file, const char* device = 0) { return false; } /** * Send digits on selected channel * @param digits The digits to send * @param id The channel id. Use the active one if empty * @return True on success */ bool emitDigits(const char* digits, const String& id = String::empty()); /** * Send a digit on selected channel * @param digit The digit to send * @param id The channel id. Use the active one if empty * @return True on success */ inline bool emitDigit(char digit, const String& id = String::empty()) { char s[2] = {digit,0}; return emitDigits(s,id); } /** * Get a boolean option of this client * @param toggle Options's id to retrieve * @return True on success */ inline bool getBoolOpt(ClientToggle toggle) { return toggle < OptCount ? m_toggles[toggle] : false; } /** * Set a boolean option of this client * @param toggle Options's id to set * @param value Value to set * @param updateUi True to update UI * @return True if the option's value changed */ bool setBoolOpt(ClientToggle toggle, bool value, bool updateUi = false); /** * Build a date/time string from UTC time * @param dest Destination string * @param secs Seconds since EPOCH * @param format Format string used to build the destination * @param utc True to build UTC time instead of local time * @return True on success */ virtual bool formatDateTime(String& dest, unsigned int secs, const char* format, bool utc = false) { return false; } /** * Engine start notification. Notify all registered logics * @param msg The engine.start message */ virtual void engineStart(Message& msg); /** * Check if the client is exiting * @return True if the client therad is exiting */ static inline bool exiting() { return s_exiting; } /** * Add a logic to the list. The added object is not owned by the client * @param logic Pointer to the logic to add * @return True on success. False if the pointer is 0 or already added */ static bool addLogic(ClientLogic* logic); /** * Remove a logic from the list without destroying it * @param logic Pointer to the logic to remove */ static void removeLogic(ClientLogic* logic); /** * Convenience method to retrieve a logic * @param name The logic's name * @return ClientLogic pointer or 0 */ static ClientLogic* findLogic(const String& name); /** * Build an 'ui.event' message * @param event Event's name * @param wnd Optional window to add to message * @param name Optional 'name' parameter value * @param params Other optional parameters to be added to the message * @return Valid Message pointer */ static Message* eventMessage(const String& event, Window* wnd = 0, const char* name = 0, NamedList* params = 0); /** * Save a configuration file. Call openMessage() on failure * @param cfg The configuration file to save * @param parent The parent of the error window if needded * @param showErr True to open a message popup on failure * @return True on success */ static bool save(Configuration& cfg, Window* parent = 0, bool showErr = true); /** * Check if a string names a client's boolean option * @param name String to check * @return Valid client option index or OptCount if not found */ static ClientToggle getBoolOpt(const String& name); /** * Set the flag indicating that the client should tick the logics */ static inline void setLogicsTick() { s_idleLogicsTick = true; } static Configuration s_settings; // Client settings static Configuration s_actions; // Logic preferrences static Configuration s_accounts; // Accounts static Configuration s_contacts; // Contacts static Configuration s_providers; // Provider settings static Configuration s_history; // Call log static Configuration s_calltoHistory; // Dialed destinations history // Holds a not selected/set value match static Regexp s_notSelected; // Paths static String s_skinPath; static String s_soundPath; // Ring name for incoming channels static String s_ringInName; // Ring name for outgoing channels static String s_ringOutName; // Status widget's name static String s_statusWidget; // Widget displaying the debug text static String s_debugWidget; // The list of cient's toggles static String s_toggles[OptCount]; protected: virtual bool createWindow(const String& name, const String& alias = String::empty()) = 0; virtual void loadWindows(const char* file = 0) = 0; virtual void initWindows(); virtual void initClient(); virtual void exitClient() {} inline bool needProxy() const { return m_oneThread && !isCurrent(); } bool driverLockLoop(); static bool driverLock(long maxwait = 0); static void driverUnlock(); static bool s_exiting; // Exiting flag ObjList m_windows; bool m_initialized; int m_line; bool m_oneThread; bool m_toggles[OptCount]; ObjList m_relays; // Message relays installed by this receiver static Client* s_client; static int s_changing; static ObjList s_logics; static bool s_idleLogicsTick; // Call logics' timerTick() }; /** * This class implements a Channel used by client programs * @short Channel used by client programs */ class YATE_API ClientChannel : public Channel { friend class ClientDriver; public: /** * Channel notifications */ enum Notification { Startup, Destroyed, Active, OnHold, Noticed, AddrChanged, Routed, Accepted, Rejected, Progressing, Ringing, Answered, Transfer, Conference, Unknown }; // Incoming (from engine) consructor ClientChannel(const Message& msg, const String& peerid); // Outgoing (to engine) constructor ClientChannel(const String& target, const NamedList& params); virtual ~ClientChannel(); virtual bool msgProgress(Message& msg); virtual bool msgRinging(Message& msg); virtual bool msgAnswered(Message& msg); virtual bool msgDrop(Message& msg, const char* reason); virtual bool callRouted(Message& msg); virtual void callAccept(Message& msg); virtual void callRejected(const char* error, const char* reason, const Message* msg); /** * Answer an incoming call. Set media channels. Enqueue a clientchan.update message */ void callAnswer(); /** * Get the remote party of this channel * @return The remote party of this channel */ inline const String& party() const { return m_party; } /** * Check if this channel is in conference * @return True if this channel is in conference */ inline bool conference() const { return m_conference; } /** * Get the transferred peer's id * @return The transferred peer's id */ inline const String& transferId() const { return m_transferId; } /** * Get the client data * @return RefObject pointer or 0 */ inline RefObject* clientData() const { return m_clientData; } /** * Set/reset the client data. * If a new client data is set its reference counter is increased * @param obj The new client data */ inline void setClientData(RefObject* obj = 0) { TelEngine::destruct(m_clientData); if (obj && obj->ref()) m_clientData = obj; } /** * Attach/detach media channels * @param open True to open, false to close * @param replace True to replace media if already open. Ignored if open is false * @return True on success */ bool setMedia(bool open = false, bool replace = false); /** * Set/reset this channel's data source/consumer * @param active True to set active, false to set inactive (mute) * @param update True to enqueue an update message * @return True on success */ bool setActive(bool active, bool update = true); /** * Set/reset the transferred peer's id. Enqueue clientchan.update if changed. * Open media when reset if the channel is active and answered * @param target The transferred peer's id. Leave it blank to reset */ void setTransfer(const String& target = String::empty()); /** * Set/reset the conference data. Enqueue clientchan.update if changed. * Open media when reset if the channel is active and answered * @param target The confeernce room's name. Leave it blank to reset */ void setConference(const String& target = String::empty()); /** * Get the peer consumer's data format * @return The peer consumer's data format */ inline const String& peerOutFormat() const { return m_peerOutFormat; } /** * Get the peer source's data format * @return The peer source's data format */ inline const String& peerInFormat() const { return m_peerInFormat; } /** * Check if this channel is the active one * @return True if this channel is the active one */ inline bool active() const { return m_active; } /** * Check if this channel was noticed * @return True if this channel was noticed */ inline bool isNoticed() const { return m_noticed; } /** * Notice this channel. Enqueue a clientchan.update message */ void noticed(); /** * Get this channel's line * @return This channel's line */ inline int line() const { return m_line; } /** * Set this channel's line * @param newLine This channel's line */ void line(int newLine); /** * Update channel. Enqueue a clientchan.update message with the given operation. * Enqueue other channel status messages if required * @param notif The value of the notify parameter * @param chan Set the channel as message's user data * @param updatePeer True to update peer's data formats * @param engineMsg Optional message to enqueue in the engine * @param minimal Set to true to fill in only a minimum of engine message's parameters * @param data Set the channel as engine message's user data */ void update(int notif, bool chan = true, bool updatePeer = true, const char* engineMsg = 0, bool minimal = false, bool data = false); /** * Lookup for a notification id * @param notif The notification's name * @param def Default value to return if not found * @return The result */ static int lookup(const char* notif, int def = Unknown) { return TelEngine::lookup(notif,s_notification,def); } /** * Lookup for a notification name * @param notif The notification's id * @param def Default value to return if not found * @return The result */ static const char* lookup(int notif, const char* def = 0) { return TelEngine::lookup(notif,s_notification,def); } /** * Channel notifications dictionary */ static TokenDict s_notification[]; protected: virtual void destroyed(); virtual void disconnected(bool final, const char* reason); // Check for a source in channel's peer or a received message's user data inline bool peerHasSource(Message& msg) { CallEndpoint* ch = getPeer(); if (!ch) ch = static_cast(msg.userObject("CallEndpoint")); return ch && ch->getSource(); } // Check if our consumer's source sent any data // Don't set the silence flag is already reset void checkSilence(); String m_party; // Remote party String m_peerOutFormat; // Peer consumer's data format String m_peerInFormat; // Peer source's data format String m_reason; // Termination reason String m_peerId; // Peer's id (used to re-connect) bool m_noticed; // Incoming channel noticed flag int m_line; // Channel's line (address) bool m_active; // Channel active flag bool m_silence; // True if the peer did't sent us any audio data bool m_conference; // True if this channel is in conference String m_transferId; // Transferred id or empty if not transferred RefObject* m_clientData; // Obscure data used by client logics }; /** * Abstract client Driver that implements some of the specific functionality * @short Base Driver with client specific functions */ class YATE_API ClientDriver : public Driver { friend class ClientChannel; // Reset active channel's id public: ClientDriver(); virtual ~ClientDriver(); virtual void initialize() = 0; virtual bool msgExecute(Message& msg, String& dest); virtual void msgTimer(Message& msg); virtual bool msgRoute(Message& msg); virtual bool received(Message& msg, int id); /** * Get the active channel's id * @return The active channel's id */ inline const String& activeId() const { return m_activeId; } /** * Set/reset the active channel. * Does nothing if the selected channel is the active one. * Put the active channel on hold before trying to set the active channel * @param id The new active channel's id. Set to empty if don't want * to set a new active channel * @return True on success */ bool setActive(const String& id = String::empty()); /** * Find a channel by its line * @param line The line to find * @return ClientChannel pointer of 0 */ ClientChannel* findLine(int line); /** * Get the global client driver object's address * @return The global client driver object's address */ inline static ClientDriver* self() { return s_driver; } /** * Get the current audio device's name * @return The current audio device's name */ inline static const String& device() { return s_device; } /** * Drop all calls belonging to the active driver * @param reason Optional drop reason */ static void dropCalls(const char* reason = 0); /** * Attach/detach client channels peers' source/consumer * @param id The id of the channel to tranfer * @param target The transfer target. Leave blank to reset the channel's transfer id * @return True on success */ static bool setAudioTransfer(const String& id, const String& target = String::empty()); /** * Attach/detach a client channel to/from a conference room * @param id The id of the channel to process * @param in True to enter the conference room, false to exit from it * @param confName Optional id of the conference. Set to 0 to use the default one * Ignored if 'in' is false * @return True on success */ static bool setConference(const String& id, bool in, const String* confName = 0); /** * Get a referenced channel found by its id * @param id The id of the channel to find * @return Referenced ClientChannel pointer or 0 */ static ClientChannel* findChan(const String& id); /** * Get a referenced channel whose stored peer is the given one * @param peer Peer id to check * @return Referenced ClientChannel pointer or 0 */ static ClientChannel* findChanByPeer(const String& peer); /** * Get the active channel * @return Referenced ClientChannel pointer or 0 */ static ClientChannel* findActiveChan() { return self() ? findChan(self()->activeId()) : 0; } /** * The name to use when the client is in conference */ static String s_confName; /** * Indicates wether a channel should drop its former peer when * terminated while in conference */ static bool s_dropConfPeer; protected: void setup(); static ClientDriver* s_driver; static String s_device; String m_activeId; // The active channel's id }; /** * This class implements the logic behind different actions in the client. * It specifies the way the graphical interface of the client will behave * in different circumstances. * @short Base client functionality */ class YATE_API ClientLogic : public GenObject { friend class Client; public: /** * Constructor. Append itself to the client's list */ ClientLogic(); /** * Constructor. Append itself to the client's list * @param name The name of this logic (module) * @param priority The priority of this logic */ ClientLogic(const char* name, int priority); /** * Destructor. Remove itself from the client's list */ virtual ~ClientLogic(); /** * Function that returns the name of the logic * @return The name of this client logic */ virtual const String& toString() const; /** * Get the priority of this logic * @return This logic's priority */ inline int priority() const { return m_prio; } /** * Process a request to set client parameters * @param params The parameter list * @return True on success */ bool setParams(const NamedList& params); /** * Handle actions from user interface * @param wnd The window in which the user did something * @param name The action's name * @param params Optional action parameters * @return True if the action was handled */ virtual bool action(Window* wnd, const String& name, NamedList* params = 0); /** * Handle actions from checkable widgets * @param wnd The window in which the user did something * @param name The object's name * @param active Object's state * @return True if the action was handled by a client logic */ virtual bool toggle(Window* wnd, const String& name, bool active); /** * Handle 'select' actions from user interface * @param wnd The window in which the user did something * @param name The object's name * @param item Item identifying the selection * @param text Selection's text * @return True if the action was handled */ virtual bool select(Window* wnd, const String& name, const String& item, const String& text = String::empty()); /** * Set a client's parameter. Save the settings file and/or update interface * @param param Parameter's name * @param value The value of the parameter * @param save True to save the configuration file * @param update True to update the interface * @return True on success */ virtual bool setClientParam(const String& param, const String& value, bool save, bool update); /** * Process an IM message * @param msg The im.execute of chan.text message */ virtual bool imIncoming(Message& msg) { return false; } /** * Call execute handler called by the client. * The default logic ask the client to build an incoming channel * @param msg The call.execute message * @param dest The destination (target) * @return True if a channel was created and connected */ virtual bool callIncoming(Message& msg, const String& dest) { return Client::self() && Client::self()->buildIncomingChannel(msg,dest); } /** * Called when the user trigger a call start action * The default logic fill the parameter list and ask the client to create an outgoing channel * @param params List of call parameters * @param wnd Optional window containing the widget that triggered the action * @return True on success */ virtual bool callStart(NamedList& params, Window* wnd = 0); /** * Called when a digit is pressed. The default logic will send the digit(s) * as DTMFs on the active channel * @param params List of parameters. It should contain a 'digits' parameter * @param wnd Optional window containing the widget that triggered the action * @return True on success */ virtual bool digitPressed(NamedList& params, Window* wnd = 0); /** * Called when the user selected a line * @param name The line name * @param wnd Optional window containing the widget that triggered the action * @return True on success */ virtual bool line(const String& name, Window* wnd = 0); /** * Show/hide widget(s) or window(s) on 'display'/'show' action * @param params Widget(s) or window(s) to show/hide * @param widget True if the operation indicates widget(s), false otherwise * @param wnd Optional window owning the action sender * @return False if failed to show/hide all widgets/windows */ virtual bool display(NamedList& params, bool widget, Window* wnd = 0); /** * Called when the user pressed the backspace key. * The default behaviour is to erase the last digit from the "callto" box * @param name The active widget (it might be the window itself) * @param wnd Optional window containing the widget that triggered the action * @return True on success */ virtual bool backspace(const String& name, Window* wnd = 0); /** * Called when the user pressed a command action. * The default behaviour is to enqueue an engine.command message * @param name The command name * @param wnd Optional window containing the widget that triggered the action * @return True on success */ virtual bool command(const String& name, Window* wnd = 0); /** * Called when the user changed the toggled state of a "debug:" widget. * The default behaviour is to enqueue an engine.debug message * @param name The debug action content (following the prefix) * @param active The widget's state * @param wnd Optional window containing the widget that triggered the action * @return True on success */ virtual bool debug(const String& name, bool active, Window* wnd = 0); /** * Called when the user wants to add a new account or edit an existing one * @param newAcc True to add a new account, false to edit an exisiting one * @param params Initial parameters * @param wnd Optional window containing the widget that triggered the action * @return True on success */ virtual bool editAccount(bool newAcc, NamedList* params, Window* wnd = 0); /** * Called when the user wants to save account data * @param params Initial parameters * @param wnd Optional window containing the widget that triggered the action * @return True on success */ virtual bool acceptAccount(NamedList* params, Window* wnd = 0); /** * Called when the user wants to delete an existing account * @param account The account's name. Set to empty to delete the current selection * @param wnd Optional window containing the widget that triggered the action * @return True on success */ virtual bool delAccount(const String& account, Window* wnd = 0); /** * Add/set an account. Login if required * @param account The account's parameters. The name of the list must be the account's name * @param login True to login the account * @param save True to save the accounts file. If true and file save fails the method will fail * @return True on success */ virtual bool updateAccount(const NamedList& account, bool login, bool save); /** * Login/logout an account * @param account The account's parameters. The name of the list must be the account's name * @param login True to login the account, false to logout * @return True on success */ virtual bool loginAccount(const NamedList& account, bool login); /** * Add/set a contact * @param contact The contact's parameters. The name of the list must be the contacts's id (name). * If it starts with 'client/' this is a contact updated from server: it can't be changed * @param save True to save data to contacts file * @param update True to update the interface * @return True on success */ virtual bool updateContact(const NamedList& contact, bool save, bool update); /** * Called when the user wants to save account data * @param params Initial parameters * @param wnd Optional window containing the widget that triggered the action * @return True on success */ virtual bool acceptContact(NamedList* params, Window* wnd = 0); /** * Called when the user wants to add a new contact or edit an existing one * @param newCont True to add a new contact, false to edit an existing one * @param params Optional initial parameters * @param wnd Optional window containing the widget that triggered the action * @return True on success */ virtual bool editContact(bool newCont, NamedList* params = 0, Window* wnd = 0); /** * Called when the user wants to delete an existing contact * @param contact The contact's id. Set to empty to delete the current selection * @param wnd Optional window containing the widget that triggered the action * @return True on success */ virtual bool delContact(const String& contact, Window* wnd = 0); /** * Called when the user wants to call an existing contact * @param params Optional parameters * @param wnd Optional window containing the widget that triggered the action * @return True on success */ virtual bool callContact(NamedList* params = 0, Window* wnd = 0); /** * Add/set account providers data * @param provider The provider's parameters. The name of the list must be the provider's id (name) * @param save True to save data to providers file * @param update True to update the interface * @return True on success */ virtual bool updateProviders(const NamedList& provider, bool save, bool update); /** * Update the call log history * @param params Call log data * @param save True to save data to history file * @param update True to update the interface * @return True */ virtual bool callLogUpdate(NamedList& params, bool save, bool update); /** * Clear the specified log and the entries from the history file and save the history file * @param table Tebale to clear * @param direction The call direction to clear (incoming,outgoing). * Note that the direction is the value saved from call.cdr messages. * If empty, all log entries will be cleared * @return True */ virtual bool callLogClear(const String& table, const String& direction); /** * Make an outgoing call to a target picked from the call log * @param billid The bill id of the call * @return True on success (call initiated) */ virtual bool callLogCall(const String& billid); /** * Create a contact from a call log entry * @param billid The bill id of the call * @return True on success (address book popup window was displayed) */ virtual bool callLogCreateContact(const String& billid); /** * Process help related actions * @param action The action's name * @param wnd The window owning the control * @return True on success */ virtual bool help(const String& action, Window* wnd); /** * Called by the client after loaded the callto history file * @return True to tell the client to stop notifying other logics */ virtual bool calltoLoaded(); /** * Called by the client after loaded the windows */ virtual void loadedWindows() {} /** * Called by the client after loaded and intialized the windows */ virtual void initializedWindows(); /** * Called by the client after loaded and intialized the windows and * loaded configuration files. * The default logic update client settings * @return True to stop processing this notification */ virtual bool initializedClient(); /** * Called by the client before exiting. * The default logic save client settings */ virtual void exitingClient(); /** * Process ui.action message * @param msg Received message * @param stopLogic Set to true on exit to tell the client to stop asking other logics * @return True to stop further processing by the engine */ virtual bool handleUiAction(Message& msg, bool& stopLogic); /** * Process call.cdr message * @param msg Received message * @param stopLogic Set to true on exit to tell the client to stop asking other logics * @return True to stop further processing by the engine */ virtual bool handleCallCdr(Message& msg, bool& stopLogic); /** * Process user.login message * @param msg Received message * @param stopLogic Set to true on exit to tell the client to stop asking other logics * @return True to stop further processing by the engine */ virtual bool handleUserLogin(Message& msg, bool& stopLogic); /** * Process user.notify message * @param msg Received message * @param stopLogic Set to true on exit to tell the client to stop asking other logics * @return True to stop further processing by the engine */ virtual bool handleUserNotify(Message& msg, bool& stopLogic); /** * Process resource.notify message * @param msg Received message * @param stopLogic Set to true on exit to tell the client to stop asking other logics * @return True to stop further processing by the engine */ virtual bool handleResourceNotify(Message& msg, bool& stopLogic); /** * Process resource.subscribe message * @param msg Received message * @param stopLogic Set to true on exit to tell the client to stop asking other logics * @return True to stop further processing by the engine */ virtual bool handleResourceSubscribe(Message& msg, bool& stopLogic); /** * Process clientchan.update message * @param msg Received message * @param stopLogic Set to true on exit to tell the client to stop asking other logics * @return True to stop further processing by the engine */ virtual bool handleClientChanUpdate(Message& msg, bool& stopLogic); /** * Default message processor called for id's not defined in client. * Descendants may override it to process custom messages installed by * them and relayed through the client * @param msg Received message * @param id Message id * @param stopLogic Set to true on exit to tell the client to stop asking other logics * @return True to stop further processing by the engine */ virtual bool defaultMsgHandler(Message& msg, int id, bool& stopLogic); /** * Update from UI or from a given value the selected item in channels list. * The selected channel may not be the active one * @param item Optional new value for current selection. Set to 0 to upadte from UI */ virtual void updateSelectedChannel(const String* item = 0); /** * Engine start notification * @param msg The engine.start message */ virtual void engineStart(Message& msg) {} /** * Add a duration object to this client's list * @param duration The object to add * @param autoDelete True to delete the object when the list is cleared * @return True on success */ bool addDurationUpdate(DurationUpdate* duration, bool autoDelete = false); /** * Remove a duration object from list * @param name The name of the object to remove * @param delObj True to destroy the object, false to remove it * @return True on success */ bool removeDurationUpdate(const String& name, bool delObj = false); /** * Remove a duration object from list * @param duration The object to remove * @param delObj True to destroy the object, false to remove it * @return True on success */ bool removeDurationUpdate(DurationUpdate* duration, bool delObj = false); /** * Find a duration update by its name * @param name The name of the object to find * @param ref True to increase its reference counter before returning * @return DurationUpdate pointer or 0 */ DurationUpdate* findDurationUpdate(const String& name, bool ref = true); /** * Remove all duration objects */ void clearDurationUpdate(); /** * Init static logic lists. * Called by the client when start running */ static void initStaticData(); // Account options string list static ObjList s_accOptions; // Parameters that are applied from provider template static const char* s_provParams[]; protected: /** * Method called by the client when idle. * This method is called in the UI's thread * @param time The current time */ virtual void idleTimerTick(Time& time); /** * Enable call actions for a selected channel * @param id Channel id * @return True on success */ virtual bool enableCallActions(const String& id); /** * Fill call start parameter list from UI * @param p The list of parameters to fill * @param wnd Optional window owning the widget triggering the action * @return True on success */ virtual bool fillCallStart(NamedList& p, Window* wnd = 0); /** * Notification on selection changes in channels list. * Enable call actions for currently selected channel * @param old The old selection */ virtual void channelSelectionChanged(const String& old); // The list of protocols supported by the client static ObjList s_protocols; // Mutext used to lock protocol list static Mutex s_protocolsMutex; String m_name; // Logic's name String m_selectedChannel; // The currently selected channel int m_prio; // Logics priority ObjList m_durationUpdate; // Duration updates Mutex m_durationMutex; // Lock duration operations String m_transferInitiated; // Tranfer initiated id bool m_accShowAdvanced; // Show/hide the account advanced options }; /** * This class holds data about an account that can be registered to a server. * It also holds a list of contacts belonging to this account. * The account's id is kept in a lower case URI * @short A client account */ class YATE_API ClientAccount : public RefObject, public Mutex { friend class ClientContact; public: /** * Constructor * @param proto The account's protocol * @param user The account's username * @param host The account's host * @param startup True if the account should login at startup */ ClientAccount(const char* proto, const char* user, const char* host, bool startup); /** * Constructor. Build an account from a list of parameters * @param params The list of parameters used to build this account */ ClientAccount(const NamedList& params); /** * Get this account's URI * @return This account's URI */ inline const URI& uri() const { return m_uri; } /** * Get this account's id * @return This account's id */ inline const URI& id() const { return m_id; } /** * Get this account's contacts. The caller should lock the account while browsing the list * @return This account's contacts list */ inline ObjList& contacts() { return m_contacts; } /** * Get a string representation of this object * @return The account's compare id */ virtual const String& toString() const { return m_id; } /** * Get this account's resource * @return ClientResource pointer or 0 */ ClientResource* resource(bool ref = false); /** * Set/reset this account's resource * @param res The new account's resource */ void setResource(ClientResource* res = 0); /** * Find a contact by its id * @param id The id of the desired contact * @param ref True to obtain a referenced pointer * @return ClientContact pointer or 0 if not found */ virtual ClientContact* findContact(const String& id, bool ref = false); /** * Find a contact having a given id and resource * @param id The id of the desired contact * @param resid The id of the desired resource * @param ref True to obtain a referenced pointer * @return ClientContact pointer or 0 if not found */ virtual ClientContact* findContact(const String& id, const String& resid, bool ref = false); /** * Build a contact and append it to the list * @param id The contact's id * @param name The contact's name * @return ClientContact pointer or 0 if a contact with the given id already exists */ virtual ClientContact* appendContact(const String& id, const char* name); /** * Build a contact and append it to the list * @param params Contact parameters * @return ClientContact pointer or 0 if a contact with the same id already exists */ virtual ClientContact* appendContact(const NamedList& params); /** * Remove a contact from list. Reset contact's owner * @param id The contact's id * @param delObj True to delete the object if found * @return ClientContact pointer if found and not deleted or 0 */ virtual ClientContact* removeContact(const String& id, bool delObj = true); /** * Build a login/logout message from account's data * @param login True to login, false to logout * @param msg Optional message name. Default to 'user.login' * @return A valid Message pointer */ virtual Message* userlogin(bool login, const char* msg = "user.login"); /** * Build an account id * @param dest Destination URI * @param proto The account's protocol * @param user The account's username * @param host The account's host */ static void buildAccountId(URI& dest, const char* proto, const char* user, const char* host) { URI u(proto,user,host); dest = u.toLower(); } String m_password; // Account's password String m_server; // Account's server (name or IP address) int m_port; // Server's port used to connect to String m_options; // Account's options bool m_startup; // Enable/disable flag String m_outbound; // Outbound server (if any) int m_expires; // Registration interval for protocols supporting it bool m_connected; // Logged in/out flag protected: // Remove from owner. Release data virtual void destroyed(); // Method used by the contact to append itself to this account's list virtual void appendContact(ClientContact* contact); // Set ID and URI inline void setIdUri(const char* proto, const char* user, const char* host) { buildAccountId(m_id,proto,user,host); m_uri = String(user) + "@" + host; } URI m_id; // The account's id URI m_uri; // Account's URI ClientResource* m_resource; // Account's resource ObjList m_contacts; // Account's contacts }; /** * This class holds an account list * @short A client account list */ class YATE_API ClientAccountList : public String, public Mutex { public: /** * Constructor * @param name List's name used for debug purposes */ inline ClientAccountList(const char* name) : String(name), Mutex(true) {} /** * Get the accounts list * @return The accounts list */ inline ObjList& accounts() { return m_accounts; } /** * Find an account * @param id The account's id * @param ref True to get a referenced pointer * @return ClientAccount pointer or 0 if not found */ virtual ClientAccount* findAccount(const String& id, bool ref = false); /** * Find an account's contact * @param account The account's id * @param id The contact's id * @param ref True to get a referenced pointer * @return ClientContact pointer or 0 if not found */ virtual ClientContact* findContact(const String& account, const String& id, bool ref = false); /** * Find an account's contact from a built id * @param builtId The string containign the account and the contact * @param ref True to get a referenced pointer * @return ClientContact pointer or 0 if not found */ virtual ClientContact* findContact(const String& builtId, bool ref = false); /** * Append a new account. The account's reference counter is increased before * @param account The account to append * @return True on succes, false if an account with the same id already exists */ virtual bool appendAccount(ClientAccount* account); /** * Remove an account * @param id The account's id */ virtual void removeAccount(const String& id); protected: ObjList m_accounts; }; /** * A client contact * The contact is using the owner's mutex to lock it's operations * @short A client contact */ class YATE_API ClientContact : public RefObject { friend class ClientAccount; public: /** * Constructor. Append itself to the owner's list * @param owner The contact's owner * @param id The contact's id * @param name Optional display name. Defaults to the id's value if 0 * @param chat True to create the chat window */ ClientContact(ClientAccount* owner, const char* id, const char* name = 0, bool chat = false); /** * Constructor. Build a contact from a list of parameters. . Append itself to the owner's list * @param owner The contact's owner * @param params The list of parameters used to build this contact * @param chat True to create the chat window */ ClientContact(ClientAccount* owner, NamedList& params, bool chat); /** * Get this contact's account * @return This contact's account */ inline ClientAccount* account() { return m_owner; } /** * Get this contact's URI * @return This contact's URI */ inline const URI& uri() const { return m_uri; } /** * Get the resource list of this contact * @return The resource list of this contact */ inline ObjList& resources() { return m_resources; } /** * Get the group list of this contact * @return The group list of this contact */ inline ObjList& groups() { return m_groups; } /** * Get a string representation of this object * @return The contact's id */ virtual const String& toString() const { return m_id; } /** * Build a contact id to be used in UI * @param dest Destination string */ inline void buildContactId(String& dest) { buildContactId(dest,m_owner ? m_owner->toString() : String::empty(),m_id); } /** * Check if a window is this contact's chat * @param wnd The window to check * @return True if the given window is this contact's chat */ inline bool isChatWnd(Window* wnd) { return wnd && wnd->toString() == m_chatWndName; } /** * Check if this contact has a chat window * @return True if this contact has a chat window */ inline bool hasChat() { return Client::self() && Client::self()->getWindow(m_chatWndName); } /** * Check if this contact's chat window is visible * @return True if this contact's chat window is visible */ inline bool isChatVisible() { return Client::self() && Client::self()->getVisible(m_chatWndName); } /** * Show or hide this contact's chat window * @param active The chat window's visibility flag * @return True on success */ inline bool showChat(bool active) { return Client::self() ? Client::self()->setVisible(m_chatWndName,active) : false; } /** * Get the chat window * @return Valid Window pointer or 0 */ inline Window* getChatWnd() const { return Client::self() ? Client::self()->getWindow(m_chatWndName) : 0; } /** * Create the chat window * @param force True to destroy the current one if any * @param name The window's name */ void createChatWindow(bool force = false, const char* name = "chat"); /** * Close (desrtoy) the chat window */ inline void destroyChatWindow() { if (m_chatWndName && Client::self()) Client::self()->closeWindow(m_chatWndName,false); } /** * Find a group this contact might belong to * @param group The name of the group to find * @return String pointer or 0 if not found */ virtual String* findGroup(const String& group); /** * Append a group to this contact * @param group Group's name * @return False if the group already exists */ virtual bool appendGroup(const String& group); /** * Remove a contact's group * @param group Group's name * @return False if the group was not found */ virtual bool removeGroup(const String& group); /** * Find a resource having a given id * @param id The id of the desired resource * @param ref True to obtain a referenced pointer * @return ClientResource pointer or 0 if not found */ virtual ClientResource* findResource(const String& id, bool ref = false); /** * Get the first resource with audio capability * @param ref True to obtain a referenced pointer * @return ClientResource pointer or 0 if not found */ virtual ClientResource* findAudioResource(bool ref = false); /** * Append a resource having a given id * @param id The id of the desired resource * @return ClientResource pointer or 0 if a resource with the given name already exists */ virtual ClientResource* appendResource(const String& id); /** * Remove a resource having a given id * @param id The id of the desired resource * @return True if the resource was removed */ virtual bool removeResource(const String& id); /** * Check if a window is a chat one * @param wnd The window to check * @return True if the given window's name starts with the chat refix */ static inline bool isChatWndPrefix(Window* wnd) { return wnd && wnd->toString().startsWith(s_chatPrefix); } /** * Build a contact id to be used in UI * @param dest Destination string * @param account Account owning the contact * @param contact The contact's id */ static inline void buildContactId(String& dest, const String& account, const String& contact) { dest << String(account).toLower() << "|" << String(contact).toLower(); } /** * Split a contact id * @param src Source string * @param account Account name * @param contact Contact's name */ static inline void splitContactId(const String& src, String& account, String& contact) { int pos = src.find('|'); if (pos < 1) { account = src; return; } account = src.substr(0,pos); contact = src.substr(pos + 1); } // Chat window prefix static String s_chatPrefix; String m_name; // Contact's display name String m_subscription; // Presence subscription state protected: // Remove from owner. Destroy the chat window. Release data virtual void destroyed(); ClientAccount* m_owner; // The account owning this contact String m_id; // The contact's id URI m_uri; // The contact's URI ObjList m_resources; // The contact's resource list ObjList m_groups; // The group(s) this contract belongs to private: String m_chatWndName; // Chat window name if any }; /** * This class holds data about a client account/contact resource * @short A client contact's resource */ class YATE_API ClientResource : public RefObject { public: /** * Constructor * @param id The resource's id * @param audio True (default) if the resource has audio capability * @param name Optional display name. Defaults to the id's value if 0 */ inline ClientResource(const char* id, const char* name = 0, bool audio = true) : m_name(name ? name : id), m_audio(audio), m_priority(0), m_id(id) {} /** * Get a string representation of this object * @return The account's id */ virtual const String& toString() const { return m_id; } String m_name; // Account's display name bool m_audio; // Audio capability flag int m_priority; // Resource priority String m_status; // Resource status string protected: String m_id; // The account's id }; /** * Class used to update UI durations. The string keeps the object's id. * This object can be used to keep additional data associated with a client channel * @short An UI time updater */ class YATE_API DurationUpdate : public RefObject { public: /** * Constructor. Add itself to logic's list * @param logic The client logic used to update this duration object * @param owner True if the logic is owning this object * @param id Object id * @param name Object name (widget or column name) * @param start Start time in seconds */ inline DurationUpdate(ClientLogic* logic, bool owner, const char* id, const char* name, unsigned int start = Time::secNow()) : m_id(id), m_logic(0), m_name(name), m_startTime(start) { setLogic(logic,owner); } /** * Destructor */ virtual ~DurationUpdate(); /** * Get a string representation of this object * @return This duration's id */ virtual const String& toString() const; /** * Set the logic used to update this duration object. Remove from the old one * @param logic The client logic used to update this duration object * @param owner True if the logic is owning this object */ void setLogic(ClientLogic* logic = 0, bool owner = true); /** * Update UI if duration is non 0 * @param secNow Current time in seconds * @param table The table to update. Set to 0 to update text widgets * @param wnd Optional window to update * @param skip Optional window to skip if wnd is 0 * @param force Set to true to update even if duration is 0 * @return The duration */ virtual unsigned int update(unsigned int secNow, const String* table = 0, Window* wnd = 0, Window* skip = 0, bool force = false); /** * Build a duration string representation and add the parameter to a list * @param dest Destination list * @param secNow Current time in seconds * @param force Set to true to add the parameter even if duration is 0 * @return The duration */ virtual unsigned int buildTimeParam(NamedList& dest, unsigned int secNow, bool force = false); /** * Build a duration string representation hh:mm:ss. The hours are added only if non 0 * @param dest Destination string * @param secNow Current time in seconds * @param force Set to true to build even if duration is 0 * @return The duration */ virtual unsigned int buildTimeString(String& dest, unsigned int secNow, bool force = false); /** * Build a duration string representation and add the parameter to a list * @param dest Destination list * @param param Parameter to add * @param secStart Starting time in seconds * @param secNow Current time in seconds * @param force Set to true to add the parameter even if duration is 0 * @return The duration */ static unsigned int buildTimeParam(NamedList& dest, const char* param, unsigned int secStart, unsigned int secNow, bool force = false); /** * Build a duration string representation hh:mm:ss. The hours are added only if non 0 * @param dest Destination string * @param secStart Starting time in seconds * @param secNow Current time in seconds * @param force Set to true to build even if duration is 0 * @return The duration */ static unsigned int buildTimeString(String& dest, unsigned int secStart, unsigned int secNow, bool force = false); protected: /** * Release memory. Remove from updater */ virtual void destroyed(); String m_id; // Duration's id ClientLogic* m_logic; // Client logic having this object in its list String m_name; // Widget/column name unsigned int m_startTime; // Start time }; /** * This class holds a sound file along with an output device used to play it * @short A sound file */ class YATE_API ClientSound : public String { public: /** * Constructor * @param name The name of this object * @param file The file to play (should contain the whole path and the file name) * @param device Optional device used to play the file. Set to 0 to use the default one */ inline ClientSound(const char* name, const char* file, const char* device = 0) : String(name), m_file(file), m_device(device), m_repeat(-1), m_started(false) {} /** * Destructor. Stop playing the file */ virtual ~ClientSound() { stop(); } /** * Stop playing. Release memory */ virtual void destruct() { stop(); String::destruct(); } /** * Check if this sound is started * @return True if this sound is started */ inline bool started() const { return m_started; } /** * Get the device used to play this sound * @return The device used to play sound */ inline const String& device() const { return m_device; } /** * Set the device used to play this sound * @param dev The device used to play sound */ inline void device(const char* dev) { Lock lock(s_soundsMutex); m_device = dev; } /** * Get the file played by this sound * @return The file played by this sound */ inline const String& file() const { return m_file; } /** * Set the file played by this sound. * The new file will not be used until the next time the sound is started * @param filename The new file played by this sound */ inline void file(const char* filename) { Lock lock(s_soundsMutex); m_file = filename; } /** * Start playing the file * @param repeat The number of times to play the file if positive, * play until explicitely stopped otherwise * @param force True to start playing the file even if already started * @return True on success */ bool start(int repeat = -1, bool force = true); /** * Stop playing the file */ void stop(); /** * Check if a sound is started * @param name The name of the sound to check * @return True if the given sound is started */ static bool started(const String& name); /** * Start playing a given sound * @param name The name of the sound to play * @param repeat The number of times to play the file if positive, * play until explicitely stopped otherwise * @param force True to start playing the file even if already started * @return True on success */ static bool start(const String& name, int repeat = -1, bool force = true); /** * Stop playing a given sound * @param name The name of the sound to stop */ static void stop(const String& name); /** * Find a sound object * @param token The token used to match the sound * @param byName True to match the sound's name, false to match its file * @return True on success */ static ClientSound* find(const String& token, bool byName = true); /** * The list of sounds */ static ObjList s_sounds; /** * Mutex used to lock the sounds list operations */ static Mutex s_soundsMutex; protected: virtual bool doStart() { return false; } virtual void doStop() {} String m_file; String m_device; int m_repeat; bool m_started; }; }; // namespace TelEngine #endif /* __YATECBASE_H */ /* vi: set ts=8 sw=4 sts=4 noet: */