From: daleharvey Date: Fri, 23 Jun 2006 13:15:16 +0000 (+0000) Subject: manually merging the INKBOARD_PEDRO branch into trunk X-Git-Url: https://git.tokkee.org/?a=commitdiff_plain;h=535b1596de71acb960a629b0f34f0d2171a34348;p=inkscape.git manually merging the INKBOARD_PEDRO branch into trunk --- diff --git a/configure.ac b/configure.ac index 8ababdbbb..e83e54676 100644 --- a/configure.ac +++ b/configure.ac @@ -464,29 +464,33 @@ dnl Inkboard dependency checking dnl ****************************** with_inkboard="no" +with_inkboard_ssl="no" -AC_MSG_CHECKING(for loudmouth-1.0+) +INKBOARD_CFLAGS="" AC_ARG_ENABLE(inkboard, AS_HELP_STRING([--enable-inkboard], [enable Inkboard online whiteboard facility (disabled by default)]), with_inkboard=$enableval,with_inkboard=no) if test "x$with_inkboard" = "xyes"; then - PKG_CHECK_MODULES(LIBLOUDMOUTH, loudmouth-1.0, loudmouth_ok=yes, loudmouth_ok=no) - if test "x$loudmouth_ok" = "xyes"; then with_inkboard="yes" AC_DEFINE(WITH_INKBOARD,1,[Build in Inkboard support]) - else - with_inkboard="no" - fi + + dnl Test for OpenSSL + PKG_CHECK_MODULES(INKBOARD, openssl, with_inkboard_ssl=yes, with_inkboard_ssl=no) + if test "x$with_inkboard_ssl" = "xyes"; then + dnl OpenSSL found; enable SSL support in Pedro + INKBOARD_CFLAGS="$INKBOARD_CFLAGS -DHAVE_SSL" + AC_DEFINE(WITH_INKBOARD_SSL,1,[Build in SSL support for Inkboard]) + fi else with_inkboard="no" fi AC_MSG_RESULT($with_inkboard) AM_CONDITIONAL(WITH_INKBOARD, test "x$with_inkboard" = "xyes") -AC_SUBST(LIBLOUDMOUTH_CFLAGS) -AC_SUBST(LIBLOUDMOUTH_LIBS) +AC_SUBST(INKBOARD_LIBS) +AC_SUBST(INKBOARD_CFLAGS) dnl ****************************** dnl Unconditional dependencies @@ -801,6 +805,7 @@ src/libnr/makefile src/libnrtype/makefile src/libavoid/makefile src/livarot/makefile +src/pedro/makefile src/jabber_whiteboard/makefile src/removeoverlap/makefile src/svg/makefile @@ -862,4 +867,5 @@ Configuration: Use relocation support: ${enable_binreloc} Enable LittleCms: ${enable_lcms} Enable Inkboard: ${with_inkboard} + Enable SSL in Inkboard: ${with_inkboard_ssl} " diff --git a/mkinstalldirs b/mkinstalldirs index d2d5f21b6..259dbfcd3 100755 --- a/mkinstalldirs +++ b/mkinstalldirs @@ -1,21 +1,33 @@ #! /bin/sh # mkinstalldirs --- make directory hierarchy -# Author: Noah Friedman + +scriptversion=2005-06-29.22 + +# Original author: Noah Friedman # Created: 1993-05-16 -# Public domain +# Public domain. +# +# This file is maintained in Automake, please report +# bugs to or send patches to +# . errstatus=0 -dirmode="" +dirmode= usage="\ -Usage: mkinstalldirs [-h] [--help] [-m mode] dir ..." +Usage: mkinstalldirs [-h] [--help] [--version] [-m MODE] DIR ... + +Create each directory DIR (with mode MODE, if specified), including all +leading file name components. + +Report bugs to ." # process command line arguments while test $# -gt 0 ; do case $1 in -h | --help | --h*) # -h for help - echo "$usage" 1>&2 - exit 0 + echo "$usage" + exit $? ;; -m) # -m PERM arg shift @@ -23,6 +35,10 @@ while test $# -gt 0 ; do dirmode=$1 shift ;; + --version) + echo "$0 $scriptversion" + exit $? + ;; --) # stop option processing shift break @@ -50,30 +66,58 @@ case $# in 0) exit 0 ;; esac +# Solaris 8's mkdir -p isn't thread-safe. If you mkdir -p a/b and +# mkdir -p a/c at the same time, both will detect that a is missing, +# one will create a, then the other will try to create a and die with +# a "File exists" error. This is a problem when calling mkinstalldirs +# from a parallel make. We use --version in the probe to restrict +# ourselves to GNU mkdir, which is thread-safe. case $dirmode in '') - if mkdir -p -- . 2>/dev/null; then + if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then echo "mkdir -p -- $*" exec mkdir -p -- "$@" + else + # On NextStep and OpenStep, the `mkdir' command does not + # recognize any option. It will interpret all options as + # directories to create, and then abort because `.' already + # exists. + test -d ./-p && rmdir ./-p + test -d ./--version && rmdir ./--version fi ;; *) - if mkdir -m "$dirmode" -p -- . 2>/dev/null; then + if mkdir -m "$dirmode" -p --version . >/dev/null 2>&1 && + test ! -d ./--version; then echo "mkdir -m $dirmode -p -- $*" exec mkdir -m "$dirmode" -p -- "$@" + else + # Clean up after NextStep and OpenStep mkdir. + for d in ./-m ./-p ./--version "./$dirmode"; + do + test -d $d && rmdir $d + done fi ;; esac for file do - set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` + case $file in + /*) pathcomp=/ ;; + *) pathcomp= ;; + esac + oIFS=$IFS + IFS=/ + set fnord $file shift + IFS=$oIFS - pathcomp= for d do - pathcomp="$pathcomp$d" + test "x$d" = x && continue + + pathcomp=$pathcomp$d case $pathcomp in -*) pathcomp=./$pathcomp ;; esac @@ -84,21 +128,21 @@ do mkdir "$pathcomp" || lasterr=$? if test ! -d "$pathcomp"; then - errstatus=$lasterr + errstatus=$lasterr else - if test ! -z "$dirmode"; then + if test ! -z "$dirmode"; then echo "chmod $dirmode $pathcomp" - lasterr="" - chmod "$dirmode" "$pathcomp" || lasterr=$? + lasterr= + chmod "$dirmode" "$pathcomp" || lasterr=$? - if test ! -z "$lasterr"; then - errstatus=$lasterr - fi - fi + if test ! -z "$lasterr"; then + errstatus=$lasterr + fi + fi fi fi - pathcomp="$pathcomp/" + pathcomp=$pathcomp/ done done @@ -107,5 +151,8 @@ exit $errstatus # Local Variables: # mode: shell-script # sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" # End: -# mkinstalldirs ends here diff --git a/pedro.ini b/pedro.ini new file mode 100644 index 000000000..ce832b49e --- /dev/null +++ b/pedro.ini @@ -0,0 +1,15 @@ + + + inkscape + conference.gristle.org + + + + + Dale + gristle.org + 5222 + Dale + hail99 + + diff --git a/src/Makefile.am b/src/Makefile.am index 9b284e27d..090b4c683 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -18,7 +18,7 @@ INCLUDES = \ $(FREETYPE_CFLAGS) \ $(GNOME_PRINT_CFLAGS) \ $(GNOME_VFS_CFLAGS) \ - $(LIBLOUDMOUTH_CFLAGS) \ + $(INKBOARD_CFLAGS) \ $(XFT_CFLAGS) \ -DPOTRACE=\"potrace\" \ $(INKSCAPE_CFLAGS) \ @@ -36,6 +36,7 @@ include extension/script/Makefile_insert include helper/Makefile_insert include inkjar/Makefile_insert include io/Makefile_insert +include pedro/Makefile_insert include jabber_whiteboard/Makefile_insert include libcroco/Makefile_insert include libnr/Makefile_insert @@ -64,6 +65,7 @@ noinst_LIBRARIES = \ libinkpre.a \ application/libinkapp.a \ dialogs/libspdialogs.a \ + pedro/libpedro.a \ jabber_whiteboard/libjabber_whiteboard.a \ display/libspdisplay.a \ dom/libdom.a \ @@ -126,6 +128,7 @@ EXTRA_DIST = \ io/makefile.in \ io/crystalegg.xml \ io/doc2html.xsl \ + pedro/makefile.in \ jabber_whiteboard/makefile.in \ libcroco/makefile.in \ libnr/makefile.in \ diff --git a/src/Makefile_insert b/src/Makefile_insert index f6c591d83..c3182f3cc 100644 --- a/src/Makefile_insert +++ b/src/Makefile_insert @@ -262,6 +262,7 @@ inkscape_private_libs = \ ui/dialog/libuidialog.a \ dialogs/libspdialogs.a \ jabber_whiteboard/libjabber_whiteboard.a \ + pedro/libpedro.a \ trace/libtrace.a \ svg/libspsvg.a \ widgets/libspwidgets.a \ @@ -300,7 +301,8 @@ all_libs = \ $(win32ldflags) \ $(PERL_LIBS) \ $(PYTHON_LIBS) \ - $(LIBLOUDMOUTH_LIBS) + $(LIBLOUDMOUTH_LIBS) \ + $(INKBOARD_LIBS) desktop.$(OBJEXT): helper/sp-marshal.h document.$(OBJEXT): helper/sp-marshal.h inkscape_version.h diff --git a/src/desktop.cpp b/src/desktop.cpp index 7d9904342..49a43bc37 100644 --- a/src/desktop.cpp +++ b/src/desktop.cpp @@ -77,10 +77,6 @@ #include "message-context.h" #include "layer-manager.h" -#ifdef WITH_INKBOARD -#include "jabber_whiteboard/session-manager.h" -#endif - namespace Inkscape { namespace XML { class Node; }} // Callback declarations @@ -245,14 +241,6 @@ SPDesktop::init (SPNamedView *nv, SPCanvas *aCanvas) /* Ugly hack */ _namedview_modified (namedview, SP_OBJECT_MODIFIED_FLAG, this); - /* Construct SessionManager - * - * SessionManager construction needs to be done after document connection - */ -#ifdef WITH_INKBOARD - _whiteboard_session_manager = new Inkscape::Whiteboard::SessionManager(this); -#endif - /* Set up notification of rebuilding the document, this allows for saving object related settings in the document. */ _reconstruction_start_connection = @@ -325,12 +313,6 @@ void SPDesktop::destroy() drawing = NULL; } -#ifdef WITH_INKBOARD - if (_whiteboard_session_manager) { - delete _whiteboard_session_manager; - } -#endif - delete _guides_message_context; _guides_message_context = NULL; diff --git a/src/document.cpp b/src/document.cpp index e42f6c8cb..cf03f4188 100644 --- a/src/document.cpp +++ b/src/document.cpp @@ -207,7 +207,7 @@ void SPDocument::reset_key (void *dummy) actionkey = NULL; } -static SPDocument * +SPDocument * sp_document_create(Inkscape::XML::Document *rdoc, gchar const *uri, gchar const *base, diff --git a/src/document.h b/src/document.h index 4d293e981..9739b6971 100644 --- a/src/document.h +++ b/src/document.h @@ -135,6 +135,9 @@ SPDocument *sp_document_new_dummy(); SPDocument *sp_document_ref (SPDocument *doc); SPDocument *sp_document_unref (SPDocument *doc); + +SPDocument *sp_document_create(Inkscape::XML::Document *rdoc, gchar const *uri, gchar const *base, gchar const *name, unsigned int keepalive); + /* * Access methods */ diff --git a/src/file.cpp b/src/file.cpp index 5c236da82..679c28801 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -204,9 +204,6 @@ sp_file_open(gchar const *uri, Inkscape::Extension::Extension *key, bool add_to_ // resize the window to match the document properties // (this may be redundant for new windows... if so, move to the "virgin" // section above) -#ifdef WITH_INKBOARD - desktop->whiteboard_session_manager()->setDesktop(desktop); -#endif sp_namedview_window_from_document(desktop); if (add_to_recent) { diff --git a/src/jabber_whiteboard/Makefile_insert b/src/jabber_whiteboard/Makefile_insert index 2603f9c67..c510b34a0 100644 --- a/src/jabber_whiteboard/Makefile_insert +++ b/src/jabber_whiteboard/Makefile_insert @@ -9,59 +9,34 @@ jabber_whiteboard/clean: rm -f jabber_whiteboard/libjabber_whiteboard.a $(jabber_whiteboard_libjabber_whiteboard_a_OBJECTS) jabber_whiteboard_SOURCES = \ - jabber_whiteboard/buddy-list-manager.cpp \ - jabber_whiteboard/buddy-list-manager.h \ - jabber_whiteboard/callbacks.cpp \ - jabber_whiteboard/callbacks.h \ - jabber_whiteboard/chat-handler.cpp \ - jabber_whiteboard/chat-handler.h \ - jabber_whiteboard/connection-establishment.cpp \ jabber_whiteboard/defines.h \ - jabber_whiteboard/deserializer.cpp \ - jabber_whiteboard/deserializer.h \ - jabber_whiteboard/error-codes.h \ + jabber_whiteboard/empty.cpp \ + jabber_whiteboard/keynode.cpp \ + jabber_whiteboard/keynode.h \ jabber_whiteboard/internal-constants.cpp \ jabber_whiteboard/internal-constants.h \ - jabber_whiteboard/invitation-confirm-dialog.cpp \ - jabber_whiteboard/invitation-confirm-dialog.h \ - jabber_whiteboard/jabber-handlers.cpp \ - jabber_whiteboard/jabber-handlers.h \ jabber_whiteboard/message-aggregator.cpp \ jabber_whiteboard/message-aggregator.h \ - jabber_whiteboard/message-contexts.cpp \ - jabber_whiteboard/message-contexts.h \ - jabber_whiteboard/message-handler.cpp \ - jabber_whiteboard/message-handler.h \ jabber_whiteboard/message-node.h \ - jabber_whiteboard/message-processors.cpp \ - jabber_whiteboard/message-processors.h \ jabber_whiteboard/message-queue.cpp \ jabber_whiteboard/message-queue.h \ jabber_whiteboard/message-tags.cpp \ jabber_whiteboard/message-tags.h \ jabber_whiteboard/message-utilities.cpp \ jabber_whiteboard/message-utilities.h \ - jabber_whiteboard/node-tracker.cpp \ - jabber_whiteboard/node-tracker-event-tracker.cpp \ - jabber_whiteboard/node-tracker-event-tracker.h \ - jabber_whiteboard/node-tracker.h \ - jabber_whiteboard/node-tracker-observer.h \ - jabber_whiteboard/node-utilities.cpp \ - jabber_whiteboard/node-utilities.h \ - jabber_whiteboard/serializer.cpp \ - jabber_whiteboard/serializer.h \ - jabber_whiteboard/session-file.cpp \ - jabber_whiteboard/session-file.h \ - jabber_whiteboard/session-file-player.cpp \ - jabber_whiteboard/session-file-player.h \ + jabber_whiteboard/new-inkboard-document.cpp \ + jabber_whiteboard/new-inkboard-document.h \ + jabber_whiteboard/inkboard-document.cpp \ + jabber_whiteboard/inkboard-document.h \ + jabber_whiteboard/invitation-confirm-dialog.cpp \ + jabber_whiteboard/invitation-confirm-dialog.h \ + jabber_whiteboard/invitation-handlers.cpp \ jabber_whiteboard/session-file-selector.cpp \ jabber_whiteboard/session-file-selector.h \ jabber_whiteboard/session-manager.cpp \ jabber_whiteboard/session-manager.h \ jabber_whiteboard/tracker-node.h \ - jabber_whiteboard/typedefs.h \ - jabber_whiteboard/undo-stack-observer.cpp \ - jabber_whiteboard/undo-stack-observer.h + jabber_whiteboard/typedefs.h if WITH_INKBOARD diff --git a/src/jabber_whiteboard/buddy-list-manager.cpp b/src/jabber_whiteboard/buddy-list-manager.cpp deleted file mode 100644 index 4cce2308c..000000000 --- a/src/jabber_whiteboard/buddy-list-manager.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/** - * Whiteboard session manager - * Buddy list management facility - * - * Authors: - * David Yip - * - * Copyright (c) 2005 Authors - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - - -#include -#include - -#include "jabber_whiteboard/typedefs.h" -#include "jabber_whiteboard/buddy-list-manager.h" - -namespace Inkscape { - -namespace Whiteboard { - -BuddyListManager::BuddyListManager() { } -BuddyListManager::~BuddyListManager() { } - -void -BuddyListManager::addInsertListener(BuddyListListener listener) -{ - this->_sig_insert.connect(listener); -} - -void -BuddyListManager::addEraseListener(BuddyListListener listener) -{ - this->_sig_erase.connect(listener); -} - -void -BuddyListManager::insert(std::string& jid) -{ - this->_bl.insert(jid); - this->_sig_insert.emit(jid); -} - -void -BuddyListManager::erase(std::string& jid) -{ - this->_bl.erase(jid); - this->_sig_erase.emit(jid); -} - -BuddyList::iterator -BuddyListManager::begin() -{ - return this->_bl.begin(); -} - -BuddyList::iterator -BuddyListManager::end() -{ - return this->_bl.end(); -} - -BuddyList& -BuddyListManager::getList() -{ - return this->_bl; -} - -} - -} - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/jabber_whiteboard/buddy-list-manager.h b/src/jabber_whiteboard/buddy-list-manager.h deleted file mode 100644 index fcd0bb688..000000000 --- a/src/jabber_whiteboard/buddy-list-manager.h +++ /dev/null @@ -1,59 +0,0 @@ -/** - * Whiteboard session manager - * Buddy list management facility - * - * Authors: - * David Yip - * - * Copyright (c) 2005 Authors - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#ifndef __WHITEBOARD_BUDDYLIST_MANAGER_H__ -#define __WHITEBOARD_BUDDYLIST_MANAGER_H__ - -#include -#include -#include "jabber_whiteboard/typedefs.h" - -namespace Inkscape { - -namespace Whiteboard { - -class BuddyListManager { -public: - BuddyListManager(); - ~BuddyListManager(); - void insert(std::string& jid); - void erase(std::string& jid); - BuddyList::iterator begin(); - BuddyList::iterator end(); - - void addInsertListener(BuddyListListener listener); - void addEraseListener(BuddyListListener listener); - - BuddyList& getList(); -private: - BuddyList _bl; - BuddyListSignal _sig_insert; - BuddyListSignal _sig_erase; - -}; - -} - -} - -#endif - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/jabber_whiteboard/callbacks.cpp b/src/jabber_whiteboard/callbacks.cpp deleted file mode 100644 index 31f536616..000000000 --- a/src/jabber_whiteboard/callbacks.cpp +++ /dev/null @@ -1,206 +0,0 @@ -/** - * Whiteboard session manager - * Message dispatch devices and timeout triggers - * - * Authors: - * David Yip - * - * Copyright (c) 2005 Authors - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -extern "C" { -#include -} - -#include - -#include "message-stack.h" -#include "document.h" -#include "desktop-handles.h" - -#include "jabber_whiteboard/undo-stack-observer.h" -#include "jabber_whiteboard/jabber-handlers.h" -#include "jabber_whiteboard/defines.h" -#include "jabber_whiteboard/typedefs.h" -#include "jabber_whiteboard/session-manager.h" -#include "jabber_whiteboard/message-queue.h" -#include "jabber_whiteboard/message-handler.h" -#include "jabber_whiteboard/message-node.h" -#include "jabber_whiteboard/callbacks.h" - -namespace Inkscape { - -namespace Whiteboard { - -Callbacks::Callbacks(SessionManager* sm) : _sm(sm) -{ - this->_sd = this->_sm->session_data; -} - -Callbacks::~Callbacks() -{ -} - -bool -Callbacks::dispatchSendQueue() -{ - // If we're not in a whiteboard session, don't dispatch anything - if (!(this->_sd->status[IN_WHITEBOARD])) { - return false; - } - - // If the connection is not open, inform the user that an error has occurred - // and stop the queue - LmConnectionState state = lm_connection_get_state(this->_sd->connection); - - if (state != LM_CONNECTION_STATE_OPEN && state != LM_CONNECTION_STATE_AUTHENTICATED) { - sp_desktop_message_stack(this->_sm->desktop())->flash(Inkscape::INFORMATION_MESSAGE, _("Jabber connection lost.")); - return false; - } - - // If there's nothing to send, don't do anything - if (this->_sd->send_queue->empty()) { - return true; - } - - // otherwise, send out the first change - MessageNode* first = this->_sd->send_queue->first(); - - sp_desktop_message_stack(this->_sm->desktop())->flashF(Inkscape::NORMAL_MESSAGE, - ngettext("Sending message; %u message remaining in send queue.", - "Sending message; %u messages remaining in send queue.", - this->_sd->send_queue->size()), - this->_sd->send_queue->size()); - - if (this->_sd->send_queue->empty()) { - sp_desktop_message_stack(this->_sm->desktop())->flash(Inkscape::NORMAL_MESSAGE, _("Receive queue empty.")); - } - - switch (first->type()) { - case CHANGE_REPEATABLE: - case CHANGE_NOT_REPEATABLE: - case CHANGE_COMMIT: - case DOCUMENT_BEGIN: - case DOCUMENT_END: - this->_sm->sendMessage(first->type(), first->sequence(), first->message(), first->recipient().c_str(), first->chatroom()); - break; - default: - g_warning("MessageNode with unknown change type found in send queue; discarding message. This may lead to desynchronization!"); - break; - } - - this->_sd->send_queue->popFront(); - - return true; -} - -bool -Callbacks::dispatchReceiveQueue() -{ - CommitsQueue& rcq = this->_sd->recipients_committed_queue; - // See if we have any commits submitted. - if (!rcq.empty()) { - // Pick the first one off the queue. - ReceivedCommitEvent& committer = rcq.front(); - - // Find the commit event sender's receive queue. - ReceiveMessageQueue* rmq = this->_sd->receive_queues[committer]; - - if (rmq != NULL) { - if (!rmq->empty()) { - // Get the first message off the sender's receive queue. - MessageNode* msg = rmq->first(); - - // There are a few message change types that demand special processing; - // handle them here. - // - // TODO: clean this up. This should be a simple dispatching routine, - // and should not be performing operations like it's doing right now. - // These really should go into connection-establishment.cpp - // (although that should only happen after SessionManager itself - // is cleaned up). - switch(msg->type()) { - case CHANGE_COMMIT: - rcq.pop_front(); - break; - case DOCUMENT_BEGIN: - if (this->_sm->session_data->status[WAITING_TO_SYNC_TO_CHAT]) { - this->_sm->session_data->status.set(WAITING_TO_SYNC_TO_CHAT, 0); - this->_sm->session_data->status.set(SYNCHRONIZING_WITH_CHAT, 1); - } - break; - case DOCUMENT_END: - rcq.pop_front(); - if (this->_sm->session_data->status[SYNCHRONIZING_WITH_CHAT]) { - this->_sm->sendMessage(CONNECTED_SIGNAL, 0, "", this->_sm->session_data->recipient, true); - this->_sm->session_data->status.set(SYNCHRONIZING_WITH_CHAT, 0); - this->_sm->session_data->status.set(IN_CHATROOM, 1); - } else { - this->_sm->sendMessage(CONNECTED_SIGNAL, 0, "", msg->sender().c_str(), false); - } - break; - case CHANGE_REPEATABLE: - case CHANGE_NOT_REPEATABLE: - default: - break; - } - - - // Pass the message to the received change handler. - this->_sm->receiveChange(msg->message()); - sp_desktop_message_stack(this->_sm->desktop())->flashF(Inkscape::NORMAL_MESSAGE, - ngettext("Receiving change; %u change left to process.", - "Receiving change; %u changes left to process.", - rmq->size()), - rmq->size()); - - - // Register this message as the latest message received from this - // sender. - rmq->setLatestProcessedPacket(msg->sequence()); - - // Pop this message off the receive queue. - rmq->popFront(); - return true; - } else { - // This really shouldn't happen. - // If we have a commit request from a valid sender, there should - // be something in the receive queue to process. However, - // if a client is buggy or has managed to trick us into accepting - // a commit, we should handle the event gracefully. - g_warning("Processing commit, but no changes to commit were found; ignoring commit event."); - - // Remove this sender from the commit list. If they want to commit - // later, they can. - rcq.pop_front(); - return true; - } - } else { - // If the receive queue returned is NULL, then we don't know about - // this sender. Remove the sender from the commit list. - g_warning("Attempting to process commit from unknown sender; ignoring."); - rcq.pop_front(); - return true; - } - } else { - return true; - } -} - -} - -} - - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/jabber_whiteboard/callbacks.h b/src/jabber_whiteboard/callbacks.h deleted file mode 100644 index 7a41a4010..000000000 --- a/src/jabber_whiteboard/callbacks.h +++ /dev/null @@ -1,79 +0,0 @@ -/** - * Whiteboard session manager - * Message dispatch devices and timeout triggers - * - * Authors: - * David Yip - * - * Copyright (c) 2005 Authors - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#ifndef __WHITEBOARD_CALLBACKS_H__ -#define __WHITEBOARD_CALLBACKS_H__ - -#include - -namespace Inkscape { - -namespace Whiteboard { - -class SessionManager; -class SessionData; - -/** - * Callback methods used in timers to dispatch MessageNodes from message queues. - */ -class Callbacks { -public: - /** - * Constructor. - * - * \param sm The SessionManager to associate with. - */ - Callbacks(SessionManager* sm); - ~Callbacks(); - - /** - * Dispatch a message from the send queue to the associated SessionManager object. - * - * The SessionManager object handles the task of actually sending out a Jabber message. - * - * \see Inkscape::Whiteboard::SessionManager::sendMessage - * \return Whether or not this callback should be called again by the timer routine. - */ - bool dispatchSendQueue(); - - /** - * Dispatch a message from the receive queue to the associated SessionManager object. - * - * The SessionManager object handles the task of actually processing a Jabber message. - * - * \see Inkscape::Whiteboard::SessionManager::receiveChange - * \return Whether or not this callback should be called again by the timer routine. - */ - bool dispatchReceiveQueue(); - -private: - SessionManager* _sm; - SessionData* _sd; -}; - - -} - -} - -#endif - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/jabber_whiteboard/chat-handler.cpp b/src/jabber_whiteboard/chat-handler.cpp deleted file mode 100644 index 0ba733a0c..000000000 --- a/src/jabber_whiteboard/chat-handler.cpp +++ /dev/null @@ -1,253 +0,0 @@ -/** - * Whiteboard session manager - * Chatroom message handler - * - * Authors: - * David Yip - * - * Copyright (c) 2005 Authors - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#include - -//#include - -#include "message-stack.h" -#include "desktop-handles.h" -#include "document.h" - -#include "util/ucompose.hpp" - -#include "xml/node.h" - -#include "jabber_whiteboard/typedefs.h" -#include "jabber_whiteboard/message-utilities.h" -#include "jabber_whiteboard/message-queue.h" -#include "jabber_whiteboard/jabber-handlers.h" -#include "jabber_whiteboard/defines.h" -#include "jabber_whiteboard/session-manager.h" -#include "jabber_whiteboard/node-tracker.h" -#include "jabber_whiteboard/chat-handler.h" -#include "jabber_whiteboard/error-codes.h" - - -namespace Inkscape { - -namespace Whiteboard { - -ChatMessageHandler::ChatMessageHandler(SessionManager* sm) : _sm(sm) -{ - -} - -ChatMessageHandler::~ChatMessageHandler() -{ - -} - -LmHandlerResult -ChatMessageHandler::parse(LmMessage* message) -{ - // Retrieve the message type - LmMessageType mtype = lm_message_get_type(message); - - // Retrieve root node of message - LmMessageNode* root = lm_message_get_node(message); - if (root == NULL) { - g_warning("Received a chat message with NULL root node; discarding."); - return LM_HANDLER_RESULT_REMOVE_MESSAGE; - } - - LmMessageSubType msubtype; - - - msubtype = lm_message_get_sub_type(message); - - switch (mtype) { - case LM_MESSAGE_TYPE_MESSAGE: - switch(msubtype) { - case LM_MESSAGE_SUB_TYPE_ERROR: - { - LmMessageNode* error = lm_message_node_get_child(root, "error"); - if (error != NULL) { - this->_handleError(lm_message_node_get_attribute(error, "code")); - } - break; - } - case LM_MESSAGE_SUB_TYPE_GROUPCHAT: - { - // FIXME: We should be checking to see if we're in a room in the presence stanzas as indicated in - // but current versions of mu-conference - // don't broadcast presence in the correct order. - // - // Therefore we need to use some sort of hacked-up method to make this work. We listen for - // the sentinel value in a groupchat message -- currently it is '[username] INKBOARD-JOINED' -- - // and begin processing that way. - - //LmMessageNode* body = lm_message_node_get_child(root, "body"); - //if (body != NULL) { - //gchar const* val = lm_message_node_get_value(body); - //g_warning("hey - %s",val); - //if (strcmp(val, String::ucompose("%1 entered the room.", this->_sm->session_data->chat_handle).c_str()) == 0) { - // return this->_finishConnection(); break; - //} else { - return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS; - break; - //} - //} else { - return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS; - break; - //} - } - - default: - return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS; - break; - } - break; - case LM_MESSAGE_TYPE_PRESENCE: - // Retrieve the subtype. - switch (msubtype) { - case LM_MESSAGE_SUB_TYPE_ERROR: - { - g_warning("Could not connect to chatroom"); - // Extract error type - LmMessageNode* error = lm_message_node_get_child(root, "error"); - if (error != NULL) { - this->_handleError(lm_message_node_get_attribute(error, "code")); - } - // Reset status bits - this->_sm->session_data->status.set(CONNECTING_TO_CHAT, 0); - this->_sm->session_data->recipient = ""; - this->_sm->session_data->chat_handle = ""; - - return LM_HANDLER_RESULT_REMOVE_MESSAGE; - break; - } - - case LM_MESSAGE_SUB_TYPE_AVAILABLE: - { - // Extract the handle - // (see JEP-0045, section 6.3.3 - ) - Glib::ustring sender = lm_message_node_get_attribute(root, MESSAGE_FROM); - Glib::ustring chatter = sender.substr(sender.find_last_of('/') + 1, sender.length()); - if (chatter != this->_sm->session_data->chat_handle) { - this->_sm->session_data->chatters.insert(g_strdup(chatter.data())); - // Make a receive queue for this chatter - this->_sm->session_data->receive_queues[sender.raw()] = new ReceiveMessageQueue(this->_sm); - - } else { - return this->_finishConnection(); break; - //g_warning("hmm, who is chatting %s",chatter); - // If the presence message is from ourselves, then we know that we - // have successfully entered the chatroom _and_ have received the entire room roster, - // and can therefore decide whether we need to synchronize with the rest of the room. - // (see JEP-0045, section 6.3.3 - ) - } - return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS; - } - - case LM_MESSAGE_SUB_TYPE_UNAVAILABLE: - { - Glib::ustring sender = lm_message_node_get_attribute(root, MESSAGE_FROM); - Glib::ustring chatter = sender.substr(sender.find_last_of('/') + 1, sender.length()); - this->_sm->session_data->chatters.erase(chatter.data()); - - // Delete the message queue used by this sender - this->_sm->session_data->receive_queues.erase(sender.raw()); - - sp_desktop_message_stack(this->_sm->desktop())->flashF(Inkscape::INFORMATION_MESSAGE, _("%s has left the chatroom."), sender.c_str()); - } - - default: - // no idea what this message is; discard it - return LM_HANDLER_RESULT_REMOVE_MESSAGE; - break; - } - break; - default: - break; - } - - return LM_HANDLER_RESULT_REMOVE_MESSAGE; -} - -LmHandlerResult -ChatMessageHandler::_finishConnection() -{ - if (this->_sm->session_data->status[CONNECTING_TO_CHAT]) { - this->_sm->session_data->status.set(CONNECTING_TO_CHAT, 0); - - if (this->_sm->session_data->chatters.empty()) { - // We are the only one in the chatroom, so there is no - // need for synchronization - this->_sm->session_data->status.set(IN_CHATROOM, 1); - - // Populate node tracker - KeyToNodeMap newids; - NodeToKeyMap newnodes; - NewChildObjectMessageList newchildren; - - XML::Node* root = this->_sm->document()->rroot; - - this->_sm->setupInkscapeInterface(); - this->_sm->setupCommitListener(); - - for ( Inkscape::XML::Node *child = root->firstChild() ; child != NULL ; child = child->next() ) { - MessageUtilities::newObjectMessage(NULL, newids, newnodes, newchildren, this->_sm->node_tracker(), child, true); - } - - this->_sm->node_tracker()->put(newids, newnodes); - // this->_sm->node_tracker()->dump(); - - } else { - this->_sm->session_data->status.set(WAITING_TO_SYNC_TO_CHAT, 1); - // Send synchronization request to chatroom - this->_sm->sendMessage(CHATROOM_SYNCHRONIZE_REQUEST, 0, "", this->_sm->session_data->recipient, true); - } - } - return LM_HANDLER_RESULT_REMOVE_MESSAGE; -} - -void -ChatMessageHandler::_handleError(char const* errcode) -{ -// try { - unsigned int code = atoi(errcode); - -// unsigned int code = boost::lexical_cast< unsigned int >(errcode); - - Glib::ustring buf; - switch (code) { - case ErrorCodes::CHAT_HANDLE_IN_USE: - buf = String::ucompose(_("Nickname %1 is already in use. Please choose a different nickname."), this->_sm->session_data->chat_handle); - this->_sm->connectionError(buf); - break; - case ErrorCodes::SERVER_CONNECT_FAILED: - buf = _("An error was encountered while attempting to connect to the server."); - this->_sm->connectionError(buf); - break; - default: - break; - } -// } catch (boost::bad_lexical_cast&) { - -// } -} - -} - -} - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/jabber_whiteboard/chat-handler.h b/src/jabber_whiteboard/chat-handler.h deleted file mode 100644 index f87c8142d..000000000 --- a/src/jabber_whiteboard/chat-handler.h +++ /dev/null @@ -1,63 +0,0 @@ -/** - * Whiteboard session manager - * Chatroom message handler - * - * Authors: - * David Yip - * - * Copyright (c) 2005 Authors - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#ifndef __WHITEBOARD_CHAT_HANDLER_H__ -#define __WHITEBOARD_CHAT_HANDLER_H__ - -extern "C" { -#include -} - -namespace Inkscape { - -namespace Whiteboard { - -class SessionManager; - - -// TODO: find some way to better integrate this with the rest of the message -// handling framework (i.e. message-processors.cpp, message-handler.cpp, -// message-contexts.cpp) -class ChatMessageHandler { -public: - ChatMessageHandler(SessionManager* sm); - ~ChatMessageHandler(); - - LmHandlerResult parse(LmMessage* message); - -private: - LmHandlerResult _finishConnection(); - void _handleError(char const* errcode); - - SessionManager* _sm; - - // noncopyable, nonassignable - ChatMessageHandler(ChatMessageHandler&); - void operator=(ChatMessageHandler&); -}; - -} - -} - -#endif - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/jabber_whiteboard/connection-establishment.cpp b/src/jabber_whiteboard/connection-establishment.cpp deleted file mode 100644 index d33d6d6b2..000000000 --- a/src/jabber_whiteboard/connection-establishment.cpp +++ /dev/null @@ -1,353 +0,0 @@ -/** - * Whiteboard session manager - * Methods for establishing connections and notifying the user of events - * - * Authors: - * David Yip - * - * Copyright (c) 2005 Authors - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#include "util/ucompose.hpp" -#include -#include -#include - -#include "desktop.h" -#include "file.h" -#include "document.h" - -#include "prefs-utils.h" - -#include "xml/repr.h" - -#include "jabber_whiteboard/defines.h" -#include "jabber_whiteboard/typedefs.h" -#include "jabber_whiteboard/node-tracker.h" -#include "jabber_whiteboard/chat-handler.h" -#include "jabber_whiteboard/message-queue.h" -#include "jabber_whiteboard/session-manager.h" -#include "jabber_whiteboard/invitation-confirm-dialog.h" - -namespace Inkscape { - -namespace Whiteboard { - -void -SessionManager::sendRequestToUser(std::string const& recipientJID) -{ - /* - Glib::ustring doccopy; - if (document != NULL) { - doccopy = *document; - } - */ - this->session_data->status.set(WAITING_FOR_INVITE_RESPONSE, 1); - this->sendMessage(CONNECT_REQUEST_USER, 0, "", recipientJID.c_str(), false); -} - -void -SessionManager::sendRequestToChatroom(Glib::ustring const& server, Glib::ustring const& chatroom, Glib::ustring const& handle, Glib::ustring const& password) -{ - // We do not yet use the Basic MUC Protocol for connection establishment etc - // . The protocol we use is the - // old GroupChat system; extension to MUC is TODO - - // Compose room@service/nick string for "to" field - Glib::ustring dest = String::ucompose("%1@%2/%3", chatroom, server, handle); - LmMessage* presence_req = lm_message_new(dest.data(), LM_MESSAGE_TYPE_PRESENCE); - - // Add 'from' attribute - LmMessageNode* preq_root = lm_message_get_node(presence_req); - - lm_message_node_set_attribute(preq_root, "from", this->session_data->jid.c_str()); - - // Add - // (Not anymore: we don't speak it! -- yipdw) - LmMessageNode* xmlns_node = lm_message_node_add_child(preq_root, "x", ""); - lm_message_node_set_attribute(xmlns_node, "xmlns", "http://jabber.org/protocol/muc/"); - - // If a password was supplied, add it to xmlns_node - if (password != NULL) { - lm_message_node_add_child(xmlns_node, "password", password.c_str()); - } - - // Create chat message handler and node tracker - if (!this->_myChatHandler) { - this->_myChatHandler = new ChatMessageHandler(this); - } - - // Flag ourselves as connecting to a chatroom (but not yet connected) - this->session_data->status.set(CONNECTING_TO_CHAT, 1); - // Send the message - GError *error = NULL; - if (!lm_connection_send(this->session_data->connection, presence_req, &error)) { - g_error("Presence message could not be sent to %s: %s", dest.data(), error->message); - this->session_data->status.set(CONNECTING_TO_CHAT, 0); - } - - this->session_data->chat_handle = handle; - this->session_data->chat_server = server; - this->session_data->chat_name = chatroom; - - prefs_set_string_attribute("whiteboard.room", "name", chatroom.c_str()); - prefs_set_string_attribute("whiteboard.room", "server", server.c_str()); - //Commented out because you can use whiteboard.server.username - //prefs_set_string_attribute("whiteboard.room", "handle", handle.c_str()); - //store password here? - - - this->setRecipient(String::ucompose("%1@%2", chatroom, server).data()); - - lm_message_unref(presence_req); -} - -void -SessionManager::sendConnectRequestResponse(char const* recipientJID, gboolean accepted_request) -{ - if (accepted_request == TRUE) { - this->setRecipient(recipientJID); - this->session_data->status.set(IN_WHITEBOARD, 1); - } - - this->sendMessage(CONNECT_REQUEST_RESPONSE_USER, accepted_request, "", recipientJID, false); -} - -// When this method is invoked, it means that the user has received an invitation from another peer -// to engage in a whiteboard session (i.e. 1:1 communication). The user may accept or reject this invitation. -void -SessionManager::receiveConnectRequest(gchar const* requesterJID) -{ - int x, y; - Gdk::ModifierType mt; - Gdk::Display::get_default()->get_pointer(x, y, mt); - - if (mt & GDK_BUTTON1_MASK) { - // Attach a polling timeout - this->_notify_incoming_request = Glib::signal_timeout().connect(sigc::bind< 0 >(sigc::mem_fun(*this, &SessionManager::_pollReceiveConnectRequest), requesterJID), 50); - return; - } - - if (this->session_data->status[WAITING_FOR_INVITE_RESPONSE]) { - // Whoops. Someone tried to invite us while we were inviting someone else - // (maybe it was the someone we were trying to invite, maybe it was someone else). - // - // Our response is to reject the second request, as we can only handle one - // invitation at a time. Also, we notify the user (who is waiting for an invitation - // response) of the rejection event. - this->sendMessage(CONNECT_REQUEST_REFUSED_BY_PEER, 0, "", requesterJID, false); - - Glib::ustring primary = ""; - - // TRANSLATORS: This string is used to inform an Inkboard user that the following - // scenario has occurred: - // 1. Alice invites Bob to an Inkboard session. - // 2. While Alice's invitation is en route, Bob invites Alice to an Inkboard session. - // - // Or, we might have the following scenario: - // 1. Alice invites Bob to an Inkboard session. - // 2. While Alice is waiting for Bob's response, Carol sends Alice an invitation. - // - // In the current implementation, we can only handle one invitation at a time, - // so we reject all others. - // - // This is a fix for bug #1352522. Probably not the friendliest, but it's about - // the best we can do without changing the protocol. - primary += _("An invitation conflict has occurred."); - primary += "\n\n"; - - // TRANSLATORS: %1 is the JID of the user who sent us the invitation request. - primary += String::ucompose(_("The Jabber user %1 attempted to invite you to a whiteboard session while you were waiting on an invitation response.\n\nThe invitation from %1 has been rejected."), requesterJID); - - Gtk::MessageDialog dialog(primary, true, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, false); - dialog.run(); - return; - } - - if (this->session_data->status[IN_WHITEBOARD]) { - this->sendMessage(ALREADY_IN_SESSION, 0, "", requesterJID, false); - return; - } - - // Check to see if the user made any modifications to this document. If so, - // we want to give them the option of (1) letting us clear their document or (2) - // opening a new, blank document for the whiteboard session. - Glib::ustring primary = "" + String::ucompose(_("%1 has invited you to a whiteboard session."), requesterJID) + "\n\n"; - Glib::ustring title = String::ucompose(_("Incoming whiteboard invitation from %1"), requesterJID); - - if (sp_document_repr_root(this->_myDoc)->attribute("sodipodi:modified") == NULL) { - primary += String::ucompose(_("Do you wish to accept %1's whiteboard session invitation?"), requesterJID); - } else { - primary += String::ucompose(_("Would you like to accept %1's invitation in a new document window?\nAccepting the invitation in your current window will discard unsaved changes."), requesterJID); - } - - // Construct confirmation dialog - InvitationConfirmDialog dialog(primary); - - dialog.add_button(_("Accept invitation"), ACCEPT_INVITATION); - dialog.add_button(_("Decline invitation"), DECLINE_INVITATION); - dialog.add_button(_("Accept invitation in new document window"), ACCEPT_INVITATION_IN_NEW_WINDOW); - - bool undecided = true; - InvitationResponses resp = static_cast< InvitationResponses >(dialog.run()); - - while(undecided) { - if (resp == ACCEPT_INVITATION) { - undecided = false; - this->clearDocument(); - - // Create a receive queue for the initiator of this request - this->session_data->receive_queues[requesterJID] = new ReceiveMessageQueue(this); - - this->setupInkscapeInterface(); - if (dialog.useSessionFile()) { - this->session_data->sessionFile = dialog.getSessionFilePath(); - this->_tryToStartLog(); - } - this->sendConnectRequestResponse(requesterJID, TRUE); - - } else if (resp == ACCEPT_INVITATION_IN_NEW_WINDOW) { - SPDesktop* newdesktop = sp_file_new_default(); - if (newdesktop != NULL) { - undecided = false; - - // Swap desktops around - - // Destroy the new desktop's session manager and add this one in - delete newdesktop->_whiteboard_session_manager; - newdesktop->_whiteboard_session_manager = this; - - // Assign a new session manager to our old desktop - this->_myDesktop->_whiteboard_session_manager = new SessionManager(this->_myDesktop); - - // Reset our desktop and document pointers - this->setDesktop(newdesktop); - - // Prepare document and send acceptance notification - this->session_data->receive_queues[requesterJID] = new ReceiveMessageQueue(this); - this->clearDocument(); - this->setupInkscapeInterface(); - if (dialog.useSessionFile()) { - this->session_data->sessionFile = dialog.getSessionFilePath(); - this->_tryToStartLog(); - } - this->sendConnectRequestResponse(requesterJID, TRUE); - - } else { - // We could not create a new desktop; ask the user if she or he wants to - // replace the current document and accept the invitation, or reject the invitation. - // TRANSLATORS: %1 is a userid here - Glib::ustring msg = "" + String::ucompose(_("A new document window could not be opened for a whiteboard session with %1"), requesterJID) + ".\n\nWould you like to accept the whiteboard connection in the active document or refuse the invitation?"; - InvitationConfirmDialog replace_dialog(msg); - dialog.add_button(_("Accept invitation"), ACCEPT_INVITATION); - dialog.add_button(_("Decline invitation"), DECLINE_INVITATION); - resp = static_cast< InvitationResponses >(dialog.run()); - } - } else { - undecided = false; - this->sendMessage(CONNECT_REQUEST_REFUSED_BY_PEER, 0, "", requesterJID, false); - } - } -} - -// When this method is invoked, it means that the other peer -// has accepted our request. -void -SessionManager::receiveConnectRequestResponse(InvitationResponses response, std::string& sender) -{ - this->session_data->status.set(WAITING_FOR_INVITE_RESPONSE, 0); - - switch(response) { - case ACCEPT_INVITATION: - { - - // Create a receive queue for the other peer. - this->session_data->receive_queues[sender] = new ReceiveMessageQueue(this); - - KeyToNodeMap newids; - NodeToKeyMap newnodes; - this->_myTracker = new XMLNodeTracker(this); - this->setupInkscapeInterface(); - this->_tryToStartLog(); - this->resendDocument(this->session_data->recipient, newids, newnodes); - this->_myTracker->put(newids, newnodes); -// this->_myTracker->dump(); - this->setupCommitListener(); - break; - } - - case DECLINE_INVITATION: - { - // TRANSLATORS: %1 is the peer whom refused our invitation. - Glib::ustring primary = String::ucompose(_("The user %1 has refused your whiteboard invitation.\n\n"), sender); - - // TRANSLATORS: %1 is the peer whom refused our invitation, %2 is our Jabber identity. - Glib::ustring secondary = String::ucompose(_("You are still connected to a Jabber server as %2, and may send an invitation to %1 again, or you may send an invitation to a different user."), sender, this->session_data->jid); - - Gtk::MessageDialog dialog(primary + secondary, true, Gtk::MESSAGE_INFO, Gtk::BUTTONS_CLOSE, false); - dialog.run(); - break; - - } - - case PEER_ALREADY_IN_SESSION: - { - // TRANSLATORS: %1 is the peer whom we tried to contact, but is already in a whiteboard session. - Glib::ustring primary = String::ucompose(_("The user %1 is already in a whiteboard session.\n\n"), sender); - - // TRANSLATORS: %1 is the peer whom we tried to contact, but is already in a whiteboard session. - Glib::ustring secondary = String::ucompose(_("You are still connected to a Jabber server as %1, and may send an invitation to a different user."), sender); - Gtk::MessageDialog dialog(primary + secondary, true, Gtk::MESSAGE_INFO, Gtk::BUTTONS_CLOSE, false); - dialog.run(); - - break; - } - default: - break; - } -} - -void -SessionManager::receiveConnectRequestResponseChat(gchar const* recipient) -{ - // When responding to connection request responses in chatrooms, - // the responding user is already established in the whiteboard session. - // Therefore we do not need to perform any setup of observers or dispatchers; the requesting user - // will do that. - - KeyToNodeMap newids; - NodeToKeyMap newnodes; - this->resendDocument(recipient, newids, newnodes); -} - -bool -SessionManager::_pollReceiveConnectRequest(Glib::ustring const recipientJID) -{ - int x, y; - Gdk::ModifierType mt; - Gdk::Display::get_default()->get_pointer(x, y, mt); - - if (mt & GDK_BUTTON1_MASK) { - return true; - } else { - this->receiveConnectRequest(recipientJID.c_str()); - return false; - } -} - -} - -} - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/jabber_whiteboard/defines.h b/src/jabber_whiteboard/defines.h index 3fc3c0e45..afed3338f 100644 --- a/src/jabber_whiteboard/defines.h +++ b/src/jabber_whiteboard/defines.h @@ -10,8 +10,8 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#ifndef __WHITEBOARD_DEFINES_H__ -#define __WHITEBOARD_DEFINES_H__ +#ifndef __INKSCAPE_WHITEBOARD_DEFINES_H__ +#define __INKSCAPE_WHITEBOARD_DEFINES_H__ #include "jabber_whiteboard/message-tags.h" #include "jabber_whiteboard/internal-constants.h" @@ -31,10 +31,10 @@ enum MessageType { DOCUMENT_BEGIN = 4, DOCUMENT_END = 5, // 1-1 connections - CONNECT_REQUEST_USER = 6, + CONNECT_REQUEST_USER = 6, CONNECT_REQUEST_RESPONSE_USER = 7, // chat connections - CONNECT_REQUEST_RESPONSE_CHAT = 8, +CONNECT_REQUEST_RESPONSE_CHAT = 8, // chatroom document synchronization CHATROOM_SYNCHRONIZE_REQUEST = 9, CHATROOM_SYNCHRONIZE_RESPONSE = 10, @@ -58,9 +58,9 @@ enum MessageType { // Responses to whiteboard invitations enum InvitationResponses { ACCEPT_INVITATION, - ACCEPT_INVITATION_IN_NEW_WINDOW, DECLINE_INVITATION, - PEER_ALREADY_IN_SESSION + PEER_ALREADY_IN_SESSION, + UNSUPPORTED_PROTOCOL }; // Message handler modes diff --git a/src/jabber_whiteboard/deserializer.cpp b/src/jabber_whiteboard/deserializer.cpp deleted file mode 100644 index 0e207122f..000000000 --- a/src/jabber_whiteboard/deserializer.cpp +++ /dev/null @@ -1,417 +0,0 @@ -/** - * Inkboard message -> XML::Event* deserializer - * - * Authors: - * David Yip - * - * Copyright (c) 2005 Authors - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#include "xml/log-builder.h" -#include "xml/event.h" -#include "xml/node.h" -#include "xml/repr.h" - -#include "util/share.h" - -#include "gc-anchored.h" - -#include "jabber_whiteboard/message-utilities.h" -#include "jabber_whiteboard/typedefs.h" -#include "jabber_whiteboard/node-utilities.h" -#include "jabber_whiteboard/node-tracker.h" -#include "jabber_whiteboard/deserializer.h" -#include - -namespace Inkscape { - -namespace Whiteboard { - -void -Deserializer::deserializeEventAdd(Glib::ustring const& msg) -{ - // 1. Extract required attributes: parent, child, node name, and node type. - // If any of these cannot be found, return. - std::string parent, child, prev; - Glib::ustring name, type; - - struct Node buf; - - buf.tag = MESSAGE_PARENT; - if (!MessageUtilities::findTag(buf, msg)) { - return; - } - parent = buf.data.c_str(); - - buf.tag = MESSAGE_CHILD; - if (!MessageUtilities::findTag(buf, msg)) { - return; - } - child = buf.data.c_str(); - - KeyToNodeMap::iterator i = this->_newnodes.find(child); - if (i != this->_newnodes.end()) { - if (this->_node_action_tracker.getAction(i->second) == NODE_ADD) { - return; - } - } - - buf.tag = MESSAGE_NAME; - if (!MessageUtilities::findTag(buf, msg)) { - return; - } else { - name = buf.data; - } - - buf.tag = MESSAGE_NODETYPE; - if (!MessageUtilities::findTag(buf, msg)) { - return; - } else { - type = buf.data; - } - - // 2. Extract optional attributes: the node previous to the new child node. - buf.tag = MESSAGE_REF; - if (MessageUtilities::findTag(buf, msg)) { - prev = buf.data.c_str(); - } - - // 3. Check if the received child node is a special node. If it is, and we are already - // tracking it, then we should not add the node. - if (this->_xnt->isSpecialNode(name)) { - if (this->_xnt->isTracking(this->_xnt->getSpecialNodeKeyFromName(name))) { - return; - } - } - - // 4. Look up the parent node. If we cannot find it, return. - XML::Node* parentRepr = this->_getNodeByID(parent); - if (parentRepr == NULL) { - g_warning("Cannot find parent node identified by %s", parent.c_str()); - return; - } - - // 5. Look up the node previous to the child, if it exists. - // If we cannot find it, we may be in a change conflict situation. - // In that case, just append the node. - XML::Node* prevRepr = NULL; - if (!prev.empty()) { - prevRepr = this->_getNodeByID(prev); - if (prevRepr == NULL) { - g_warning("Prev node %s could not be found; appending incoming node. Document may not be synchronized.", prev.c_str()); - prevRepr = parentRepr->lastChild(); - } - } - - if (prevRepr) { - if (prevRepr->parent() != parentRepr) { - if (this->_parent_child_map[prevRepr] != parentRepr) { - g_warning("ref mismatch on node %s: child=%s ref=%p parent=%p ref->parent()=%p", prev.c_str(), child.c_str(), prevRepr, parentRepr, prevRepr->parent()); - g_warning("parent_child_map[%p (%s)] = %p (%s)", prevRepr, this->_xnt->get(*prevRepr).c_str(), this->_parent_child_map[prevRepr], this->_xnt->get(*(this->_parent_child_map[prevRepr])).c_str()); - return; - } - } - } - - XML::Node* childRepr = NULL; - - // 6. Create the child node. - - switch (NodeUtilities::stringToNodeType(type)) { - case XML::TEXT_NODE: - buf.tag = MESSAGE_CONTENT; - if (!MessageUtilities::findTag(buf, msg)) { - childRepr = sp_repr_new_text(""); - } else { - childRepr = sp_repr_new_text(buf.data.c_str()); - } - break; - case XML::DOCUMENT_NODE: - // TODO - case XML::COMMENT_NODE: - buf.tag = MESSAGE_CONTENT; - if (!MessageUtilities::findTag(buf, msg)) { - childRepr = sp_repr_new_comment(""); - } else { - childRepr = sp_repr_new_comment(buf.data.c_str()); - } - break; - case XML::ELEMENT_NODE: - default: - childRepr = sp_repr_new(name.data()); - break; - } - - - this->_actions.push_back(SerializedEventNodeAction(KeyNodePair(child, childRepr), NODE_ADD)); - this->_newnodes[child] = childRepr; - this->_newkeys[childRepr] = child; - - - // 8. Deserialize the event. - this->_builder.addChild(*parentRepr, *childRepr, prevRepr); - this->_parent_child_map.erase(childRepr); - this->_parent_child_map[childRepr] = parentRepr; - this->_addOneEvent(this->_builder.detach()); - Inkscape::GC::release(childRepr); -} - -void -Deserializer::deserializeEventDel(Glib::ustring const& msg) -{ - // 1. Extract required attributes: parent, child. If we do not know these, - // return. - std::string parent, child, prev; - - struct Node buf; - - buf.tag = MESSAGE_PARENT; - if (!MessageUtilities::findTag(buf, msg)) { - return; - } - parent = buf.data.c_str(); - - buf.tag = MESSAGE_CHILD; - if (!MessageUtilities::findTag(buf, msg)) { - return; - } - child = buf.data.c_str(); - - KeyToNodeMap::iterator i = this->_newnodes.find(child); - if (i != this->_newnodes.end()) { - if (this->_node_action_tracker.getAction(i->second) == NODE_REMOVE) { - return; - } - } - - // 2. Extract optional attributes: previous node. - buf.tag = MESSAGE_REF; - if (MessageUtilities::findTag(buf, msg)) { - prev = buf.data.c_str(); - } - - // 3. Retrieve nodes. If we cannot find all nodes involved, return. - XML::Node* parentRepr = this->_getNodeByID(parent); - XML::Node* childRepr = this->_getNodeByID(child); - XML::Node* prevRepr = NULL; - if (!prev.empty()) { - prevRepr = this->_getNodeByID(prev); - if (prevRepr == NULL) { - return; - } - } - - // 4. Deserialize the event. - if (parentRepr && childRepr) { - if (childRepr->parent() == parentRepr || this->_parent_child_map[childRepr] == parentRepr) { -// this->_actions.push_back(SerializedEventNodeAction(KeyNodePair(child, childRepr), NODE_REMOVE)); - this->_builder.removeChild(*parentRepr, *childRepr, prevRepr); - this->_parent_child_map.erase(childRepr); - this->_addOneEvent(this->_builder.detach()); - - // 5. Mark the removed node and all its children for removal from the tracker. - this->_recursiveMarkForRemoval(childRepr); - } else { - g_warning("child->parent() == parent mismatch on child=%s (%p), parent=%s: parent=%p child->parent()=%p", child.c_str(), childRepr, parent.c_str(), parentRepr, childRepr->parent()); - g_warning("parent_child_map[%p] = %p", childRepr, this->_parent_child_map[childRepr]); - } - } else { - g_warning("Missing parentRepr and childRepr: parent=%p, child=%p", parentRepr, childRepr); - } -} - -void -Deserializer::deserializeEventChgOrder(Glib::ustring const& msg) -{ - // 1. Extract required attributes: node ID, parent ID, new previous node ID. - // If we do not know these, return. - std::string id, parentid, oldprevid, newprevid; - Node buf; - - buf.tag = MESSAGE_ID; - if (MessageUtilities::findTag(buf, msg)) { - id = buf.data.raw(); - } else { - return; - } - - buf.tag = MESSAGE_PARENT; - if (MessageUtilities::findTag(buf, msg)) { - parentid = buf.data.raw(); - } else { - return; - } - - // 2. Extract optional attributes: old previous node, new previous node. - buf.tag = MESSAGE_OLDVAL; - if (MessageUtilities::findTag(buf, msg)) { - oldprevid = buf.data.raw(); - } - - buf.tag = MESSAGE_NEWVAL; - if (MessageUtilities::findTag(buf, msg)) { - newprevid = buf.data.raw(); - } else { - return; - } - - // 3. Find the identified nodes. If we do not know about the parent and child, return. - XML::Node* node = this->_getNodeByID(id); - XML::Node* parent = this->_getNodeByID(parentid); - XML::Node* oldprev = NULL; - XML::Node* newprev = NULL; - if (!oldprevid.empty()) { - oldprev = this->_getNodeByID(oldprevid); - } - - if (!newprevid.empty()) { - newprev = this->_getNodeByID(newprevid); - } - - if (parent && node) { - // 4. Deserialize the event. - this->_builder.setChildOrder(*parent, *node, oldprev, newprev); - this->_addOneEvent(this->_builder.detach()); - } else { - return; - } -} - -void -Deserializer::deserializeEventChgContent(Glib::ustring const& msg) -{ - // 1. Extract required attributes: node ID. If we do not know these, return. - std::string id; - Util::ptr_shared oldval, newval; - Node buf; - - buf.tag = MESSAGE_ID; - if (!MessageUtilities::findTag(buf, msg)) { - return; - } else { - id = buf.data.raw(); - } - - // 2. Extract optional attributes: old value, new value. - buf.tag = MESSAGE_OLDVAL; - if (MessageUtilities::findTag(buf, msg)) { - oldval = Util::share_string(buf.data.c_str()); - } else { - oldval = Util::share_static_string(""); - } - - buf.tag = MESSAGE_NEWVAL; - if (MessageUtilities::findTag(buf, msg)) { - newval = Util::share_string(buf.data.c_str()); - } else { - newval = Util::share_static_string(""); - } - - // 3. Find the node identified by the ID. If we cannot find it, return. - XML::Node* node = this->_getNodeByID(id); - if (node == NULL) { - return; - } - - // 4. Deserialize the event. - this->_builder.setContent(*node, oldval, newval); - this->_addOneEvent(this->_builder.detach()); -} - -void -Deserializer::deserializeEventChgAttr(Glib::ustring const& msg) -{ - // 1. Extract required attributes: node ID, attribute key. If we do not know these, - // return. - - struct Node buf; - buf.tag = MESSAGE_ID; - if (!MessageUtilities::findTag(buf, msg)) { - return; - } - - std::string id = buf.data.data(); - - buf.tag = MESSAGE_KEY; - if (!MessageUtilities::findTag(buf, msg)) { - return; - } - - Glib::ustring key = buf.data; - - // 2. Extract optional attributes: new value. If we do not find it in the message, - // assume there is no new value. - buf.tag = MESSAGE_NEWVAL; - Util::ptr_shared newval; - if (MessageUtilities::findTag(buf, msg)) { - newval = Util::share_string(buf.data.c_str()); - } else { - newval = Util::share_static_string(""); - } - - // 3. Extract optional attributes: old value. If we do not find it in the message, - // assume that there is no old value. - buf.tag = MESSAGE_OLDVAL; - Util::ptr_shared oldval; - if (MessageUtilities::findTag(buf, msg)) { - oldval = Util::share_string(buf.data.c_str()); - } else { - oldval = Util::share_static_string(""); - } - - // 4. Look up this node in the local node database and external tracker. - // If it cannot be found, return. - XML::Node* node = this->_getNodeByID(id); - if (node == NULL) { - g_warning("Could not find node %s on which to change attribute", id.c_str()); - return; - } - - // 5. If this node is in the actions queue and is marked as "new", we need to apply - // _all_ received attributes to it _before_ adding it to the document tree. - if (this->_newnodes.find(id) != this->_newnodes.end()) { - node->setAttribute(key.c_str(), newval.pointer()); - } - - // 6. Deserialize the event. - this->_builder.setAttribute(*node, g_quark_from_string(key.c_str()), oldval, newval); - this->_updated.insert(node); - this->_addOneEvent(this->_builder.detach()); -} - -void -Deserializer::_recursiveMarkForRemoval(XML::Node* node) -{ - if (node != NULL) { - NodeToKeyMap::iterator i = this->_newkeys.find(node); - if (i == this->_newkeys.end()) { - std::string id = this->_xnt->get(*node); - if (!id.empty()) { - this->_actions.push_back(SerializedEventNodeAction(KeyNodePair(id, node), NODE_REMOVE)); - } - } else { - this->_actions.push_back(SerializedEventNodeAction(KeyNodePair((*i).second, node), NODE_REMOVE)); - } - - for (XML::Node* child = node->firstChild(); child; child = child->next()) { - this->_recursiveMarkForRemoval(child); - } - } -} - -} - -} - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/jabber_whiteboard/deserializer.h b/src/jabber_whiteboard/deserializer.h deleted file mode 100644 index 715ca4c66..000000000 --- a/src/jabber_whiteboard/deserializer.h +++ /dev/null @@ -1,285 +0,0 @@ -/** - * Inkboard message -> XML::Event* deserializer - * - * Authors: - * David Yip - * - * Copyright (c) 2005 Authors - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#ifndef __WHITEBOARD_MESSAGE_DESERIALIZER_H__ -#define __WHITEBOARD_MESSAGE_DESERIALIZER_H__ - -#include "xml/log-builder.h" -#include "xml/event.h" - -#include "jabber_whiteboard/node-tracker-event-tracker.h" -#include "jabber_whiteboard/node-tracker.h" -#include "jabber_whiteboard/typedefs.h" - -#include -#include -#include - -namespace Inkscape { - -namespace Whiteboard { - -/** - * A stateful XML::Event deserializer. - * - * The Deserializer class is meant to deserialize XML::Events serialized by - * Inkscape::Whiteboard::Serializer or a serializer that serializes - * XML::Events into the same format. - * - * Usage is as follows: - *
    - *
  1. For each serialized event called, call the appropriate deserialization method.
  2. - *
  3. Detach the deserialized event.
  4. - *
- * - * The deserializer does not actually modify any aspect of the document or node-tracking systems. - * Methods are provided to provide the information necessary to perform the modifications outside - * of the deserializer. - */ -class Deserializer { -public: - /** - * Constructor. - * - * \param xnt The XMLNodeTracker that a Deserializer should use for retrieving - * XML::Nodes based on string keys. - */ - Deserializer(XMLNodeTracker* xnt) : _xnt(xnt) - { - this->clearEventLog(); - } - - ~Deserializer() { } - - /** - * Deserialize a node add event. - * - * \see XML::EventAdd - * \param msg The message that describes the event. - */ - void deserializeEventAdd(Glib::ustring const& msg); - - /** - * Deserialize a node remove event. - * - * \see XML::EventDel - * \param msg The message that describes the event. - */ - void deserializeEventDel(Glib::ustring const& msg); - - /** - * Deserialize a node order change event. - * - * \see XML::EventChgOrder - * \param msg The message that describes the event. - */ - void deserializeEventChgOrder(Glib::ustring const& msg); - - /** - * Deserialize a node content change event. - * - * \see XML::EventChgContent - * \param msg The message that describes the event. - */ - void deserializeEventChgContent(Glib::ustring const& msg); - - /** - * Deserialize a node attribute change event. - * - * \see XML::EventChgAttr - * \param msg The message that describes the event. - */ - void deserializeEventChgAttr(Glib::ustring const& msg); - - /** - * Retrieve the deserialized event log. - * This method does not clear the internal event log kept by the deserializer. - * To do that, use detachEventLog. - * - * \return The deserialized event log. - */ - XML::Event* getEventLog() - { - return this->_log; - } - - /** - * Retrieve the deserialized event log and clear the internal event log kept by the deserializer. - * - * \return The deserialized event log. - */ - XML::Event* detachEventLog() - { - XML::Event* ret = this->_log; - this->clearEventLog(); - return ret; - } - - /** - * Clear the internal event log. - */ - void clearEventLog() - { - g_log(NULL, G_LOG_LEVEL_DEBUG, "Clearing event log"); - this->_log = NULL; - } - - /** - * Retrieve a list of node entry actions (add node entry, remove node entry) - * that need to be performed on the XMLNodeTracker. - * - * Because this method returns a reference to a list, it is not safe for use - * across multiple invocations of this Deserializer. - * - * \return A reference to a list of node entry actions generated while deserializing. - */ - KeyToNodeActionList& getNodeTrackerActions() - { - return this->_actions; - } - - /** - * Retrieve a list of node entry actions (add node entry, remove node entry) - * that need to be performed on the XMLNodeTracker. - * - * \return A list of node entry actions generated while deserializing. - */ - KeyToNodeActionList getNodeTrackerActionsCopy() - { - return this->_actions; - } - - /** - * Retrieve a set of nodes for which an EventChgAttr was deserialized. - * - * For some actions (i.e. text tool) it is necessary to call updateRepr() on - * the updated nodes. This method provides the information required to perform - * that action. - * - * Because this method returns a reference to a set, it is not safe for use - * across multiple invocations of this Deserializer. - * - * \return A reference to a set of nodes for which an EventChgAttr was deserialized. - */ - AttributesUpdatedSet& getUpdatedAttributeNodeSet() - { - return this->_updated; - } - - /** - * Retrieve a set of nodes for which an EventChgAttr was deserialized. - * - * For some actions (i.e. text tool) it is necessary to call updateRepr() on - * the updated nodes. This method provides the information required to perform - * that action. - * - * \return A set of nodes for which an EventChgAttr was deserialized. - */ - AttributesUpdatedSet getUpdatedAttributeNodeSetCopy() - { - return this->_updated; - } - - /** - * Clear all internal node buffers. - */ - void clearNodeBuffers() - { - g_log(NULL, G_LOG_LEVEL_DEBUG, "Clearing deserializer node buffers"); - this->_newnodes.clear(); - this->_actions.clear(); - this->_newkeys.clear(); - this->_parent_child_map.clear(); - this->_updated.clear(); - } - - /** - * Clear all internal state. - */ - void reset() - { - this->clearEventLog(); - this->clearNodeBuffers(); - } - -private: - XML::Node* _getNodeByID(std::string const& id) - { - KeyToNodeMap::iterator i = this->_newnodes.find(id); - if (i != this->_newnodes.end()) { - return const_cast< XML::Node* >(i->second); - } else { - if (this->_xnt->isTracking(id)) { - return this->_xnt->get(id); - } else { - return NULL; - } - } - } - - void _addOneEvent(XML::Event* event) - { - if (this->_log == NULL) { - this->_log = event; - } else { - event->next = this->_log; - this->_log = event; - } - } - - void _recursiveMarkForRemoval(XML::Node* node); - - // internal states with accessors: - - // node tracker actions (add node, remove node) - KeyToNodeActionList _actions; - - // nodes that have had their attributes updated - AttributesUpdatedSet _updated; - - // the deserialized event log - XML::Event* _log; - - - // for internal use: - - // These maps only store information on a single node. That's fine, though; - // all we care about is the ability to do key <-> node association. The NodeTrackerEventTracker - // and KeyToNodeActionList keep track of the actual actions we need to perform - // on the node tracker. - NodeToKeyMap _newkeys; - KeyToNodeMap _newnodes; - NodeTrackerEventTracker _node_action_tracker; - - typedef std::map< XML::Node*, XML::Node* > _pc_map_type; - _pc_map_type _parent_child_map; - - XMLNodeTracker* _xnt; - - XML::LogBuilder _builder; -}; - -} - -} - -#endif - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/jabber_whiteboard/empty.cpp b/src/jabber_whiteboard/empty.cpp index 0fed24e45..2f20405d6 100644 --- a/src/jabber_whiteboard/empty.cpp +++ b/src/jabber_whiteboard/empty.cpp @@ -1,14 +1 @@ -/// Some archivers don't seem to like creating an archive without being -/// given any members to archive. This file acts as a placeholder - - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : +// empty file to generate a null object file; needed by some archiver tools diff --git a/src/jabber_whiteboard/error-codes.h b/src/jabber_whiteboard/error-codes.h deleted file mode 100644 index e5c6268fa..000000000 --- a/src/jabber_whiteboard/error-codes.h +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Whiteboard session manager - * Error codes - * - * Authors: - * David Yip - * - * Copyright (c) 2005 Authors - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#ifndef __WHITEBOARD_JABBER_ERROR_CODES_H__ -#define __WHITEBOARD_JABBER_ERROR_CODES_H__ - -namespace Inkscape { - -namespace Whiteboard { - -namespace ErrorCodes { - -static unsigned int const SERVER_CONNECT_FAILED = 502; -static unsigned int const CHAT_HANDLE_IN_USE = 409; - -} - -} - -} -#endif - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/jabber_whiteboard/inkboard-document.cpp b/src/jabber_whiteboard/inkboard-document.cpp new file mode 100644 index 000000000..a3881af39 --- /dev/null +++ b/src/jabber_whiteboard/inkboard-document.cpp @@ -0,0 +1,91 @@ +/** + * Inkscape::Whiteboard::InkboardDocument - Inkboard document implementation + * + * Authors: + * David Yip + * + * Copyright (c) 2005 Authors + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include +#include + +#include "jabber_whiteboard/inkboard-document.h" + +#include "xml/simple-session.h" +#include "jabber_whiteboard/inkboard-session.h" + +#include "jabber_whiteboard/session-manager.h" + +namespace Inkscape { + +namespace Whiteboard { + +InkboardDocument::InkboardDocument(int code, SessionType type, Glib::ustring const& to) : + XML::SimpleNode(code), _type(type), _recipient(to) +{ + _initBindings(); +} + +void +InkboardDocument::_initBindings() +{ + _bindDocument(*this); + _bindLogger(*(new XML::SimpleSession())); +} + +void +InkboardDocument::setRecipient(Glib::ustring const& val) +{ + this->_recipient = val; +} + +Glib::ustring +InkboardDocument::getRecipient() const +{ + return this->_recipient; +} + +void +InkboardDocument::startSessionNegotiation() +{ + SessionManager& sm = SessionManager::instance(); + switch (_type) { + case INKBOARD_MUC: + sm.sendGroup(_recipient, CHATROOM_SYNCHRONIZE_REQUEST, " "); + break; + case INKBOARD_PRIVATE: + default: + sm.send(_recipient, CONNECT_REQUEST_USER, " "); + break; + } +} + +void +InkboardDocument::terminateSession() +{ + +} + +void +InkboardDocument::processInkboardEvent(MessageType mtype, unsigned int seqnum, Glib::ustring const& data) +{ + g_log(NULL, G_LOG_LEVEL_DEBUG, "Processing Inkboard event: mtype=%d seqnum=%d data=%s\n", mtype, seqnum, data.c_str()); +} + +} + +} + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/jabber_whiteboard/inkboard-document.h b/src/jabber_whiteboard/inkboard-document.h new file mode 100644 index 000000000..0c147d35e --- /dev/null +++ b/src/jabber_whiteboard/inkboard-document.h @@ -0,0 +1,84 @@ +/** + * Inkscape::Whiteboard::InkboardDocument - Inkboard document implementation + * + * Authors: + * David Yip + * + * Copyright (c) 2005 Authors + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef __INKSCAPE_WHITEBOARD_INKBOARDDOCUMENT_H__ +#define __INKSCAPE_WHITEBOARD_INKBOARDDOCUMENT_H__ + +#include + +#include "xml/document.h" +#include "xml/simple-node.h" + +#include "jabber_whiteboard/keynode.h" +#include "jabber_whiteboard/session-manager.h" + +namespace Inkscape { + +namespace Whiteboard { + +class InkboardDocument : public XML::SimpleNode, public XML::Document { +public: + explicit InkboardDocument(int code, SessionType type, Glib::ustring const& to); + + XML::NodeType type() const + { + return Inkscape::XML::DOCUMENT_NODE; + } + + void setRecipient(Glib::ustring const& val); + Glib::ustring getRecipient() const; + + void startSessionNegotiation(); + void terminateSession(); + void processInkboardEvent(MessageType mtype, unsigned int seqnum, Glib::ustring const& data); + +protected: + /** + * Copy constructor. + * + * \param orig Instance to copy. + */ + InkboardDocument(InkboardDocument const& orig) : + XML::Node(), XML::SimpleNode(orig), XML::Document(), _recipient(orig._recipient) + { + _initBindings(); + } + + XML::SimpleNode* _duplicate() const + { + return new InkboardDocument(*this); + } + +private: + void _initBindings(); + + SessionType _type; + Glib::ustring _recipient; + + KeyNodeTable _tracker; +}; + +} + +} + +#endif + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/jabber_whiteboard/inkboard-session.cpp b/src/jabber_whiteboard/inkboard-session.cpp new file mode 100644 index 000000000..e6ff67f4b --- /dev/null +++ b/src/jabber_whiteboard/inkboard-session.cpp @@ -0,0 +1,128 @@ +/** + * Inkscape::Whiteboard::InkboardSession - Whiteboard implementation of XML::Session + * + * Authors: + * David Yip + * + * Copyright (c) 2005 Authors + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include +#include +#include + +#include "jabber_whiteboard/inkboard-session.h" + +#include "xml/node.h" +#include "xml/event.h" +#include "xml/element-node.h" +#include "xml/text-node.h" +#include "xml/comment-node.h" + +#include "util/share.h" + +namespace Inkscape { + +namespace Whiteboard { + +using XML::Node; + +void +InkboardSession::beginTransaction() +{ + g_assert(!_in_transaction); + _in_transaction = true; +} + +void +InkboardSession::rollback() +{ + g_assert(_in_transaction); + _in_transaction = false; +} + +void +InkboardSession::commit() +{ + g_assert(_in_transaction); + _in_transaction = false; +} + +XML::Event* +InkboardSession::commitUndoable() +{ + g_assert(_in_transaction); + _in_transaction = false; + return NULL; +} + +XML::Node* +InkboardSession::createElementNode(char const* name) +{ + g_log(NULL, G_LOG_LEVEL_DEBUG, "InkboardSession::createElementNode"); + return new XML::ElementNode(g_quark_from_string(name)); +} + +XML::Node* +InkboardSession::createTextNode(char const* content) +{ + g_log(NULL, G_LOG_LEVEL_DEBUG, "InkboardSession::createTextNode"); + return new XML::TextNode(Util::share_string(content)); +} + +XML::Node* +InkboardSession::createCommentNode(char const* content) +{ + g_log(NULL, G_LOG_LEVEL_DEBUG, "InkboardSession::createCommentNode"); + return new XML::CommentNode(Util::share_string(content)); +} + + +void InkboardSession::notifyChildAdded(Node &parent, + Node &child, + Node *prev) +{ + if (_in_transaction) { + + } +} + +void InkboardSession::notifyChildRemoved(Node &parent, + Node &child, + Node *prev) +{ + if (_in_transaction) { + } +} + +void InkboardSession::notifyChildOrderChanged(Node &parent, + Node &child, + Node *old_prev, + Node *new_prev) +{ + if (_in_transaction) { + } +} + +void InkboardSession::notifyContentChanged(Node &node, + Util::SharedCStringPtr old_content, + Util::SharedCStringPtr new_content) +{ + if (_in_transaction) { + } +} + +void InkboardSession::notifyAttributeChanged(Node &node, + GQuark name, + Util::SharedCStringPtr old_value, + Util::SharedCStringPtr new_value) +{ + if (_in_transaction) { + } +} + +} + +} diff --git a/src/jabber_whiteboard/inkboard-session.h b/src/jabber_whiteboard/inkboard-session.h new file mode 100644 index 000000000..7ac5e4a90 --- /dev/null +++ b/src/jabber_whiteboard/inkboard-session.h @@ -0,0 +1,121 @@ +/** + * Inkscape::Whiteboard::InkboardSession - Whiteboard implementation of XML::Session interface + * + * Authors: + * David Yip + * + * Copyright (c) 2005 Authors + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef __INKSCAPE_WHITEBOARD_SESSION_H__ +#define __INKSCAPE_WHITEBOARD_SESSION_H__ + +#include +#include + +#include "pedro/pedroxmpp.h" +#include "jabber_whiteboard/internal-constants.h" + +#include "xml/simple-session.h" +#include "util/share.h" + +namespace Inkscape { + +namespace Whiteboard { + +class InkboardSession : public GC::Managed<>, + public XML::Session, + public XML::TransactionLogger +{ +public: + InkboardSession() : _in_transaction(false) { } + InkboardSession(Glib::ustring const& name) : _in_transaction(false), _name(name) { } + virtual ~InkboardSession() { } + + /** + * Returns the name of this session. + * \return The name of this session. + */ + virtual Glib::ustring getName() const + { return _name; } + + /** + * Sets the name of this session. + * + * \param val The name to use. + */ + virtual void setName(const Glib::ustring &val) + { _name = val; } + + /** + * Returns status attributes of this session. + * + * \return Status of this session. + */ + virtual std::bitset< NUM_FLAGS > const& getStatus() const + { + return status; + } + + // + // XML::TransactionLogger methods + // + Session& session() + { + return *this; + } + + // + // XML::Session methods + // + bool inTransaction() + { + return _in_transaction; + } + + void beginTransaction(); + void rollback(); + void commit(); + + XML::Event* commitUndoable(); + + XML::Node* createElementNode(char const* name); + XML::Node* createTextNode(char const* content); + XML::Node* createCommentNode(char const* content); + + // + // XML::NodeObserver methods + // (inherited from XML::TransactionLogger) + // + void notifyChildAdded(Inkscape::XML::Node &parent, Inkscape::XML::Node &child, Inkscape::XML::Node *prev); + + void notifyChildRemoved(Inkscape::XML::Node &parent, Inkscape::XML::Node &child, Inkscape::XML::Node *prev); + + void notifyChildOrderChanged(Inkscape::XML::Node &parent, Inkscape::XML::Node &child, + Inkscape::XML::Node *old_prev, Inkscape::XML::Node *new_prev); + + void notifyContentChanged(Inkscape::XML::Node &node, + Util::ptr_shared old_content, + Util::ptr_shared new_content); + + void notifyAttributeChanged(Inkscape::XML::Node &node, GQuark name, + Util::ptr_shared old_value, + Util::ptr_shared new_value); + +private: + InkboardSession(InkboardSession const &); // no copy + void operator=(InkboardSession const &); // no assign + + bool _in_transaction; + + std::bitset< NUM_FLAGS > status; + Glib::ustring _name; +}; + +} + +} + +#endif diff --git a/src/jabber_whiteboard/internal-constants.cpp b/src/jabber_whiteboard/internal-constants.cpp index 4956a402c..44355c8a0 100644 --- a/src/jabber_whiteboard/internal-constants.cpp +++ b/src/jabber_whiteboard/internal-constants.cpp @@ -68,9 +68,9 @@ int const SEND_TIMEOUT = 35; Local Variables: mode:c++ c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + c-file-offsets:((innamespace . 0)(inline-open . 0)) indent-tabs-mode:nil fill-column:99 End: */ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : +// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/jabber_whiteboard/internal-constants.h b/src/jabber_whiteboard/internal-constants.h index 5a14737be..737eacdc7 100644 --- a/src/jabber_whiteboard/internal-constants.h +++ b/src/jabber_whiteboard/internal-constants.h @@ -65,6 +65,7 @@ extern int const PLAYING_SESSION_FILE; // accomodate Inkscape, not the other way around... // Dispatch interval (in milliseconds) extern int const SEND_TIMEOUT; + } } @@ -75,9 +76,9 @@ extern int const SEND_TIMEOUT; Local Variables: mode:c++ c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + c-file-offsets:((innamespace . 0)(inline-open . 0)) indent-tabs-mode:nil fill-column:99 End: */ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : +// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/jabber_whiteboard/invitation-confirm-dialog.cpp b/src/jabber_whiteboard/invitation-confirm-dialog.cpp index 8590abab8..77fd75fcd 100644 --- a/src/jabber_whiteboard/invitation-confirm-dialog.cpp +++ b/src/jabber_whiteboard/invitation-confirm-dialog.cpp @@ -10,6 +10,8 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ +#include +#include #include #include "invitation-confirm-dialog.h" diff --git a/src/jabber_whiteboard/invitation-confirm-dialog.h b/src/jabber_whiteboard/invitation-confirm-dialog.h index 42cea9b56..b73a0e3bc 100644 --- a/src/jabber_whiteboard/invitation-confirm-dialog.h +++ b/src/jabber_whiteboard/invitation-confirm-dialog.h @@ -13,12 +13,10 @@ #ifndef __WHITEBOARD_INVITATION_CONFIRM_DIALOG_H__ #define __WHITEBOARD_INVITATION_CONFIRM_DIALOG_H__ -#include -#include -#include - -#include "jabber_whiteboard/session-file-selector.h" +#include +#include +#include "session-file-selector.h" namespace Inkscape { diff --git a/src/jabber_whiteboard/invitation-handlers.cpp b/src/jabber_whiteboard/invitation-handlers.cpp new file mode 100644 index 000000000..124b9515b --- /dev/null +++ b/src/jabber_whiteboard/invitation-handlers.cpp @@ -0,0 +1,150 @@ +/** + * Whiteboard session manager - invitation handling methods + * + * Authors: + * David Yip + * Bob Jamison (Pedro port) + * + * Copyright (c) 2005 Authors + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include +#include + +#include "util/ucompose.hpp" + +#include "document.h" +#include "desktop-handles.h" + +#include "jabber_whiteboard/inkboard-document.h" +#include "jabber_whiteboard/session-manager.h" +#include "jabber_whiteboard/invitation-confirm-dialog.h" + + +namespace Inkscape { + +namespace Whiteboard { + +bool +SessionManager::_checkInvitationQueue() +{ + int x, y; + Gdk::ModifierType mt; + Gdk::Display::get_default()->get_pointer(x, y, mt); + if (mt & GDK_BUTTON1_MASK) { + // The user is currently busy with an action. Defer invitation processing + // until the user is free. + return true; + } + + if (_pending_invitations.size() > 0) { + // There's an invitation to process; process it. + Glib::ustring from = _pending_invitations.front(); + + Glib::ustring primary = "" + String::ucompose(_("%1 has invited you to a whiteboard session."), from) + "\n\n"; + primary += String::ucompose(_("Do you wish to accept %1's whiteboard session invitation?"), from); + + InvitationConfirmDialog dialog(primary); + + dialog.add_button(_("Accept invitation"), ACCEPT_INVITATION); + dialog.add_button(_("Decline invitation"), DECLINE_INVITATION); + + InvitationResponses resp = static_cast< InvitationResponses >(dialog.run()); + + switch (resp) { + case ACCEPT_INVITATION: + { + SPDesktop* dt = createInkboardDesktop(from, INKBOARD_PRIVATE); + InkboardDocument* idoc = dynamic_cast< InkboardDocument* >(sp_desktop_document(dt)->rdoc); + send(from, CONNECT_REQUEST_RESPONSE_USER, " "); + break; + } + case DECLINE_INVITATION: + { + break; + } + default: + send(from, CONNECT_REQUEST_REFUSED_BY_PEER, " "); + break; + } + + _pending_invitations.pop_front(); + } + + return true; +} + + +bool +SessionManager::_checkInvitationResponseQueue() +{ + int x, y; + Gdk::ModifierType mt; + Gdk::Display::get_default()->get_pointer(x, y, mt); + if (mt & GDK_BUTTON1_MASK) { + // The user is currently busy with an action. Defer invitation response processing + // until the user is free. + return true; + } + + if (_invitation_responses.size() > 0) { + Invitation_response_type response = _invitation_responses.front(); + + switch (response.second) { + case ACCEPT_INVITATION: + { + break; + } + case DECLINE_INVITATION: + { + Glib::ustring primary = String::ucompose(_("The user %1 has refused your whiteboard invitation.\n\n"), response.first); + + // TRANSLATORS: %1 is the peer whom refused our invitation, %2 is our Jabber identity. + Glib::ustring secondary = String::ucompose(_("You are still connected to a Jabber server as %2, and may send an invitation to %1 again, or you may send an invitation to a different user."), response.first, this->getClient().getJid()); + + Gtk::MessageDialog dialog(primary + secondary, true, Gtk::MESSAGE_INFO, Gtk::BUTTONS_CLOSE, false); + dialog.run(); + terminateInkboardSession(response.first); + break; + } + case PEER_ALREADY_IN_SESSION: + break; + + case UNSUPPORTED_PROTOCOL: + { + Glib::ustring primary = String::ucompose(_("The user %1 is using an incompatible version of Inkboard.\n\n"), response.first); + + // TRANSLATORS: %1 is the peer whom refused our invitation, %2 is our Jabber identity. + Glib::ustring secondary = String::ucompose(_("Inkscape cannot connect to %1.\n\nYou are still connected to a Jabber server as %2."), response.first, this->getClient().getJid()); + + Gtk::MessageDialog dialog(primary + secondary, true, Gtk::MESSAGE_INFO, Gtk::BUTTONS_CLOSE, false); + dialog.run(); + terminateInkboardSession(response.first); + break; + } + default: + break; + } + + _invitation_responses.pop_front(); + } + + return true; +} + +} + +} + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/jabber_whiteboard/jabber-handlers.cpp b/src/jabber_whiteboard/jabber-handlers.cpp deleted file mode 100644 index 308978025..000000000 --- a/src/jabber_whiteboard/jabber-handlers.cpp +++ /dev/null @@ -1,65 +0,0 @@ -/** - * Whiteboard session manager - * C-style Loudmouth callbacks - * - * Authors: - * David Yip - * - * Copyright (c) 2005 Authors - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#include "jabber_whiteboard/defines.h" -#include "jabber_whiteboard/jabber-handlers.h" -#include "jabber_whiteboard/message-handler.h" -#include "jabber_whiteboard/session-manager.h" - -namespace Inkscape { - -namespace Whiteboard { - -LmHandlerResult -default_handler(LmMessageHandler* handler, LmConnection* connection, LmMessage* message, gpointer user_data) -{ - MessageHandler* mh = reinterpret_cast< MessageHandler* >(user_data); - return mh->handle(message, DEFAULT); -} - - -LmHandlerResult -presence_handler(LmMessageHandler* handler, LmConnection* connection, LmMessage* message, gpointer user_data) -{ - MessageHandler* mh = reinterpret_cast< MessageHandler* >(user_data); - return mh->handle(message, PRESENCE); -} - - -LmHandlerResult -stream_error_handler(LmMessageHandler* handler, LmConnection* connection, LmMessage* message, gpointer user_data) -{ - MessageHandler* mh = reinterpret_cast< MessageHandler* >(user_data); - return mh->handle(message, ERROR); -} - -LmSSLResponse -ssl_error_handler(LmSSL* ssl, LmSSLStatus status, gpointer user_data) -{ - SessionManager* sm = reinterpret_cast< SessionManager* >(user_data); - return sm->handleSSLError(ssl, status); -} - -} - -} - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/jabber_whiteboard/jabber-handlers.h b/src/jabber_whiteboard/jabber-handlers.h deleted file mode 100644 index 2eec08c78..000000000 --- a/src/jabber_whiteboard/jabber-handlers.h +++ /dev/null @@ -1,86 +0,0 @@ -/** - * Whiteboard session manager - * C-style Loudmouth callbacks - * - * Authors: - * David Yip - * - * Copyright (c) 2005 Authors - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#ifndef __WHITEBOARD_LOUDMOUTH_CALLBACKS__ -#define __WHITEBOARD_LOUDMOUTH_CALLBACKS__ - -extern "C" { -#include -} - -#include - -namespace Inkscape { - -namespace Whiteboard { - -/** - * C-style callback for Loudmouth to handle received presence messages. - * - * \param handler The LmMessageHandler handling this event. - * \param connection The LmConnection with which the LmMessageHandler is associated. - * \param message The Jabber message received that triggered this handler. - * \param user_data A pointer to an instance of Inkscape::Whiteboard::MessageHandler, which performs - * the real message processing work. - */ -LmHandlerResult presence_handler(LmMessageHandler* handler, LmConnection* connection, LmMessage* message, gpointer user_data); - -/** - * C-style callback for Loudmouth to handle received messages. - * - * This handler handles messages that are not presence or error messages. - * - * \param handler The LmMessageHandler handling this event. - * \param connection The LmConnection with which the LmMessageHandler is associated. - * \param message The Jabber message received that triggered this handler. - * \param user_data A pointer to an instance of Inkscape::Whiteboard::MessageHandler, which performs - * the real message processing work. - */ -LmHandlerResult default_handler(LmMessageHandler* handler, LmConnection* connection, LmMessage* message, gpointer user_data); - -/** - * C-style callback for Loudmouth to handle received error messages. - * - * \param handler The LmMessageHandler handling this event. - * \param connection The LmConnection with which the LmMessageHandler is associated. - * \param message The Jabber message received that triggered this handler. - * \param user_data A pointer to an instance of Inkscape::Whiteboard::MessageHandler, which performs - * the real message processing work. - */ -LmHandlerResult stream_error_handler(LmMessageHandler* handler, LmConnection* connection, LmMessage* message, gpointer user_data); - -/** - * C-style callback for Loudmouth to handle SSL errors. - * - * \param ssl The SSL data structure used by Loudmouth. - * \param status The error code representing the error that occurred. - * \param user_data A pointer to the SessionManager instance handling associated with the connection attempt that - * threw the SSL error. - */ -LmSSLResponse ssl_error_handler(LmSSL* ssl, LmSSLStatus status, gpointer user_data); - -} - -} - -#endif - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/jabber_whiteboard/keynode.cpp b/src/jabber_whiteboard/keynode.cpp new file mode 100644 index 000000000..d9af43f63 --- /dev/null +++ b/src/jabber_whiteboard/keynode.cpp @@ -0,0 +1,128 @@ +/** + * Inkscape::Whiteboard::KeyNodeTable - structure for lookup of values from keys + * and vice versa + * + * Authors: + * Bob Jamison + * + * Copyright (c) 2005 Authors + */ +#include "keynode.h" + + +namespace Inkscape +{ +namespace Whiteboard +{ + + + +void KeyNodeTable::clear() +{ + items.clear(); +} + +void KeyNodeTable::append(const KeyNodeTable &other) +{ + for (unsigned int i = 0; i::iterator iter; + for (iter = items.begin() ; iter != items.end() ; ) + { + if (key == iter->key || node == iter->node) + iter = items.erase(iter); + else + iter++; + } + + //add new + KeyNodePair pair(key, node); + items.push_back(pair); +} + +XML::Node * KeyNodeTable::get(const Glib::ustring &key) const +{ + std::vector::const_iterator iter; + for (iter = items.begin() ; iter != items.end() ; iter++) + { + if (key == iter->key) + return iter->node; + } + return NULL; +} + + +void KeyNodeTable::remove(const Glib::ustring &key) +{ + std::vector::iterator iter; + for (iter = items.begin() ; iter != items.end() ; ) + { + if (key == iter->key) + iter = items.erase(iter); + else + iter++; + } +} + + +Glib::ustring KeyNodeTable::get(XML::Node *node) const +{ + std::vector::const_iterator iter; + for (iter = items.begin() ; iter != items.end() ; iter++) + { + if (node == iter->node) + return iter->key; + } + return ""; +} + + +void KeyNodeTable::remove(XML::Node *node) +{ + std::vector::iterator iter; + for (iter = items.begin() ; iter != items.end() ; ) + { + if (node == iter->node) + iter = items.erase(iter); + else + iter++; + } +} + +unsigned int KeyNodeTable::size() const +{ + return items.size(); +} + + +KeyNodePair KeyNodeTable::item(unsigned int index) const +{ + if (index>=items.size()) + { + KeyNodePair pair("", NULL); + return pair; + } + return items[index]; +} + + + +} // namespace Whiteboard + +} // namespace Inkscape +//######################################################################### +//# E N D O F F I L E +//######################################################################### diff --git a/src/jabber_whiteboard/keynode.h b/src/jabber_whiteboard/keynode.h new file mode 100644 index 000000000..a224b7c53 --- /dev/null +++ b/src/jabber_whiteboard/keynode.h @@ -0,0 +1,95 @@ +/** + * Inkscape::Whiteboard::KeyNodeTable - structure for lookup of values from keys + * and vice versa + * + * Authors: + * Bob Jamison + * + * Copyright (c) 2005 Authors + */ +#ifndef __KEY_NODE_H__ +#define __KEY_NODE_H__ + +#include + +#include + +#include "xml/node.h" + + +namespace Inkscape +{ +namespace Whiteboard +{ + + +class KeyNodePair +{ +public: + KeyNodePair(const Glib::ustring &keyArg, const XML::Node *nodeArg) + { + key = keyArg; + node = (XML::Node *)nodeArg; + } + KeyNodePair(const KeyNodePair &other) + { + key = other.key; + node = other.node; + } + virtual ~KeyNodePair() + {} + Glib::ustring key; + XML::Node *node; +}; + +class KeyNodeTable +{ +public: + + KeyNodeTable() + {} + + KeyNodeTable(const KeyNodeTable &other) + { + items = other.items; + } + + virtual ~KeyNodeTable() + {} + + virtual void clear(); + + virtual void append(const KeyNodeTable &other); + + virtual void put(const KeyNodePair &pair); + + virtual void put(const Glib::ustring &key, const XML::Node *node); + + virtual XML::Node * get(const Glib::ustring &key) const; + + virtual void remove(const Glib::ustring &key); + + virtual Glib::ustring get(XML::Node *node) const; + + virtual void remove(XML::Node *node); + + virtual unsigned int size() const; + + virtual KeyNodePair item(unsigned int index) const; + +private: + + std::vector items; + +}; + + + +} // namespace Whiteboard + +} // namespace Inkscape + + +#endif /* __KEY_NODE_H__ */ + + diff --git a/src/jabber_whiteboard/message-aggregator.cpp b/src/jabber_whiteboard/message-aggregator.cpp index 2077dcc6d..7d4ee4b3f 100644 --- a/src/jabber_whiteboard/message-aggregator.cpp +++ b/src/jabber_whiteboard/message-aggregator.cpp @@ -56,9 +56,9 @@ MessageAggregator::addOne(Glib::ustring const& msg) Local Variables: mode:c++ c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + c-file-offsets:((innamespace . 0)(inline-open . 0)) indent-tabs-mode:nil fill-column:99 End: */ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : +// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/jabber_whiteboard/message-aggregator.h b/src/jabber_whiteboard/message-aggregator.h index 56cd8e3da..505e65f12 100644 --- a/src/jabber_whiteboard/message-aggregator.h +++ b/src/jabber_whiteboard/message-aggregator.h @@ -73,8 +73,9 @@ public: /** * Return the aggregate message. * - * Because this method returns a reference to a string, it is not safe for use - * across multiple invocations of this Deserializer. + * Because this method returns a reference to a string, it is not safe to assume + * that its contents will remain untouched across two calls to this MessageAggregator. + * If you require that guarantee, make a copy. * * \return A reference to the aggregate message. */ @@ -127,9 +128,9 @@ private: Local Variables: mode:c++ c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + c-file-offsets:((innamespace . 0)(inline-open . 0)) indent-tabs-mode:nil fill-column:99 End: */ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : +// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/jabber_whiteboard/message-contexts.cpp b/src/jabber_whiteboard/message-contexts.cpp deleted file mode 100644 index 70983bad0..000000000 --- a/src/jabber_whiteboard/message-contexts.cpp +++ /dev/null @@ -1,139 +0,0 @@ -/** - * Whiteboard session manager - * Inkboard message context definitions - * - * Authors: - * David Yip - * - * Copyright (c) 2005 Authors - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#include "jabber_whiteboard/defines.h" -#include "jabber_whiteboard/message-contexts.h" - -#include - -namespace Inkscape { - -namespace Whiteboard { - -void -initialize_received_message_contexts(MessageContextMap& mcm) -{ - - // Each Inkboard message has a context of validity according to an Inkboard - // client's state. That is, certain messages should be acknowledged and processed - // in some states, whereas other messages should not. - // For instance, a whiteboard invitation should be acknowledged if an Inkboard - // client is not in a whiteboard session, but should be refused if said client - // _is_ in a whiteboard session. - - // Only the flags that are required to be set must be set; all flags, by default, - // are zero. Explicit definition doesn't hurt, though. - - // The general format of message context creation and registration is - // std::bitset< NUM_FLAGS > m_ - // m_.set( ); - // m_.set( ); - // mcm[ ] = m_; - - - // Begin - - // Special bitsets - std::bitset< NUM_FLAGS > all_contexts; - all_contexts.flip(); - - // Messages: CHANGE_NOT_REPEATABLE, CHANGE_REPEATABLE, DUMMY_CHANGE, CHANGE_COMMIT - std::bitset< NUM_FLAGS > m1; - m1.set(LOGGED_IN); - m1.set(IN_WHITEBOARD); - m1.set(IN_CHATROOM); - m1.set(SYNCHRONIZING_WITH_CHAT); - mcm[CHANGE_NOT_REPEATABLE] = m1; - mcm[CHANGE_REPEATABLE] = m1; - mcm[DUMMY_CHANGE] = m1; - mcm[CHANGE_COMMIT] = m1; - - // Messages: DOCUMENT_BEGIN, DOCUMENT_END - std::bitset< NUM_FLAGS > m4; - m4.set(LOGGED_IN); - m4.set(IN_WHITEBOARD); - m4.set(SYNCHRONIZING_WITH_CHAT); - mcm[DOCUMENT_BEGIN] = m4; - mcm[DOCUMENT_END] = m4; - - // Message: CONNECT_REQUEST_USER - std::bitset< NUM_FLAGS > m5; - m5.set(LOGGED_IN); - - // We should still _accept_ CONNECT_REQUEST_USER messages even if we're already - // waiting for a response. It is up to the higher-level handler (i.e. the connection - // request handler) to properly handle it. - m5.set(WAITING_FOR_INVITE_RESPONSE); - mcm[CONNECT_REQUEST_USER] = m5; - - // Message: CONNECT_REQUEST_RESPONSE_USER - std::bitset< NUM_FLAGS > m6; - m6.set(LOGGED_IN); - m6.set(WAITING_FOR_INVITE_RESPONSE); - mcm[CONNECT_REQUEST_RESPONSE_USER] = m6; - - // Message: CHATROOM_SYNCHRONIZE_REQUEST - std::bitset< NUM_FLAGS > m7; - m7.set(LOGGED_IN); - m7.set(IN_CHATROOM); - m7.set(IN_WHITEBOARD); - mcm[CHATROOM_SYNCHRONIZE_REQUEST] = m7; - - // Message: CHATROOM_SYNCHRONIZE_RESPONSE - std::bitset< NUM_FLAGS > m8; - m8.set(LOGGED_IN); - m8.set(WAITING_TO_SYNC_TO_CHAT); - mcm[CHATROOM_SYNCHRONIZE_RESPONSE] = m8; - - // Message: CONNECT_REQUEST_RESPONSE_CHAT - std::bitset< NUM_FLAGS > m9; - m9.set(LOGGED_IN); - m9.set(IN_CHATROOM); - m9.set(IN_WHITEBOARD); - mcm[CONNECT_REQUEST_RESPONSE_CHAT] = m9; - - // Message: CONNECTED_SIGNAL - mcm[CONNECTED_SIGNAL] = all_contexts; - - // Message: DISCONNECTED_FROM_USER_SIGNAL - std::bitset< NUM_FLAGS > m11; - m11.set(LOGGED_IN); - m11.set(IN_WHITEBOARD); - mcm[DISCONNECTED_FROM_USER_SIGNAL] = m11; - - // Messages: CONNECT_REQUEST_REFUSED_BY_PEER, ALREADY_IN_SESSION - std::bitset< NUM_FLAGS > m12; - m12.set(LOGGED_IN); - m12.set(WAITING_FOR_INVITE_RESPONSE); - mcm[CONNECT_REQUEST_REFUSED_BY_PEER] = m12; - mcm[ALREADY_IN_SESSION] = m12; - - // Message: UNSUPPORTED_PROTOCOL_VERSION - std::bitset< NUM_FLAGS > m14; - m14.set(LOGGED_IN); - mcm[UNSUPPORTED_PROTOCOL_VERSION] = m14; -} - -} - -} - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/jabber_whiteboard/message-contexts.h b/src/jabber_whiteboard/message-contexts.h deleted file mode 100644 index 49653c693..000000000 --- a/src/jabber_whiteboard/message-contexts.h +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Whiteboard session manager - * Inkboard message context definitions - * - * Authors: - * David Yip - * - * Copyright (c) 2005 Authors - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#ifndef __WHITEBOARD_MESSAGE_CONTEXTS_H__ -#define __WHITEBOARD_MESSAGE_CONTEXTS_H__ - -#include "jabber_whiteboard/typedefs.h" - -namespace Inkscape { - -namespace Whiteboard { - -void initialize_received_message_contexts(MessageContextMap& mcm); - -} - -} - -#endif - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/jabber_whiteboard/message-handler.cpp b/src/jabber_whiteboard/message-handler.cpp deleted file mode 100644 index 9551a8e27..000000000 --- a/src/jabber_whiteboard/message-handler.cpp +++ /dev/null @@ -1,459 +0,0 @@ -/** - * Whiteboard session manager - * Jabber received message handling - * - * Authors: - * David Yip - * Steven Montgomery, Jonas Collaros (original C version) - * - * Copyright (c) 2004-2005 Authors - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -extern "C" { -#include -} - -#include -#include -#include -#include - -#include "jabber_whiteboard/defines.h" -#include "jabber_whiteboard/typedefs.h" -#include "jabber_whiteboard/message-processors.h" -#include "jabber_whiteboard/message-handler.h" -#include "jabber_whiteboard/session-manager.h" -#include "jabber_whiteboard/chat-handler.h" -#include "jabber_whiteboard/buddy-list-manager.h" - -namespace Inkscape { - -namespace Whiteboard { - -bool message_contexts_initialized = false; -MessageContextMap _received_message_contexts; - -MessageHandler::MessageHandler(SessionManager* sm) : _sm(sm) -{ - if (message_contexts_initialized == false) { -// this->_initializeContexts(); - MessageHandler::_initializeContexts(); - } - this->_initializeProcessors(); -} - -MessageHandler::~MessageHandler() -{ - this->_destructProcessors(); -} - -LmHandlerResult -MessageHandler::handle(LmMessage* message, HandlerMode mode) -{ - if (this->_isValidMessage(message)) { - switch(mode) { - case DEFAULT: - return this->_default(message); - case PRESENCE: - return this->_presence(message); - case ERROR: - return this->_error(message); - default: - g_warning("Jabber message handler was asked to process a message of an unhandled type; discarding message."); - return LM_HANDLER_RESULT_REMOVE_MESSAGE; - } - } else { - return LM_HANDLER_RESULT_REMOVE_MESSAGE; - } -} - -bool -MessageHandler::_hasValidReceiveContext(LmMessage* message) -{ - MessageType type = this->_getType(message); - std::bitset< NUM_FLAGS >& status = this->_sm->session_data->status; - - std::string s1 = status.to_string< char, std::char_traits< char >, std::allocator< char > >(); - - - if (type == UNKNOWN) { - // unknown types never have a valid receive context - return false; - } else { - std::bitset< NUM_FLAGS >& recvcontext = _received_message_contexts[type]; - - // TODO: remove this debug block - if ((status & recvcontext).to_ulong() < status.to_ulong()) { - g_warning("Received message in incorrect context; discarding message."); - - std::string s2 = recvcontext.to_string< char, std::char_traits< char >, std::allocator< char > >(); - - g_warning("current context=%s required context=%s (msgtype %s)", s1.c_str(), s2.c_str(), MessageHandler::ink_type_to_string(type)); - } - - return ((status & recvcontext).to_ulong() >= status.to_ulong()); - } -} - -bool -MessageHandler::_isValidMessage(LmMessage* message) -{ - // Global sanity checks - LmMessageNode* root; - LmMessageNode* protocolver; - LmMessageNode* offline; - LmMessageType mtype; - LmMessageSubType msubtype; - gchar const* tmp; - - Glib::ustring sender; - - - // 0. The message must have a root node. - root = lm_message_get_node(message); - if (root == NULL) { - g_warning("Check 0 failed (message has no root node)"); - return false; - } - - - // 1. The message must be of LM_MESSAGE_TYPE_MESSAGE to continue the sanity checks. - // If it is not, check to see if it is either - // a presence message or an error message. If it is either of these, then automatically - // consider it sane. - // - // FIXME: - // (That is probably a dangerous assumption. We should probably at least validate - // the source for error messages.) - // - // We do not handle IQ stanzas or STREAM messages (yet), and we certainly don't - // handle unknowns. - - mtype = lm_message_get_type(message); - switch(mtype) { - case LM_MESSAGE_TYPE_PRESENCE: - case LM_MESSAGE_TYPE_STREAM_ERROR: - return true; - case LM_MESSAGE_TYPE_IQ: - case LM_MESSAGE_TYPE_STREAM: - case LM_MESSAGE_TYPE_UNKNOWN: - g_warning("Check 1 failed (Loudmouth reported type IQ, STREAM, or UNKNOWN)"); - return false; - case LM_MESSAGE_TYPE_MESSAGE: - break; - } - - // 2. The message must contain the JID of the sender. - tmp = lm_message_node_get_attribute(root, MESSAGE_FROM); - - if (tmp == NULL) { - g_warning("Check 2 failed (no sender attribute present)"); - return false; - } else { - sender = tmp; - } - - // 3. We do not yet handle messages from offline storage, so ensure that this is not - // such a message. - offline = lm_message_node_get_child(root, "x"); - if (offline != NULL) { - gchar const* val = lm_message_node_get_value(offline); - if (val != NULL) { - if (strcmp(val, "Offline Storage") == 0) { - return false; - } - } - } - - - // 4. If this is a regular chat message... - msubtype = lm_message_get_sub_type(message); - - if (msubtype == LM_MESSAGE_SUB_TYPE_CHAT) { - // 4a. A protocol version node must be present. - protocolver = lm_message_node_get_child(root, MESSAGE_PROTOCOL_VER); - if (protocolver == NULL) { - g_warning("Check 4a failed (no protocol attribute in chat message)"); - return false; - } else { - tmp = lm_message_node_get_value(protocolver); - if (tmp == NULL) { - g_warning("Check 4a failed (no protocol attribute in chat message)"); - return false; - } - } - - // 5a. The protocol version must be supported. - if (atoi(tmp) > HIGHEST_SUPPORTED) { - g_warning("Check 5a failed (received a message with protocol version %s, but version %s is not supported)", tmp, tmp); - return false; - } - - // ...otherwise, if this is a groupchat message, we may not have a protocol version - // (since it may be communication from the Jabber server). In this case, we have a - // different set of sanity checks. - } else if (msubtype == LM_MESSAGE_SUB_TYPE_GROUPCHAT) { - // 4b. - // In a chatroom situation, we need to ensure that we don't process messages that - // originated from us. - int cutoff = sender.find_last_of('/') + 1; - if (sender.substr(cutoff, sender.length()) == this->_sm->session_data->chat_handle) { - return false; - } - // TODO: 6b. If the message is NOT from the Jabber server, then check the protocol version. - } - - // If all tests pass, then the message is at least valid. - // Correct context has not yet been established, however; that is the job of the default handler - // and hasValidReceiveContext. - - return true; -} - -MessageType -MessageHandler::_getType(LmMessage* message) -{ - LmMessageNode* root; - LmMessageNode* typenode; - - root = lm_message_get_node(message); - if (root != NULL) { - typenode = lm_message_node_get_child(root, MESSAGE_TYPE); - if (typenode != NULL) { - return static_cast< MessageType >(atoi(lm_message_node_get_value(typenode))); - } - } - return UNKNOWN; -} - -JabberMessage -MessageHandler::_extractData(LmMessage* message) -{ - - JabberMessage jm(message); - LmMessageNode* root; - LmMessageNode* sequence; - LmMessageNode* body; - gchar const* tmp; - - root = lm_message_get_node(message); - - if (root != NULL) { - sequence = lm_message_node_get_child(root, MESSAGE_SEQNUM); - body = lm_message_node_get_child(root, MESSAGE_BODY); - - jm.sender = lm_message_node_get_attribute(root, MESSAGE_FROM); - - if (sequence) { - tmp = lm_message_node_get_value(sequence); - if (tmp != NULL) { - jm.sequence = atoi(tmp); - } - } - - if (body) { - tmp = lm_message_node_get_value(body); - if (tmp != NULL) { - jm.body = tmp; - } - } - - } else { - jm.sequence = 0; - jm.sender = ""; - jm.body = ""; - } - - return jm; -} - -LmHandlerResult -MessageHandler::_default(LmMessage* message) -{ - std::bitset< NUM_FLAGS >& status = this->_sm->session_data->status; - - // Pass groupchat messages with no Inkboard type off to the chat message handler - if (this->_getType(message) == UNKNOWN) { - if (lm_message_get_sub_type(message) == LM_MESSAGE_SUB_TYPE_GROUPCHAT) { - if (status[IN_CHATROOM] || status[CONNECTING_TO_CHAT]) { - return this->_sm->chat_handler()->parse(message); - } - } else { - return LM_HANDLER_RESULT_REMOVE_MESSAGE; - } - } - - if (this->_hasValidReceiveContext(message)) { - // Extract message data - JabberMessage msg = this->_extractData(message); - MessageType type = this->_getType(message); - - // Call message handler and return instruction value to Loudmouth - - return (*this->_received_message_processors[type])(type, msg); - } else { - g_warning("Default message handler received message in invalid receive context; discarding message."); - return LM_HANDLER_RESULT_REMOVE_MESSAGE; - } -} - -LmHandlerResult -MessageHandler::_presence(LmMessage* message) -{ - LmMessageNode* root; - LmMessageSubType msubtype; - gchar const* tmp; - std::string sender; - - SessionData* sd = this->_sm->session_data; - std::bitset< NUM_FLAGS >& status = this->_sm->session_data->status; - - root = lm_message_get_node(message); - if (root == NULL) { - return LM_HANDLER_RESULT_REMOVE_MESSAGE; - } - - tmp = lm_message_node_get_attribute(root, MESSAGE_FROM); - if (tmp == NULL) { - return LM_HANDLER_RESULT_REMOVE_MESSAGE; - } else { - sender = tmp; - } - - msubtype = lm_message_get_sub_type(message); - if (status[CONNECTING_TO_CHAT] || status[IN_CHATROOM]) { - this->_sm->chat_handler()->parse(message); - } else { - switch(msubtype) { - case LM_MESSAGE_SUB_TYPE_UNAVAILABLE: - // remove buddy from online roster - sd->buddyList.erase(sender); - - // if this buddy is in a 1-1 session with us, we need to exit - // the whiteboard - if (status[IN_WHITEBOARD] && !(status[IN_CHATROOM]) && strcasecmp(sender.c_str(), sd->recipient) == 0) { - status.set(IN_WHITEBOARD, 0); - this->_sm->userDisconnectedFromWhiteboard(sender); - this->_sm->closeSession(); - } - return LM_HANDLER_RESULT_REMOVE_MESSAGE; - - case LM_MESSAGE_SUB_TYPE_AVAILABLE: - // we don't want to insert an entry into a buddy list - // if it's our own presence - if (sender != this->_sm->session_data->jid.c_str()) { - sd->buddyList.insert(sender); - } - return LM_HANDLER_RESULT_REMOVE_MESSAGE; - default: - break; - } - } - return LM_HANDLER_RESULT_REMOVE_MESSAGE; -} - -LmHandlerResult -MessageHandler::_error(LmMessage* message) -{ - LmMessageNode* root; - LmMessageSubType msubtype; - - root = lm_message_get_node(message); - if (root != NULL) { - msubtype = lm_message_get_sub_type(message); - if (msubtype == LM_MESSAGE_SUB_TYPE_ERROR) { - gchar* error = g_strdup(lm_message_node_get_value(root)); - g_warning(error); - - // TODO: more robust error handling code - this->_sm->disconnectFromDocument(); - this->_sm->disconnectFromServer(); - this->_sm->connectionError(error); - } - } - - return LM_HANDLER_RESULT_REMOVE_MESSAGE; -} - -void -MessageHandler::_initializeContexts() -{ - initialize_received_message_contexts(_received_message_contexts); - message_contexts_initialized = true; -} - -void -MessageHandler::_initializeProcessors() -{ - initialize_received_message_processors(this->_sm, this->_received_message_processors); -} - -void -MessageHandler::_destructProcessors() -{ - destroy_received_message_processors(this->_received_message_processors); -} - - -char const* -MessageHandler::ink_type_to_string(gint ink_type) { - switch(ink_type) { - case Inkscape::Whiteboard::CHANGE_NOT_REPEATABLE: - return "CHANGE_NOT_REPEATABLE"; - case Inkscape::Whiteboard::CHANGE_REPEATABLE: - return "CHANGE_REPEATABLE"; - case Inkscape::Whiteboard::DUMMY_CHANGE: - return "DUMMY_CHANGE"; - case Inkscape::Whiteboard::CHANGE_COMMIT: - return "CHANGE_COMMIT"; - case Inkscape::Whiteboard::CONNECT_REQUEST_USER: - return "CONNECT_REQUEST_USER"; - case Inkscape::Whiteboard::CONNECT_REQUEST_RESPONSE_USER: - return "CONNECT_REQUEST_RESPONSE_USER"; - case Inkscape::Whiteboard::CONNECT_REQUEST_RESPONSE_CHAT: - return "CONNECT_REQUEST_RESPONSE_CHAT"; - case Inkscape::Whiteboard::DOCUMENT_SENDER_REQUEST: - return "DOCUMENT_SENDER_REQUEST"; - case Inkscape::Whiteboard::DOCUMENT_SENDER_REQUEST_RESPONSE: - return "DOCUMENT_SENDER_REQUEST_RESPONSE"; - case Inkscape::Whiteboard::DOCUMENT_REQUEST: - return "DOCUMENT_REQUEST"; - case Inkscape::Whiteboard::DOCUMENT_BEGIN: - return "DOCUMENT_BEGIN"; - case Inkscape::Whiteboard::DOCUMENT_END: - return "DOCUMENT_END"; - case Inkscape::Whiteboard::CONNECTED_SIGNAL: - return "CONNECTED_SIGNAL"; - case Inkscape::Whiteboard::DISCONNECTED_FROM_USER_SIGNAL: - return "DISCONNECTED_FROM_USER_SIGNAL"; - case Inkscape::Whiteboard::CONNECT_REQUEST_REFUSED_BY_PEER: - return "CONNECT_REQUEST_REFUSED_BY_PEER"; - case Inkscape::Whiteboard::UNSUPPORTED_PROTOCOL_VERSION: - return "UNSUPPORTED_PROTOCOL_VERSION"; - case Inkscape::Whiteboard::CHATROOM_SYNCHRONIZE_REQUEST: - return "CHATROOM_SYNCHRONIZE_REQUEST"; - case Inkscape::Whiteboard::CHATROOM_SYNCHRONIZE_RESPONSE: - return "CHATROOM_SYNCHRONIZE_RESPONSE"; - case Inkscape::Whiteboard::ALREADY_IN_SESSION: - return "ALREADY_IN_SESSION"; - default: - return "UNKNOWN"; - } -} - -} - -} - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/jabber_whiteboard/message-handler.h b/src/jabber_whiteboard/message-handler.h deleted file mode 100644 index 700665f74..000000000 --- a/src/jabber_whiteboard/message-handler.h +++ /dev/null @@ -1,88 +0,0 @@ -/** - * Whiteboard session manager - * Jabber message handling - * - * Authors: - * David Yip - * Steven Montgomery, Jonas Collaros (original C version) - * - * Copyright (c) 2004-2005 Authors - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#ifndef __WHITEBOARD_MESSAGE_HANDLER_H__ -#define __WHITEBOARD_MESSAGE_HANDLER_H__ - -extern "C" { -#include -} - -#include "jabber_whiteboard/defines.h" -#include "jabber_whiteboard/typedefs.h" -#include "jabber_whiteboard/message-contexts.h" - -namespace Inkscape { - -namespace Whiteboard { - -struct JabberMessage; -class SessionManager; - -/** - * Handles received Jabber messages. - */ -class MessageHandler { -public: - MessageHandler(SessionManager* sm); - ~MessageHandler(); - LmHandlerResult handle(LmMessage* message, HandlerMode mode); - - bool _hasValidReceiveContext(LmMessage* message); - - static char const* ink_type_to_string(gint ink_type); - -private: - static void _initializeContexts(); - - void _initializeProcessors(); - void _destructProcessors(); - - // Utilities - bool _isValidMessage(LmMessage* message); - MessageType _getType(LmMessage* message); - struct JabberMessage _extractData(LmMessage* message); - - - // Individual message handlers - LmHandlerResult _default(LmMessage* message); - LmHandlerResult _error(LmMessage* message); - LmHandlerResult _presence(LmMessage* message); - - // Message processors map -// MessageContextMap _received_message_contexts; - MessageProcessorMap _received_message_processors; - - SessionManager* _sm; - - // noncopyable, nonassignable - MessageHandler(MessageHandler const&); - MessageHandler& operator=(MessageHandler const&); -}; - -} - -} - -#endif - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/jabber_whiteboard/message-node.h b/src/jabber_whiteboard/message-node.h index 5e1b6a674..a9ed84e6f 100644 --- a/src/jabber_whiteboard/message-node.h +++ b/src/jabber_whiteboard/message-node.h @@ -126,9 +126,9 @@ private: Local Variables: mode:c++ c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + c-file-offsets:((innamespace . 0)(inline-open . 0)) indent-tabs-mode:nil fill-column:99 End: */ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : +// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/jabber_whiteboard/message-processors.cpp b/src/jabber_whiteboard/message-processors.cpp deleted file mode 100644 index f44224cbd..000000000 --- a/src/jabber_whiteboard/message-processors.cpp +++ /dev/null @@ -1,330 +0,0 @@ -/** - * Whiteboard session manager - * Jabber received message processors - * - * Authors: - * David Yip - * - * Copyright (c) 2005 Authors - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -extern "C" { -#include -} - -#include - -#include "xml/session.h" -#include "xml/document.h" - -#include "desktop-handles.h" -#include "document.h" -#include "message-stack.h" - -#include "jabber_whiteboard/undo-stack-observer.h" -#include "jabber_whiteboard/session-manager.h" -#include "jabber_whiteboard/message-node.h" -#include "jabber_whiteboard/message-queue.h" -#include "jabber_whiteboard/message-processors.h" -#include "jabber_whiteboard/typedefs.h" - -namespace Inkscape { - -namespace Whiteboard { - -// Message processors are here! - -// TODO: Remove unnecessary status checks from processors -- -// we do all of that in MessageHandler::_hasValidReceiveContext - -// ********************************************************************* -// ChangeHandler begin -// ********************************************************************* - -/** - * MessageProcessor for document change and event commit messages. - */ -struct ChangeHandler : public MessageProcessor { -public: - ~ChangeHandler() - { - - } - - ChangeHandler(SessionManager* sm) : MessageProcessor(sm) - { - - } - - LmHandlerResult - operator()(MessageType mode, JabberMessage& p) - { - MessageNode* msgNode; - bool chatroom = this->_sm->session_data->status[IN_CHATROOM]; - - ReceiveMessageQueue* rmq = this->_sm->session_data->receive_queues[p.sender]; - - if (rmq != NULL) { - switch (mode) { - case CHANGE_REPEATABLE: - case CHANGE_NOT_REPEATABLE: - case DOCUMENT_BEGIN: - msgNode = new MessageNode(p.sequence, p.sender, "", p.body, mode, false, chatroom); - rmq->insert(msgNode); - Inkscape::GC::release(msgNode); - break; - case DOCUMENT_END: - this->_sm->session_data->recipients_committed_queue.push_back(p.sender); - msgNode = new MessageNode(p.sequence, p.sender, "", p.body, mode, false, chatroom); - rmq->insert(msgNode); - Inkscape::GC::release(msgNode); - break; - case CHANGE_COMMIT: - this->_sm->session_data->recipients_committed_queue.push_back(p.sender); - msgNode = new MessageNode(p.sequence, p.sender, "", p.body, CHANGE_COMMIT, false, chatroom); - rmq->insert(msgNode); - Inkscape::GC::release(msgNode); - break; - case DUMMY_CHANGE: - default: - break; - } - } else { - g_warning("Received message from unknown sender %s", p.sender.c_str()); - } - - return LM_HANDLER_RESULT_REMOVE_MESSAGE; - } -}; -// ********************************************************************* -// ChangeHandler end -// ********************************************************************* - - -// ********************************************************************* -// ConnectRequestHandler begin -// ********************************************************************* -/** - * MessageProcessor for connection request messages. - */ -struct ConnectRequestHandler : public MessageProcessor { -public: - ~ConnectRequestHandler() - { - - } - - ConnectRequestHandler(SessionManager* sm) : MessageProcessor(sm) - { - - } - - LmHandlerResult - operator()(MessageType mode, JabberMessage& m) - { - std::bitset< NUM_FLAGS >& status = this->_sm->session_data->status; - switch(mode) { - case CONNECT_REQUEST_USER: - this->_sm->receiveConnectRequest(m.sender.c_str()); - break; - case CONNECT_REQUEST_RESPONSE_USER: - if (m.sequence == 0) { - this->_sm->receiveConnectRequestResponse(DECLINE_INVITATION, m.sender); - } else { // FIXME: this has got to be buggy... - this->_sm->setRecipient(m.sender.c_str()); - this->_sm->receiveConnectRequestResponse(ACCEPT_INVITATION, m.sender); - } - break; - case Inkscape::Whiteboard::CONNECTED_SIGNAL: - if (!status[IN_CHATROOM] && !status[CONNECTING_TO_CHAT] && !status[SYNCHRONIZING_WITH_CHAT] && !status[WAITING_TO_SYNC_TO_CHAT]) { - this->_sm->userConnectedToWhiteboard(m.sender.c_str()); - this->_sm->setRecipient(m.sender.c_str()); - } else { - sp_desktop_message_stack(this->_sm->desktop())->flashF(Inkscape::INFORMATION_MESSAGE, _("%s has joined the chatroom."), m.sender.c_str()); - } - break; - default: - break; - } - return LM_HANDLER_RESULT_REMOVE_MESSAGE; - } -}; -// ********************************************************************* -// ConnectRequestHandler end -// ********************************************************************* - - - - -// ********************************************************************* -// ConnectErrorHandler begin -// ********************************************************************* -/** - * MessageProcessor for connection error messages. - */ -struct ConnectErrorHandler : public MessageProcessor { -public: - ~ConnectErrorHandler() - { - - } - - ConnectErrorHandler(SessionManager* sm) : MessageProcessor(sm) - { - - } - - LmHandlerResult - operator()(MessageType mode, JabberMessage& m) - { - switch(mode) { - case CONNECT_REQUEST_REFUSED_BY_PEER: - if (this->_sm->session_data->status[WAITING_FOR_INVITE_RESPONSE]) { - this->_sm->receiveConnectRequestResponse(DECLINE_INVITATION, m.sender); - } - break; - case Inkscape::Whiteboard::ALREADY_IN_SESSION: - if (this->_sm->session_data->status[WAITING_FOR_INVITE_RESPONSE]) { - this->_sm->receiveConnectRequestResponse(PEER_ALREADY_IN_SESSION, m.sender); - } - break; - case Inkscape::Whiteboard::DISCONNECTED_FROM_USER_SIGNAL: - if (!this->_sm->session_data->status[IN_CHATROOM]) { - this->_sm->closeSession(); - this->_sm->userDisconnectedFromWhiteboard(m.sender.c_str()); - } - break; - default: - break; - } - return LM_HANDLER_RESULT_REMOVE_MESSAGE; - } -}; -// ********************************************************************* -// ConnectErrorHandler end -// ********************************************************************* - - - - -// ********************************************************************* -// ChatSynchronizeHandler begin -// ********************************************************************* -/** - * MessageProcessor for messages specific to chatroom synchronization. - */ -struct ChatSynchronizeHandler : public MessageProcessor { -public: - ~ChatSynchronizeHandler() - { - - } - - ChatSynchronizeHandler(SessionManager* sm) : MessageProcessor(sm) - { - - } - - LmHandlerResult - operator()(MessageType mode, JabberMessage& m) - { - switch(mode) { - case CONNECT_REQUEST_RESPONSE_CHAT: - this->_sm->receiveConnectRequestResponseChat(m.sender.c_str()); - break; - case CHATROOM_SYNCHRONIZE_REQUEST: - if (this->_sm->session_data->status[IN_CHATROOM] && this->_sm->session_data->status[IN_WHITEBOARD]) { - // Send response. Everyone in the chatroom will do this, - // but the client will accept only one response. - // The response is sent privately to the client - // - this->_sm->sendMessage(CHATROOM_SYNCHRONIZE_RESPONSE, this->_sm->session_data->sequence_number, "", m.sender.c_str(), false); - } - break; - case CHATROOM_SYNCHRONIZE_RESPONSE: - if (m.sequence != 0) { - // Set sequence number - this->_sm->session_data->sequence_number = m.sequence; - - // Set status flags - this->_sm->session_data->status.set(WAITING_TO_SYNC_TO_CHAT, 0); - this->_sm->session_data->status.set(SYNCHRONIZING_WITH_CHAT, 1); - - // Send document synchronization request - this->_sm->clearDocument(); - this->_sm->setupInkscapeInterface(); - this->_sm->sendMessage(CONNECT_REQUEST_RESPONSE_CHAT, m.sequence, "", m.sender.c_str(), false); - } else { - this->_sm->sendMessage(CHATROOM_SYNCHRONIZE_REQUEST, 0, "", this->_sm->session_data->recipient, true); - } - break; - default: - break; - } - return LM_HANDLER_RESULT_REMOVE_MESSAGE; - } -}; -// ********************************************************************* -// ChatSynchronizeHandler end -// ********************************************************************* - - - - -// ********************************************************************* -// Initializer -// ********************************************************************* -void -initialize_received_message_processors(SessionManager* sm, MessageProcessorMap& mpm) -{ - MessageProcessor* ch = new ChangeHandler(sm); - MessageProcessor* crh = new ConnectRequestHandler(sm); - MessageProcessor* ceh = new ConnectErrorHandler(sm); - MessageProcessor* csh = new ChatSynchronizeHandler(sm); - - mpm[CHANGE_REPEATABLE] = ch; - mpm[CHANGE_NOT_REPEATABLE] = ch; - mpm[DUMMY_CHANGE] = ch; - mpm[CHANGE_COMMIT] = ch; - mpm[DOCUMENT_BEGIN] = ch; - mpm[DOCUMENT_END] = ch; - - mpm[CONNECT_REQUEST_USER] = crh; - mpm[CONNECT_REQUEST_RESPONSE_USER] = crh; - mpm[CONNECTED_SIGNAL] = crh; - - mpm[CONNECT_REQUEST_REFUSED_BY_PEER] = ceh; - mpm[ALREADY_IN_SESSION] = ceh; - mpm[DISCONNECTED_FROM_USER_SIGNAL] = ceh; - - mpm[CONNECT_REQUEST_RESPONSE_CHAT] = csh; - mpm[CHATROOM_SYNCHRONIZE_REQUEST] = csh; - mpm[CHATROOM_SYNCHRONIZE_RESPONSE] = csh; -} - -/* - * This function is provided solely for convenience and style. You can, of course, - * delete every MessageProcessor in the map with your own loop. - */ -void -destroy_received_message_processors(MessageProcessorMap& mpm) -{ - mpm.clear(); -} - -} - -} - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/jabber_whiteboard/message-processors.h b/src/jabber_whiteboard/message-processors.h deleted file mode 100644 index 8b0887444..000000000 --- a/src/jabber_whiteboard/message-processors.h +++ /dev/null @@ -1,176 +0,0 @@ -/** - * Whiteboard session manager - * Jabber received message processors - * - * Authors: - * David Yip - * - * Copyright (c) 2005 Authors - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#ifndef __WHITEBOARD_MESSAGE_PROCESSORS_H__ -#define __WHITEBOARD_MESSAGE_PROCESSORS_H__ - -#include "jabber_whiteboard/typedefs.h" - -#include "gc-managed.h" -#include "gc-finalized.h" - -namespace Inkscape { - -namespace Whiteboard { - -class SessionManager; - -// Processor forward declarations -struct ChangeHandler; -struct DocumentSignalHandler; -struct ConnectRequestHandler; -struct ConnectErrorHandler; -struct ChatSynchronizeHandler; - -/** - * Encapsulates a pointer to an LmMessage along with additional information, - * such as the message's sequence number, its sender, and its body. - * - * All of the above data members can be extracted directly from the LmMessage; - * they are provided for convenience. - */ -struct JabberMessage { -public: - /** - * Constructor. - * - * The constructor attaches a reference to the LmMessage to prevent Loudmouth from - * freeing the message. - */ - JabberMessage(LmMessage* m) : message(m), sequence(0) - { - lm_message_ref(this->message); - } - - /** - * Destructor. - * - * The destructor deletes a reference to the LmMessage, which, assuming all other - * references have been deleted, will allow Loudmouth to free the LmMessage object. - */ - ~JabberMessage() - { - lm_message_unref(this->message); - } - - - // TODO: Hide, or, better, remove this. There's no real reason why it should be here, - // and it allows for the possibility of reference count-induced memory leaks. - /** - * Pointer to original Loudmouth message object. - */ - LmMessage* message; - - /** - * Sequence number of this message. - */ - unsigned int sequence; - - /** - * The JID of this message's sender. - */ - std::string sender; - - /** - * The body of this message. - */ - Glib::ustring body; - -private: - // noncopyable, nonassignable (for now, anyway...) -// JabberMessage(JabberMessage const&); -// JabberMessage& operator=(JabberMessage const&); -}; - -/** - * A MessageProcessor is a functor that is associated with one or more Inkboard message types. - * When an Inkboard client receives an Inkboard message, it passes it to the appropriate - * MessageProcessor. - */ -struct MessageProcessor : public GC::Managed<>, public GC::Finalized { -public: - virtual ~MessageProcessor() - { - - } - - /** - * Functor action operator. - * - * \param mode The type of the message being processed. - * \param m A reference to the JabberMessage encapsulating the received Jabber message. - */ - virtual LmHandlerResult operator()(MessageType mode, JabberMessage& m) = 0; - - /** - * Constructor. - * - * \param sm The SessionManager with which a MessageProcessor instance is associated. - */ - MessageProcessor(SessionManager* sm) : _sm(sm) { } -protected: - /** - * Pointer to the associated SessionManager object. - */ - SessionManager *_sm; - -private: - // noncopyable, nonassignable - MessageProcessor(MessageProcessor const&); - MessageProcessor& operator=(MessageProcessor const&); -}; - -/* -struct ProcessorShell : public GC::Managed<>, public std::binary_function< MessageType, JabberMessage, LmHandlerResult > { -public: - ProcessorShell(MessageProcessor* mpm) : _mpm(mpm) { } - - LmHandlerResult operator()(MessageType type, JabberMessage msg) - { - return (*this->_mpm)(type, msg); - } -private: - MessageProcessor* _mpm; -}; -*/ - -/** - * Initialize the message -> MessageProcessor map. - * - * \param sm The SessionManager with which all created MessageProcessors should be associated with. - * \param mpm Reference to the MessageProcessorMap to initialize. - */ -void initialize_received_message_processors(SessionManager* sm, MessageProcessorMap& mpm); - -/** - * Clean up the message -> MessageProcessor map. - * - * \param mpm Reference to the MessageProcessorMap to clean up. - */ -void destroy_received_message_processors(MessageProcessorMap& mpm); - -} - -} - -#endif - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/jabber_whiteboard/message-queue.cpp b/src/jabber_whiteboard/message-queue.cpp index 4bd1e9ab1..b2c5d28d4 100644 --- a/src/jabber_whiteboard/message-queue.cpp +++ b/src/jabber_whiteboard/message-queue.cpp @@ -22,117 +22,117 @@ namespace Inkscape { namespace Whiteboard { -MessageQueue::MessageQueue(SessionManager* sm) : _sm(sm) -{ - -} - -MessageQueue::~MessageQueue() -{ - -} +//################################### +//# MESSAGE QUEUE +//################################### MessageNode* MessageQueue::first() { - return this->_queue.front(); + return _queue.front(); } void MessageQueue::popFront() { - this->_queue.pop_front(); -// g_log(NULL, G_LOG_LEVEL_DEBUG, "Removed element, queue size (for %s): %u", this->_sm->session_data->jid, this->_queue.size()); + _queue.pop_front(); + //g_log(NULL, G_LOG_LEVEL_DEBUG, + // "Removed element, queue size (for %s): %u", + //lm_connection_get_jid(this->_sm->session_data->connection), this->_queue.size()); } unsigned int MessageQueue::size() { - return this->_queue.size(); + return _queue.size(); } bool MessageQueue::empty() { - return this->_queue.empty(); + return _queue.empty(); } void MessageQueue::clear() { - this->_queue.clear(); + _queue.clear(); } -ReceiveMessageQueue::ReceiveMessageQueue(SessionManager* sm) : MessageQueue(sm), _latest(0) -{ -} +//################################### +//# RECEIVE MESSAGE QUEUE +//################################### void ReceiveMessageQueue::insert(MessageNode* msg) { - // Check to see if the incoming message has a sequence number - // lower than the sequence number of the latest message processed - // by this message's sender. If it does, drop the message and produce - // a warning. - if (msg->sequence() < this->_latest) { - g_warning("Received late message (message sequence number is %u, but latest processed message had sequence number %u). Discarding message; session may be desynchronized.", msg->sequence(), this->_latest); - return; - } - - // Otherwise, it is safe to insert this message. -// Inkscape::GC::anchor(msg); - this->_queue.push_back(msg); - sp_desktop_message_stack(this->_sm->desktop())->flashF(Inkscape::NORMAL_MESSAGE, - ngettext("%u change in receive queue.", - "%u changes in receive queue.", - this->_queue.size()), - this->_queue.size()); -// g_log(NULL, G_LOG_LEVEL_DEBUG, "Receive queue size (for %s): %u", this->_sm->session_data->jid, this->_queue.size()); + // Check to see if the incoming message has a sequence number + // lower than the sequence number of the latest message processed + // by this message's sender. If it does, drop the message and produce + // a warning. + if (msg->sequence() < _latest) { + g_warning(_("Received late message (message sequence number is %u, but latest processed message had sequence number %u). Discarding message; session may be desynchronized."), msg->sequence(), this->_latest); + return; + } + + // Otherwise, it is safe to insert this message. + //Inkscape::GC::anchor(msg); + _queue.push_back(msg); + /* + SP_DT_MSGSTACK(_sm->getDesktop())->flashF( + Inkscape::NORMAL_MESSAGE, + _("%u changes queued in receive queue."), + _queue.size()); + */ + //g_log(NULL, G_LOG_LEVEL_DEBUG, "Receive queue size (for %s): %u", + // lm_connection_get_jid(this->_sm->session_data->connection), this->_queue.size()); } void ReceiveMessageQueue::insertDeferred(MessageNode* msg) { - this->_deferred.push_back(msg); + _deferred.push_back(msg); } void ReceiveMessageQueue::setLatestProcessedPacket(unsigned int seq) { - this->_latest = seq; + _latest = seq; } -SendMessageQueue::SendMessageQueue(SessionManager* sm) : MessageQueue(sm) -{ - -} +//################################### +//# SEND MESSAGE QUEUE +//################################### void SendMessageQueue::insert(MessageNode* msg) { -// Inkscape::GC::anchor(msg); - this->_queue.push_back(msg); - sp_desktop_message_stack(this->_sm->desktop())->flashF(Inkscape::NORMAL_MESSAGE, - ngettext("%u change in send queue.", - "%u changes in send queue.", - this->_queue.size()), - this->_queue.size()); -// g_log(NULL, G_LOG_LEVEL_DEBUG, "Send queue size (for %s): %u", this->_sm->session_data->jid, this->_queue.size()); + //Inkscape::GC::anchor(msg); + _queue.push_back(msg); + /* + SP_DT_MSGSTACK(_sm->getDesktop())->flashF( + Inkscape::NORMAL_MESSAGE, + _("%u changes queued in send queue."), + _queue.size()); + */ + //g_log(NULL, G_LOG_LEVEL_DEBUG, "Send queue size (for %s): %u", + // lm_connection_get_jid(this->_sm->session_data->connection), + //this->_queue.size()); } -} +} // namespace Whiteboard -} +} // namespace Inkscape /* Local Variables: mode:c++ c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + c-file-offsets:((innamespace . 0)(inline-open . 0)) indent-tabs-mode:nil fill-column:99 End: */ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : +// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/jabber_whiteboard/message-queue.h b/src/jabber_whiteboard/message-queue.h index e607ed81b..700a53bae 100644 --- a/src/jabber_whiteboard/message-queue.h +++ b/src/jabber_whiteboard/message-queue.h @@ -16,7 +16,6 @@ #include #include "gc-alloc.h" - #include "gc-managed.h" #include "util/list-container.h" @@ -25,7 +24,6 @@ namespace Inkscape { namespace Whiteboard { -class SessionManager; class MessageNode; /// Definition of the basic message node queue @@ -50,37 +48,40 @@ public: * * \param sm The SessionManager to associate this MessageQueue with. */ - MessageQueue(SessionManager *sm); - virtual ~MessageQueue(); + MessageQueue() { } + virtual ~MessageQueue() + { + this->_queue.clear(); + } /** * Retrieve the MessageNode at the front of the queue. */ - MessageNode* first(); + virtual MessageNode* first(); /** * Remove the element at the front of the queue. */ - void popFront(); + virtual void popFront(); /** * Get the size of the queue. * * \return The size of the queue. */ - unsigned int size(); + virtual unsigned int size(); /** * Returns whether or not the queue is empty. * * \return Whether or not the queue is empty. */ - bool empty(); + virtual bool empty(); /** * Clear the queue. */ - void clear(); + virtual void clear(); /** * The insertion method. The insertion procedure must be defined @@ -95,11 +96,6 @@ protected: * Implementation of the queue. */ MessageQueueBuffer _queue; - - /** - * Pointer to SessionManager. - */ - SessionManager* _sm; }; @@ -111,7 +107,7 @@ protected: */ class ReceiveMessageQueue : public MessageQueue, public GC::Managed<> { public: - ReceiveMessageQueue(SessionManager* sm); + ReceiveMessageQueue() : _latest(0) { } /** * Insert a message into the queue. @@ -149,7 +145,7 @@ private: */ class SendMessageQueue : public MessageQueue { public: - SendMessageQueue(SessionManager* sm); + SendMessageQueue() { } /** * Insert a message into the queue. @@ -169,9 +165,9 @@ public: Local Variables: mode:c++ c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + c-file-offsets:((innamespace . 0)(inline-open . 0)) indent-tabs-mode:nil fill-column:99 End: */ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : +// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/jabber_whiteboard/message-tags.cpp b/src/jabber_whiteboard/message-tags.cpp index a46c27356..c82cd0c62 100644 --- a/src/jabber_whiteboard/message-tags.cpp +++ b/src/jabber_whiteboard/message-tags.cpp @@ -59,9 +59,9 @@ const char* MESSAGE_PROTOCOL_VER = "inkboard-protocol"; Local Variables: mode:c++ c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + c-file-offsets:((innamespace . 0)(inline-open . 0)) indent-tabs-mode:nil fill-column:99 End: */ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : +// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/jabber_whiteboard/message-tags.h b/src/jabber_whiteboard/message-tags.h index 5cbb8a079..de14778b1 100644 --- a/src/jabber_whiteboard/message-tags.h +++ b/src/jabber_whiteboard/message-tags.h @@ -131,9 +131,9 @@ extern char const* MESSAGE_PROTOCOL_VER; Local Variables: mode:c++ c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + c-file-offsets:((innamespace . 0)(inline-open . 0)) indent-tabs-mode:nil fill-column:99 End: */ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : +// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/jabber_whiteboard/message-utilities.cpp b/src/jabber_whiteboard/message-utilities.cpp index c10521b61..095c6bab3 100644 --- a/src/jabber_whiteboard/message-utilities.cpp +++ b/src/jabber_whiteboard/message-utilities.cpp @@ -39,10 +39,16 @@ namespace Whiteboard { // // only_collect_nodes defaults to false because most invocations of this method also use the message string. void -MessageUtilities::newObjectMessage(Glib::ustring* msgbuf, KeyToNodeMap& newidsbuf, NodeToKeyMap& newnodesbuf, NewChildObjectMessageList& childmsgbuf, XMLNodeTracker* xmt, Inkscape::XML::Node const* node, bool only_collect_nodes, bool collect_children) +MessageUtilities::newObjectMessage(Glib::ustring &msgbuf, + KeyNodeTable& newnodesbuf, + NewChildObjectMessageList& childmsgbuf, + XMLNodeTracker* xmt, + Inkscape::XML::Node const* node, + bool only_collect_nodes, + bool collect_children) { // Initialize pointers - std::string id, refid, parentid; + Glib::ustring id, refid, parentid; gchar const* name = NULL; XML::Node* parent = NULL; @@ -50,16 +56,17 @@ MessageUtilities::newObjectMessage(Glib::ustring* msgbuf, KeyToNodeMap& newidsbu bool only_add_children = false; + //g_log(NULL, G_LOG_LEVEL_DEBUG, "newObjectMessage: processing node %p of type %s", node, NodeUtilities::nodeTypeToString(*node).data()); if (node != NULL) { parent = sp_repr_parent(node); if (parent != NULL) { + //g_log(NULL, G_LOG_LEVEL_DEBUG, "Attempting to find ID for parent node %p (on node %p)", parent, node); parentid = NodeUtilities::findNodeID(*parent, xmt, newnodesbuf); if (parentid.empty()) { g_warning("Parent %p is not being tracked, creating new ID", parent); parentid = xmt->generateKey(); - newidsbuf[parentid] = parent; - newnodesbuf[parent] = parentid; + newnodesbuf.put(parentid, parent); } if ( node != parent->firstChild() && parent != NULL ) { @@ -71,12 +78,12 @@ MessageUtilities::newObjectMessage(Glib::ustring* msgbuf, KeyToNodeMap& newidsbu } if (ref != NULL) { + //g_log(NULL, G_LOG_LEVEL_DEBUG, "Attempting to find ID for ref node %p (on %p)", ref, node); refid = NodeUtilities::findNodeID(*ref, xmt, newnodesbuf); if (refid.empty() && ref != NULL) { g_warning("Ref %p is not being tracked, creating new ID", ref); refid = xmt->generateKey(); - newidsbuf[refid] = ref; - newnodesbuf[ref] = refid; + newnodesbuf.put(refid, ref); } } @@ -88,18 +95,19 @@ MessageUtilities::newObjectMessage(Glib::ustring* msgbuf, KeyToNodeMap& newidsbu if (!xmt->isSpecialNode(node->name())) { if (!xmt->isTracking(*node)) { id = xmt->generateKey(); - newidsbuf[id] = node; - newnodesbuf[node] = id; + //g_log(NULL, G_LOG_LEVEL_DEBUG, "Inserting %p with id %s", node, id.c_str()); + newnodesbuf.put(id, node); } else { id = xmt->get(*node); + //g_log(NULL, G_LOG_LEVEL_DEBUG, "Found id %s for node %p; not inserting into new nodes buffers.", id.c_str(), node); } } else { + //g_log(NULL, G_LOG_LEVEL_DEBUG, "Processing special node; not generating key"); id = xmt->get(*node); if (id.empty()) { - g_warning("Node %p (name %s) is a special node, but it could not be found in the node tracker (possible unexpected duplicate?) Generating unique ID anyway.", node, node->name()); + g_warning(_("Node %p (name %s) is a special node, but it could not be found in the node tracker (possible unexpected duplicate?) Generating unique ID anyway."), node, node->name()); id = xmt->generateKey(); - newidsbuf[id] = node; - newnodesbuf[node] = id; + newnodesbuf.put(id, node); } only_add_children = true; } @@ -108,92 +116,85 @@ MessageUtilities::newObjectMessage(Glib::ustring* msgbuf, KeyToNodeMap& newidsbu // don't process the given node. if( !only_add_children && !id.empty() && msgbuf != NULL && !only_collect_nodes ) { // - (*msgbuf) = (*msgbuf) + "<" + MESSAGE_NEWOBJ + ">"; + msgbuf = msgbuf + "<" + MESSAGE_NEWOBJ + ">"; // - (*msgbuf) = (*msgbuf) + "<" + MESSAGE_PARENT + ">"; + msgbuf = msgbuf + "<" + MESSAGE_PARENT + ">"; if(!parentid.empty()) { - (*msgbuf) += parentid; + msgbuf += parentid; } // id - (*msgbuf) = (*msgbuf) + ""; + msgbuf = msgbuf + ""; - (*msgbuf) = (*msgbuf) + "<" + MESSAGE_CHILD + ">"; - (*msgbuf) += id; + msgbuf = msgbuf + "<" + MESSAGE_CHILD + ">"; + msgbuf += id; - (*msgbuf) = (*msgbuf) + ""; + msgbuf = msgbuf + ""; if(!refid.empty()) { // refid - (*msgbuf) = (*msgbuf) + "<" + MESSAGE_REF + ">"; + msgbuf = msgbuf + "<" + MESSAGE_REF + ">"; - (*msgbuf) += refid; + msgbuf += refid; - (*msgbuf) = (*msgbuf) + ""; + msgbuf = msgbuf + ""; } // *node.type() - (*msgbuf) = (*msgbuf) + "<" + MESSAGE_NODETYPE + ">" + NodeUtilities::nodeTypeToString(*node); - (*msgbuf) = (*msgbuf) + ""; + msgbuf = msgbuf + "<" + MESSAGE_NODETYPE + ">" + NodeUtilities::nodeTypeToString(*node); + msgbuf = msgbuf + ""; if (node->content() != NULL) { // node->content() - (*msgbuf) = (*msgbuf) + "<" + MESSAGE_CONTENT + ">" + node->content(); - (*msgbuf) = (*msgbuf) + ""; + msgbuf = msgbuf + "<" + MESSAGE_CONTENT + ">" + node->content(); + msgbuf = msgbuf + ""; } // name - (*msgbuf) = (*msgbuf) + "<" + MESSAGE_NAME + ">"; + msgbuf = msgbuf + "<" + MESSAGE_NAME + ">"; - if( name != NULL ) { - (*msgbuf) += name; - } + if( name != NULL ) + msgbuf += name; - (*msgbuf) = (*msgbuf) + ""; + msgbuf = msgbuf + ""; // - (*msgbuf) = (*msgbuf) + ""; + msgbuf = msgbuf + ""; } else if (id.empty()) { // if ID is NULL, then we have a real problem -- we were not able to find a key // nor generate one. The only thing we can really do here is abort, since we have // no way to let the other client(s) uniquely identify this object. - /* FIXME: If this indicates a programming bug, then don't request translation with - * _(...): it is most useful in untranslated form so that developers may search for - * it when someone reports it in a bug report (as we want users to do for all bugs, - * as indicated by it being a g_warning string). - * - * Otherwise, if it is not a programming bug but a network error or a bug in the - * remote peer (perhaps running different software) or whatever, then present it in - * an alert box, and avoid use of technical jargon `NULL'. - */ g_warning(_("ID for new object is NULL even after generation and lookup attempts: the new object will NOT be sent, nor will any of its child objects!")); return; } else { } + //g_log(NULL, G_LOG_LEVEL_DEBUG, "Generated message"); if (!only_collect_nodes && msgbuf != NULL && !id.empty()) { // Collect new object's attributes and append them onto the msgbuf Inkscape::Util::List attrlist = node->attributeList(); for(; attrlist; attrlist++) { - MessageUtilities::objectChangeMessage(msgbuf, xmt, id, g_quark_to_string(attrlist->key), NULL, attrlist->value, false); + MessageUtilities::objectChangeMessage(msgbuf, + xmt, id, g_quark_to_string(attrlist->key), + NULL, attrlist->value, false); } } - if (!only_collect_nodes) { - childmsgbuf.push_back(*msgbuf); - } + if (!only_collect_nodes) + childmsgbuf.push_back(msgbuf); if (!id.empty() && collect_children) { Glib::ustring childbuf; // Collect any child objects of this new object for ( Inkscape::XML::Node const *child = node->firstChild(); child != NULL; child = child->next() ) { childbuf.clear(); - MessageUtilities::newObjectMessage(&childbuf, newidsbuf, newnodesbuf, childmsgbuf, xmt, child, only_collect_nodes); + MessageUtilities::newObjectMessage(childbuf, + newnodesbuf, childmsgbuf, xmt, child, only_collect_nodes); if (!only_collect_nodes) { // we're recursing down the tree, so we're picking up child nodes first // and parents afterwards @@ -205,232 +206,251 @@ MessageUtilities::newObjectMessage(Glib::ustring* msgbuf, KeyToNodeMap& newidsbu } void -MessageUtilities::objectChangeMessage(ustring* msgbuf, XMLNodeTracker* xmt, std::string const id, gchar const* key, gchar const* oldval, gchar const* newval, bool is_interactive) +MessageUtilities::objectChangeMessage(Glib::ustring &msgbuf, + XMLNodeTracker* xmt, + const Glib::ustring &id, + gchar const* key, + gchar const* oldval, + gchar const* newval, + bool is_interactive) { - // Construct message - - // id - (*msgbuf) = (*msgbuf) + "<" + MESSAGE_CHANGE + ">"; - (*msgbuf) = (*msgbuf) + "<" + MESSAGE_ID + ">"; - (*msgbuf) += id; - (*msgbuf) = (*msgbuf) + ""; - - // key - (*msgbuf) = (*msgbuf) + "<" + MESSAGE_KEY + ">"; - if (key != NULL) { - (*msgbuf) += key; - } - (*msgbuf) = (*msgbuf) + ""; - - // oldval - (*msgbuf) = (*msgbuf) + "<" + MESSAGE_OLDVAL + ">"; - if (oldval != NULL) { - (*msgbuf) += oldval; - } - (*msgbuf) = (*msgbuf) + ""; - - // newval - (*msgbuf) = (*msgbuf) + "<" + MESSAGE_NEWVAL + ">"; - if (newval != NULL) { - (*msgbuf) += newval; - } - (*msgbuf) = (*msgbuf) + ""; - - // is_interactive - (*msgbuf) = (*msgbuf) + "<" + MESSAGE_ISINTERACTIVE + ">"; - if (is_interactive) { - (*msgbuf) += "true"; - } else { - (*msgbuf) += "false"; - } - (*msgbuf) = (*msgbuf) + ""; - - // - (*msgbuf) = (*msgbuf) + ""; + // Construct message + + // id + msgbuf = msgbuf + "<" + MESSAGE_CHANGE + ">"; + msgbuf = msgbuf + "<" + MESSAGE_ID + ">"; + msgbuf += id; + msgbuf = msgbuf + ""; + + // key + msgbuf = msgbuf + "<" + MESSAGE_KEY + ">"; + if (key != NULL) { + msgbuf += key; + } + msgbuf = msgbuf + ""; + + // oldval + msgbuf = msgbuf + "<" + MESSAGE_OLDVAL + ">"; + if (oldval != NULL) { + msgbuf += oldval; + } + msgbuf = msgbuf + ""; + + // newval + msgbuf = msgbuf + "<" + MESSAGE_NEWVAL + ">"; + if (newval != NULL) { + msgbuf += newval; + } + msgbuf = msgbuf + ""; + + // is_interactive + msgbuf = msgbuf + "<" + MESSAGE_ISINTERACTIVE + ">"; + if (is_interactive) { + msgbuf += "true"; + } else { + msgbuf += "false"; + } + msgbuf = msgbuf + ""; + + // + msgbuf = msgbuf + ""; } void -MessageUtilities::objectDeleteMessage(Glib::ustring* msgbuf, XMLNodeTracker* xmt, Inkscape::XML::Node const& parent, Inkscape::XML::Node const& child, Inkscape::XML::Node const* prev) +MessageUtilities::objectDeleteMessage(Glib::ustring &msgbuf, + XMLNodeTracker* xmt, + Inkscape::XML::Node const& parent, + Inkscape::XML::Node const& child, + Inkscape::XML::Node const* prev) { - /* - gchar const* parentid = NULL; - gchar const* previd = NULL; - gchar const* childid = NULL; - - childid = child.attribute("id"); - parentid = parent.attribute("id"); - if (prev != NULL) { - previd = prev->attribute("id"); - }*/ - - std::string parentid, previd, childid; - - childid = xmt->get(child); - parentid = xmt->get(parent); - previd = xmt->get(*prev); - - if (!childid.empty()) { - // parentid - (*msgbuf) = (*msgbuf) + "<" + MESSAGE_DELETE + ">" + "<" + MESSAGE_PARENT + ">"; - if (!parentid.empty()) { - (*msgbuf) += parentid; - } - (*msgbuf) = (*msgbuf) + ""; - - // childid - (*msgbuf) = (*msgbuf) + "<" + MESSAGE_CHILD + ">"; - if (!childid.empty()) { - (*msgbuf) += childid; - } - (*msgbuf) = (*msgbuf) + ""; - - // previd - (*msgbuf) = (*msgbuf) + "<" + MESSAGE_REF + ">"; - if (!previd.empty()) { - (*msgbuf) += previd; - } - (*msgbuf) = (*msgbuf) + ""; - - // - (*msgbuf) = (*msgbuf) + ""; - } + /* + gchar const* parentid = NULL; + gchar const* previd = NULL; + gchar const* childid = NULL; + + childid = child.attribute("id"); + parentid = parent.attribute("id"); + if (prev != NULL) { + previd = prev->attribute("id"); + }*/ + + Glib::ustring parentid, previd, childid; + + childid = xmt->get(child); + parentid = xmt->get(parent); + previd = xmt->get(*prev); + + if (childid.empty()) + return; + + + // parentid + msgbuf = msgbuf + "<" + MESSAGE_DELETE + ">" + "<" + MESSAGE_PARENT + ">"; + if (!parentid.empty()) { + msgbuf += parentid; + } + msgbuf = msgbuf + ""; + + // childid + msgbuf = msgbuf + "<" + MESSAGE_CHILD + ">"; + if (!childid.empty()) { + msgbuf += childid; + } + msgbuf = msgbuf + ""; + + // previd + msgbuf = msgbuf + "<" + MESSAGE_REF + ">"; + if (!previd.empty()) { + msgbuf += previd; + } + msgbuf = msgbuf + ""; + + // + msgbuf = msgbuf + ""; } void -MessageUtilities::contentChangeMessage(Glib::ustring& msgbuf, std::string const nodeid, Util::ptr_shared old_value, Util::ptr_shared new_value) +MessageUtilities::contentChangeMessage(Glib::ustring& msgbuf, + const Glib::ustring &nodeid, + Util::ptr_shared old_value, + Util::ptr_shared new_value) { - if (!nodeid.empty()) { - // - msgbuf = msgbuf + "<" + MESSAGE_NODECONTENT + ">"; - - // nodeid - msgbuf = msgbuf + "<" + MESSAGE_ID + ">"; - msgbuf += nodeid; - msgbuf = msgbuf + ""; - - // old_value - msgbuf = msgbuf + "<" + MESSAGE_OLDVAL + ">"; - msgbuf += old_value.pointer(); - msgbuf = msgbuf + ""; - - // new_value - msgbuf = msgbuf + "<" + MESSAGE_NEWVAL + ">"; - msgbuf += new_value.pointer(); - msgbuf = msgbuf + ""; - - // - msgbuf = msgbuf + ""; - } + if (nodeid.empty()) + return; + + // + msgbuf = msgbuf + "<" + MESSAGE_NODECONTENT + ">"; + + // nodeid + msgbuf = msgbuf + "<" + MESSAGE_ID + ">"; + msgbuf += nodeid; + msgbuf = msgbuf + ""; + + // old_value + msgbuf = msgbuf + "<" + MESSAGE_OLDVAL + ">"; + msgbuf += old_value.pointer(); + msgbuf = msgbuf + ""; + + // new_value + msgbuf = msgbuf + "<" + MESSAGE_NEWVAL + ">"; + msgbuf += new_value.pointer(); + msgbuf = msgbuf + ""; + + // + msgbuf = msgbuf + ""; } void -MessageUtilities::childOrderChangeMessage(Glib::ustring& msgbuf, std::string const childid, std::string const oldprevid, std::string const newprevid) +MessageUtilities::childOrderChangeMessage(Glib::ustring& msgbuf, + const Glib::ustring &childid, + const Glib::ustring &oldprevid, + const Glib::ustring &newprevid) { - if (!childid.empty()) { - // - msgbuf = msgbuf + "<" + MESSAGE_ORDERCHANGE + ">"; + if (childid.empty()) + return; + + // + msgbuf = msgbuf + "<" + MESSAGE_ORDERCHANGE + ">"; + + // nodeid + msgbuf = msgbuf + "<" + MESSAGE_CHILD + ">"; + msgbuf += childid; + msgbuf = msgbuf + ""; + + // oldprevid + /* + msgbuf = msgbuf + "<" + MESSAGE_OLDVAL + ">"; + msgbuf += (*oldprevid); + msgbuf = msgbuf + ""; + */ + + // newprevid + msgbuf = msgbuf + "<" + MESSAGE_NEWVAL + ">"; + msgbuf += newprevid; + msgbuf = msgbuf + ""; + + // + msgbuf = msgbuf + ""; - // nodeid - msgbuf = msgbuf + "<" + MESSAGE_CHILD + ">"; - msgbuf += childid; - msgbuf = msgbuf + ""; - - // oldprevid - /* - msgbuf = msgbuf + "<" + MESSAGE_OLDVAL + ">"; - msgbuf += (*oldprevid); - msgbuf = msgbuf + ""; - */ - - // newprevid - msgbuf = msgbuf + "<" + MESSAGE_NEWVAL + ">"; - msgbuf += newprevid; - msgbuf = msgbuf + ""; - - // - msgbuf = msgbuf + ""; - } } bool -MessageUtilities::getFirstMessageTag(struct Node& buf, Glib::ustring const& msg) +MessageUtilities::getFirstMessageTag(struct Node& buf, const Glib::ustring &msg) { - if (msg.empty()) { - return false; - } - - // See if we have a valid start tag, i.e. < ... >. If we do, - // continue; if not, stop and return NULL. - // - // find_first_of returns ULONG_MAX when it cannot find the first - // instance of the given character. - - Glib::ustring::size_type startDelim = msg.find_first_of('<'); - if (startDelim != ULONG_MAX) { - Glib::ustring::size_type endDelim = msg.find_first_of('>'); - if (endDelim != ULONG_MAX) { - if (endDelim > startDelim) { - buf.tag = msg.substr(startDelim+1, (endDelim-startDelim)-1); - if (buf.tag.find_first_of('/') == ULONG_MAX) { // start tags should not be end tags - - - // construct end tag () - Glib::ustring endTag(buf.tag); - endTag.insert(0, "/"); - - Glib::ustring::size_type endTagLoc = msg.find(endTag, endDelim); - if (endTagLoc != ULONG_MAX) { - buf.data = msg.substr(endDelim+1, ((endTagLoc - 1) - (endDelim + 1))); - buf.next_pos = endTagLoc + endTag.length() + 1; - - return true; - } - } - } - } - } - - return false; + if (msg.empty()) + return false; + + // See if we have a valid start tag, i.e. < ... >. If we do, + // continue; if not, stop and return NULL. + // + // find_first_of returns ULONG_MAX when it cannot find the first + // instance of the given character. + + Glib::ustring::size_type startDelim = msg.find_first_of('<'); + if (startDelim != ULONG_MAX) { + Glib::ustring::size_type endDelim = msg.find_first_of('>'); + if (endDelim != ULONG_MAX) { + if (endDelim > startDelim) { + buf.tag = msg.substr(startDelim+1, (endDelim-startDelim)-1); + if (buf.tag.find_first_of('/') == ULONG_MAX) { // start tags should not be end tags + + + // construct end tag () + Glib::ustring endTag(buf.tag); + endTag.insert(0, "/"); + + Glib::ustring::size_type endTagLoc = msg.find(endTag, endDelim); + if (endTagLoc != ULONG_MAX) { + buf.data = msg.substr(endDelim+1, ((endTagLoc - 1) - (endDelim + 1))); + buf.next_pos = endTagLoc + endTag.length() + 1; + + return true; + } + } + } + } + } + + return false; } bool -MessageUtilities::findTag(struct Node& buf, Glib::ustring const& msg) +MessageUtilities::findTag(struct Node& buf, const Glib::ustring &msg) { - if (msg.empty()) { - return false; - } - - // Read desired tag type out of buffer, and append - // < > to it - - Glib::ustring searchterm("<"); - searchterm += buf.tag; - searchterm + ">"; - - Glib::ustring::size_type tagStart = msg.find(searchterm, 0); - if (tagStart != ULONG_MAX) { - // Find ending tag starting at the point at the end of - // the start tag. - searchterm.insert(1, "/"); - Glib::ustring::size_type tagEnd = msg.find(searchterm, tagStart + searchterm.length()); - if (tagEnd != ULONG_MAX) { - Glib::ustring::size_type start = tagStart + searchterm.length(); - buf.data = msg.substr(start, tagEnd - start); - return true; - } - } - return false; + if (msg.empty()) + return false; + + // Read desired tag type out of buffer, and append + // < > to it + + Glib::ustring searchterm("<"); + searchterm += buf.tag; + searchterm + ">"; + + Glib::ustring::size_type tagStart = msg.find(searchterm, 0); + if (tagStart != ULONG_MAX) { + // Find ending tag starting at the point at the end of + // the start tag. + searchterm.insert(1, "/"); + Glib::ustring::size_type tagEnd = msg.find(searchterm, tagStart + searchterm.length()); + if (tagEnd != ULONG_MAX) { + Glib::ustring::size_type start = tagStart + searchterm.length(); + buf.data = msg.substr(start, tagEnd - start); + return true; + } + } + return false; } Glib::ustring -MessageUtilities::makeTagWithContent(Glib::ustring tagname, Glib::ustring content) +MessageUtilities::makeTagWithContent(const Glib::ustring &tagname, + const Glib::ustring &content) { - Glib::ustring buf; - buf = "<" + tagname + ">"; - buf += content; - buf += ""; - return buf; + Glib::ustring buf = "<" + tagname + ">"; + buf += content; + buf += ""; + return buf; } @@ -444,9 +464,9 @@ MessageUtilities::makeTagWithContent(Glib::ustring tagname, Glib::ustring conten Local Variables: mode:c++ c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + c-file-offsets:((innamespace . 0)(inline-open . 0)) indent-tabs-mode:nil fill-column:99 End: */ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : +// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/jabber_whiteboard/message-utilities.h b/src/jabber_whiteboard/message-utilities.h index c6d464f08..dad805c41 100644 --- a/src/jabber_whiteboard/message-utilities.h +++ b/src/jabber_whiteboard/message-utilities.h @@ -26,7 +26,7 @@ namespace Inkscape { namespace Util { -template +template< typename T > class ptr_shared; } @@ -43,24 +43,49 @@ class XMLNodeTracker; class MessageUtilities { public: - // Message generation utilities - static void newObjectMessage(ustring* msgbuf, KeyToNodeMap& newidsbuf, NodeToKeyMap& newnodesbuf, NewChildObjectMessageList& childmsgbuf, XMLNodeTracker* xmt, Inkscape::XML::Node const* node, bool only_collect_nodes = false, bool collect_children = true); - static void objectChangeMessage(ustring* msgbuf, XMLNodeTracker* xmt, std::string const id, gchar const* key, gchar const* oldval, gchar const* newval, bool is_interactive); - static void objectDeleteMessage(ustring* msgbuf, XMLNodeTracker* xmt, Inkscape::XML::Node const& parent, Inkscape::XML::Node const& child, Inkscape::XML::Node const* prev); - static void contentChangeMessage(ustring& msgbuf, std::string const nodeid, Util::ptr_shared old_value, Util::ptr_shared new_value); - static void childOrderChangeMessage(ustring& msgbuf, std::string const childid, std::string const oldprevid, std::string const newprevid); - - // Message parsing utilities - static bool getFirstMessageTag(struct Node& buf, ustring const& msg); - static bool findTag(struct Node& buf, ustring const& msg); - - // Message tag generation utilities - static Glib::ustring makeTagWithContent(Glib::ustring tagname, Glib::ustring content); + // Message generation utilities + static void newObjectMessage(Glib::ustring &msgbuf, + KeyNodeTable& newnodesbuf, + NewChildObjectMessageList& childmsgbuf, + XMLNodeTracker* xmt, + Inkscape::XML::Node const* node, + bool only_collect_nodes = false, + bool collect_children = true); + static void objectChangeMessage(Glib::ustring &msgbuf, + XMLNodeTracker* xmt, + const Glib::ustring &id, + gchar const* key, + gchar const* oldval, + gchar const* newval, + bool is_interactive); + static void objectDeleteMessage(Glib::ustring &msgbuf, + XMLNodeTracker* xmt, + Inkscape::XML::Node const& parent, + Inkscape::XML::Node const& child, + Inkscape::XML::Node const* prev); + static void contentChangeMessage(Glib::ustring &msgbuf, + const Glib::ustring &nodeid, + Util::ptr_shared old_value, + Util::ptr_shared new_value); + static void childOrderChangeMessage(Glib::ustring &msgbuf, + const Glib::ustring &childid, + const Glib::ustring &oldprevid, + const Glib::ustring &newprevid); + + // Message parsing utilities + static bool getFirstMessageTag(struct Node& buf, + const Glib::ustring &msg); + static bool findTag(struct Node& buf, + const Glib::ustring &msg); + + // Message tag generation utilities + static Glib::ustring makeTagWithContent(const Glib::ustring &tagname, + const Glib::ustring &content); private: - // noncopyable, nonassignable - MessageUtilities(MessageUtilities const&); - MessageUtilities& operator=(MessageUtilities const&); + // noncopyable, nonassignable + MessageUtilities(MessageUtilities const&); + MessageUtilities& operator=(MessageUtilities const&); }; @@ -81,5 +106,5 @@ private: fill-column:99 End: */ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : +// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : #endif diff --git a/src/jabber_whiteboard/message-verifier.h b/src/jabber_whiteboard/message-verifier.h new file mode 100644 index 000000000..48ef01b4d --- /dev/null +++ b/src/jabber_whiteboard/message-verifier.h @@ -0,0 +1,47 @@ +#ifndef __INKSCAPE_WHITEBOARD_MESSAGE_VERIFIER_H__ +#define __INKSCAPE_WHITEBOARD_MESSAGE_VERIFIER_H__ + +/** + * Inkscape::Whiteboard::MessageVerifier -- performs basic XMPP-related + * validity checks on incoming messages + * + * Authors: + * David Yip + * + * Copyright (c) 2006 Authors + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +namespace Inkscape { + +namespace Whiteboard { + + /** + * The class has been written, but I forgot to commit that file to SVN, + * and the only other copy I have is on a computer that I do not currently + * have access to. So, for now, this is just a placeholder with enums + * to get things working. + */ + +enum MessageValidityTestResult { + RESULT_VALID, + RESULT_INVALID +}; + +} + +} + +#endif + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/jabber_whiteboard/new-inkboard-document.cpp b/src/jabber_whiteboard/new-inkboard-document.cpp new file mode 100644 index 000000000..e67a3c88e --- /dev/null +++ b/src/jabber_whiteboard/new-inkboard-document.cpp @@ -0,0 +1,94 @@ +/** + * new-inkboard-document.h + * Functions to create new Inkboard documents, based off of sp_document_new / + * sp_file_new + * + * Authors: + * David Yip + * + * Copyright (c) 2006 Authors + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include +#include +#include + +#include "document.h" +#include "document-private.h" +#include "desktop.h" +#include "desktop-handles.h" +#include "interface.h" +#include "sp-namedview.h" +#include "desktop-handles.h" + +#include "gc-anchored.h" + +#include "ui/view/view-widget.h" + +#include "application/application.h" +#include "application/editor.h" + +#include "util/ucompose.hpp" + +#include "xml/node.h" +#include "xml/repr.h" + +#include "jabber_whiteboard/inkboard-document.h" +#include "jabber_whiteboard/new-inkboard-document.h" + +namespace Inkscape { + +namespace Whiteboard { + +SPDocument* +makeInkboardDocument(int code, gchar const* rootname, SessionType type, Glib::ustring const& to) +{ + SPDocument* doc; + InkboardDocument* rdoc = new InkboardDocument(g_quark_from_static_string("xml"), type, to); + rdoc->setAttribute("version", "1.0"); + rdoc->setAttribute("standalone", "no"); + XML::Node *comment = sp_repr_new_comment(" Created with Inkscape (http://www.inkscape.org/) "); + rdoc->appendChild(comment); + GC::release(comment); + + XML::Node* root = sp_repr_new(rootname); + rdoc->appendChild(root); + GC::release(root); + + Glib::ustring name = String::ucompose(_("Inkboard session (%1 to %2)"), SessionManager::instance().getClient().getJid(), to); + + doc = sp_document_create(rdoc, NULL, NULL, name.c_str(), TRUE); + return doc; +} + +// TODO: When the switchover to the new GUI is complete, this function should go away +// and be replaced with a call to Inkscape::NSApplication::Editor::createDesktop. +// It currently only exists to correctly mimic the desktop creation functionality +// in file.cpp. +// +// \see sp_file_new +SPDesktop* +makeInkboardDesktop(SPDocument* doc) +{ + SPDesktop* dt; + + if (NSApplication::Application::getNewGui()) { + dt = NSApplication::Editor::createDesktop(doc); + } else { + SPViewWidget *dtw = sp_desktop_widget_new(sp_document_namedview(doc, NULL)); + g_return_val_if_fail(dtw != NULL, NULL); + sp_document_unref(doc); + + sp_create_window(dtw, TRUE); + dt = static_cast(dtw->view); + sp_namedview_window_from_document(dt); + } + + return dt; +} + +} + +} diff --git a/src/jabber_whiteboard/new-inkboard-document.h b/src/jabber_whiteboard/new-inkboard-document.h new file mode 100644 index 000000000..d55cfe73d --- /dev/null +++ b/src/jabber_whiteboard/new-inkboard-document.h @@ -0,0 +1,33 @@ +/** + * new-inkboard-document.h + * Functions to create new Inkboard documents, based off of sp_document_new / + * sp_file_new + * + * Authors: + * David Yip + * + * Copyright (c) 2006 Authors + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef __INKSCAPE_WHITEBOARD_NEW_DOCUMENT_H__ +#define __INKSCAPE_WHITEBOARD_NEW_DOCUMENT_H__ + +#include + +class SPDocument; +class SPDesktop; + +namespace Inkscape { + +namespace Whiteboard { + +SPDocument* makeInkboardDocument(int code, gchar const* rootname, SessionType type, Glib::ustring const& to); +SPDesktop* makeInkboardDesktop(SPDocument* doc); + +} + +} + +#endif diff --git a/src/jabber_whiteboard/node-tracker-event-tracker.cpp b/src/jabber_whiteboard/node-tracker-event-tracker.cpp deleted file mode 100644 index da872c5e6..000000000 --- a/src/jabber_whiteboard/node-tracker-event-tracker.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/** - * Tracks node add/remove events to an XMLNodeTracker, and eliminates cases such as - * consecutive add/remove. - * - * Authors: - * David Yip - * - * Copyright (c) 2005 Authors - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#include "xml/node.h" - -#include "jabber_whiteboard/node-tracker-event-tracker.h" - -namespace Inkscape { - -namespace Whiteboard { - -bool -NodeTrackerEventTracker::tryToTrack(XML::Node* node, NodeTrackerAction action) -{ - // 1. Check if node is being tracked. - NodeActionMap::iterator i = this->_actions.find(node); - if (i != this->_actions.end()) { - // 2a. Check the action. If it is the same as the action we are registering, - // return false. Otherwise, register the action with the actions map - // and return true. - if (i->second == action) { - return false; - } else { - this->_actions[node] = action; - return true; - } - } else { - // 2b. If we aren't tracking this node, insert it with the given action. - this->_actions[node] = action; - return true; - } -} - -} - -} - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/jabber_whiteboard/node-tracker-event-tracker.h b/src/jabber_whiteboard/node-tracker-event-tracker.h deleted file mode 100644 index c600592d4..000000000 --- a/src/jabber_whiteboard/node-tracker-event-tracker.h +++ /dev/null @@ -1,66 +0,0 @@ -/** - * Tracks node add/remove events to an XMLNodeTracker, and eliminates cases such as - * consecutive add/remove. - * - * Authors: - * David Yip - * - * Copyright (c) 2005 Authors - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#ifndef __WHITEBOARD_NODE_TRACKER_EVENT_TRACKER_H__ -#define __WHITEBOARD_NODE_TRACKER_EVENT_TRACKER_H__ - -#include - -#include "jabber_whiteboard/typedefs.h" - -namespace Inkscape { - -namespace Whiteboard { - -typedef std::pair< XML::Node*, std::string > NodeKeyPair; -typedef std::map< XML::Node*, NodeTrackerAction > NodeActionMap; - -class NodeTrackerEventTracker { -public: - NodeTrackerEventTracker() { } - ~NodeTrackerEventTracker() { } - bool tryToTrack(XML::Node* node, NodeTrackerAction action); - - NodeTrackerAction getAction(XML::Node const* node) - { - NodeActionMap::iterator i = this->_actions.find(const_cast< XML::Node* >(node)); - if (i != this->_actions.end()) { - return i->second; - } else { - return NODE_UNKNOWN; - } - } - - void clear() - { - this->_actions.clear(); - } -private: - NodeActionMap _actions; -}; - -} - -} - -#endif - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/jabber_whiteboard/node-tracker-observer.h b/src/jabber_whiteboard/node-tracker-observer.h deleted file mode 100644 index 86aa5c304..000000000 --- a/src/jabber_whiteboard/node-tracker-observer.h +++ /dev/null @@ -1,119 +0,0 @@ -/** - * Convenience base class for XML::NodeObservers that need to extract data - * from an XMLNodeTracker and queue up added or removed nodes for later - * processing - * - * Authors: - * David Yip - * - * Copyright (c) 2005 Authors - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#ifndef __WHITEBOARD_NODE_TRACKER_OBSERVER_H__ -#define __WHITEBOARD_NODE_TRACKER_OBSERVER_H__ - -#include "xml/node-observer.h" - -#include "jabber_whiteboard/node-tracker-event-tracker.h" -#include "jabber_whiteboard/node-tracker.h" -#include "jabber_whiteboard/typedefs.h" - -namespace Inkscape { - -namespace XML { - -class Node; - -} - -namespace Whiteboard { - -class NodeTrackerObserver : public XML::NodeObserver { -public: - NodeTrackerObserver(XMLNodeTracker* xnt) : _xnt(xnt) { } - virtual ~NodeTrackerObserver() { } - - // just reinforce the fact that we don't implement any of the - // notification methods here - virtual void notifyChildAdded(XML::Node &node, XML::Node &child, XML::Node *prev)=0; - - virtual void notifyChildRemoved(XML::Node &node, XML::Node &child, XML::Node *prev)=0; - - virtual void notifyChildOrderChanged(XML::Node &node, XML::Node &child, - XML::Node *old_prev, XML::Node *new_prev)=0; - - virtual void notifyContentChanged(XML::Node &node, - Util::ptr_shared old_content, - Util::ptr_shared new_content)=0; - - virtual void notifyAttributeChanged(XML::Node &node, GQuark name, - Util::ptr_shared old_value, - Util::ptr_shared new_value)=0; - - - // ...but we do provide node tracking facilities - KeyToNodeActionList& getNodeTrackerActions() - { - return this->newnodes; - } - - KeyToNodeActionList getNodeTrackerActionsCopy() - { - return this->newnodes; - } - - void clearNodeBuffers() - { - this->newnodes.clear(); - this->newkeys.clear(); - this->actions.clear(); - } - -protected: - std::string _findOrGenerateNodeID(XML::Node& node) - { - NodeToKeyMap::iterator i = newkeys.find(&node); - if (i != newkeys.end()) { -// g_log(NULL, G_LOG_LEVEL_DEBUG, "Found key for %p (local): %s", &node, i->second.c_str()); - return i->second; - } else { - std::string nodeid = this->_xnt->get(node); - if (nodeid.empty()) { -// g_log(NULL, G_LOG_LEVEL_DEBUG, "Generating key for %p", &node); - return this->_xnt->generateKey(); - } else { -// g_log(NULL, G_LOG_LEVEL_DEBUG, "Found key for %p (tracker): %s", &node, nodeid.c_str()); - return nodeid; - } - } - } - - KeyToNodeActionList newnodes; - NodeTrackerEventTracker actions; - NodeToKeyMap newkeys; - XMLNodeTracker* _xnt; - -private: - // noncopyable, nonassignable - NodeTrackerObserver(NodeTrackerObserver const& other); - NodeTrackerObserver& operator=(NodeTrackerObserver const& other); - -}; - -} - -} -#endif - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/jabber_whiteboard/node-tracker.cpp b/src/jabber_whiteboard/node-tracker.cpp index 84bc12945..a506d472a 100644 --- a/src/jabber_whiteboard/node-tracker.cpp +++ b/src/jabber_whiteboard/node-tracker.cpp @@ -52,217 +52,187 @@ char const* specialnodenames[] = { }; XMLNodeTracker::XMLNodeTracker(SessionManager* sm) : - _rootKey(DOCUMENT_ROOT_NODE), - _namedviewKey(DOCUMENT_NAMEDVIEW_NODE) + _rootKey(DOCUMENT_ROOT_NODE), + _namedviewKey(DOCUMENT_NAMEDVIEW_NODE) { - this->_sm = sm; - this->_counter = 0; - - // Construct special node maps - this->createSpecialNodeTables(); - this->reset(); + _sm = sm; + init(); } -XMLNodeTracker::~XMLNodeTracker() +XMLNodeTracker::XMLNodeTracker() : + _rootKey(DOCUMENT_ROOT_NODE), + _namedviewKey(DOCUMENT_NAMEDVIEW_NODE) { - this->_clear(); + _sm = NULL; + init(); } -void -XMLNodeTracker::put(std::string key, XML::Node const& node) +XMLNodeTracker::~XMLNodeTracker() { - this->put(key, const_cast< XML::Node& >(node)); + _clear(); } -void -XMLNodeTracker::put(std::string key, XML::Node& node) -{ - KeyToTrackerNodeMap::iterator i = this->_keyToNode.find(key); - if (i != this->_keyToNode.end()) { - this->_keyToNode.erase(i); - } - this->_keyToNode.insert(std::make_pair< std::string, XML::Node* >(key, &node)); - - TrackerNodeToKeyMap::iterator j = this->_nodeToKey.find(&node); - if (j != this->_nodeToKey.end()) { - this->_nodeToKey.erase(j); - } - this->_nodeToKey.insert(std::make_pair< XML::Node*, std::string >(&node, key)); -} void -XMLNodeTracker::put(KeyToNodeMap& newids, NodeToKeyMap& newnodes) +XMLNodeTracker::init() { - // TODO: redo - KeyToNodeMap::iterator i = newids.begin(); + _counter = 0; - for(; i != newids.end(); i++) { - this->put((*i).first, *((*i).second)); - } + // Construct special node maps + createSpecialNodeTables(); + if (_sm) + reset(); } void -XMLNodeTracker::process(KeyToNodeActionList& actions) +XMLNodeTracker::setSessionManager(const SessionManager *val) { - KeyToNodeActionList::iterator i = actions.begin(); - for(; i != actions.end(); i++) { - // Get the action to perform. - SerializedEventNodeAction action = *i; - switch(action.second) { - case NODE_ADD: - this->put(action.first.first, *action.first.second); - break; - case NODE_REMOVE: - // this->remove(const_cast< XML::Node& >(*action.first.second)); - break; - default: - break; - } - } + _sm = (SessionManager *)val; + if (_sm) + reset(); } -XML::Node* -XMLNodeTracker::get(std::string& key) -{ - KeyToTrackerNodeMap::iterator i = this->_keyToNode.find(key); - if (i != this->_keyToNode.end()) { - return (*i).second; - } else { - g_warning("Key %s is not being tracked!", key.c_str()); - return NULL; - } -} - -XML::Node* -XMLNodeTracker::get(std::string const& key) -{ - return this->get(const_cast< std::string& >(key)); +void +XMLNodeTracker::put(const Glib::ustring &key, const XML::Node &nodeArg) +{ + keyNodeTable.put(key, &nodeArg); } -std::string const -XMLNodeTracker::get(XML::Node& node) +void +XMLNodeTracker::process(const KeyToNodeActionList &actions) { - TrackerNodeToKeyMap::iterator i = this->_nodeToKey.find(&node); - if (i != this->_nodeToKey.end()) { - return (*i).second; - } else { - return ""; - } + KeyToNodeActionList::const_iterator iter = actions.begin(); + for(; iter != actions.end(); iter++) { + // Get the action to perform. + SerializedEventNodeAction action = *iter; + switch(action.second) { + case NODE_ADD: + //g_log(NULL, G_LOG_LEVEL_DEBUG, + //"NODE_ADD event: key %s, node %p", + //action.first.first.c_str(), action.first.second); + put(action.first.key, *action.first.node); + break; + case NODE_REMOVE: + //g_log(NULL, G_LOG_LEVEL_DEBUG, + //"NODE_REMOVE event: key %s, node %p", + // action.first.first.c_str(), action.first.second); + //remove(const_cast< XML::Node& >(*action.first.second)); + break; + default: + break; + } + } } -std::string const -XMLNodeTracker::get(XML::Node const& node) +XML::Node* +XMLNodeTracker::get(const Glib::ustring &key) { - return this->get(const_cast< XML::Node& >(node)); -} + XML::Node *node = keyNodeTable.get(key); + if (node) + return node; -bool -XMLNodeTracker::isTracking(std::string& key) -{ - return (this->_keyToNode.find(key) != this->_keyToNode.end()); + g_warning("Key %s is not being tracked!", key.c_str()); + return NULL; } -bool -XMLNodeTracker::isTracking(std::string const& key) +Glib::ustring +XMLNodeTracker::get(const XML::Node &nodeArg) { - return this->isTracking(const_cast< std::string& >(key)); + Glib::ustring key = keyNodeTable.get((XML::Node *)&nodeArg); + return key; } bool -XMLNodeTracker::isTracking(XML::Node& node) +XMLNodeTracker::isTracking(const Glib::ustring &key) { - return (this->_nodeToKey.find(&node) != this->_nodeToKey.end()); + return (get(key)!=NULL); } bool -XMLNodeTracker::isTracking(XML::Node const& node) +XMLNodeTracker::isTracking(const XML::Node &node) { - return this->isTracking(const_cast< XML::Node& >(node)); + return (get(node).size()>0); } + bool -XMLNodeTracker::isRootNode(XML::Node& node) +XMLNodeTracker::isRootNode(const XML::Node &node) { - XML::Node* docroot = sp_document_repr_root(this->_sm->document()); - return (docroot == &node); + XML::Node* docroot = sp_document_repr_root(_sm->getDocument()); + return (docroot == &node); } void -XMLNodeTracker::remove(std::string& key) +XMLNodeTracker::remove(const Glib::ustring& key) { - if (this->isTracking(key)) { - XML::Node* element = this->get(key); - this->_keyToNode.erase(key); - this->_nodeToKey.erase(element); - } + g_log(NULL, G_LOG_LEVEL_DEBUG, "Removing node with key %s", key.c_str()); + keyNodeTable.remove(key); } void -XMLNodeTracker::remove(XML::Node& node) +XMLNodeTracker::remove(const XML::Node &nodeArg) { - if (this->isTracking(node)) { - std::string const element = this->get(node); - this->_nodeToKey.erase(&node); - this->_keyToNode.erase(element); - } + //g_log(NULL, G_LOG_LEVEL_DEBUG, "Removing node %p", &node); + keyNodeTable.remove((XML::Node *)&nodeArg); } -bool -XMLNodeTracker::isSpecialNode(char const* name) -{ - return (this->_specialnodes.find(name) != this->_specialnodes.end()); -} bool -XMLNodeTracker::isSpecialNode(std::string const& name) +XMLNodeTracker::isSpecialNode(const Glib::ustring &name) { - return (this->_specialnodes.find(name.data()) != this->_specialnodes.end()); + return (_specialnodes.find(name.data()) != _specialnodes.end()); } -std::string const +Glib::ustring XMLNodeTracker::getSpecialNodeKeyFromName(Glib::ustring const& name) { - return this->_specialnodes[name.data()]; + return _specialnodes[name.data()]; } -std::string const -XMLNodeTracker::getSpecialNodeKeyFromName(Glib::ustring const* name) -{ - return this->_specialnodes[name->data()]; -} - -std::string +Glib::ustring XMLNodeTracker::generateKey(gchar const* JID) { - return String::compose("%1;%2", this->_counter++, JID); + return String::compose("%1;%2", _counter++, JID); } -std::string +Glib::ustring XMLNodeTracker::generateKey() { - SessionData* sd = this->_sm->session_data; - std::bitset< NUM_FLAGS >& status = sd->status; - if (status[IN_CHATROOM]) { - // This is not strictly required for chatrooms: chatrooms will - // function just fine with the user-to-user ID scheme. However, - // the user-to-user scheme can lead to loss of anonymity - // in anonymous chat rooms, since it contains the real JID - // of a user. - return String::compose("%1;%2@%3/%4", this->_counter++, sd->chat_name, sd->chat_server, sd->chat_handle); - } else { - return String::compose("%1;%2", this->_counter++, sd->jid); - } + std::bitset< NUM_FLAGS >& status = _sm->getStatus(); + Glib::ustring ret; + if (status[IN_CHATROOM]) { + // This is not strictly required for chatrooms: chatrooms will + // function just fine with the user-to-user ID scheme. However, + // the user-to-user scheme can lead to loss of anonymity + // in anonymous chat rooms, since it contains the real JID + // of a user. + /* + ret = String::compose("%1;%2@%3/%4", + _counter++, + _sm->getClient().getUsername(), + _sm->getClient().getHost(), + sd->chat_handle); + */ + //We need to work on this since Pedro allows multiple chatrooms + ret = String::compose("%1;%2", + _counter++, + _sm->getClient().getJid()); + } else { + ret = String::compose("%1;%2", + _counter++, + _sm->getClient().getJid()); + } + return ret; } void XMLNodeTracker::createSpecialNodeTables() { - int const sz = sizeof(specialnodekeys) / sizeof(char const*); - for(int i = 0; i < sz; i++) { - this->_specialnodes[specialnodenames[i]] = specialnodekeys[i]; - } + int const sz = sizeof(specialnodekeys) / sizeof(char const*); + for(int i = 0; i < sz; i++) + _specialnodes[specialnodenames[i]] = specialnodekeys[i]; } @@ -270,89 +240,69 @@ XMLNodeTracker::createSpecialNodeTables() void XMLNodeTracker::dump() { - g_log(NULL, G_LOG_LEVEL_DEBUG, "XMLNodeTracker dump for %s", this->_sm->session_data->jid.c_str()); - KeyToTrackerNodeMap::iterator i = this->_keyToNode.begin(); - TrackerNodeToKeyMap::iterator j = this->_nodeToKey.begin(); - std::map< char const*, char const* >::iterator k = this->_specialnodes.begin(); - - - g_log(NULL, G_LOG_LEVEL_DEBUG, "%u entries in keyToNode, %u entries in nodeToKey", this->_keyToNode.size(), this->_nodeToKey.size()); - - if (this->_keyToNode.size() != this->_nodeToKey.size()) { - g_warning("Map sizes do not match!"); - } - - g_log(NULL, G_LOG_LEVEL_DEBUG, "XMLNodeTracker keyToNode dump"); - while(i != this->_keyToNode.end()) { - if (!((*i).first.empty())) { - if ((*i).second != NULL) { - g_log(NULL, G_LOG_LEVEL_DEBUG, "%s\t->\t%p (%s) (%s)", (*i).first.c_str(), (*i).second, (*i).second->name(), (*i).second->content()); - } else { - g_log(NULL, G_LOG_LEVEL_DEBUG, "%s\t->\t(null)", (*i).first.c_str()); - } - } else { - g_log(NULL, G_LOG_LEVEL_DEBUG, "(null)\t->\t%p (%s)", (*i).second, (*i).second->name()); - } - i++; - } - - g_log(NULL, G_LOG_LEVEL_DEBUG, "XMLNodeTracker nodeToKey dump"); - while(j != this->_nodeToKey.end()) { - if (!((*j).second.empty())) { - if ((*j).first) { - g_log(NULL, G_LOG_LEVEL_DEBUG, "%p\t->\t%s (parent %p)", (*j).first, (*j).second.c_str(), (*j).first->parent()); - } else { - g_log(NULL, G_LOG_LEVEL_DEBUG, "(null)\t->\t%s", (*j).second.c_str()); - } - } else { - g_log(NULL, G_LOG_LEVEL_DEBUG, "%p\t->\t(null)", (*j).first); - } - j++; - } - - g_log(NULL, G_LOG_LEVEL_DEBUG, "_specialnodes dump"); - while(k != this->_specialnodes.end()) { - g_log(NULL, G_LOG_LEVEL_DEBUG, "%s\t->\t%s", (*k).first, (*k).second); - k++; - } + g_log(NULL, G_LOG_LEVEL_DEBUG, "XMLNodeTracker dump for %s", + _sm->getClient().getJid().c_str()); + + + + g_log(NULL, G_LOG_LEVEL_DEBUG, "%u entries in keyNodeTable", + keyNodeTable.size()); + + g_log(NULL, G_LOG_LEVEL_DEBUG, "XMLNodeTracker keyNodeTable dump"); + for (unsigned int i=0 ; iname(); + content = (char *)node->content(); + } + g_log(NULL, G_LOG_LEVEL_DEBUG, "%s\t->\t%p (%s) (%s)", + key.c_str(), node, name, content); + } + + g_log(NULL, G_LOG_LEVEL_DEBUG, "_specialnodes dump"); + std::map< char const*, char const* >::iterator k = _specialnodes.begin(); + while(k != _specialnodes.end()) { + g_log(NULL, G_LOG_LEVEL_DEBUG, "%s\t->\t%s", (*k).first, (*k).second); + k++; + } } void XMLNodeTracker::reset() { - this->_clear(); - - // Find and insert special nodes - // root node - this->put(this->_rootKey, *(sp_document_repr_root(this->_sm->document()))); - - // namedview node - SPObject* namedview = sp_item_group_get_child_by_name((SPGroup *)this->_sm->document()->root, NULL, DOCUMENT_NAMEDVIEW_NAME); - if (!namedview) { - g_warning("namedview node does not exist; it will be created during synchronization"); - } else { - this->put(this->_namedviewKey, *(SP_OBJECT_REPR(namedview))); - } + _clear(); + + // Find and insert special nodes + // root node + put(_rootKey, *(sp_document_repr_root(_sm->getDocument()))); + + // namedview node + SPObject* namedview = sp_item_group_get_child_by_name( + (SPGroup *)_sm->getDocument()->root, + NULL, DOCUMENT_NAMEDVIEW_NAME); + if (!namedview) { + g_warning("namedview node does not exist; it will be created during synchronization"); + } else { + put(_namedviewKey, *(SP_OBJECT_REPR(namedview))); + } } void XMLNodeTracker::_clear() { - // Remove all keys in both trackers, and delete each key. - this->_keyToNode.clear(); - this->_nodeToKey.clear(); - - /* - TrackerNodeToKeyMap::iterator j = this->_nodeToKey.begin(); - for(; j != this->_nodeToKey.end(); j++) { - this->_nodeToKey.erase(j); - } - */ + // Remove all keys in both trackers, and delete each key. + keyNodeTable.clear(); } -} +} // namespace Whiteboard -} +} // namespace Inkscape @@ -360,9 +310,9 @@ XMLNodeTracker::_clear() Local Variables: mode:c++ c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + c-file-offsets:((innamespace . 0)(inline-open . 0)) indent-tabs-mode:nil fill-column:99 End: */ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : +// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/jabber_whiteboard/node-tracker.h b/src/jabber_whiteboard/node-tracker.h index 9c92b815a..660b784fb 100644 --- a/src/jabber_whiteboard/node-tracker.h +++ b/src/jabber_whiteboard/node-tracker.h @@ -67,21 +67,21 @@ struct strcmpless : public std::binary_function< char const*, char const*, bool */ class XMLNodeTracker { public: + /** + * Constructor. + */ + XMLNodeTracker(); + /** * Constructor. * * \param sm The SessionManager with which an XMLNodeTracker instance is to be associated with. */ XMLNodeTracker(SessionManager* sm); + ~XMLNodeTracker(); - /** - * Insert a (key,node) pair into the tracker. - * - * \param key The key to associate with the node. - * \param node The node to associate with the key. - */ - void put(std::string key, XML::Node& node); + void setSessionManager(const SessionManager *val); /** * Insert a (key,node) pair into the tracker. @@ -89,31 +89,14 @@ public: * \param key The key to associate with the node. * \param node The node to associate with the key. */ - void put(std::string key, XML::Node const& node); - - /** - * Insert a range of (key,node) pairs into the tracker. - * - * The size of the two maps must be the same. - * \param newids The keys to associate with the nodes. - * \param newnodes The nodes to associate with the keys. - */ - void put(KeyToNodeMap& newids, NodeToKeyMap& newnodes); + void put(const Glib::ustring &key, const XML::Node &node); /** * Process a list of node actions to add and remove nodes from the tracker. * * \param actions The action list to process. */ - void process(KeyToNodeActionList& actions); - - /** - * Retrieve an XML::Node given a key. - * - * \param key Reference to a string key. - * \return Pointer to an XML::Node, or NULL if no associated node could be found. - */ - XML::Node* get(std::string& key); + void process(const KeyToNodeActionList& actions); /** * Retrieve an XML::Node given a key. @@ -121,15 +104,7 @@ public: * \param key Reference to a const string key. * \return Pointer to an XML::Node, or NULL if no associated node could be found. */ - XML::Node* get(std::string const& key); - - /** - * Retrieve a string key given a reference to an XML::Node. - * - * \param node Reference to an XML::Node. - * \return The associated string key, or an empty string if no associated key could be found. - */ - std::string const get(XML::Node& node); + XML::Node* get(const Glib::ustring &key); /** * Retrieve a string key given a reference to an XML::Node. @@ -137,21 +112,21 @@ public: * \param node Reference to a const XML::Node. * \return The associated string key, or an empty string if no associated key could be found. */ - std::string const get(XML::Node const& node); + Glib::ustring get(const XML::Node &node); /** * Remove an entry from the tracker based on key. * * \param The key of the entry to remove. */ - void remove(std::string& key); + void remove(const Glib::ustring& key); /** * Remove an entry from the tracker based on XML::Node. * * \param A reference to the XML::Node associated with the entry to remove. */ - void remove(XML::Node& node); + void remove(const XML::Node& node); /** * Return whether or not a (key,node) pair is being tracked, given a string key. @@ -159,15 +134,7 @@ public: * \param The key associated with the pair to check. * \return Whether or not the pair is being tracked. */ - bool isTracking(std::string& key); - - /** - * Return whether or not a (key,node) pair is being tracked, given a string key. - * - * \param The key associated with the pair to check. - * \return Whether or not the pair is being tracked. - */ - bool isTracking(std::string const& key); + bool isTracking(const Glib::ustring &key); /** * Return whether or not a (key,node) pair is being tracked, given a node. @@ -175,26 +142,7 @@ public: * \param The node associated with the pair to check. * \return Whether or not the pair is being tracked. */ - bool isTracking(XML::Node& node); - - /** - * Return whether or not a (key,node) pair is being tracked, given a node. - * - * \param The node associated with the pair to check. - * \return Whether or not the pair is being tracked. - */ - bool isTracking(XML::Node const& node); - - /** - * Return whether or not a node identified by a given name is a special node. - * - * \see Inkscape::Whiteboard::specialnodekeys - * \see Inkscape::Whiteboard::specialnodenames - * - * \param The name associated with the node. - * \return Whether or not the node is a special node. - */ - bool isSpecialNode(char const* name); + bool isTracking(const XML::Node & node); /** * Return whether or not a node identified by a given name is a special node. @@ -205,7 +153,7 @@ public: * \param The name associated with the node. * \return Whether or not the node is a special node. */ - bool isSpecialNode(std::string const& name); + bool isSpecialNode(Glib::ustring const& name); /** * Retrieve the key of a special node given the name of a special node. @@ -216,18 +164,8 @@ public: * \param The name associated with the node. * \return The key of the special node. */ - std::string const getSpecialNodeKeyFromName(Glib::ustring const& name); - - /** - * Retrieve the key of a special node given the name of a special node. - * - * \see Inkscape::Whiteboard::specialnodekeys - * \see Inkscape::Whiteboard::specialnodenames - * - * \param The name associated with the node. - * \return The key of the special node. - */ - std::string const getSpecialNodeKeyFromName(Glib::ustring const* name); + Glib::ustring getSpecialNodeKeyFromName( + const Glib::ustring &name); /** * Returns whether or not the given node is the root node of the SPDocument associated @@ -236,7 +174,7 @@ public: * \param Reference to an XML::Node to test. * \return Whether or not the given node is the document root node. */ - bool isRootNode(XML::Node& node); + bool isRootNode(const XML::Node& node); /** * Generate a node key given a JID. @@ -244,7 +182,7 @@ public: * \param The JID to use in the key. * \return A node string key. */ - std::string generateKey(gchar const* JID); + Glib::ustring generateKey(gchar const* JID); /** * Generate a node key given the JID specified in the SessionData structure associated @@ -252,30 +190,31 @@ public: * * \return A node string key. */ - std::string generateKey(); + Glib::ustring generateKey(); // TODO: remove debugging function void dump(); void reset(); private: + //common code called by constructors + void init(); + void createSpecialNodeTables(); void _clear(); unsigned int _counter; SessionManager* _sm; - - // defined in typedefs.h - KeyToTrackerNodeMap _keyToNode; - TrackerNodeToKeyMap _nodeToKey; + + KeyNodeTable keyNodeTable; std::map< char const*, char const*, strcmpless > _specialnodes; // Keys for special nodes - std::string _rootKey; - std::string _defsKey; - std::string _namedviewKey; - std::string _metadataKey; + Glib::ustring _rootKey; + Glib::ustring _defsKey; + Glib::ustring _namedviewKey; + Glib::ustring _metadataKey; // noncopyable, nonassignable XMLNodeTracker(XMLNodeTracker const&); @@ -292,9 +231,9 @@ private: Local Variables: mode:c++ c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + c-file-offsets:((innamespace . 0)(inline-open . 0)) indent-tabs-mode:nil fill-column:99 End: */ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : +// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/jabber_whiteboard/node-utilities.cpp b/src/jabber_whiteboard/node-utilities.cpp index f0cbacddc..cbf4b6ea1 100644 --- a/src/jabber_whiteboard/node-utilities.cpp +++ b/src/jabber_whiteboard/node-utilities.cpp @@ -10,7 +10,7 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include "util/share.h" +#include "util/shared-c-string-ptr.h" #include "util/list.h" #include "xml/node-observer.h" @@ -54,7 +54,7 @@ NodeUtilities::lookupReprByValue(Inkscape::XML::Node* root, gchar const* key, Gl } */ -Glib::ustring const +Glib::ustring NodeUtilities::nodeTypeToString(XML::Node const& node) { switch(node.type()) { @@ -84,21 +84,21 @@ NodeUtilities::stringToNodeType(Glib::ustring const& type) } } -std::string const -NodeUtilities::findNodeID(XML::Node const& node, XMLNodeTracker* tracker, NodeToKeyMap const& newnodes) +Glib::ustring +NodeUtilities::findNodeID(XML::Node const& node, + XMLNodeTracker* tracker, + KeyNodeTable const& newnodes) { -// g_log(NULL, G_LOG_LEVEL_DEBUG, "Attempting to locate id for %p", &node); - NodeToKeyMap::const_iterator result = newnodes.find(&node); - if (result != newnodes.end()) { -// g_log(NULL, G_LOG_LEVEL_DEBUG, "Located id for %p: %s", &node, (*result).second.c_str()); - return (*result).second; - } + //g_log(NULL, G_LOG_LEVEL_DEBUG, "Attempting to locate id for %p", &node); + Glib::ustring key = newnodes.get((XML::Node *)&node); + if (key.size()>0) + return key; if (tracker->isTracking(node)) { -// g_log(NULL, G_LOG_LEVEL_DEBUG, "Located id for %p (in tracker): %s", &node, tracker->get(node).c_str()); + //g_log(NULL, G_LOG_LEVEL_DEBUG, "Located id for %p (in tracker): %s", &node, tracker->get(node).c_str()); return tracker->get(node); } else { -// g_log(NULL, G_LOG_LEVEL_DEBUG, "Failed to locate id"); + //g_log(NULL, G_LOG_LEVEL_DEBUG, "Failed to locate id"); return ""; } } @@ -111,9 +111,9 @@ NodeUtilities::findNodeID(XML::Node const& node, XMLNodeTracker* tracker, NodeTo Local Variables: mode:c++ c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + c-file-offsets:((innamespace . 0)(inline-open . 0)) indent-tabs-mode:nil fill-column:99 End: */ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : +// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/jabber_whiteboard/node-utilities.h b/src/jabber_whiteboard/node-utilities.h index c74027de2..4a025f149 100644 --- a/src/jabber_whiteboard/node-utilities.h +++ b/src/jabber_whiteboard/node-utilities.h @@ -30,12 +30,15 @@ class XMLNodeTracker; class NodeUtilities { public: // Node utilities -// static Inkscape::XML::Node* lookupReprByValue(Inkscape::XML::Node* root, gchar const* key, ustring const* value); - static Glib::ustring const nodeTypeToString(XML::Node const& node); + //static Inkscape::XML::Node* lookupReprByValue(Inkscape::XML::Node* root, + // gchar const* key, Glib::ustring const* value); + static Glib::ustring nodeTypeToString(XML::Node const& node); static XML::NodeType stringToNodeType(Glib::ustring const& type); // Node key search utility method - static std::string const findNodeID(XML::Node const& node, XMLNodeTracker* tracker, NodeToKeyMap const& newnodes); + static Glib::ustring findNodeID(XML::Node const& node, + XMLNodeTracker* tracker, + KeyNodeTable const& newnodes); private: // noncopyable, nonassignable @@ -53,9 +56,9 @@ private: Local Variables: mode:c++ c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + c-file-offsets:((innamespace . 0)(inline-open . 0)) indent-tabs-mode:nil fill-column:99 End: */ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : +// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/jabber_whiteboard/pedrodom.cpp b/src/jabber_whiteboard/pedrodom.cpp deleted file mode 100644 index 903c159ec..000000000 --- a/src/jabber_whiteboard/pedrodom.cpp +++ /dev/null @@ -1,784 +0,0 @@ -/* - * Implementation of the Pedro mini-DOM parser and tree - * - * Authors: - * Bob Jamison - * - * Copyright (C) 2005 Bob Jamison - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - - -#ifdef HAVE_MALLOC_H -#include -#endif - -#include -#include -#include -#include -#include - - -#include "pedrodom.h" - -namespace Pedro -{ - - - -//######################################################################## -//# E L E M E N T -//######################################################################## - -Element *Element::clone() -{ - Element *elem = new Element(name, value); - elem->parent = parent; - elem->attributes = attributes; - elem->namespaces = namespaces; - - std::vector::iterator iter; - for (iter = children.begin(); iter != children.end() ; iter++) - { - elem->addChild((*iter)->clone()); - } - return elem; -} - - -void Element::findElementsRecursive(std::vector&res, const DOMString &name) -{ - if (getName() == name) - { - res.push_back(this); - } - for (unsigned int i=0; ifindElementsRecursive(res, name); -} - -std::vector Element::findElements(const DOMString &name) -{ - std::vector res; - findElementsRecursive(res, name); - return res; -} - -DOMString Element::getAttribute(const DOMString &name) -{ - for (unsigned int i=0 ; ielems = findElements(tagName); - if (elems.size() <1) - return ""; - DOMString res = elems[0]->getAttribute(attrName); - return res; -} - -DOMString Element::getTagValue(const DOMString &tagName) -{ - std::vectorelems = findElements(tagName); - if (elems.size() <1) - return ""; - DOMString res = elems[0]->getValue(); - return res; -} - -void Element::addChild(Element *child) -{ - if (!child) - return; - child->parent = this; - children.push_back(child); -} - - -void Element::addAttribute(const DOMString &name, const DOMString &value) -{ - Attribute attr(name, value); - attributes.push_back(attr); -} - -void Element::addNamespace(const DOMString &prefix, const DOMString &namespaceURI) -{ - Namespace ns(prefix, namespaceURI); - namespaces.push_back(ns); -} - -void Element::writeIndentedRecursive(FILE *f, int indent) -{ - int i; - if (!f) - return; - //Opening tag, and attributes - for (i=0;i\n"); - - //Between the tags - if (value.size() > 0) - { - for (int i=0;iwriteIndentedRecursive(f, indent+2); - - //Closing tag - for (int i=0; i\n", name.c_str()); -} - -void Element::writeIndented(FILE *f) -{ - writeIndentedRecursive(f, 0); -} - -void Element::print() -{ - writeIndented(stdout); -} - - -//######################################################################## -//# P A R S E R -//######################################################################## - - - -typedef struct - { - char *escaped; - char value; - } EntityEntry; - -static EntityEntry entities[] = -{ - { "&" , '&' }, - { "<" , '<' }, - { ">" , '>' }, - { "'", '\'' }, - { """, '"' }, - { NULL , '\0' } -}; - - - -void Parser::getLineAndColumn(long pos, long *lineNr, long *colNr) -{ - long line = 1; - long col = 1; - for (long i=0 ; i= parselen) - return -1; - currentPosition = pos; - int ch = parsebuf[pos]; - //printf("ch:%c\n", ch); - return ch; -} - - - -DOMString Parser::encode(const DOMString &str) -{ - DOMString ret; - for (unsigned int i=0 ; i') - ret.append(">"); - else if (ch == '\'') - ret.append("'"); - else if (ch == '"') - ret.append("""); - else - ret.push_back(ch); - - } - return ret; -} - - -int Parser::match(long p0, const char *text) -{ - int p = p0; - while (*text) - { - if (peek(p) != *text) - return p0; - p++; text++; - } - return p; -} - - - -int Parser::skipwhite(long p) -{ - - while (p p) - { - p = p2; - while (p"); - if (p2 > p) - { - p = p2; - break; - } - p++; - } - } - XMLCh b = peek(p); - if (!isspace(b)) - break; - p++; - } - return p; -} - -/* modify this to allow all chars for an element or attribute name*/ -int Parser::getWord(int p0, DOMString &buf) -{ - int p = p0; - while (p' || b=='=') - break; - buf.push_back(b); - p++; - } - return p; -} - -int Parser::getQuoted(int p0, DOMString &buf, int do_i_parse) -{ - - int p = p0; - if (peek(p) != '"' && peek(p) != '\'') - return p0; - p++; - - while ( pvalue ; ee++) - { - int p2 = match(p, ee->escaped); - if (p2>p) - { - buf.push_back(ee->value); - p = p2; - found = true; - break; - } - } - if (!found) - { - error("unterminated entity"); - return false; - } - } - else - { - buf.push_back(b); - p++; - } - } - return p; -} - -int Parser::parseVersion(int p0) -{ - //printf("### parseVersion: %d\n", p0); - - int p = p0; - - p = skipwhite(p0); - - if (peek(p) != '<') - return p0; - - p++; - if (p>=parselen || peek(p)!='?') - return p0; - - p++; - - DOMString buf; - - while (p=parselen || peek(p)!='<') - return p0; - - p++; - - if (peek(p)!='!' || peek(p+1)=='-') - return p0; - p++; - - DOMString buf; - while (p') - { - p++; - break; - } - buf.push_back(ch); - p++; - } - - //printf("Got doctype:%s\n",buf.c_str()); - return p; -} - -int Parser::parseElement(int p0, Element *par,int depth) -{ - - int p = p0; - - int p2 = p; - - p = skipwhite(p); - - //## Get open tag - XMLCh ch = peek(p); - if (ch!='<') - return p0; - - p++; - - DOMString openTagName; - p = skipwhite(p); - p = getWord(p, openTagName); - //printf("####tag :%s\n", openTagName.c_str()); - p = skipwhite(p); - - //Add element to tree - Element *n = new Element(openTagName); - n->parent = par; - par->addChild(n); - - // Get attributes - if (peek(p) != '>') - { - while (p') - break; - else if (ch=='/' && p') - { - p++; - //printf("quick close\n"); - return p; - } - } - DOMString attrName; - p2 = getWord(p, attrName); - if (p2==p) - break; - //printf("name:%s",buf); - p=p2; - p = skipwhite(p); - ch = peek(p); - //printf("ch:%c\n",ch); - if (ch!='=') - break; - p++; - p = skipwhite(p); - // ch = parsebuf[p]; - // printf("ch:%c\n",ch); - DOMString attrVal; - p2 = getQuoted(p, attrVal, true); - p=p2+1; - //printf("name:'%s' value:'%s'\n",attrName.c_str(),attrVal.c_str()); - char *namestr = (char *)attrName.c_str(); - if (strncmp(namestr, "xmlns:", 6)==0) - n->addNamespace(attrName, attrVal); - else - n->addAttribute(attrName, attrVal); - } - } - - bool cdata = false; - - p++; - // ### Get intervening data ### */ - DOMString data; - while (pp) - { - p = p2; - while (p"); - if (p2 > p) - { - p = p2; - break; - } - p++; - } - } - - ch = peek(p); - //# END TAG - if (ch=='<' && !cdata && peek(p+1)=='/') - { - break; - } - //# CDATA - p2 = match(p, " p) - { - cdata = true; - p = p2; - continue; - } - - //# CHILD ELEMENT - if (ch == '<') - { - p2 = parseElement(p, n, depth+1); - if (p2 == p) - { - /* - printf("problem on element:%s. p2:%d p:%d\n", - openTagName.c_str(), p2, p); - */ - return p0; - } - p = p2; - continue; - } - //# ENTITY - if (ch=='&' && !cdata) - { - bool found = false; - for (EntityEntry *ee = entities ; ee->value ; ee++) - { - int p2 = match(p, ee->escaped); - if (p2>p) - { - data.push_back(ee->value); - p = p2; - found = true; - break; - } - } - if (!found) - { - error("unterminated entity"); - return -1; - } - continue; - } - - //# NONE OF THE ABOVE - data.push_back(ch); - p++; - }/*while*/ - - - n->value = data; - //printf("%d : data:%s\n",p,data.c_str()); - - //## Get close tag - p = skipwhite(p); - ch = peek(p); - if (ch != '<') - { - error("no < for end tag\n"); - return p0; - } - p++; - ch = peek(p); - if (ch != '/') - { - error("no / on end tag"); - return p0; - } - p++; - ch = peek(p); - p = skipwhite(p); - DOMString closeTagName; - p = getWord(p, closeTagName); - if (openTagName != closeTagName) - { - error("Mismatched closing tag. Expected . Got '%S'.", - openTagName.c_str(), closeTagName.c_str()); - return p0; - } - p = skipwhite(p); - if (peek(p) != '>') - { - error("no > on end tag for '%s'", closeTagName.c_str()); - return p0; - } - p++; - // printf("close element:%s\n",closeTagName.c_str()); - p = skipwhite(p); - return p; -} - - - - -Element *Parser::parse(XMLCh *buf,int pos,int len) -{ - parselen = len; - parsebuf = buf; - Element *rootNode = new Element("root"); - pos = parseVersion(pos); - pos = parseDoctype(pos); - pos = parseElement(pos, rootNode, 0); - return rootNode; -} - - -Element *Parser::parse(const char *buf, int pos, int len) -{ - - XMLCh *charbuf = (XMLCh *)malloc((len+1) * sizeof(XMLCh)); - long i = 0; - while (i< len) - { - charbuf[i] = (XMLCh)buf[i]; - i++; - } - charbuf[i] = '\0'; - Element *n = parse(charbuf, 0, len); - free(charbuf); - return n; -} - -Element *Parser::parse(const DOMString &buf) -{ - long len = buf.size(); - XMLCh *charbuf = (XMLCh *)malloc((len+1) * sizeof(XMLCh)); - long i = 0; - while (i< len) - { - charbuf[i] = (XMLCh)buf[i]; - i++; - } - charbuf[i] = '\0'; - Element *n = parse(charbuf, 0, len); - free(charbuf); - return n; -} - -Element *Parser::parseFile(const char *fileName) -{ - - //##### LOAD INTO A CHAR BUF, THEN CONVERT TO XMLCh - if (!fileName) - return NULL; - - FILE *f = fopen(fileName, "rb"); - if (!f) - return NULL; - - struct stat statBuf; - if (fstat(fileno(f),&statBuf)<0) - { - fclose(f); - return NULL; - } - long filelen = statBuf.st_size; - - //printf("length:%d\n",filelen); - XMLCh *charbuf = (XMLCh *)malloc((filelen+1) * sizeof(XMLCh)); - for (XMLCh *p=charbuf ; !feof(f) ; p++) - { - *p = (XMLCh)fgetc(f); - } - fclose(f); - charbuf[filelen] = '\0'; - - - /* - printf("nrbytes:%d\n",wc_count); - printf("buf:%ls\n======\n",charbuf); - */ - Element *n = parse(charbuf, 0, filelen); - free(charbuf); - return n; -} - - - - - - - -}//namespace Pedro - -#if 0 -//######################################################################## -//# T E S T -//######################################################################## - -bool doTest(char *fileName) -{ - Pedro::Parser parser; - - Pedro::Element *elem = parser.parseFile(fileName); - - if (!elem) - { - printf("Parsing failed\n"); - return false; - } - - elem->print(); - - delete elem; - - return true; -} - - - -int main(int argc, char **argv) -{ - if (argc != 2) - { - printf("usage: %s \n", argv[0]); - return 1; - } - - if (!doTest(argv[1])) - return 1; - - return 0; -} - -#endif - -//######################################################################## -//# E N D O F F I L E -//######################################################################## - - diff --git a/src/jabber_whiteboard/pedrodom.h b/src/jabber_whiteboard/pedrodom.h deleted file mode 100644 index 9c6651259..000000000 --- a/src/jabber_whiteboard/pedrodom.h +++ /dev/null @@ -1,343 +0,0 @@ -#ifndef __PEDRODOM_H__ -#define __PEDRODOM_H__ -/* - * API for the Pedro mini-DOM parser and tree - * - * Authors: - * Bob Jamison - * - * Copyright (C) 2005-2006 Bob Jamison - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include - - -namespace Pedro -{ - -typedef std::string DOMString; -typedef unsigned int XMLCh; - - -class Namespace -{ -public: - Namespace() - {} - - Namespace(const DOMString &prefixArg, const DOMString &namespaceURIArg) - { - prefix = prefixArg; - namespaceURI = namespaceURIArg; - } - - Namespace(const Namespace &other) - { - assign(other); - } - - Namespace &operator=(const Namespace &other) - { - assign(other); - return *this; - } - - virtual ~Namespace() - {} - - virtual DOMString getPrefix() - { return prefix; } - - virtual DOMString getNamespaceURI() - { return namespaceURI; } - -protected: - - void assign(const Namespace &other) - { - prefix = other.prefix; - namespaceURI = other.namespaceURI; - } - - DOMString prefix; - DOMString namespaceURI; - -}; - -class Attribute -{ -public: - Attribute() - {} - - Attribute(const DOMString &nameArg, const DOMString &valueArg) - { - name = nameArg; - value = valueArg; - } - - Attribute(const Attribute &other) - { - assign(other); - } - - Attribute &operator=(const Attribute &other) - { - assign(other); - return *this; - } - - virtual ~Attribute() - {} - - virtual DOMString getName() - { return name; } - - virtual DOMString getValue() - { return value; } - -protected: - - void assign(const Attribute &other) - { - name = other.name; - value = other.value; - } - - DOMString name; - DOMString value; - -}; - - -class Element -{ -friend class Parser; - -public: - Element() - { - parent = NULL; - } - - Element(const DOMString &nameArg) - { - parent = NULL; - name = nameArg; - } - - Element(const DOMString &nameArg, const DOMString &valueArg) - { - parent = NULL; - name = nameArg; - value = valueArg; - } - - Element(const Element &other) - { - assign(other); - } - - Element &operator=(const Element &other) - { - assign(other); - return *this; - } - - virtual Element *clone(); - - virtual ~Element() - { - for (unsigned int i=0 ; i getChildren() - { return children; } - - std::vector findElements(const DOMString &name); - - DOMString getAttribute(const DOMString &name); - - DOMString getTagAttribute(const DOMString &tagName, const DOMString &attrName); - - DOMString getTagValue(const DOMString &tagName); - - void addChild(Element *child); - - void addAttribute(const DOMString &name, const DOMString &value); - - void addNamespace(const DOMString &prefix, const DOMString &namespaceURI); - - - /** - * Prettyprint an XML tree to an output stream. Elements are indented - * according to element hierarchy. - * @param f a stream to receive the output - * @param elem the element to output - */ - void writeIndented(FILE *f); - - /** - * Prettyprint an XML tree to standard output. This is the equivalent of - * writeIndented(stdout). - * @param elem the element to output - */ - void print(); - -protected: - - void assign(const Element &other) - { - parent = other.parent; - children = other.children; - attributes = other.attributes; - namespaces = other.namespaces; - name = other.name; - value = other.value; - } - - void findElementsRecursive(std::vector&res, const DOMString &name); - - void writeIndentedRecursive(FILE *f, int indent); - - Element *parent; - - std::vectorchildren; - - std::vector attributes; - std::vector namespaces; - - DOMString name; - DOMString value; - -}; - - - - - -class Parser -{ -public: - /** - * Constructor - */ - Parser() - { init(); } - - virtual ~Parser() - {} - - /** - * Parse XML in a char buffer. - * @param buf a character buffer to parse - * @param pos position to start parsing - * @param len number of chars, from pos, to parse. - * @return a pointer to the root of the XML document; - */ - Element *parse(const char *buf,int pos,int len); - - /** - * Parse XML in a char buffer. - * @param buf a character buffer to parse - * @param pos position to start parsing - * @param len number of chars, from pos, to parse. - * @return a pointer to the root of the XML document; - */ - Element *parse(const DOMString &buf); - - /** - * Parse a named XML file. The file is loaded like a data file; - * the original format is not preserved. - * @param fileName the name of the file to read - * @return a pointer to the root of the XML document; - */ - Element *parseFile(const char *fileName); - - /** - * Utility method to preprocess a string for XML - * output, escaping its entities. - * @param str the string to encode - */ - static DOMString encode(const DOMString &str); - - -private: - - void init() - { - keepGoing = true; - currentNode = NULL; - parselen = 0; - parsebuf = NULL; - currentPosition = 0; - } - - void getLineAndColumn(long pos, long *lineNr, long *colNr); - - void error(char *fmt, ...); - - int peek(long pos); - - int match(long pos, const char *text); - - int skipwhite(long p); - - int getWord(int p0, DOMString &buf); - - int getQuoted(int p0, DOMString &buf, int do_i_parse); - - int parseVersion(int p0); - - int parseDoctype(int p0); - - int parseElement(int p0, Element *par,int depth); - - Element *parse(XMLCh *buf,int pos,int len); - - bool keepGoing; - Element *currentNode; - long parselen; - XMLCh *parsebuf; - DOMString cdatabuf; - long currentPosition; - int colNr; - -}; - - - -}//namespace Pedro - - -#endif /* __PEDRODOM_H__ */ - -//######################################################################## -//# E N D O F F I L E -//######################################################################## - diff --git a/src/jabber_whiteboard/pedroxmpp.cpp b/src/jabber_whiteboard/pedroxmpp.cpp deleted file mode 100644 index f5ce69e0b..000000000 --- a/src/jabber_whiteboard/pedroxmpp.cpp +++ /dev/null @@ -1,4842 +0,0 @@ -/* - * Implementation the Pedro mini-XMPP client - * - * Authors: - * Bob Jamison - * - * Copyright (C) 2005 Bob Jamison - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - - -#include -#include - -#include - -#include "pedroxmpp.h" -#include "pedrodom.h" - -#ifdef __WIN32__ - -#include - -#else /* UNIX */ - -#include -#include -#include -#include -#include -#include - -#include - -#endif - -#ifdef HAVE_SSL -#include -#include -#endif - - -namespace Pedro -{ - -//######################################################################## -//######################################################################## -//### U T I L I T Y -//######################################################################## -//######################################################################## - - -//######################################################################## -//# B A S E 6 4 -//######################################################################## - -//################# -//# ENCODER -//################# - - -static char *base64encode = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - -/** - * This class is for Base-64 encoding - */ -class Base64Encoder -{ - -public: - - Base64Encoder() - { - reset(); - } - - virtual ~Base64Encoder() - {} - - virtual void reset() - { - outBuf = 0L; - bitCount = 0; - buf = ""; - } - - virtual void append(int ch); - - virtual void append(char *str); - - virtual void append(unsigned char *str, int len); - - virtual void append(const DOMString &str); - - virtual DOMString finish(); - - static DOMString encode(const DOMString &str); - - -private: - - - unsigned long outBuf; - - int bitCount; - - DOMString buf; - -}; - - - -/** - * Writes the specified byte to the output buffer - */ -void Base64Encoder::append(int ch) -{ - outBuf <<= 8; - outBuf |= (ch & 0xff); - bitCount += 8; - if (bitCount >= 24) - { - int indx = (int)((outBuf & 0x00fc0000L) >> 18); - int obyte = (int)base64encode[indx & 63]; - buf.push_back(obyte); - - indx = (int)((outBuf & 0x0003f000L) >> 12); - obyte = (int)base64encode[indx & 63]; - buf.push_back(obyte); - - indx = (int)((outBuf & 0x00000fc0L) >> 6); - obyte = (int)base64encode[indx & 63]; - buf.push_back(obyte); - - indx = (int)((outBuf & 0x0000003fL) ); - obyte = (int)base64encode[indx & 63]; - buf.push_back(obyte); - - bitCount = 0; - outBuf = 0L; - } -} - -/** - * Writes the specified string to the output buffer - */ -void Base64Encoder::append(char *str) -{ - while (*str) - append((int)*str++); -} - -/** - * Writes the specified string to the output buffer - */ -void Base64Encoder::append(unsigned char *str, int len) -{ - while (len>0) - { - append((int)*str++); - len--; - } -} - -/** - * Writes the specified string to the output buffer - */ -void Base64Encoder::append(const DOMString &str) -{ - append((char *)str.c_str()); -} - -/** - * Closes this output stream and releases any system resources - * associated with this stream. - */ -DOMString Base64Encoder::finish() -{ - //get any last bytes (1 or 2) out of the buffer - if (bitCount == 16) - { - outBuf <<= 2; //pad to make 18 bits - - int indx = (int)((outBuf & 0x0003f000L) >> 12); - int obyte = (int)base64encode[indx & 63]; - buf.push_back(obyte); - - indx = (int)((outBuf & 0x00000fc0L) >> 6); - obyte = (int)base64encode[indx & 63]; - buf.push_back(obyte); - - indx = (int)((outBuf & 0x0000003fL) ); - obyte = (int)base64encode[indx & 63]; - buf.push_back(obyte); - - buf.push_back('='); - } - else if (bitCount == 8) - { - outBuf <<= 4; //pad to make 12 bits - - int indx = (int)((outBuf & 0x00000fc0L) >> 6); - int obyte = (int)base64encode[indx & 63]; - buf.push_back(obyte); - - indx = (int)((outBuf & 0x0000003fL) ); - obyte = (int)base64encode[indx & 63]; - buf.push_back(obyte); - - buf.push_back('='); - buf.push_back('='); - } - - DOMString ret = buf; - reset(); - return ret; -} - - -DOMString Base64Encoder::encode(const DOMString &str) -{ - Base64Encoder encoder; - encoder.append(str); - DOMString ret = encoder.finish(); - return ret; -} - - - -//################# -//# DECODER -//################# - -static int base64decode[] = -{ -/*00*/ -1, -1, -1, -1, -1, -1, -1, -1, -/*08*/ -1, -1, -1, -1, -1, -1, -1, -1, -/*10*/ -1, -1, -1, -1, -1, -1, -1, -1, -/*18*/ -1, -1, -1, -1, -1, -1, -1, -1, -/*20*/ -1, -1, -1, -1, -1, -1, -1, -1, -/*28*/ -1, -1, -1, 62, -1, -1, -1, 63, -/*30*/ 52, 53, 54, 55, 56, 57, 58, 59, -/*38*/ 60, 61, -1, -1, -1, -1, -1, -1, -/*40*/ -1, 0, 1, 2, 3, 4, 5, 6, -/*48*/ 7, 8, 9, 10, 11, 12, 13, 14, -/*50*/ 15, 16, 17, 18, 19, 20, 21, 22, -/*58*/ 23, 24, 25, -1, -1, -1, -1, -1, -/*60*/ -1, 26, 27, 28, 29, 30, 31, 32, -/*68*/ 33, 34, 35, 36, 37, 38, 39, 40, -/*70*/ 41, 42, 43, 44, 45, 46, 47, 48, -/*78*/ 49, 50, 51, -1, -1, -1, -1, -1 -}; - -class Base64Decoder -{ -public: - Base64Decoder() - { - reset(); - } - - virtual ~Base64Decoder() - {} - - virtual void reset() - { - inCount = 0; - buf.clear(); - } - - - virtual void append(int ch); - - virtual void append(char *str); - - virtual void append(const DOMString &str); - - std::vector finish(); - - static std::vector decode(const DOMString &str); - - static DOMString decodeToString(const DOMString &str); - -private: - - int inBytes[4]; - int inCount; - std::vector buf; -}; - -/** - * Appends one char to the decoder - */ -void Base64Decoder::append(int ch) -{ - if (isspace(ch)) - return; - else if (ch == '=') //padding - { - inBytes[inCount++] = 0; - } - else - { - int byteVal = base64decode[ch & 0x7f]; - //printf("char:%c %d\n", ch, byteVal); - if (byteVal < 0) - { - //Bad lookup value - } - inBytes[inCount++] = byteVal; - } - - if (inCount >=4 ) - { - unsigned char b0 = ((inBytes[0]<<2) & 0xfc) | ((inBytes[1]>>4) & 0x03); - unsigned char b1 = ((inBytes[1]<<4) & 0xf0) | ((inBytes[2]>>2) & 0x0f); - unsigned char b2 = ((inBytes[2]<<6) & 0xc0) | ((inBytes[3] ) & 0x3f); - buf.push_back(b0); - buf.push_back(b1); - buf.push_back(b2); - inCount = 0; - } - -} - -void Base64Decoder::append(char *str) -{ - while (*str) - append((int)*str++); -} - -void Base64Decoder::append(const DOMString &str) -{ - append((char *)str.c_str()); -} - -std::vector Base64Decoder::finish() -{ - std::vector ret = buf; - reset(); - return ret; -} - -std::vector Base64Decoder::decode(const DOMString &str) -{ - Base64Decoder decoder; - decoder.append(str); - std::vector ret = decoder.finish(); - return ret; -} - -DOMString Base64Decoder::decodeToString(const DOMString &str) -{ - Base64Decoder decoder; - decoder.append(str); - std::vector ret = decoder.finish(); - DOMString buf; - for (unsigned int i=0 ; i>4) & 15 ]); - ret.push_back(sha1hex[ ch & 15 ]); - } - return ret; -} - - -void Sha1::init() -{ - - lenW = 0; - sizeHi = 0; - sizeLo = 0; - - // Initialize H with the magic constants (see FIPS180 for constants) - H[0] = 0x67452301L; - H[1] = 0xefcdab89L; - H[2] = 0x98badcfeL; - H[3] = 0x10325476L; - H[4] = 0xc3d2e1f0L; - - for (int i = 0; i < 80; i++) - W[i] = 0; -} - - -void Sha1::append(unsigned char *dataIn, int len) -{ - // Read the data into W and process blocks as they get full - for (int i = 0; i < len; i++) - { - W[lenW / 4] <<= 8; - W[lenW / 4] |= (unsigned long)dataIn[i]; - if ((++lenW) % 64 == 0) - { - hashblock(); - lenW = 0; - } - sizeLo += 8; - sizeHi += (sizeLo < 8); - } -} - - -void Sha1::finish(unsigned char hashout[20]) -{ - unsigned char pad0x80 = 0x80; - unsigned char pad0x00 = 0x00; - unsigned char padlen[8]; - - // Pad with a binary 1 (e.g. 0x80), then zeroes, then length - padlen[0] = (unsigned char)((sizeHi >> 24) & 255); - padlen[1] = (unsigned char)((sizeHi >> 16) & 255); - padlen[2] = (unsigned char)((sizeHi >> 8) & 255); - padlen[3] = (unsigned char)((sizeHi >> 0) & 255); - padlen[4] = (unsigned char)((sizeLo >> 24) & 255); - padlen[5] = (unsigned char)((sizeLo >> 16) & 255); - padlen[6] = (unsigned char)((sizeLo >> 8) & 255); - padlen[7] = (unsigned char)((sizeLo >> 0) & 255); - - append(&pad0x80, 1); - - while (lenW != 56) - append(&pad0x00, 1); - append(padlen, 8); - - // Output hash - for (int i = 0; i < 20; i++) - { - hashout[i] = (unsigned char)(H[i / 4] >> 24); - H[i / 4] <<= 8; - } - - // Re-initialize the context (also zeroizes contents) - init(); -} - - -#define SHA_ROTL(X,n) ((((X) << (n)) | ((X) >> (32-(n)))) & 0xffffffffL) - -void Sha1::hashblock() -{ - - for (int t = 16; t <= 79; t++) - W[t] = SHA_ROTL(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16], 1); - - unsigned long A = H[0]; - unsigned long B = H[1]; - unsigned long C = H[2]; - unsigned long D = H[3]; - unsigned long E = H[4]; - - unsigned long TEMP; - - for (int t = 0; t <= 19; t++) - { - TEMP = (SHA_ROTL(A,5) + (((C^D)&B)^D) + - E + W[t] + 0x5a827999L) & 0xffffffffL; - E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP; - } - for (int t = 20; t <= 39; t++) - { - TEMP = (SHA_ROTL(A,5) + (B^C^D) + - E + W[t] + 0x6ed9eba1L) & 0xffffffffL; - E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP; - } - for (int t = 40; t <= 59; t++) - { - TEMP = (SHA_ROTL(A,5) + ((B&C)|(D&(B|C))) + - E + W[t] + 0x8f1bbcdcL) & 0xffffffffL; - E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP; - } - for (int t = 60; t <= 79; t++) - { - TEMP = (SHA_ROTL(A,5) + (B^C^D) + - E + W[t] + 0xca62c1d6L) & 0xffffffffL; - E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP; - } - - H[0] += A; - H[1] += B; - H[2] += C; - H[3] += D; - H[4] += E; -} - - - - - -//######################################################################## -//# M D 5 -//######################################################################## - -class Md5 -{ -public: - - /** - * - */ - Md5() - { init(); } - - /** - * - */ - virtual ~Md5() - {} - - /** - * Static convenience method. - * @parm digest points to an buffer of 16 unsigned chars - */ - static void hash(unsigned char *dataIn, - unsigned long len, unsigned char *digest); - - static DOMString Md5::hashHex(unsigned char *dataIn, unsigned long len); - - /** - * Initialize the context (also zeroizes contents) - */ - virtual void init(); - - /** - * - */ - virtual void append(unsigned char *dataIn, unsigned long len); - - /** - * - */ - virtual void append(const DOMString &str); - - /** - * Finalize and output the hash. - * @parm digest points to an buffer of 16 unsigned chars - */ - virtual void finish(unsigned char *digest); - - - /** - * Same as above , but hex to an output String - */ - virtual DOMString finishHex(); - -private: - - void transform(unsigned long *buf, unsigned long *in); - - unsigned long buf[4]; - unsigned long bits[2]; - unsigned char in[64]; - -}; - - - - -void Md5::hash(unsigned char *dataIn, unsigned long len, unsigned char *digest) -{ - Md5 md5; - md5.append(dataIn, len); - md5.finish(digest); -} - -DOMString Md5::hashHex(unsigned char *dataIn, unsigned long len) -{ - Md5 md5; - md5.append(dataIn, len); - DOMString ret = md5.finishHex(); - return ret; -} - - - -/* - * Note: this code is harmless on little-endian machines. - */ -/* -static void byteReverse(unsigned char *buf, unsigned long longs) -{ - do - { - unsigned long t = (unsigned long) - ((unsigned) buf[3] << 8 | buf[2]) << 16 | - ((unsigned) buf[1] << 8 | buf[0]); - *(unsigned long *) buf = t; - buf += 4; - } while (--longs); -} -*/ - -static void md5_memcpy(void *dest, void *src, int n) -{ - unsigned char *s1 = (unsigned char *)dest; - unsigned char *s2 = (unsigned char *)src; - while (n--) - *s1++ = *s2++; -} - -static void md5_memset(void *dest, char v, int n) -{ - unsigned char *s = (unsigned char *)dest; - while (n--) - *s++ = v; -} - -/** - * Initialize MD5 polynomials and storage - */ -void Md5::init() -{ - buf[0] = 0x67452301; - buf[1] = 0xefcdab89; - buf[2] = 0x98badcfe; - buf[3] = 0x10325476; - - bits[0] = 0; - bits[1] = 0; -} - -/* - * Update context to reflect the concatenation of another buffer full - * of bytes. - */ -void Md5::append(unsigned char *source, unsigned long len) -{ - - // Update bitcount - unsigned long t = bits[0]; - if ((bits[0] = t + ((unsigned long) len << 3)) < t) - bits[1]++;// Carry from low to high - bits[1] += len >> 29; - - //Bytes already in shsInfo->data - t = (t >> 3) & 0x3f; - - - // Handle any leading odd-sized chunks - if (t) - { - unsigned char *p = (unsigned char *) in + t; - t = 64 - t; - if (len < t) - { - md5_memcpy(p, source, len); - return; - } - md5_memcpy(p, source, t); - //byteReverse(in, 16); - transform(buf, (unsigned long *) in); - source += t; - len -= t; - } - - // Process data in 64-byte chunks - while (len >= 64) - { - md5_memcpy(in, source, 64); - //byteReverse(in, 16); - transform(buf, (unsigned long *) in); - source += 64; - len -= 64; - } - - // Handle any remaining bytes of data. - md5_memcpy(in, source, len); -} - -/* - * Update context to reflect the concatenation of another string - */ -void Md5::append(const DOMString &str) -{ - append((unsigned char *)str.c_str(), str.size()); -} - -/* - * Final wrapup - pad to 64-byte boundary with the bit pattern - * 1 0* (64-bit count of bits processed, MSB-first) - */ -void Md5::finish(unsigned char *digest) -{ - // Compute number of bytes mod 64 - unsigned int count = (bits[0] >> 3) & 0x3F; - - // Set the first char of padding to 0x80. - // This is safe since there is always at least one byte free - unsigned char *p = in + count; - *p++ = 0x80; - - // Bytes of padding needed to make 64 bytes - count = 64 - 1 - count; - - // Pad out to 56 mod 64 - if (count < 8) - { - // Two lots of padding: Pad the first block to 64 bytes - md5_memset(p, 0, count); - //byteReverse(in, 16); - transform(buf, (unsigned long *) in); - - // Now fill the next block with 56 bytes - md5_memset(in, 0, 56); - } - else - { - // Pad block to 56 bytes - md5_memset(p, 0, count - 8); - } - //byteReverse(in, 14); - - // Append length in bits and transform - ((unsigned long *) in)[14] = bits[0]; - ((unsigned long *) in)[15] = bits[1]; - - transform(buf, (unsigned long *) in); - //byteReverse((unsigned char *) buf, 4); - md5_memcpy(digest, buf, 16); - init(); // Security! ;-) -} - -static char *md5hex = "0123456789abcdef"; - -DOMString Md5::finishHex() -{ - unsigned char hashout[16]; - finish(hashout); - DOMString ret; - for (int i=0 ; i<16 ; i++) - { - unsigned char ch = hashout[i]; - ret.push_back(md5hex[ (ch>>4) & 15 ]); - ret.push_back(md5hex[ ch & 15 ]); - } - return ret; -} - - - -//# The four core functions - F1 is optimized somewhat - -// #define F1(x, y, z) (x & y | ~x & z) -#define F1(x, y, z) (z ^ (x & (y ^ z))) -#define F2(x, y, z) F1(z, x, y) -#define F3(x, y, z) (x ^ y ^ z) -#define F4(x, y, z) (y ^ (x | ~z)) - -// ## This is the central step in the MD5 algorithm. -#define MD5STEP(f, w, x, y, z, data, s) \ - ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) - -/* - * The core of the MD5 algorithm, this alters an existing MD5 hash to - * reflect the addition of 16 longwords of new data. MD5Update blocks - * the data and converts bytes into longwords for this routine. - * @parm buf points to an array of 4 unsigned longs - * @parm in points to an array of 16 unsigned longs - */ -void Md5::transform(unsigned long *buf, unsigned long *in) -{ - unsigned long a = buf[0]; - unsigned long b = buf[1]; - unsigned long c = buf[2]; - unsigned long d = buf[3]; - - MD5STEP(F1, a, b, c, d, in[ 0] + 0xd76aa478, 7); - MD5STEP(F1, d, a, b, c, in[ 1] + 0xe8c7b756, 12); - MD5STEP(F1, c, d, a, b, in[ 2] + 0x242070db, 17); - MD5STEP(F1, b, c, d, a, in[ 3] + 0xc1bdceee, 22); - MD5STEP(F1, a, b, c, d, in[ 4] + 0xf57c0faf, 7); - MD5STEP(F1, d, a, b, c, in[ 5] + 0x4787c62a, 12); - MD5STEP(F1, c, d, a, b, in[ 6] + 0xa8304613, 17); - MD5STEP(F1, b, c, d, a, in[ 7] + 0xfd469501, 22); - MD5STEP(F1, a, b, c, d, in[ 8] + 0x698098d8, 7); - MD5STEP(F1, d, a, b, c, in[ 9] + 0x8b44f7af, 12); - MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); - MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); - MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); - MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); - MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); - MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); - - MD5STEP(F2, a, b, c, d, in[ 1] + 0xf61e2562, 5); - MD5STEP(F2, d, a, b, c, in[ 6] + 0xc040b340, 9); - MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); - MD5STEP(F2, b, c, d, a, in[ 0] + 0xe9b6c7aa, 20); - MD5STEP(F2, a, b, c, d, in[ 5] + 0xd62f105d, 5); - MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); - MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); - MD5STEP(F2, b, c, d, a, in[ 4] + 0xe7d3fbc8, 20); - MD5STEP(F2, a, b, c, d, in[ 9] + 0x21e1cde6, 5); - MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); - MD5STEP(F2, c, d, a, b, in[ 3] + 0xf4d50d87, 14); - MD5STEP(F2, b, c, d, a, in[ 8] + 0x455a14ed, 20); - MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); - MD5STEP(F2, d, a, b, c, in[ 2] + 0xfcefa3f8, 9); - MD5STEP(F2, c, d, a, b, in[ 7] + 0x676f02d9, 14); - MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); - - MD5STEP(F3, a, b, c, d, in[ 5] + 0xfffa3942, 4); - MD5STEP(F3, d, a, b, c, in[ 8] + 0x8771f681, 11); - MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); - MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); - MD5STEP(F3, a, b, c, d, in[ 1] + 0xa4beea44, 4); - MD5STEP(F3, d, a, b, c, in[ 4] + 0x4bdecfa9, 11); - MD5STEP(F3, c, d, a, b, in[ 7] + 0xf6bb4b60, 16); - MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); - MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); - MD5STEP(F3, d, a, b, c, in[ 0] + 0xeaa127fa, 11); - MD5STEP(F3, c, d, a, b, in[ 3] + 0xd4ef3085, 16); - MD5STEP(F3, b, c, d, a, in[ 6] + 0x04881d05, 23); - MD5STEP(F3, a, b, c, d, in[ 9] + 0xd9d4d039, 4); - MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); - MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); - MD5STEP(F3, b, c, d, a, in[ 2] + 0xc4ac5665, 23); - - MD5STEP(F4, a, b, c, d, in[ 0] + 0xf4292244, 6); - MD5STEP(F4, d, a, b, c, in[ 7] + 0x432aff97, 10); - MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); - MD5STEP(F4, b, c, d, a, in[ 5] + 0xfc93a039, 21); - MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); - MD5STEP(F4, d, a, b, c, in[ 3] + 0x8f0ccc92, 10); - MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); - MD5STEP(F4, b, c, d, a, in[ 1] + 0x85845dd1, 21); - MD5STEP(F4, a, b, c, d, in[ 8] + 0x6fa87e4f, 6); - MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); - MD5STEP(F4, c, d, a, b, in[ 6] + 0xa3014314, 15); - MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); - MD5STEP(F4, a, b, c, d, in[ 4] + 0xf7537e82, 6); - MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); - MD5STEP(F4, c, d, a, b, in[ 2] + 0x2ad7d2bb, 15); - MD5STEP(F4, b, c, d, a, in[ 9] + 0xeb86d391, 21); - - buf[0] += a; - buf[1] += b; - buf[2] += c; - buf[3] += d; -} - - - - - - - -//######################################################################## -//######################################################################## -//### T H R E A D -//######################################################################## -//######################################################################## - - -//######################################################################## -//### T H R E A D -//######################################################################## - -/** - * This is the interface for a delegate class which can - * be run by a Thread. - * Thread thread(runnable); - * thread.start(); - */ -class Runnable -{ -public: - - Runnable() - {} - virtual ~Runnable() - {} - - /** - * The method of a delegate class which can - * be run by a Thread. Thread is completed when this - * method is done. - */ - virtual void run() = 0; - -}; - - - -/** - * A simple wrapper of native threads in a portable class. - * It can be used either to execute its own run() method, or - * delegate to a Runnable class's run() method. - */ -class Thread -{ -public: - - /** - * Create a thread which will execute its own run() method. - */ - Thread() - { runnable = NULL ; started = false; } - - /** - * Create a thread which will run a Runnable class's run() method. - */ - Thread(const Runnable &runner) - { runnable = (Runnable *)&runner; started = false; } - - /** - * This does not kill a spawned thread. - */ - virtual ~Thread() - {} - - /** - * Static method to pause the current thread for a given - * number of milliseconds. - */ - static void sleep(unsigned long millis); - - /** - * This method will be executed if the Thread was created with - * no delegated Runnable class. The thread is completed when - * the method is done. - */ - virtual void run() - {} - - /** - * Starts the thread. - */ - virtual void start(); - - /** - * Calls either this class's run() method, or that of a Runnable. - * A user would normally not call this directly. - */ - virtual void execute() - { - started = true; - if (runnable) - runnable->run(); - else - run(); - } - -private: - - Runnable *runnable; - - bool started; - -}; - - - - - -#ifdef __WIN32__ - - -static DWORD WINAPI WinThreadFunction(LPVOID context) -{ - Thread *thread = (Thread *)context; - thread->execute(); - return 0; -} - - -void Thread::start() -{ - DWORD dwThreadId; - HANDLE hThread = CreateThread(NULL, 0, WinThreadFunction, - (LPVOID)this, 0, &dwThreadId); - //Make sure the thread is started before 'this' is deallocated - while (!started) - sleep(10); - CloseHandle(hThread); -} - -void Thread::sleep(unsigned long millis) -{ - Sleep(millis); -} - -#else /* UNIX */ - - -void *PthreadThreadFunction(void *context) -{ - Thread *thread = (Thread *)context; - thread->execute(); - return NULL; -} - - -void Thread::start() -{ - pthread_t thread; - - int ret = pthread_create(&thread, NULL, - PthreadThreadFunction, (void *)this); - if (ret != 0) - printf("Thread::start: thread creation failed: %s\n", strerror(ret)); - - //Make sure the thread is started before 'this' is deallocated - while (!started) - sleep(10); - -} - -void Thread::sleep(unsigned long millis) -{ - timespec requested; - requested.tv_sec = millis / 1000; - requested.tv_nsec = (millis % 1000 ) * 1000000L; - nanosleep(&requested, NULL); -} - -#endif - - -//######################################################################## -//######################################################################## -//### S O C K E T -//######################################################################## -//######################################################################## - - - - - -class TcpSocket -{ -public: - - TcpSocket(); - - TcpSocket(const std::string &hostname, int port); - - TcpSocket(const char *hostname, int port); - - TcpSocket(const TcpSocket &other); - - virtual ~TcpSocket(); - - bool isConnected(); - - void enableSSL(bool val); - - bool connect(const std::string &hostname, int portno); - - bool connect(const char *hostname, int portno); - - bool startTls(); - - bool connect(); - - bool disconnect(); - - bool setReceiveTimeout(unsigned long millis); - - long available(); - - bool write(int ch); - - bool write(char *str); - - bool write(const std::string &str); - - int read(); - - std::string readLine(); - -private: - void init(); - - std::string hostname; - int portno; - int sock; - bool connected; - - bool sslEnabled; - - unsigned long receiveTimeout; - -#ifdef HAVE_SSL - SSL_CTX *sslContext; - SSL *sslStream; -#endif - -}; - - - -//######################################################################### -//# U T I L I T Y -//######################################################################### - -static void mybzero(void *s, size_t n) -{ - unsigned char *p = (unsigned char *)s; - while (n > 0) - { - *p++ = (unsigned char)0; - n--; - } -} - -static void mybcopy(void *src, void *dest, size_t n) -{ - unsigned char *p = (unsigned char *)dest; - unsigned char *q = (unsigned char *)src; - while (n > 0) - { - *p++ = *q++; - n--; - } -} - - - -//######################################################################### -//# T C P C O N N E C T I O N -//######################################################################### - -TcpSocket::TcpSocket() -{ - init(); -} - - -TcpSocket::TcpSocket(const char *hostnameArg, int port) -{ - init(); - hostname = hostnameArg; - portno = port; -} - -TcpSocket::TcpSocket(const std::string &hostnameArg, int port) -{ - init(); - hostname = hostnameArg; - portno = port; -} - - -#ifdef HAVE_SSL - -static void cryptoLockCallback(int mode, int type, const char *file, int line) -{ - //printf("########### LOCK\n"); - static int modes[CRYPTO_NUM_LOCKS]; /* = {0, 0, ... } */ - const char *errstr = NULL; - - int rw = mode & (CRYPTO_READ|CRYPTO_WRITE); - if (!((rw == CRYPTO_READ) || (rw == CRYPTO_WRITE))) - { - errstr = "invalid mode"; - goto err; - } - - if (type < 0 || type >= CRYPTO_NUM_LOCKS) - { - errstr = "type out of bounds"; - goto err; - } - - if (mode & CRYPTO_LOCK) - { - if (modes[type]) - { - errstr = "already locked"; - /* must not happen in a single-threaded program - * (would deadlock) - */ - goto err; - } - - modes[type] = rw; - } - else if (mode & CRYPTO_UNLOCK) - { - if (!modes[type]) - { - errstr = "not locked"; - goto err; - } - - if (modes[type] != rw) - { - errstr = (rw == CRYPTO_READ) ? - "CRYPTO_r_unlock on write lock" : - "CRYPTO_w_unlock on read lock"; - } - - modes[type] = 0; - } - else - { - errstr = "invalid mode"; - goto err; - } - - err: - if (errstr) - { - /* we cannot use bio_err here */ - fprintf(stderr, "openssl (lock_dbg_cb): %s (mode=%d, type=%d) at %s:%d\n", - errstr, mode, type, file, line); - } -} - -static unsigned long cryptoIdCallback() -{ -#ifdef __WIN32__ - unsigned long ret = (unsigned long) GetCurrentThreadId(); -#else - unsigned long ret = (unsigned long) pthread_self(); -#endif - return ret; -} - -#endif - - -TcpSocket::TcpSocket(const TcpSocket &other) -{ - init(); - sock = other.sock; - hostname = other.hostname; - portno = other.portno; -} - -static bool tcp_socket_inited = false; - -void TcpSocket::init() -{ - if (!tcp_socket_inited) - { -#ifdef __WIN32__ - WORD wVersionRequested = MAKEWORD( 2, 2 ); - WSADATA wsaData; - WSAStartup( wVersionRequested, &wsaData ); -#endif -#ifdef HAVE_SSL - sslStream = NULL; - sslContext = NULL; - CRYPTO_set_locking_callback(cryptoLockCallback); - CRYPTO_set_id_callback(cryptoIdCallback); - SSL_library_init(); - SSL_load_error_strings(); -#endif - tcp_socket_inited = true; - } - sock = -1; - connected = false; - hostname = ""; - portno = -1; - sslEnabled = false; - receiveTimeout = 0; -} - -TcpSocket::~TcpSocket() -{ - disconnect(); -} - -bool TcpSocket::isConnected() -{ - if (!connected || sock < 0) - return false; - return true; -} - -void TcpSocket::enableSSL(bool val) -{ - sslEnabled = val; -} - - -bool TcpSocket::connect(const char *hostnameArg, int portnoArg) -{ - hostname = hostnameArg; - portno = portnoArg; - return connect(); -} - -bool TcpSocket::connect(const std::string &hostnameArg, int portnoArg) -{ - hostname = hostnameArg; - portno = portnoArg; - return connect(); -} - - - -#ifdef HAVE_SSL -/* -static int password_cb(char *buf, int bufLen, int rwflag, void *userdata) -{ - char *password = "password"; - if (bufLen < (int)(strlen(password)+1)) - return 0; - - strcpy(buf,password); - int ret = strlen(password); - return ret; -} - -static void infoCallback(const SSL *ssl, int where, int ret) -{ - switch (where) - { - case SSL_CB_ALERT: - { - printf("## %d SSL ALERT: %s\n", where, SSL_alert_desc_string_long(ret)); - break; - } - default: - { - printf("## %d SSL: %s\n", where, SSL_state_string_long(ssl)); - break; - } - } -} -*/ -#endif - - -bool TcpSocket::startTls() -{ -#ifdef HAVE_SSL - sslStream = NULL; - sslContext = NULL; - - //SSL_METHOD *meth = SSLv23_method(); - //SSL_METHOD *meth = SSLv3_client_method(); - SSL_METHOD *meth = TLSv1_client_method(); - sslContext = SSL_CTX_new(meth); - //SSL_CTX_set_info_callback(sslContext, infoCallback); - -#if 0 - char *keyFile = "client.pem"; - char *caList = "root.pem"; - /* Load our keys and certificates*/ - if (!(SSL_CTX_use_certificate_chain_file(sslContext, keyFile))) - { - fprintf(stderr, "Can't read certificate file\n"); - disconnect(); - return false; - } - - SSL_CTX_set_default_passwd_cb(sslContext, password_cb); - - if (!(SSL_CTX_use_PrivateKey_file(sslContext, keyFile, SSL_FILETYPE_PEM))) - { - fprintf(stderr, "Can't read key file\n"); - disconnect(); - return false; - } - - /* Load the CAs we trust*/ - if (!(SSL_CTX_load_verify_locations(sslContext, caList, 0))) - { - fprintf(stderr, "Can't read CA list\n"); - disconnect(); - return false; - } -#endif - - /* Connect the SSL socket */ - sslStream = SSL_new(sslContext); - SSL_set_fd(sslStream, sock); - - if (SSL_connect(sslStream)<=0) - { - fprintf(stderr, "SSL connect error\n"); - disconnect(); - return false; - } - - sslEnabled = true; -#endif /*HAVE_SSL*/ - return true; -} - - -bool TcpSocket::connect() -{ - if (hostname.size()<1) - { - printf("open: null hostname\n"); - return false; - } - - if (portno<1) - { - printf("open: bad port number\n"); - return false; - } - - sock = socket(PF_INET, SOCK_STREAM, 0); - if (sock < 0) - { - printf("open: error creating socket\n"); - return false; - } - - char *c_hostname = (char *)hostname.c_str(); - struct hostent *server = gethostbyname(c_hostname); - if (!server) - { - printf("open: could not locate host '%s'\n", c_hostname); - return false; - } - - struct sockaddr_in serv_addr; - mybzero((char *) &serv_addr, sizeof(serv_addr)); - serv_addr.sin_family = AF_INET; - mybcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, - server->h_length); - serv_addr.sin_port = htons(portno); - - int ret = ::connect(sock, (const sockaddr *)&serv_addr, sizeof(serv_addr)); - if (ret < 0) - { - printf("open: could not connect to host '%s'\n", c_hostname); - return false; - } - - if (sslEnabled) - { - if (!startTls()) - return false; - } - connected = true; - return true; -} - -bool TcpSocket::disconnect() -{ - bool ret = true; - connected = false; -#ifdef HAVE_SSL - if (sslEnabled) - { - if (sslStream) - { - int r = SSL_shutdown(sslStream); - switch(r) - { - case 1: - break; /* Success */ - case 0: - case -1: - default: - //printf("Shutdown failed"); - ret = false; - } - SSL_free(sslStream); - } - if (sslContext) - SSL_CTX_free(sslContext); - } - sslStream = NULL; - sslContext = NULL; -#endif /*HAVE_SSL*/ - -#ifdef __WIN32__ - closesocket(sock); -#else - ::close(sock); -#endif - sock = -1; - sslEnabled = false; - - return ret; -} - - - -bool TcpSocket::setReceiveTimeout(unsigned long millis) -{ - receiveTimeout = millis; - return true; -} - -/** - * For normal sockets, return the number of bytes waiting to be received. - * For SSL, just return >0 when something is ready to be read. - */ -long TcpSocket::available() -{ - if (!isConnected()) - return -1; - - long count = 0; -#ifdef __WIN32__ - if (ioctlsocket(sock, FIONREAD, (unsigned long *)&count) != 0) - return -1; -#else - if (ioctl(sock, FIONREAD, &count) != 0) - return -1; -#endif - if (count<=0 && sslEnabled) - { -#ifdef HAVE_SSL - return SSL_pending(sslStream); -#endif - } - return count; -} - - - -bool TcpSocket::write(int ch) -{ - if (!isConnected()) - { - printf("write: socket closed\n"); - return false; - } - unsigned char c = (unsigned char)ch; - - if (sslEnabled) - { -#ifdef HAVE_SSL - int r = SSL_write(sslStream, &c, 1); - if (r<=0) - { - switch(SSL_get_error(sslStream, r)) - { - default: - printf("SSL write problem"); - return -1; - } - } -#endif - } - else - { - if (send(sock, (const char *)&c, 1, 0) < 0) - //if (send(sock, &c, 1, 0) < 0) - { - printf("write: could not send data\n"); - return false; - } - } - return true; -} - -bool TcpSocket::write(char *str) -{ - if (!isConnected()) - { - printf("write(str): socket closed\n"); - return false; - } - int len = strlen(str); - - if (sslEnabled) - { -#ifdef HAVE_SSL - int r = SSL_write(sslStream, (unsigned char *)str, len); - if (r<=0) - { - switch(SSL_get_error(sslStream, r)) - { - default: - printf("SSL write problem"); - return -1; - } - } -#endif - } - else - { - if (send(sock, str, len, 0) < 0) - //if (send(sock, &c, 1, 0) < 0) - { - printf("write: could not send data\n"); - return false; - } - } - return true; -} - -bool TcpSocket::write(const std::string &str) -{ - return write((char *)str.c_str()); -} - -int TcpSocket::read() -{ - if (!isConnected()) - return -1; - - //We'll use this loop for timeouts, so that SSL and plain sockets - //will behave the same way - if (receiveTimeout > 0) - { - unsigned long tim = 0; - while (true) - { - int avail = available(); - if (avail > 0) - break; - if (tim >= receiveTimeout) - return -2; - Thread::sleep(20); - tim += 20; - } - } - - //check again - if (!isConnected()) - return -1; - - unsigned char ch; - if (sslEnabled) - { -#ifdef HAVE_SSL - if (!sslStream) - return -1; - int r = SSL_read(sslStream, &ch, 1); - unsigned long err = SSL_get_error(sslStream, r); - switch (err) - { - case SSL_ERROR_NONE: - break; - case SSL_ERROR_ZERO_RETURN: - return -1; - case SSL_ERROR_SYSCALL: - printf("SSL read problem(syscall) %s\n", - ERR_error_string(ERR_get_error(), NULL)); - return -1; - default: - printf("SSL read problem %s\n", - ERR_error_string(ERR_get_error(), NULL)); - return -1; - } -#endif - } - else - { - if (recv(sock, (char *)&ch, 1, 0) <= 0) - { - printf("read: could not receive data\n"); - disconnect(); - return -1; - } - } - return (int)ch; -} - -std::string TcpSocket::readLine() -{ - std::string ret; - - while (isConnected()) - { - int ch = read(); - if (ch<0) - return ret; - if (ch=='\r' || ch=='\n') - return ret; - ret.push_back((char)ch); - } - - return ret; -} - - -//######################################################################## -//######################################################################## -//### X M P P -//######################################################################## -//######################################################################## - - - - -//######################################################################## -//# X M P P E V E N T -//######################################################################## - - -XmppEvent::XmppEvent(int type) -{ - eventType = type; - presence = false; - dom = NULL; -} - -XmppEvent::XmppEvent(const XmppEvent &other) -{ - assign(other); -} - -XmppEvent &XmppEvent::operator=(const XmppEvent &other) -{ - assign(other); - return (*this); -} - -XmppEvent::~XmppEvent() -{ - if (dom) - delete dom; -} - -void XmppEvent::assign(const XmppEvent &other) -{ - eventType = other.eventType; - presence = other.presence; - status = other.status; - show = other.show; - to = other.to; - from = other.from; - group = other.group; - data = other.data; - fileName = other.fileName; - fileDesc = other.fileDesc; - fileSize = other.fileSize; - fileHash = other.fileHash; - setDOM(other.dom); -} - -int XmppEvent::getType() const -{ - return eventType; -} - -DOMString XmppEvent::getIqId() const -{ - return iqId; -} - -void XmppEvent::setIqId(const DOMString &val) -{ - iqId = val; -} - -DOMString XmppEvent::getStreamId() const -{ - return streamId; -} - -void XmppEvent::setStreamId(const DOMString &val) -{ - streamId = val; -} - -bool XmppEvent::getPresence() const -{ - return presence; -} - -void XmppEvent::setPresence(bool val) -{ - presence = val; -} - -DOMString XmppEvent::getShow() const -{ - return show; -} - -void XmppEvent::setShow(const DOMString &val) -{ - show = val; -} - -DOMString XmppEvent::getStatus() const -{ - return status; -} - -void XmppEvent::setStatus(const DOMString &val) -{ - status = val; -} - -DOMString XmppEvent::getTo() const -{ - return to; -} - -void XmppEvent::setTo(const DOMString &val) -{ - to = val; -} - -DOMString XmppEvent::getFrom() const -{ - return from; -} - -void XmppEvent::setFrom(const DOMString &val) -{ - from = val; -} - -DOMString XmppEvent::getGroup() const -{ - return group; -} - -void XmppEvent::setGroup(const DOMString &val) -{ - group = val; -} - -DOMString XmppEvent::getData() const -{ - return data; -} - -void XmppEvent::setData(const DOMString &val) -{ - data = val; -} - -DOMString XmppEvent::getFileName() const -{ - return fileName; -} - -void XmppEvent::setFileName(const DOMString &val) -{ - fileName = val; -} - -DOMString XmppEvent::getFileDesc() const -{ - return fileDesc; -} - -void XmppEvent::setFileDesc(const DOMString &val) -{ - fileDesc = val; -} - -long XmppEvent::getFileSize() const -{ - return fileSize; -} - -void XmppEvent::setFileSize(long val) -{ - fileSize = val; -} - -DOMString XmppEvent::getFileHash() const -{ - return fileHash; -} - -void XmppEvent::setFileHash(const DOMString &val) -{ - fileHash = val; -} - -Element *XmppEvent::getDOM() const -{ - return dom; -} - -void XmppEvent::setDOM(const Element *val) -{ - if (!val) - dom = NULL; - else - dom = ((Element *)val)->clone(); -} - - -std::vector XmppEvent::getUserList() const -{ - return userList; -} - -void XmppEvent::setUserList(const std::vector &val) -{ - userList = val; -} - -//######################################################################## -//# X M P P E V E N T T A R G E T -//######################################################################## - -//########################### -//# CONSTRUCTORS -//########################### - -XmppEventTarget::XmppEventTarget() -{ - eventQueueEnabled = false; -} - - -XmppEventTarget::XmppEventTarget(const XmppEventTarget &other) -{ - listeners = other.listeners; - eventQueueEnabled = other.eventQueueEnabled; -} - -XmppEventTarget::~XmppEventTarget() -{ -} - - -//########################### -//# M E S S A G E S -//########################### - -void XmppEventTarget::error(char *fmt, ...) -{ - va_list args; - va_start(args,fmt); - vsnprintf(targetWriteBuf, targetWriteBufLen, fmt, args); - va_end(args) ; - printf("Error:%s\n", targetWriteBuf); - XmppEvent evt(XmppEvent::EVENT_ERROR); - evt.setData(targetWriteBuf); - dispatchXmppEvent(evt); -} - -void XmppEventTarget::status(char *fmt, ...) -{ - va_list args; - va_start(args,fmt); - vsnprintf(targetWriteBuf, targetWriteBufLen, fmt, args); - va_end(args) ; - //printf("Status:%s\n", targetWriteBuf); - XmppEvent evt(XmppEvent::EVENT_STATUS); - evt.setData(targetWriteBuf); - dispatchXmppEvent(evt); -} - - - -//########################### -//# L I S T E N E R S -//########################### - -void XmppEventTarget::dispatchXmppEvent(const XmppEvent &event) -{ - std::vector::iterator iter; - for (iter = listeners.begin(); iter != listeners.end() ; iter++) - (*iter)->processXmppEvent(event); - if (eventQueueEnabled) - eventQueue.push_back(event); -} - -void XmppEventTarget::addXmppEventListener(const XmppEventListener &listener) -{ - XmppEventListener *lsnr = (XmppEventListener *)&listener; - std::vector::iterator iter; - for (iter = listeners.begin(); iter != listeners.end() ; iter++) - if (*iter == lsnr) - return; - listeners.push_back(lsnr); -} - -void XmppEventTarget::removeXmppEventListener(const XmppEventListener &listener) -{ - XmppEventListener *lsnr = (XmppEventListener *)&listener; - std::vector::iterator iter; - for (iter = listeners.begin(); iter != listeners.end() ; iter++) - if (*iter == lsnr) - listeners.erase(iter); -} - -void XmppEventTarget::clearXmppEventListeners() -{ - listeners.clear(); -} - - -//########################### -//# E V E N T Q U E U E -//########################### - -void XmppEventTarget::eventQueueEnable(bool val) -{ - eventQueueEnabled = val; - if (!eventQueueEnabled) - eventQueue.clear(); -} - -int XmppEventTarget::eventQueueAvailable() -{ - return eventQueue.size(); -} - -XmppEvent XmppEventTarget::eventQueuePop() -{ - if (!eventQueueEnabled || eventQueue.size()<1) - { - XmppEvent dummy(XmppEvent::EVENT_NONE); - return dummy; - } - XmppEvent event = *(eventQueue.begin()); - eventQueue.erase(eventQueue.begin()); - return event; -} - - -//######################################################################## -//# X M P P S T R E A M -//######################################################################## - -/** - * - */ -class XmppStream -{ -public: - - /** - * - */ - XmppStream(); - - /** - * - */ - virtual ~XmppStream(); - - /** - * - */ - virtual void reset(); - - /** - * - */ - virtual int getState(); - - /** - * - */ - virtual void setState(int val); - - /** - * - */ - virtual DOMString getStreamId(); - - /** - * - */ - void setStreamId(const DOMString &val); - - /** - * - */ - virtual DOMString getIqId(); - - /** - * - */ - void setIqId(const DOMString &val); - - /** - * - */ - virtual int getSeqNr(); - - /** - * - */ - virtual DOMString getPeerId(); - - /** - * - */ - virtual void setPeerId(const DOMString &val); - - /** - * - */ - int available(); - - /** - * - */ - void receiveData(std::vector &newData); - - /** - * - */ - std::vector read(); - -private: - - - DOMString streamId; - - DOMString iqId; - - DOMString sourceId; - - int state; - - long seqNr; - - std::vector data; -}; - - -/** - * - */ -XmppStream::XmppStream() -{ - reset(); -} - -/** - * - */ -XmppStream::~XmppStream() -{ - reset(); -} - -/** - * - */ -void XmppStream::reset() -{ - state = XmppClient::STREAM_AVAILABLE; - seqNr = 0; - data.clear(); -} - -/** - * - */ -int XmppStream::getState() -{ - return state; -} - -/** - * - */ -void XmppStream::setState(int val) -{ - state = val; -} - -/** - * - */ -DOMString XmppStream::getStreamId() -{ - return streamId; -} - -/** - * - */ -void XmppStream::setStreamId(const DOMString &val) -{ - streamId = val; -} - -/** - * - */ -DOMString XmppStream::getIqId() -{ - return iqId; -} - - -/** - * - */ -void XmppStream::setIqId(const DOMString &val) -{ - iqId = val; -} - -/** - * Source or destination JID - */ -void XmppStream::setPeerId(const DOMString &val) -{ - sourceId = val; -} - -/** - * Source or destination JID - */ -DOMString XmppStream::getPeerId() -{ - return sourceId; -} - -/** - * Stream packet sequence number - */ -int XmppStream::getSeqNr() -{ - seqNr++; - if (seqNr >= 65535) - seqNr = 0; - return seqNr; -} - -/** - * - */ -int XmppStream::available() -{ - return data.size(); -} - -/** - * - */ -void XmppStream::receiveData(std::vector &newData) -{ - std::vector::iterator iter; - for (iter=newData.begin() ; iter!=newData.end() ; iter++) - data.push_back(*iter); -} - -/** - * - */ -std::vector XmppStream::read() -{ - if (state != XmppClient::STREAM_OPEN) - { - std::vectordummy; - return dummy; - } - std::vector ret = data; - data.clear(); - return ret; -} - - - - - - -//######################################################################## -//# X M P P C L I E N T -//######################################################################## -class ReceiverThread : public Runnable -{ -public: - - ReceiverThread(XmppClient &par) : client(par) {} - - virtual ~ReceiverThread() {} - - void run() - { client.receiveAndProcessLoop(); } - -private: - - XmppClient &client; -}; - - -//########################### -//# CONSTRUCTORS -//########################### - -XmppClient::XmppClient() -{ - init(); -} - - -XmppClient::XmppClient(const XmppClient &other) : XmppEventTarget(other) -{ - init(); - assign(other); -} - -void XmppClient::assign(const XmppClient &other) -{ - msgId = other.msgId; - host = other.host; - realm = other.realm; - port = other.port; - username = other.username; - password = other.password; - resource = other.resource; - connected = other.connected; - groupChats = other.groupChats; -} - - -void XmppClient::init() -{ - sock = new TcpSocket(); - msgId = 0; - connected = false; - - for (int i=0 ; i0 ; i--) - if (!isspace(str[i-1])) - break; - int end = i; - if (start>=end) - return ""; - return str.substr(start, end); -} - -//############################################## -//# VARIABLES (ones that need special handling) -//############################################## -/** - * - */ -DOMString XmppClient::getUsername() -{ - return username; -} - -/** - * - */ -void XmppClient::setUsername(const DOMString &val) -{ - int p = strIndex(val, "@"); - if (p > 0) - { - username = val.substr(0, p); - realm = val.substr(p+1, jid.size()-p-1); - } - else - { - realm = host; - username = val; - } -} - -//############################################## -//# CONNECTION -//############################################## - -//####################### -//# RECEIVING -//####################### -DOMString XmppClient::readStanza() -{ - int openCount = 0; - bool inTag = false; - bool slashSeen = false; - bool trivialTag = false; - bool querySeen = false; - bool inQuote = false; - bool textSeen = false; - DOMString buf; - - while (true) - { - int ch = sock->read(); - //printf("%c", ch); fflush(stdout); - if (ch<0) - { - if (ch == -2) //a simple timeout, not an error - { - //Since we are timed out, let's assume that we - //are between chunks of text. Let's reset all states. - //printf("-----#### Timeout\n"); - continue; - } - else - { - keepGoing = false; - if (!sock->isConnected()) - { - disconnect(); - return ""; - } - else - { - error("socket read error"); - disconnect(); - return ""; - } - } - } - buf.push_back(ch); - if (ch == '<') - { - inTag = true; - slashSeen = false; - querySeen = false; - inQuote = false; - textSeen = false; - trivialTag = false; - } - else if (ch == '>') - { - if (!inTag) //unescaped '>' in pcdata? horror - continue; - inTag = false; - if (!trivialTag && !querySeen) - { - if (slashSeen) - openCount--; - else - openCount++; - } - //printf("# openCount:%d t:%d q:%d\n", - // openCount, trivialTag, querySeen); - //check if we are 'balanced', but not a tag - if (openCount <= 0 && !querySeen) - { - break; - } - //we know that this one will be open-ended - if (strIndex(buf, "= 0) - { - buf.append(""); - break; - } - } - else if (ch == '/') - { - if (inTag && !inQuote) - { - slashSeen = true; - if (textSeen) // <--looks like this - trivialTag = true; - } - } - else if (ch == '?') - { - if (inTag && !inQuote) - querySeen = true; - } - else if (ch == '"' || ch == '\'') - { - if (inTag) - inQuote = !inQuote; - } - else - { - if (inTag && !inQuote && !isspace(ch)) - textSeen = true; - } - } - return buf; -} - - - -static bool isGroupChat(Element *root) -{ - if (!root) - return false; - std::vectorelems = root->findElements("x"); - for (unsigned int i=0 ; igetAttribute("xmlns"); - //printf("### XMLNS ### %s\n", xmlns.c_str()); - if (strIndex(xmlns, "http://jabber.org/protocol/muc") >=0 ) - return true; - } - return false; -} - - - - -static bool parseJid(const DOMString &fullJid, - DOMString &jid, DOMString &resource) -{ - int p = strIndex(fullJid, "/"); - if (p < 0) - { - jid = fullJid; - resource = ""; - return true; - } - jid = fullJid.substr(0, p); - resource = fullJid.substr(p+1, fullJid.size()-p-1); - return true; -} - - - - -bool XmppClient::processMessage(Element *root) -{ - DOMString from = root->getTagAttribute("message", "from"); - DOMString to = root->getTagAttribute("message", "to"); - DOMString type = root->getTagAttribute("message", "type"); - - //####Check for embedded namespaces here - //# IN BAND BYTESTREAMS - DOMString ibbNamespace = "http://jabber.org/protocol/ibb"; - if (root->getTagAttribute("data", "xmlns") == ibbNamespace) - { - DOMString streamId = root->getTagAttribute("data", "sid"); - if (streamId.size() > 0) - { - for (int i=0 ; igetStreamId().c_str(), streamId.c_str()); - if (ins->getStreamId() == streamId) - { - //# We have a winner - if (ins->getState() != STREAM_OPEN) - { - XmppEvent event(XmppEvent::EVENT_ERROR); - event.setFrom(from); - event.setData("received unrequested stream data"); - dispatchXmppEvent(event); - return true; - } - DOMString data = root->getTagValue("data"); - std::vectorbinData = - Base64Decoder::decode(data); - ins->receiveData(binData); - } - } - } - } - - - //#### NORMAL MESSAGES - DOMString subject = root->getTagValue("subject"); - DOMString body = root->getTagValue("body"); - DOMString thread = root->getTagValue("thread"); - //##rfc 3921, para 2.4. ignore if no recognizable info - if (subject.size() < 1 && body.size()<1 && thread.size()<1) - return true; - - if (type == "groupchat") - { - DOMString fromGid; - DOMString fromNick; - parseJid(from, fromGid, fromNick); - //printf("fromGid:%s fromNick:%s\n", - // fromGid.c_str(), fromNick.c_str()); - DOMString toGid; - DOMString toNick; - parseJid(to, toGid, toNick); - //printf("toGid:%s toNick:%s\n", - // toGid.c_str(), toNick.c_str()); - - if (fromNick.size() > 0)//normal group message - { - XmppEvent event(XmppEvent::EVENT_MUC_MESSAGE); - event.setGroup(fromGid); - event.setFrom(fromNick); - event.setData(body); - event.setDOM(root); - dispatchXmppEvent(event); - } - else // from the server itself - { - //note the space before, so it doesnt match 'unlocked' - if (strIndex(body, " locked") >= 0) - { - printf("LOCKED!! ;)\n"); - char *fmt = - "" - "" - "" - "\n"; - if (!write(fmt, jid.c_str(), msgId++, fromGid.c_str())) - return false; - } - } - } - else - { - XmppEvent event(XmppEvent::EVENT_MESSAGE); - event.setFrom(from); - event.setData(body); - event.setDOM(root); - dispatchXmppEvent(event); - } - - return true; -} - - - - -bool XmppClient::processPresence(Element *root) -{ - - DOMString fullJid = root->getTagAttribute("presence", "from"); - DOMString to = root->getTagAttribute("presence", "to"); - DOMString presenceStr = root->getTagAttribute("presence", "type"); - bool presence = true; - if (presenceStr == "unavailable") - presence = false; - DOMString status = root->getTagValue("status"); - DOMString show = root->getTagValue("show"); - - if (isGroupChat(root)) - { - DOMString fromGid; - DOMString fromNick; - parseJid(fullJid, fromGid, fromNick); - //printf("fromGid:%s fromNick:%s\n", - // fromGid.c_str(), fromNick.c_str()); - DOMString item_jid = root->getTagAttribute("item", "jid"); - if (item_jid == jid) //Me - { - if (presence) - { - groupChatCreate(fromGid); - groupChatUserAdd(fromGid, fromNick, ""); - groupChatUserShow(fromGid, fromNick, "available"); - - XmppEvent event(XmppEvent::EVENT_MUC_JOIN); - event.setGroup(fromGid); - event.setFrom(fromNick); - event.setPresence(presence); - event.setShow(show); - event.setStatus(status); - dispatchXmppEvent(event); - } - else - { - groupChatDelete(fromGid); - groupChatUserDelete(fromGid, fromNick); - - XmppEvent event(XmppEvent::EVENT_MUC_LEAVE); - event.setGroup(fromGid); - event.setFrom(fromNick); - event.setPresence(presence); - event.setShow(show); - event.setStatus(status); - dispatchXmppEvent(event); - } - } - else // someone else - { - if (presence) - { - groupChatUserAdd(fromGid, fromNick, ""); - } - else - groupChatUserDelete(fromGid, fromNick); - groupChatUserShow(fromGid, fromNick, show); - XmppEvent event(XmppEvent::EVENT_MUC_PRESENCE); - event.setGroup(fromGid); - event.setFrom(fromNick); - event.setPresence(presence); - event.setShow(show); - event.setStatus(status); - dispatchXmppEvent(event); - } - } - else - { - DOMString shortJid; - DOMString dummy; - parseJid(fullJid, shortJid, dummy); - rosterShow(shortJid, show); //users in roster do not have resource - - XmppEvent event(XmppEvent::EVENT_PRESENCE); - event.setFrom(fullJid); - event.setPresence(presence); - event.setShow(show); - event.setStatus(status); - dispatchXmppEvent(event); - } - - return true; -} - - - -bool XmppClient::processIq(Element *root) -{ - DOMString from = root->getTagAttribute("iq", "from"); - DOMString id = root->getTagAttribute("iq", "id"); - DOMString type = root->getTagAttribute("iq", "type"); - DOMString xmlns = root->getTagAttribute("query", "xmlns"); - - if (id.size()<1) - return true; - - //Group chat - if (strIndex(xmlns, "http://jabber.org/protocol/muc") >=0 ) - { - printf("results of MUC query\n"); - } - //printf("###IQ xmlns:%s\n", xmlns.c_str()); - - //### FILE TRANSFERS - DOMString siNamespace = "http://jabber.org/protocol/si"; - if (root->getTagAttribute("si", "xmlns") == siNamespace) - { - if (type == "set") - { - DOMString streamId = root->getTagAttribute("si", "id"); - DOMString fname = root->getTagAttribute("file", "name"); - DOMString sizeStr = root->getTagAttribute("file", "size"); - DOMString hash = root->getTagAttribute("file", "hash"); - XmppEvent event(XmppEvent::XmppEvent::EVENT_FILE_RECEIVE); - event.setFrom(from); - event.setIqId(id); - event.setStreamId(streamId); - event.setFileName(fname); - event.setFileHash(hash); - event.setFileSize(atol(sizeStr.c_str())); - dispatchXmppEvent(event); - } - else //result - { - printf("Got result\n"); - for (int i=0 ; igetIqId() == id && - from == outf->getPeerId()) - { - if (type == "error") - { - outf->setState(STREAM_ERROR); - error("user '%s' rejected file", from.c_str()); - return true; - } - else if (type == "result") - { - if (outf->getState() == STREAM_OPENING) - { - XmppEvent event(XmppEvent::XmppEvent::EVENT_FILE_ACCEPTED); - event.setFrom(from); - dispatchXmppEvent(event); - outf->setState(STREAM_OPEN); - } - else if (outf->getState() == STREAM_CLOSING) - { - outf->setState(STREAM_CLOSED); - } - return true; - } - } - } - } - return true; - } - - - //### IN-BAND BYTESTREAMS - //### Incoming stream requests - DOMString ibbNamespace = "http://jabber.org/protocol/ibb"; - if (root->getTagAttribute("open", "xmlns") == ibbNamespace) - { - DOMString streamId = root->getTagAttribute("open", "sid"); - XmppEvent event(XmppEvent::XmppEvent::EVENT_STREAM_RECEIVE_INIT); - dispatchXmppEvent(event); - if (streamId.size()>0) - { - for (int i=0 ; igetStreamId() == streamId) - { - ins->setState(STREAM_OPENING); - ins->setIqId(id); - return true; - } - } - } - return true; - } - else if (root->getTagAttribute("close", "xmlns") == ibbNamespace) - { - XmppEvent event(XmppEvent::XmppEvent::EVENT_STREAM_RECEIVE_CLOSE); - dispatchXmppEvent(event); - DOMString streamId = root->getTagAttribute("close", "sid"); - if (streamId.size()>0) - { - for (int i=0 ; igetStreamId() == streamId && - from == ins->getPeerId()) - { - ins->setState(STREAM_CLOSING); - ins->setIqId(id); - return true; - } - } - } - return true; - } - //### Responses to outgoing requests - for (int i=0 ; igetIqId() == id) - { - if (type == "error") - { - outs->setState(STREAM_ERROR); - return true; - } - else if (type == "result") - { - if (outs->getState() == STREAM_OPENING) - { - outs->setState(STREAM_OPEN); - } - else if (outs->getState() == STREAM_CLOSING) - { - outs->setState(STREAM_CLOSED); - } - return true; - } - } - } - - //###Normal Roster stuff - if (root->getTagAttribute("query", "xmlns") == "jabber:iq:roster") - { - roster.clear(); - std::vectorelems = root->findElements("item"); - for (unsigned int i=0 ; igetAttribute("jid"); - DOMString name = item->getAttribute("name"); - DOMString subscription = item->getAttribute("subscription"); - DOMString group = item->getTagValue("group"); - //printf("jid:%s name:%s sub:%s group:%s\n", userJid.c_str(), name.c_str(), - // subscription.c_str(), group.c_str()); - XmppUser user(userJid, name, subscription, group); - roster.push_back(user); - } - XmppEvent event(XmppEvent::XmppEvent::EVENT_ROSTER); - dispatchXmppEvent(event); - } - - return true; -} - - - -bool XmppClient::receiveAndProcess() -{ - if (!keepGoing) - return false; - - Parser parser; - - DOMString recvBuf = readStanza(); - recvBuf = trim(recvBuf); - if (recvBuf.size() < 1) - return true; - - //Ugly hack. Apparently the first char can be dropped on timeouts - //if (recvBuf[0] != '<') - // recvBuf.insert(0, "<"); - - status("RECV: %s", recvBuf.c_str()); - Element *root = parser.parse(recvBuf); - if (!root) - { - printf("Bad elem\n"); - return true; - } - - //#### MESSAGE - std::vectorelems = root->findElements("message"); - if (elems.size()>0) - { - if (!processMessage(root)) - return false; - } - - //#### PRESENCE - elems = root->findElements("presence"); - if (elems.size()>0) - { - if (!processPresence(root)) - return false; - } - - //#### INFO - elems = root->findElements("iq"); - if (elems.size()>0) - { - if (!processIq(root)) - return false; - } - - delete root; - - return true; -} - - -bool XmppClient::receiveAndProcessLoop() -{ - keepGoing = true; - while (true) - { - if (!keepGoing) - { - printf("Abort requested\n"); - break; - } - if (!receiveAndProcess()) - return false; - } - return true; -} - -//####################### -//# SENDING -//####################### - -bool XmppClient::write(char *fmt, ...) -{ - va_list args; - va_start(args,fmt); - vsnprintf((char *)writeBuf, writeBufLen, fmt,args); - va_end(args) ; - status("SEND: %s", writeBuf); - if (!sock->write((char *)writeBuf)) - { - error("Cannot write to socket"); - return false; - } - return true; -} - -//####################### -//# CONNECT -//####################### - -bool XmppClient::checkConnect() -{ - if (!connected) - { - XmppEvent evt(XmppEvent::EVENT_ERROR); - evt.setData("Attempted operation while disconnected"); - dispatchXmppEvent(evt); - return false; - } - return true; -} - -bool XmppClient::iqAuthenticate(const DOMString &streamId) -{ - Parser parser; - - char *fmt = - "" - "%s" - "\n"; - if (!write(fmt, realm.c_str(), msgId++, username.c_str())) - return false; - - DOMString recbuf = readStanza(); - //printf("iq received: '%s'\n", recbuf.c_str()); - Element *elem = parser.parse(recbuf); - //elem->print(); - DOMString iqType = elem->getTagAttribute("iq", "type"); - //printf("##iqType:%s\n", iqType.c_str()); - delete elem; - - if (iqType != "result") - { - error("error:server does not allow login"); - return false; - } - - bool digest = true; - if (digest) - { - //## Digest authentication - DOMString digest = streamId; - digest.append(password); - digest = Sha1::hashHex((unsigned char *)digest.c_str(), digest.size()); - //printf("digest:%s\n", digest.c_str()); - fmt = - "" - "" - "%s" - "%s" - "%s" - "" - "\n"; - if (!write(fmt, msgId++, username.c_str(), - digest.c_str(), resource.c_str())) - return false; - } - else - { - - //## Plaintext authentication - fmt = - "" - "" - "%s" - "%s" - "%s" - "" - "\n"; - if (!write(fmt, msgId++, username.c_str(), - password.c_str(), resource.c_str())) - return false; - } - - recbuf = readStanza(); - //printf("iq received: '%s'\n", recbuf.c_str()); - elem = parser.parse(recbuf); - //elem->print(); - iqType = elem->getTagAttribute("iq", "type"); - //printf("##iqType:%s\n", iqType.c_str()); - delete elem; - - if (iqType != "result") - { - error("server does not allow login"); - return false; - } - - return true; -} - - - -bool XmppClient::saslMd5Authenticate() -{ - Parser parser; - char *fmt = - "\n"; - if (!write(fmt)) - return false; - - DOMString recbuf = readStanza(); - status("challenge received: '%s'", recbuf.c_str()); - Element *elem = parser.parse(recbuf); - //elem->print(); - DOMString b64challenge = elem->getTagValue("challenge"); - delete elem; - - if (b64challenge.size() < 1) - { - error("login: no SASL challenge offered by server"); - return false; - } - DOMString challenge = Base64Decoder::decodeToString(b64challenge); - status("challenge:'%s'", challenge.c_str()); - - unsigned int p1 = challenge.find("nonce=\""); - if (p1 == DOMString::npos) - { - error("login: no SASL nonce sent by server"); - return false; - } - p1 += 7; - unsigned int p2 = challenge.find("\"", p1); - if (p2 == DOMString::npos) - { - error("login: unterminated SASL nonce sent by server"); - return false; - } - DOMString nonce = challenge.substr(p1, p2-p1); - //printf("nonce: '%s'\n", nonce.c_str()); - char idBuf[7]; - snprintf(idBuf, 6, "%dsasl", msgId++); - DOMString cnonce = Sha1::hashHex((unsigned char *)idBuf, 7); - DOMString authzid = username; authzid.append("@"); authzid.append(host); - DOMString digest_uri = "xmpp/"; digest_uri.append(host); - - //## Make A1 - Md5 md5; - md5.append(username); - md5.append(":"); - md5.append(realm); - md5.append(":"); - md5.append(password); - unsigned char a1tmp[16]; - md5.finish(a1tmp); - md5.init(); - md5.append(a1tmp, 16); - md5.append(":"); - md5.append(nonce); - md5.append(":"); - md5.append(cnonce); - md5.append(":"); - md5.append(authzid); - DOMString a1 = md5.finishHex(); - status("##a1:'%s'", a1.c_str()); - - //# Make A2 - md5.init(); - md5.append("AUTHENTICATE:"); - md5.append(digest_uri); - DOMString a2 = md5.finishHex(); - status("##a2:'%s'", a2.c_str()); - - //# Now make the response - md5.init(); - md5.append(a1); - md5.append(":"); - md5.append(nonce); - md5.append(":"); - md5.append("00000001");//nc - md5.append(":"); - md5.append(cnonce); - md5.append(":"); - md5.append("auth");//qop - md5.append(":"); - md5.append(a2); - DOMString response = md5.finishHex(); - - DOMString resp; - resp.append("username=\""); resp.append(username); resp.append("\","); - resp.append("realm=\""); resp.append(realm); resp.append("\","); - resp.append("nonce=\""); resp.append(nonce); resp.append("\","); - resp.append("cnonce=\""); resp.append(cnonce); resp.append("\","); - resp.append("nc=00000001,qop=auth,"); - resp.append("digest-uri=\""); resp.append(digest_uri); resp.append("\"," ); - resp.append("authzid=\""); resp.append(authzid); resp.append("\","); - resp.append("response=\""); resp.append(response); resp.append("\","); - resp.append("charset=utf-8"); - status("sending response:'%s'", resp.c_str()); - resp = Base64Encoder::encode(resp); - status("base64 response:'%s'", resp.c_str()); - fmt = - "%s\n"; - if (!write(fmt, resp.c_str())) - return false; - - recbuf = readStanza(); - status("server says:: '%s'", recbuf.c_str()); - elem = parser.parse(recbuf); - //elem->print(); - b64challenge = elem->getTagValue("challenge"); - delete elem; - - if (b64challenge.size() < 1) - { - error("login: no second SASL challenge offered by server"); - return false; - } - - challenge = Base64Decoder::decodeToString(b64challenge); - status("challenge: '%s'", challenge.c_str()); - p1 = challenge.find("rspauth="); - if (p1 == DOMString::npos) - { - error("login: no SASL respauth sent by server\n"); - return false; - } - - fmt = - "\n"; - if (!write(fmt)) - return false; - - recbuf = readStanza(); - status("server says: '%s", recbuf.c_str()); - elem = parser.parse(recbuf); - //elem->print(); - b64challenge = elem->getTagValue("challenge"); - bool success = (elem->findElements("success").size() > 0); - delete elem; - - return success; -} - -bool XmppClient::saslPlainAuthenticate() -{ - Parser parser; - - DOMString id = username; - //id.append("@"); - //id.append(host); - Base64Encoder encoder; - encoder.append('\0'); - encoder.append(id); - encoder.append('\0'); - encoder.append(password); - DOMString base64Auth = encoder.finish(); - //printf("authbuf:%s\n", base64Auth.c_str()); - - char *fmt = - "%s\n"; - if (!write(fmt, base64Auth.c_str())) - return false; - DOMString recbuf = readStanza(); - status("challenge received: '%s'", recbuf.c_str()); - Element *elem = parser.parse(recbuf); - - bool success = (elem->findElements("success").size() > 0); - delete elem; - - return success; -} - - - -bool XmppClient::saslAuthenticate() -{ - Parser parser; - - DOMString recbuf = readStanza(); - status("RECV: '%s'\n", recbuf.c_str()); - Element *elem = parser.parse(recbuf); - //elem->print(); - - //Check for starttls - bool wantStartTls = false; - if (elem->findElements("starttls").size() > 0) - { - wantStartTls = true; - if (elem->findElements("required").size() > 0) - status("login: STARTTLS required"); - else - status("login: STARTTLS available"); - } - - if (wantStartTls) - { - delete elem; - char *fmt = - "\n"; - if (!write(fmt)) - return false; - recbuf = readStanza(); - status("RECV: '%s'\n", recbuf.c_str()); - elem = parser.parse(recbuf); - if (elem->getTagAttribute("proceed", "xmlns").size()<1) - { - error("Server rejected TLS negotiation"); - disconnect(); - return false; - } - delete elem; - if (!sock->startTls()) - { - error("Could not start TLS"); - disconnect(); - return false; - } - - fmt = - "\n\n"; - if (!write(fmt, realm.c_str())) - return false; - - recbuf = readStanza(); - status("RECVx: '%s'", recbuf.c_str()); - recbuf.append(""); - elem = parser.parse(recbuf); - bool success = - (elem->getTagAttribute("stream:stream", "id").size()>0); - if (!success) - { - error("STARTTLS negotiation failed"); - disconnect(); - return false; - } - delete elem; - recbuf = readStanza(); - status("RECV: '%s'\n", recbuf.c_str()); - elem = parser.parse(recbuf); - } - - //check for sasl authentication mechanisms - std::vector elems = - elem->findElements("mechanism"); - if (elems.size() < 1) - { - error("login: no SASL mechanism offered by server"); - return false; - } - bool md5Found = false; - bool plainFound = false; - for (unsigned int i=0 ; igetValue(); - if (mech == "DIGEST-MD5") - { - status("MD5 authentication offered"); - md5Found = true; - } - else if (mech == "PLAIN") - { - status("PLAIN authentication offered"); - plainFound = true; - } - } - delete elem; - - bool success = false; - if (md5Found) - { - success = saslMd5Authenticate(); - } - else if (plainFound) - { - success = saslPlainAuthenticate(); - } - else - { - error("not able to handle sasl authentication mechanisms"); - return false; - } - - if (success) - status("###### SASL authentication success\n"); - else - error("###### SASL authentication failure\n"); - - return success; -} - - - - - -bool XmppClient::createSession() -{ - - Parser parser; - if (port==443 || port==5223) - sock->enableSSL(true); - if (!sock->connect(host, port)) - { - return false; - } - - char *fmt = - "\n\n"; - if (!write(fmt, realm.c_str())) - return false; - - DOMString recbuf = readStanza(); - //printf("received: '%s'\n", recbuf.c_str()); - recbuf.append(""); - Element *elem = parser.parse(recbuf); - //elem->print(); - bool useSasl = false; - DOMString streamId = elem->getTagAttribute("stream:stream", "id"); - //printf("### StreamID: %s\n", streamId.c_str()); - DOMString streamVersion = elem->getTagAttribute("stream:stream", "version"); - if (streamVersion == "1.0") - useSasl = true; - - if (useSasl) - { - if (!saslAuthenticate()) - return false; - fmt = - "\n\n"; - - if (!write(fmt, realm.c_str())) - return false; - recbuf = readStanza(); - recbuf.append("\n"); - //printf("now server says:: '%s'\n", recbuf.c_str()); - elem = parser.parse(recbuf); - //elem->print(); - delete elem; - - recbuf = readStanza(); - //printf("now server says:: '%s'\n", recbuf.c_str()); - elem = parser.parse(recbuf); - bool hasBind = (elem->findElements("bind").size() > 0); - //elem->print(); - delete elem; - - if (!hasBind) - { - error("no binding provided by server"); - return false; - } - - - } - else // not SASL - { - if (!iqAuthenticate(streamId)) - return false; - } - - - //### Resource binding - fmt = - "" - "" - "%s" - "\n"; - if (!write(fmt, msgId++, resource.c_str())) - return false; - - recbuf = readStanza(); - status("bind result: '%s'", recbuf.c_str()); - elem = parser.parse(recbuf); - //elem->print(); - DOMString bindType = elem->getTagAttribute("iq", "type"); - //printf("##bindType:%s\n", bindType.c_str()); - delete elem; - - if (bindType != "result") - { - error("no binding with server failed"); - return false; - } - - fmt = - "" - "" - "\n"; - if (!write(fmt, msgId++)) - return false; - - recbuf = readStanza(); - status("session received: '%s'", recbuf.c_str()); - elem = parser.parse(recbuf); - //elem->print(); - DOMString sessionType = elem->getTagAttribute("iq", "type"); - //printf("##sessionType:%s\n", sessionType.c_str()); - delete elem; - - if (sessionType != "result") - { - error("no session provided by server"); - return false; - } - - //printf("########## COOL #########\n"); - //Now that we are bound, we have a valid JID - jid = username; - jid.append("@"); - jid.append(realm); - jid.append("/"); - jid.append(resource); - - //We are now done with the synchronous handshaking. Let's go into - //async mode - - fmt = - "\n"; - if (!write(fmt, msgId++)) - return false; - - fmt = - "" - "\n"; - if (!write(fmt, msgId++, realm.c_str())) - return false; - - fmt = - "" - "\n"; - if (!write(fmt, msgId++, realm.c_str())) - return false; - - fmt = - "\n"; - if (!write(fmt)) - return false; - - /* - recbuf = readStanza(); - status("stream received: '%s'", recbuf.c_str()); - elem = parser.parse(recbuf); - //elem->print(); - delete elem; - */ - - //We are now logged in - status("Connected"); - connected = true; - XmppEvent evt(XmppEvent::EVENT_CONNECTED); - dispatchXmppEvent(evt); - //Thread::sleep(1000000); - - sock->setReceiveTimeout(1000); - ReceiverThread runner(*this); - Thread thread(runner); - thread.start(); - - return true; -} - -bool XmppClient::connect() -{ - if (!createSession()) - { - disconnect(); - return false; - } - return true; -} - - -bool XmppClient::connect(DOMString hostArg, int portArg, - DOMString usernameArg, - DOMString passwordArg, - DOMString resourceArg) -{ - host = hostArg; - port = portArg; - password = passwordArg; - resource = resourceArg; - - //parse this one - setUsername(usernameArg); - - bool ret = connect(); - return ret; -} - -bool XmppClient::disconnect() -{ - if (connected) - { - char *fmt = - "\n"; - write(fmt, jid.c_str()); - } - keepGoing = false; - connected = false; - Thread::sleep(3000); //allow receiving thread to quit - sock->disconnect(); - roster.clear(); - groupChatsClear(); - XmppEvent event(XmppEvent::EVENT_DISCONNECTED); - dispatchXmppEvent(event); - return true; -} - -//####################### -//# ROSTER -//####################### - -bool XmppClient::rosterAdd(const DOMString &rosterGroup, - const DOMString &otherJid, - const DOMString &name) -{ - if (!checkConnect()) - return false; - char *fmt = - "" - "" - "%s" - "\n"; - if (!write(fmt, jid.c_str(), msgId++, otherJid.c_str(), - name.c_str(), rosterGroup.c_str())) - { - return false; - } - return true; -} - -bool XmppClient::rosterDelete(const DOMString &otherJid) -{ - if (!checkConnect()) - return false; - char *fmt = - "" - "" - "%s" - "\n"; - if (!write(fmt, jid.c_str(), msgId++, otherJid.c_str())) - { - return false; - } - return true; -} - - -static bool xmppRosterCompare(const XmppUser& p1, const XmppUser& p2) -{ - DOMString s1 = p1.group; - DOMString s2 = p2.group; - for (unsigned int len=0 ; len XmppClient::getRoster() -{ - std::vector ros = roster; - std::sort(ros.begin(), ros.end(), xmppRosterCompare); - return ros; -} - -void XmppClient::rosterShow(const DOMString &jid, const DOMString &show) -{ - DOMString theShow = show; - if (theShow == "") - theShow = "available"; - - std::vector::iterator iter; - for (iter=roster.begin() ; iter != roster.end() ; iter++) - { - if (iter->jid == jid) - iter->show = theShow; - } -} - -//####################### -//# CHAT (individual) -//####################### - -bool XmppClient::message(const DOMString &user, const DOMString &subj, - const DOMString &msg) -{ - if (!checkConnect()) - return false; - - DOMString xmlSubj = toXml(subj); - DOMString xmlMsg = toXml(msg); - - if (xmlSubj.size() > 0) - { - char *fmt = - "" - "%s%s\n"; - if (!write(fmt, jid.c_str(), user.c_str(), - xmlSubj.c_str(), xmlMsg.c_str())) - return false; - } - else - { - char *fmt = - "" - "%s\n"; - if (!write(fmt, jid.c_str(), user.c_str(), xmlMsg.c_str())) - return false; - } - return true; -} - - - -bool XmppClient::message(const DOMString &user, const DOMString &msg) -{ - return message(user, "", msg); -} - - - -bool XmppClient::presence(const DOMString &presence) -{ - if (!checkConnect()) - return false; - - DOMString xmlPres = toXml(presence); - - char *fmt = - "%s\n"; - if (!write(fmt, jid.c_str(), xmlPres.c_str())) - return false; - return true; -} - -//####################### -//# GROUP CHAT -//####################### - -bool XmppClient::groupChatCreate(const DOMString &groupJid) -{ - std::vector::iterator iter; - for (iter=groupChats.begin() ; iter!=groupChats.end() ; iter++) - { - if ((*iter)->getGroupJid() == groupJid) - { - error("Group chat '%s' already exists", groupJid.c_str()); - return false; - } - } - XmppGroupChat *chat = new XmppGroupChat(groupJid); - groupChats.push_back(chat); - return true; -} - -/** - * - */ -void XmppClient::groupChatDelete(const DOMString &groupJid) -{ - std::vector::iterator iter; - for (iter=groupChats.begin() ; iter!=groupChats.end() ; ) - { - XmppGroupChat *chat = *iter; - if (chat->getGroupJid() == groupJid) - { - iter = groupChats.erase(iter); - delete chat; - } - else - iter++; - } -} - -/** - * - */ -bool XmppClient::groupChatExists(const DOMString &groupJid) -{ - std::vector::iterator iter; - for (iter=groupChats.begin() ; iter!=groupChats.end() ; iter++) - if ((*iter)->getGroupJid() == groupJid) - return true; - return false; -} - -/** - * - */ -void XmppClient::groupChatsClear() -{ - std::vector::iterator iter; - for (iter=groupChats.begin() ; iter!=groupChats.end() ; iter++) - delete (*iter); - groupChats.clear(); -} - - -/** - * - */ -void XmppClient::groupChatUserAdd(const DOMString &groupJid, - const DOMString &nick, - const DOMString &jid) -{ - std::vector::iterator iter; - for (iter=groupChats.begin() ; iter!=groupChats.end() ; iter++) - { - if ((*iter)->getGroupJid() == groupJid) - { - (*iter)->userAdd(nick, jid); - } - } -} - -/** - * - */ -void XmppClient::groupChatUserShow(const DOMString &groupJid, - const DOMString &nick, - const DOMString &show) -{ - std::vector::iterator iter; - for (iter=groupChats.begin() ; iter!=groupChats.end() ; iter++) - { - if ((*iter)->getGroupJid() == groupJid) - { - (*iter)->userShow(nick, show); - } - } -} - -/** - * - */ -void XmppClient::groupChatUserDelete(const DOMString &groupJid, - const DOMString &nick) -{ - std::vector::iterator iter; - for (iter=groupChats.begin() ; iter!=groupChats.end() ; iter++) - { - if ((*iter)->getGroupJid() == groupJid) - { - (*iter)->userDelete(nick); - } - } -} - -static bool xmppUserCompare(const XmppUser& p1, const XmppUser& p2) -{ - DOMString s1 = p1.nick; - DOMString s2 = p2.nick; - int comp = 0; - for (unsigned int len=0 ; len XmppClient::groupChatGetUserList( - const DOMString &groupJid) -{ - if (!checkConnect()) - { - std::vector dummy; - return dummy; - } - - std::vector::iterator iter; - for (iter=groupChats.begin() ; iter!=groupChats.end() ; iter++) - { - if ((*iter)->getGroupJid() == groupJid ) - { - std::vector uList = (*iter)->getUserList(); - std::sort(uList.begin(), uList.end(), xmppUserCompare); - return uList; - } - } - std::vector dummy; - return dummy; -} - -bool XmppClient::groupChatJoin(const DOMString &groupJid, - const DOMString &nick, - const DOMString &pass) -{ - if (!checkConnect()) - return false; - - DOMString user = nick; - if (user.size()<1) - user = username; - - char *fmt = - "" - "\n"; - if (!write(fmt, groupJid.c_str(), user.c_str())) - return false; - return true; -} - - -bool XmppClient::groupChatLeave(const DOMString &groupJid, - const DOMString &nick) -{ - if (!checkConnect()) - return false; - - DOMString user = nick; - if (user.size()<1) - user = username; - - char *fmt = - "" - "\n"; - if (!write(fmt, groupJid.c_str(), user.c_str())) - return false; - return true; -} - - -bool XmppClient::groupChatMessage(const DOMString &groupJid, - const DOMString &msg) -{ - if (!checkConnect()) - { - return false; - } - - DOMString xmlMsg = toXml(msg); - - char *fmt = - "" - "%s\n"; - if (!write(fmt, jid.c_str(), groupJid.c_str(), xmlMsg.c_str())) - return false; - return true; -} - -bool XmppClient::groupChatPrivateMessage(const DOMString &groupJid, - const DOMString &toNick, - const DOMString &msg) -{ - if (!checkConnect()) - return false; - - DOMString xmlMsg = toXml(msg); - - char *fmt = - "" - "%s\n"; - if (!write(fmt, jid.c_str(), groupJid.c_str(), - toNick.c_str(), xmlMsg.c_str())) - return false; - return true; -} - -bool XmppClient::groupChatPresence(const DOMString &groupJid, - const DOMString &myNick, - const DOMString &presence) -{ - if (!checkConnect()) - return false; - - DOMString user = myNick; - if (user.size()<1) - user = username; - - DOMString xmlPresence = toXml(presence); - - char *fmt = - "" - "\n"; - if (!write(fmt, jid.c_str(), groupJid.c_str(), user.c_str(), xmlPresence.c_str())) - return true; - return true; -} - - - -//####################### -//# S T R E A M S -//####################### - - -/** - * - */ -int XmppClient::outputStreamOpen(const DOMString &destId, - const DOMString &streamIdArg) -{ - int i; - for (i=0; igetState() == STREAM_AVAILABLE) - break; - if (i>=outputStreamCount) - { - error("No available output streams"); - return -1; - } - int streamNr = i; - XmppStream *outs = outputStreams[streamNr]; - - outs->setState(STREAM_OPENING); - - char buf[32]; - snprintf(buf, 31, "inband%d", getMsgId()); - DOMString iqId = buf; - - DOMString streamId = streamIdArg; - if (streamId.size()<1) - { - snprintf(buf, 31, "stream%d", getMsgId()); - DOMString streamId = buf; - } - outs->setIqId(iqId); - outs->setStreamId(streamId); - outs->setPeerId(destId); - - char *fmt = - "" - "\n"; - if (!write(fmt, jid.c_str(), - destId.c_str(), iqId.c_str(), - streamId.c_str())) - { - outs->reset(); - return -1; - } - - int state = outs->getState(); - for (int tim=0 ; tim<20 ; tim++) - { - if (state == STREAM_OPEN) - break; - else if (state == STREAM_ERROR) - { - printf("ERROR\n"); - outs->reset(); - return -1; - } - Thread::sleep(1000); - state = outs->getState(); - } - if (state != STREAM_OPEN) - { - printf("TIMEOUT ERROR\n"); - outs->reset(); - return -1; - } - - return streamNr; -} - -/** - * - */ -int XmppClient::outputStreamWrite(int streamNr, - const unsigned char *buf, unsigned long len) -{ - XmppStream *outs = outputStreams[streamNr]; - - unsigned long outLen = 0; - unsigned char *p = (unsigned char *)buf; - - while (outLen < len) - { - unsigned long chunksize = 1024; - if (chunksize + outLen > len) - chunksize = len - outLen; - - Base64Encoder encoder; - encoder.append(p, chunksize); - DOMString b64data = encoder.finish(); - p += chunksize; - outLen += chunksize; - - char *fmt = - "" - "" - "%s" - "" - "" - "" - "" - "" - "\n"; - if (!write(fmt, jid.c_str(), - outs->getPeerId().c_str(), - getMsgId(), - outs->getStreamId().c_str(), - outs->getSeqNr(), - b64data.c_str())) - { - outs->reset(); - return -1; - } - pause(5000); - } - return outLen; -} - -/** - * - */ -int XmppClient::outputStreamClose(int streamNr) -{ - XmppStream *outs = outputStreams[streamNr]; - - char buf[32]; - snprintf(buf, 31, "inband%d", getMsgId()); - DOMString iqId = buf; - outs->setIqId(iqId); - - outs->setState(STREAM_CLOSING); - char *fmt = - "" - "\n"; - if (!write(fmt, jid.c_str(), - outs->getPeerId().c_str(), - iqId.c_str(), - outs->getStreamId().c_str())) - return false; - - int state = outs->getState(); - for (int tim=0 ; tim<20 ; tim++) - { - if (state == STREAM_CLOSED) - break; - else if (state == STREAM_ERROR) - { - printf("ERROR\n"); - outs->reset(); - return -1; - } - Thread::sleep(1000); - state = outs->getState(); - } - if (state != STREAM_CLOSED) - { - printf("TIMEOUT ERROR\n"); - outs->reset(); - return -1; - } - - outs->reset(); - return 1; -} - - -/** - * - */ -int XmppClient::inputStreamOpen(const DOMString &fromJid, const DOMString &streamId, - const DOMString &iqId) -{ - int i; - for (i=0 ; igetState() == STREAM_AVAILABLE) - break; - } - if (i>=inputStreamCount) - { - error("No available input streams"); - return -1; - } - int streamNr = i; - XmppStream *ins = inputStreams[streamNr]; - ins->reset(); - ins->setPeerId(fromJid); - ins->setState(STREAM_CLOSED); - ins->setStreamId(streamId); - - int state = ins->getState(); - for (int tim=0 ; tim<20 ; tim++) - { - if (state == STREAM_OPENING) - break; - else if (state == STREAM_ERROR) - { - printf("ERROR\n"); - ins->reset(); - return -1; - } - Thread::sleep(1000); - state = ins->getState(); - } - if (state != STREAM_OPENING) - { - printf("TIMEOUT ERROR\n"); - ins->reset(); - return -1; - } - char *fmt = - "\n"; - if (!write(fmt, jid.c_str(), fromJid.c_str(), ins->getIqId().c_str())) - { - return -1; - } - - ins->setState(STREAM_OPEN); - return streamNr; -} - -/** - * - */ -int XmppClient::inputStreamAvailable(int streamNr) -{ - XmppStream *ins = inputStreams[streamNr]; - return ins->available(); -} - -/** - * - */ -std::vector XmppClient::inputStreamRead(int streamNr) -{ - XmppStream *ins = inputStreams[streamNr]; - return ins->read(); -} - -/** - * - */ -bool XmppClient::inputStreamClosing(int streamNr) -{ - XmppStream *ins = inputStreams[streamNr]; - if (ins->getState() == STREAM_CLOSING) - return true; - return false; -} - - -/** - * - */ -int XmppClient::inputStreamClose(int streamNr) -{ - int ret=1; - XmppStream *ins = inputStreams[streamNr]; - if (ins->getState() == STREAM_CLOSING) - { - char *fmt = - "\n"; - if (!write(fmt, jid.c_str(), ins->getPeerId().c_str(), - ins->getIqId().c_str())) - { - ret = -1; - } - } - ins->reset(); - return ret; -} - - - - -//####################### -//# FILE TRANSFERS -//####################### - - -/** - * - */ -bool XmppClient::fileSend(const DOMString &destJidArg, - const DOMString &offeredNameArg, - const DOMString &fileNameArg, - const DOMString &descriptionArg) -{ - DOMString destJid = destJidArg; - DOMString offeredName = offeredNameArg; - DOMString fileName = fileNameArg; - DOMString description = descriptionArg; - - int i; - for (i=0; igetState() == STREAM_AVAILABLE) - break; - if (i>=fileSendCount) - { - error("No available file send streams"); - return false; - } - int fileSendNr = i; - XmppStream *outf = fileSends[fileSendNr]; - - outf->setState(STREAM_OPENING); - - struct stat finfo; - if (stat(fileName.c_str(), &finfo)<0) - { - error("Cannot stat file '%s' for sending", fileName.c_str()); - return false; - } - long fileLen = finfo.st_size; - if (!fileLen > 1000000) - { - error("'%s' too large", fileName.c_str()); - return false; - } - if (!S_ISREG(finfo.st_mode)) - { - error("'%s' is not a regular file", fileName.c_str()); - return false; - } - FILE *f = fopen(fileName.c_str(), "rb"); - if (!f) - { - error("cannot open '%s' for sending", fileName.c_str()); - return false; - } - unsigned char *sendBuf = (unsigned char *)malloc(fileLen+1); - if (!sendBuf) - { - error("cannot cannot allocate send buffer for %s", fileName.c_str()); - return false; - } - for (long i=0 ; i=0 && slashPos<=(int)(fileName.size()-1)) - { - offeredName = fileName.substr(slashPos+1, - fileName.size()-slashPos-1); - printf("offeredName:%s\n", offeredName.c_str()); - } - } - - char buf[32]; - snprintf(buf, 31, "file%d", getMsgId()); - DOMString iqId = buf; - outf->setIqId(iqId); - - snprintf(buf, 31, "stream%d", getMsgId()); - DOMString streamId = buf; - //outf->setStreamId(streamId); - - DOMString hash = Md5::hashHex(sendBuf, fileLen); - printf("Hash:%s\n", hash.c_str()); - - outf->setPeerId(destJid); - - char dtgBuf[81]; - struct tm *timeVal = gmtime(&(finfo.st_mtime)); - strftime(dtgBuf, 80, "%Y-%m-%dT%H:%M:%Sz", timeVal); - - char *fmt = - "" - "" - "%s" - "" - "" - "" - //"" - "" - "\n"; - if (!write(fmt, iqId.c_str(), destJid.c_str(), - streamId.c_str(), offeredName.c_str(), fileLen, - hash.c_str(), dtgBuf, description.c_str())) - { - free(sendBuf); - return false; - } - - int state = outf->getState(); - for (int tim=0 ; tim<20 ; tim++) - { - printf("##### waiting for open\n"); - if (state == STREAM_OPEN) - { - outf->reset(); - break; - } - else if (state == STREAM_ERROR) - { - printf("ERROR\n"); - outf->reset(); - return false; - } - Thread::sleep(1000); - state = outf->getState(); - } - if (state != STREAM_OPEN) - { - printf("TIMEOUT ERROR\n"); - outf->reset(); - return false; - } - - //free up this reqource - outf->reset(); - - int streamNr = outputStreamOpen(destJid, streamId); - if (streamNr<0) - { - error("cannot open output stream %s", streamId.c_str()); - outf->reset(); - return false; - } - - int ret = outputStreamWrite(streamNr, sendBuf, fileLen); - - if (ret<0) - { - } - - outputStreamClose(streamNr); - - free(sendBuf); - return true; -} - - -class FileSendThread : public Thread -{ -public: - - FileSendThread(XmppClient &par, - const DOMString &destJidArg, - const DOMString &offeredNameArg, - const DOMString &fileNameArg, - const DOMString &descriptionArg) : client(par) - { - destJid = destJidArg; - offeredName = offeredNameArg; - fileName = fileNameArg; - description = descriptionArg; - } - - virtual ~FileSendThread() {} - - void run() - { - client.fileSend(destJid, offeredName, - fileName, description); - } - -private: - - XmppClient &client; - DOMString destJid; - DOMString offeredName; - DOMString fileName; - DOMString description; -}; - -/** - * - */ -bool XmppClient::fileSendBackground(const DOMString &destJid, - const DOMString &offeredName, - const DOMString &fileName, - const DOMString &description) -{ - FileSendThread thread(*this, destJid, offeredName, - fileName, description); - thread.start(); - return true; -} - - -/** - * - */ -bool XmppClient::fileReceive(const DOMString &fromJid, - const DOMString &iqId, - const DOMString &streamId, - const DOMString &fileName, - long fileSize, - const DOMString &fileHash) -{ - char *fmt = - "" - "" - "" - "" - "" - "" - "http://jabber.org/protocol/ibb" - "\n"; - if (!write(fmt, fromJid.c_str(), iqId.c_str())) - { - return false; - } - - int streamNr = inputStreamOpen(fromJid, streamId, iqId); - if (streamNr < 0) - { - return false; - } - - - Md5 md5; - FILE *f = fopen(fileName.c_str(), "wb"); - if (!f) - { - return false; - } - - while (true) - { - if (inputStreamAvailable(streamNr)<1) - { - if (inputStreamClosing(streamNr)) - break; - pause(100); - continue; - } - std::vector ret = inputStreamRead(streamNr); - std::vector::iterator iter; - for (iter=ret.begin() ; iter!=ret.end() ; iter++) - { - unsigned char ch = *iter; - md5.append(&ch, 1); - fwrite(&ch, 1, 1, f); - } - } - - inputStreamClose(streamNr); - fclose(f); - - DOMString hash = md5.finishHex(); - printf("received file hash:%s\n", hash.c_str()); - - return true; -} - - - -class FileReceiveThread : public Thread -{ -public: - - FileReceiveThread(XmppClient &par, - const DOMString &fromJidArg, - const DOMString &iqIdArg, - const DOMString &streamIdArg, - const DOMString &fileNameArg, - long fileSizeArg, - const DOMString &fileHashArg) : client(par) - { - fromJid = fromJidArg; - iqId = iqIdArg; - streamId = streamIdArg; - fileName = fileNameArg; - fileSize = fileSizeArg; - fileHash = fileHashArg; - } - - virtual ~FileReceiveThread() {} - - void run() - { - client.fileReceive(fromJid, iqId, streamId, - fileName, fileSize, fileHash); - } - -private: - - XmppClient &client; - DOMString fromJid; - DOMString iqId; - DOMString streamId; - DOMString fileName; - long fileSize; - DOMString fileHash; -}; - -/** - * - */ -bool XmppClient::fileReceiveBackground(const DOMString &fromJid, - const DOMString &iqId, - const DOMString &streamId, - const DOMString &fileName, - long fileSize, - const DOMString &fileHash) -{ - FileReceiveThread thread(*this, fromJid, iqId, streamId, - fileName, fileSize, fileHash); - thread.start(); - return true; -} - - - -//######################################################################## -//# X M P P G R O U P C H A T -//######################################################################## - -/** - * - */ -XmppGroupChat::XmppGroupChat(const DOMString &groupJidArg) -{ - groupJid = groupJidArg; -} - -/** - * - */ -XmppGroupChat::XmppGroupChat(const XmppGroupChat &other) -{ - groupJid = other.groupJid; - userList = other.userList; -} - -/** - * - */ -XmppGroupChat::~XmppGroupChat() -{ -} - - -/** - * - */ -DOMString XmppGroupChat::getGroupJid() -{ - return groupJid; -} - - -void XmppGroupChat::userAdd(const DOMString &nick, - const DOMString &jid) -{ - std::vector::iterator iter; - for (iter= userList.begin() ; iter!=userList.end() ; iter++) - { - if (iter->nick == nick) - return; - } - XmppUser user(jid, nick); - userList.push_back(user); -} - -void XmppGroupChat::userShow(const DOMString &nick, - const DOMString &show) -{ - DOMString theShow = show; - if (theShow == "") - theShow = "available"; // a join message will now have a show - std::vector::iterator iter; - for (iter= userList.begin() ; iter!=userList.end() ; iter++) - { - if (iter->nick == nick) - iter->show = theShow; - } -} - -void XmppGroupChat::userDelete(const DOMString &nick) -{ - std::vector::iterator iter; - for (iter= userList.begin() ; iter!=userList.end() ; ) - { - if (iter->nick == nick) - iter = userList.erase(iter); - else - iter++; - } -} - -std::vector XmppGroupChat::getUserList() const -{ - return userList; -} - - - - - - -} //namespace Pedro -//######################################################################## -//# E N D O F F I L E -//######################################################################## - - - - - - - - - - - - - - - diff --git a/src/jabber_whiteboard/pedroxmpp.h b/src/jabber_whiteboard/pedroxmpp.h deleted file mode 100644 index d938a25fd..000000000 --- a/src/jabber_whiteboard/pedroxmpp.h +++ /dev/null @@ -1,1040 +0,0 @@ -#ifndef __XMPP_H__ -#define __XMPP_H__ -/* - * API for the Pedro mini-XMPP client. - * - * Authors: - * Bob Jamison - * - * Copyright (C) 2005 Bob Jamison - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include - -#include - -#include "pedrodom.h" - -namespace Pedro -{ - -typedef std::string DOMString; - - -//######################################################################## -//# X M P P E V E N T -//######################################################################## -class XmppUser -{ -public: - XmppUser() - { - } - XmppUser(const DOMString &jidArg, const DOMString &nickArg) - { - jid = jidArg; - nick = nickArg; - } - XmppUser(const DOMString &jidArg, const DOMString &nickArg, - const DOMString &subscriptionArg, const DOMString &groupArg) - { - jid = jidArg; - nick = nickArg; - subscription = subscriptionArg; - group = groupArg; - } - XmppUser(const XmppUser &other) - { - jid = other.jid; - nick = other.nick; - subscription = other.subscription; - group = other.group; - show = other.show; - } - XmppUser &operator=(const XmppUser &other) - { - jid = other.jid; - nick = other.nick; - subscription = other.subscription; - group = other.group; - show = other.show; - return *this; - } - virtual ~XmppUser() - {} - DOMString jid; - DOMString nick; - DOMString subscription; - DOMString group; - DOMString show; -}; - -class XmppEvent -{ - -public: - -typedef enum - { - EVENT_NONE, - EVENT_STATUS, - EVENT_ERROR, - EVENT_CONNECTED, - EVENT_DISCONNECTED, - EVENT_PRESENCE, - EVENT_ROSTER, - EVENT_MESSAGE, - EVENT_MUC_JOIN, - EVENT_MUC_LEAVE, - EVENT_MUC_PRESENCE, - EVENT_MUC_MESSAGE, - EVENT_STREAM_RECEIVE_INIT, - EVENT_STREAM_RECEIVE, - EVENT_STREAM_RECEIVE_CLOSE, - EVENT_FILE_ACCEPTED, - EVENT_FILE_RECEIVE - } XmppEventType; - - - /** - * - */ - XmppEvent(int type); - - /** - * - */ - XmppEvent(const XmppEvent &other); - - /** - * - */ - virtual XmppEvent &operator=(const XmppEvent &other); - - /** - * - */ - virtual ~XmppEvent(); - - /** - * - */ - virtual void assign(const XmppEvent &other); - - /** - * - */ - virtual int getType() const; - - - /** - * - */ - virtual DOMString getIqId() const; - - - /** - * - */ - virtual void setIqId(const DOMString &val); - - /** - * - */ - virtual DOMString getStreamId() const; - - - /** - * - */ - virtual void setStreamId(const DOMString &val); - - /** - * - */ - virtual bool getPresence() const; - - - /** - * - */ - virtual void setPresence(bool val); - - /** - * - */ - virtual DOMString getShow() const; - - - /** - * - */ - virtual void setShow(const DOMString &val); - - /** - * - */ - virtual DOMString getStatus() const; - - /** - * - */ - virtual void setStatus(const DOMString &val); - - /** - * - */ - virtual DOMString getTo() const; - - /** - * - */ - virtual void setTo(const DOMString &val); - - /** - * - */ - virtual DOMString getFrom() const; - - /** - * - */ - virtual void setFrom(const DOMString &val); - - /** - * - */ - virtual DOMString getGroup() const; - - /** - * - */ - virtual void setGroup(const DOMString &val); - - /** - * - */ - virtual Element *getDOM() const; - - - /** - * - */ - virtual void setDOM(const Element *val); - - /** - * - */ - virtual std::vector getUserList() const; - - /** - * - */ - virtual void setUserList(const std::vector &userList); - - /** - * - */ - virtual DOMString getFileName() const; - - - /** - * - */ - virtual void setFileName(const DOMString &val); - - - /** - * - */ - virtual DOMString getFileDesc() const; - - - /** - * - */ - virtual void setFileDesc(const DOMString &val); - - - /** - * - */ - virtual long getFileSize() const; - - - /** - * - */ - virtual void setFileSize(long val); - - /** - * - */ - virtual DOMString getFileHash() const; - - /** - * - */ - virtual void setFileHash(const DOMString &val); - - /** - * - */ - virtual DOMString getData() const; - - - /** - * - */ - virtual void setData(const DOMString &val); - -private: - - int eventType; - - DOMString iqId; - - DOMString streamId; - - bool presence; - - DOMString show; - - DOMString status; - - DOMString to; - - DOMString from; - - DOMString group; - - DOMString data; - - DOMString fileName; - DOMString fileDesc; - long fileSize; - DOMString fileHash; - - Element *dom; - - std::vectoruserList; - -}; - - -//######################################################################## -//# X M P P E V E N T L I S T E N E R -//######################################################################## - -class XmppEventListener -{ -public: - - /** - * - */ - XmppEventListener() - {} - - /** - * - */ - XmppEventListener(const XmppEventListener &other) - {} - - - /** - * - */ - virtual ~XmppEventListener() - {} - - /** - * - */ - virtual void processXmppEvent(const XmppEvent &event) - {} - -}; - - - -//######################################################################## -//# X M P P E V E N T T A R G E T -//######################################################################## - -class XmppEventTarget -{ -public: - - /** - * - */ - XmppEventTarget(); - - /** - * - */ - XmppEventTarget(const XmppEventTarget &other); - - /** - * - */ - virtual ~XmppEventTarget(); - - - //########################### - //# M E S S A G E S - //########################### - - - /** - * Send an error message to all subscribers - */ - void error(char *fmt, ...); - - - /** - * Send a status message to all subscribers - */ - void status(char *fmt, ...); - - //########################### - //# LISTENERS - //########################### - - /** - * - */ - virtual void dispatchXmppEvent(const XmppEvent &event); - - /** - * - */ - virtual void addXmppEventListener(const XmppEventListener &listener); - - /** - * - */ - virtual void removeXmppEventListener(const XmppEventListener &listener); - - /** - * - */ - virtual void clearXmppEventListeners(); - - /** - * - */ - void eventQueueEnable(bool val); - - /** - * - */ - int eventQueueAvailable(); - - /** - * - */ - XmppEvent eventQueuePop(); - - -private: - - std::vector listeners; - - std::vector eventQueue; - bool eventQueueEnabled; - - static const int targetWriteBufLen = 2048; - - char targetWriteBuf[targetWriteBufLen]; -}; - - - - - -//######################################################################## -//# X M P P C L I E N T -//######################################################################## - - -class TcpSocket; -class XmppChat; -class XmppGroupChat; -class XmppStream; - -class XmppClient : public XmppEventTarget -{ - -public: - - //########################### - //# CONSTRUCTORS - //########################### - - /** - * - */ - XmppClient(); - - /** - * - */ - XmppClient(const XmppClient &other); - - /** - * - */ - void assign(const XmppClient &other); - - /** - * - */ - virtual ~XmppClient(); - - - //########################### - //# UTILITY - //########################### - - /** - * - */ - virtual bool pause(unsigned long millis); - - /** - * - */ - DOMString toXml(const DOMString &str); - - //########################### - //# CONNECTION - //########################### - - /** - * - */ - virtual bool connect(); - - /** - * - */ - virtual bool connect(DOMString host, int port, - DOMString userName, - DOMString password, - DOMString resource); - - /** - * - */ - virtual bool disconnect(); - - - /** - * - */ - virtual bool write(char *fmt, ...); - - /** - * - */ - virtual bool isConnected() - { return connected; } - - /** - * - */ - virtual DOMString getHost() - { return host; } - - /** - * - */ - virtual void setHost(const DOMString &val) - { host = val; } - - /** - * - */ - virtual DOMString getRealm() - { return realm; } - - /** - * - */ - virtual void setRealm(const DOMString &val) - { realm = val; } - - /** - * - */ - virtual int getPort() - { return port; } - - /** - * - */ - virtual void setPort(int val) - { port = val; } - - /** - * - */ - virtual DOMString getUsername(); - - /** - * - */ - virtual void setUsername(const DOMString &val); - - /** - * - */ - virtual DOMString getPassword() - { return password; } - - /** - * - */ - virtual void setPassword(const DOMString &val) - { password = val; } - - /** - * - */ - virtual DOMString getResource() - { return resource; } - - /** - * - */ - virtual void setResource(const DOMString &val) - { resource = val; } - - /** - * - */ - virtual DOMString getJid() - { return jid; } - /** - * - */ - virtual int getMsgId() - { return msgId++; } - - /** - * - */ - bool processMessage(Element *root); - - /** - * - */ - bool processPresence(Element *root); - - /** - * - */ - bool processIq(Element *root); - - /** - * - */ - virtual bool receiveAndProcess(); - - /** - * - */ - virtual bool receiveAndProcessLoop(); - - //####################### - //# ROSTER - //####################### - - /** - * - */ - bool rosterAdd(const DOMString &rosterGroup, - const DOMString &otherJid, - const DOMString &name); - - /** - * - */ - bool rosterDelete(const DOMString &otherJid); - - /** - * - */ - std::vector getRoster(); - - /** - * - */ - virtual void rosterShow(const DOMString &jid, const DOMString &show); - - //####################### - //# CHAT (individual) - //####################### - - /** - * - */ - virtual bool message(const DOMString &user, const DOMString &subj, - const DOMString &text); - - /** - * - */ - virtual bool message(const DOMString &user, const DOMString &text); - - /** - * - */ - virtual bool presence(const DOMString &presence); - - //####################### - //# GROUP CHAT - //####################### - - /** - * - */ - virtual bool groupChatCreate(const DOMString &groupJid); - - /** - * - */ - virtual void groupChatDelete(const DOMString &groupJid); - - /** - * - */ - bool groupChatExists(const DOMString &groupJid); - - /** - * - */ - virtual void groupChatsClear(); - - /** - * - */ - virtual void groupChatUserAdd(const DOMString &groupJid, - const DOMString &nick, - const DOMString &jid); - /** - * - */ - virtual void groupChatUserShow(const DOMString &groupJid, - const DOMString &nick, - const DOMString &show); - - /** - * - */ - virtual void groupChatUserDelete(const DOMString &groupJid, - const DOMString &nick); - - /** - * - */ - virtual std::vector - XmppClient::groupChatGetUserList(const DOMString &groupJid); - - /** - * - */ - virtual bool groupChatJoin(const DOMString &groupJid, - const DOMString &nick, - const DOMString &pass); - - /** - * - */ - virtual bool groupChatLeave(const DOMString &groupJid, - const DOMString &nick); - - /** - * - */ - virtual bool groupChatMessage(const DOMString &groupJid, - const DOMString &msg); - - /** - * - */ - virtual bool groupChatPrivateMessage(const DOMString &groupJid, - const DOMString &toNick, - const DOMString &msg); - - /** - * - */ - virtual bool groupChatPresence(const DOMString &groupJid, - const DOMString &nick, - const DOMString &presence); - - - //####################### - //# STREAMS - //####################### - - typedef enum - { - STREAM_AVAILABLE, - STREAM_OPENING, - STREAM_OPEN, - STREAM_CLOSING, - STREAM_CLOSED, - STREAM_ERROR - } StreamStates; - - /** - * - */ - virtual int outputStreamOpen(const DOMString &jid, - const DOMString &streamId); - - /** - * - */ - virtual int outputStreamWrite(int streamId, - const unsigned char *buf, unsigned long len); - - /** - * - */ - virtual int outputStreamClose(int streamId); - - /** - * - */ - virtual int inputStreamOpen(const DOMString &jid, - const DOMString &streamId, - const DOMString &iqId); - - /** - * - */ - virtual int inputStreamAvailable(int streamId); - - /** - * - */ - virtual std::vector inputStreamRead(int streamId); - - /** - * - */ - virtual bool inputStreamClosing(int streamId); - - /** - * - */ - virtual int inputStreamClose(int streamId); - - - //####################### - //# FILE TRANSFERS - //####################### - - /** - * - */ - virtual bool fileSend(const DOMString &destJid, - const DOMString &offeredName, - const DOMString &fileName, - const DOMString &description); - - /** - * - */ - virtual bool fileSendBackground(const DOMString &destJid, - const DOMString &offeredName, - const DOMString &fileName, - const DOMString &description); - - /** - * - */ - virtual bool fileReceive(const DOMString &fromJid, - const DOMString &iqId, - const DOMString &streamId, - const DOMString &fileName, - long fileSize, - const DOMString &fileHash); - /** - * - */ - virtual bool fileReceiveBackground(const DOMString &fromJid, - const DOMString &iqId, - const DOMString &streamId, - const DOMString &fileName, - long fileSize, - const DOMString &fileHash); - - -private: - - void init(); - - DOMString host; - - /** - * will be same as host, unless username is - * user@realm - */ - DOMString realm; - - int port; - - DOMString username; - - DOMString password; - - DOMString resource; - - DOMString jid; - - int msgId; - - TcpSocket *sock; - - bool connected; - - bool createSession(); - - bool checkConnect(); - - DOMString readStanza(); - - bool saslMd5Authenticate(); - - bool saslPlainAuthenticate(); - - bool saslAuthenticate(); - - bool iqAuthenticate(const DOMString &streamId); - - bool keepGoing; - - static const int writeBufLen = 2048; - - unsigned char writeBuf[writeBufLen]; - - std::vectorgroupChats; - - static const int outputStreamCount = 16; - - XmppStream *outputStreams[outputStreamCount]; - - static const int inputStreamCount = 16; - - XmppStream *inputStreams[inputStreamCount]; - - static const int fileSendCount = 16; - - XmppStream *fileSends[fileSendCount]; - - std::vectorroster; -}; - - - - -//######################################################################## -//# X M P P G R O U P C H A T -//######################################################################## - -/** - * - */ -class XmppGroupChat -{ -public: - - /** - * - */ - XmppGroupChat(const DOMString &groupJid); - - /** - * - */ - XmppGroupChat(const XmppGroupChat &other); - - /** - * - */ - virtual ~XmppGroupChat(); - - /** - * - */ - virtual DOMString getGroupJid(); - - /** - * - */ - virtual void userAdd(const DOMString &nick, - const DOMString &jid); - /** - * - */ - virtual void userShow(const DOMString &nick, - const DOMString &show); - - /** - * - */ - virtual void userDelete(const DOMString &nick); - - /** - * - */ - virtual std::vector getUserList() const; - - -private: - - DOMString groupJid; - - std::vectoruserList; - -}; - - - - - - - - - - -} //namespace Pedro - -#endif /* __XMPP_H__ */ - -//######################################################################## -//# E N D O F F I L E -//######################################################################## - diff --git a/src/jabber_whiteboard/serializer.cpp b/src/jabber_whiteboard/serializer.cpp deleted file mode 100644 index 094944257..000000000 --- a/src/jabber_whiteboard/serializer.cpp +++ /dev/null @@ -1,304 +0,0 @@ -/** - * Inkboard message -> XML::Event* serializer - * - * Authors: - * David Yip - * - * Copyright (c) 2005 Authors - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#include "xml/attribute-record.h" - -#include "jabber_whiteboard/serializer.h" - -#include "util/list.h" -#include "util/share.h" - -#include "jabber_whiteboard/message-utilities.h" -#include "jabber_whiteboard/message-tags.h" -#include "jabber_whiteboard/typedefs.h" -#include "jabber_whiteboard/node-tracker.h" -#include "jabber_whiteboard/node-utilities.h" -#include "jabber_whiteboard/node-tracker-observer.h" - -namespace Inkscape { - -namespace Whiteboard { - -void -Serializer::notifyChildAdded(XML::Node& node, XML::Node& child, XML::Node* prev) -{ - // do not recurse upon initial notification - this->_newObjectEventHelper(node, child, prev, false); - this->_nn.insert(&child); -} - -void -Serializer::_newObjectEventHelper(XML::Node& node, XML::Node& child, XML::Node* prev, bool recurse) -{ - // 1. Check if we are tracking the parent node, - // and issue it an ID if we are not. - std::string parentid = this->_findOrGenerateNodeID(node); - - // 2. Check if the child node is a special node. - // Special nodes are nodes that should appear only once in a document. - // If it is, we do not want to generate a new ID for the child; we will use - // the existing ID. Otherwise, we will generate a new ID for it, since we - // have not yet seen it. - std::string childid; - if (this->_xnt->isSpecialNode(child.name())) { - childid = this->_xnt->get(child); - } else { - // If the child id already exists in the new node buffer, then we've already seen it. - if (!this->actions.tryToTrack(&child, NODE_ADD)) { - return; - } else { - childid = this->_xnt->generateKey(); -// childid = this->_findOrGenerateNodeID(child); - } - } - - // 3. Find this node's previous node, and, if it has one, retrieve its ID. - std::string previd; - if (prev) { - previd = this->_findOrGenerateNodeID(*prev); - } - - // 4. Serialize. - Glib::ustring childmsg = MessageUtilities::makeTagWithContent(MESSAGE_CHILD, childid); - Glib::ustring parentmsg = MessageUtilities::makeTagWithContent(MESSAGE_PARENT, parentid); - Glib::ustring namemsg = MessageUtilities::makeTagWithContent(MESSAGE_NAME, child.name()); - Glib::ustring nodetype = MessageUtilities::makeTagWithContent(MESSAGE_NODETYPE, NodeUtilities::nodeTypeToString(child)); - - Glib::ustring prevmsg; - if (!previd.empty()) { - prevmsg = MessageUtilities::makeTagWithContent(MESSAGE_REF, previd); - } - - Glib::ustring buf = MessageUtilities::makeTagWithContent(MESSAGE_NEWOBJ, childmsg + parentmsg + prevmsg + namemsg + nodetype); - - - this->_events.push_back(buf); - - // 5. Add the child node to the new nodes buffers. - this->newnodes.push_back(SerializedEventNodeAction(KeyNodePair(childid, &child), NODE_ADD)); - this->newkeys[&child] = childid; - this->_parent_child_map[&child] = &node; - - // 6. Scan attributes and content. - Inkscape::Util::List attrlist = child.attributeList(); - - for(; attrlist; attrlist++) { - this->notifyAttributeChanged(child, attrlist->key, Util::ptr_shared(), attrlist->value); - } - - if (child.content()) { - this->notifyContentChanged(child, Util::ptr_shared(), Util::share_string(child.content())); - } - - this->_attributes_scanned.insert(childid); - - // 7. Repeat this process for each child of this child. - if (recurse && child.childCount() > 0) { - XML::Node* prev = child.firstChild(); - for(XML::Node* ch = child.firstChild(); ch; ch = ch->next()) { - if (ch == child.firstChild()) { - // No prev node in this case. - this->_newObjectEventHelper(child, *ch, NULL, true); - } else { - this->_newObjectEventHelper(child, *ch, prev, true); - prev = ch; - } - } - } - - return; -} - - -void -Serializer::notifyChildRemoved(XML::Node& node, XML::Node& child, XML::Node* prev) -{ - // 1. Get the ID of the child. - std::string childid; - - _pc_map_type::iterator i = this->_parent_child_map.find(&child); - if (i != this->_parent_child_map.end() && i->second != &node) { - // Don't look in local! Go for the tracker. - childid = this->_xnt->get(child); - } else if (i == this->_parent_child_map.end()) { - childid = this->_findOrGenerateNodeID(child); - } else if (i->second == &node) { - childid = this->_findOrGenerateNodeID(child); - this->_parent_child_map.erase(i); - } else { - childid = this->_findOrGenerateNodeID(child); - } - - // 2. Double-deletes don't make any sense. If we've seen this node already and if it's - // marked for deletion, return. - if (!this->actions.tryToTrack(&child, NODE_REMOVE)) { - return; - } else { - // 2a. Although we do not have to remove all child nodes of this subtree, - // we _do_ have to mark each child node as deleted. - this->_recursiveMarkAsRemoved(child); - } - - // 2. Mark this node as deleted. We don't want to be faced with the possibility of - // generating a new key for this deleted node, so insert it into both maps. - this->newnodes.push_back(SerializedEventNodeAction(KeyNodePair(childid, &child), NODE_REMOVE)); - this->newkeys[&child] = childid; - this->_nn.erase(&child); - std::string parentid = this->_findOrGenerateNodeID(node); - - - // 4. Serialize the event. - this->_attributes_scanned.erase(childid); - Glib::ustring childidmsg = MessageUtilities::makeTagWithContent(MESSAGE_CHILD, childid); - Glib::ustring parentidmsg = MessageUtilities::makeTagWithContent(MESSAGE_PARENT, parentid); - this->_events.push_back(MessageUtilities::makeTagWithContent(MESSAGE_DELETE, childidmsg + parentidmsg)); -} - - -void -Serializer::notifyChildOrderChanged(XML::Node& node, XML::Node& child, XML::Node* old_prev, XML::Node* new_prev) -{ - // 1. Find the ID of the node, or generate it if it does not exist. - std::string nodeid = this->_findOrGenerateNodeID(child); - - // 2. Find the ID of the parent of this node, or generate it if it does not exist. - std::string parentid = this->_findOrGenerateNodeID(*(child.parent())); - - // 3. Get the ID for the new child reference node, or generate it if it does not exist. - std::string newprevid = this->_findOrGenerateNodeID(*new_prev); - - // 4. Get the ID for the old child reference node, or generate it if it does not exist. - std::string oldprevid = this->_findOrGenerateNodeID(*old_prev); - - // 5. Serialize the event. - Glib::ustring nodeidmsg = MessageUtilities::makeTagWithContent(MESSAGE_ID, nodeid); - Glib::ustring parentidmsg = MessageUtilities::makeTagWithContent(MESSAGE_PARENT, parentid); - Glib::ustring oldprevidmsg = MessageUtilities::makeTagWithContent(MESSAGE_OLDVAL, oldprevid); - Glib::ustring newprevidmsg = MessageUtilities::makeTagWithContent(MESSAGE_NEWVAL, newprevid); - - this->_events.push_back(MessageUtilities::makeTagWithContent(MESSAGE_ORDERCHANGE, nodeidmsg + parentidmsg + oldprevidmsg + newprevidmsg)); -} - -void -Serializer::notifyContentChanged(XML::Node& node, Util::ptr_shared old_content, Util::ptr_shared new_content) -{ - // 1. Find the ID of the node, or generate it if it does not exist. - std::string nodeid = this->_findOrGenerateNodeID(node); - - std::string oldvalmsg, newvalmsg; - - // 2. If the old and new content are identical, don't send out this change. - // (identical meaning "same string" or "same string content") - if (old_content == new_content) { - return; - } - - if (old_content.pointer() != NULL && new_content.pointer() != NULL) { - if (strcmp(old_content.pointer(), new_content.pointer()) == 0) { - return; - } - } - - // 3. Serialize the event. - if (old_content.pointer() != NULL) { - oldvalmsg = MessageUtilities::makeTagWithContent(MESSAGE_OLDVAL, old_content.pointer()); - } - - if (new_content.pointer() != NULL) { - newvalmsg = MessageUtilities::makeTagWithContent(MESSAGE_NEWVAL, new_content.pointer()); - } - - Glib::ustring nodeidmsg = MessageUtilities::makeTagWithContent(MESSAGE_ID, nodeid); - this->_events.push_back(MessageUtilities::makeTagWithContent(MESSAGE_NODECONTENT, nodeidmsg + oldvalmsg + newvalmsg)); -} - -void -Serializer::notifyAttributeChanged(XML::Node& node, GQuark name, Util::ptr_shared old_value, Util::ptr_shared new_value) -{ - // 1. Find the ID of the node that has had an attribute modified, or generate it if it - // does not exist. - std::string nodeid = this->_findOrGenerateNodeID(node); - - // Proceed with 2-4 if the node has not already been scanned by notifyChildAdded. - if (this->_attributes_scanned.find(nodeid) == this->_attributes_scanned.end()) { - // 2. Convert the key to a string. - Glib::ustring key = g_quark_to_string(name); - - // 3. If oldval == newval, don't echo this change. - if (new_value.pointer() != NULL && old_value.pointer() != NULL) { - if (strcmp(new_value.pointer(), old_value.pointer()) == 0) { - return; - } - } - - // 4. Serialize the event. - Glib::ustring keymsg = MessageUtilities::makeTagWithContent(MESSAGE_KEY, key); - Glib::ustring oldvalmsg, newvalmsg; - - if (old_value.pointer() != NULL) { - oldvalmsg = MessageUtilities::makeTagWithContent(MESSAGE_OLDVAL, old_value.pointer()); - } - - if (new_value.pointer() != NULL) { - newvalmsg = MessageUtilities::makeTagWithContent(MESSAGE_NEWVAL, new_value.pointer()); - } - - Glib::ustring nodeidmsg = MessageUtilities::makeTagWithContent(MESSAGE_ID, nodeid); - - this->_events.push_back(MessageUtilities::makeTagWithContent(MESSAGE_CHANGE, nodeidmsg + keymsg + oldvalmsg + newvalmsg)); - } -} - -void -Serializer::synthesizeChildNodeAddEvents() -{ - _New_nodes_type::iterator i = this->_nn.begin(); - for(; i != this->_nn.end(); ++i) { - XML::Node* parent = *i; - // The root of the subtree defined by parent has already been considered; now, - // recursively look at the rest of the tree. - XML::Node* prev = parent->firstChild(); - for(XML::Node* ch = parent->firstChild(); ch; ch = ch->next()) { - if (ch == parent->firstChild()) { - this->_newObjectEventHelper(*parent, *ch, NULL, true); - } else { - this->_newObjectEventHelper(*parent, *ch, prev, true); - prev = ch; - } - } - } -} - - -void -Serializer::_recursiveMarkAsRemoved(XML::Node& node) -{ - this->actions.tryToTrack(&node, NODE_REMOVE); - - for(XML::Node* ch = node.firstChild(); ch; ch = ch->next()) { - this->_recursiveMarkAsRemoved(*ch); - } -} - -} - -} - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/jabber_whiteboard/serializer.h b/src/jabber_whiteboard/serializer.h deleted file mode 100644 index 2884d43d3..000000000 --- a/src/jabber_whiteboard/serializer.h +++ /dev/null @@ -1,118 +0,0 @@ -/** - * Inkboard message -> XML::Event* serializer - * - * Authors: - * David Yip - * - * Copyright (c) 2005 Authors - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#ifndef __WHITEBOARD_MESSAGE_SERIALIZER_H__ -#define __WHITEBOARD_MESSAGE_SERIALIZER_H__ - -#include "xml/node-observer.h" - -#include "util/share.h" - -#include "jabber_whiteboard/node-tracker.h" -#include "jabber_whiteboard/typedefs.h" -#include "jabber_whiteboard/node-tracker-observer.h" - -#include - -namespace Inkscape { - -namespace Whiteboard { - -class Serializer : public NodeTrackerObserver { -public: - Serializer(XMLNodeTracker* xnt) : NodeTrackerObserver(xnt) { } - ~Serializer() { } - - void notifyChildAdded(XML::Node &node, XML::Node &child, XML::Node *prev); - - void notifyChildRemoved(XML::Node &node, XML::Node &child, XML::Node *prev); - - void notifyChildOrderChanged(XML::Node &node, XML::Node &child, - XML::Node *old_prev, XML::Node *new_prev); - - void notifyContentChanged(XML::Node &node, - Util::ptr_shared old_content, - Util::ptr_shared new_content); - - void notifyAttributeChanged(XML::Node &node, GQuark name, - Util::ptr_shared old_value, - Util::ptr_shared new_value); - - void synthesizeChildNodeAddEvents(); - - SerializedEventList& getEventList() - { - return this->_events; - } - - SerializedEventList getEventListCopy() - { - return this->_events; - } - - SerializedEventList getAndClearEventList() - { - SerializedEventList ret = this->_events; - this->_events.clear(); - return ret; - } - - void clearEventList() - { - this->_events.clear(); - } - - void clearAttributesScannedBuffer() - { - this->_attributes_scanned.clear(); - } - - // Convenience method for resetting all stateful aspects of the serializer - void reset() - { - g_log(NULL, G_LOG_LEVEL_DEBUG, "Clearing serializer buffers"); - this->clearEventList(); - this->_parent_child_map.clear(); - this->_nn.clear(); - this->clearNodeBuffers(); - this->clearAttributesScannedBuffer(); - } - -private: - typedef std::set< XML::Node* > _New_nodes_type; - typedef std::map< XML::Node*, XML::Node* > _pc_map_type; - - SerializedEventList _events; - AttributesScannedSet _attributes_scanned; - - _New_nodes_type _nn; - _pc_map_type _parent_child_map; - - void _newObjectEventHelper(XML::Node& parent, XML::Node& child, XML::Node* prev, bool recurse); - void _recursiveMarkAsRemoved(XML::Node& node); -}; - -} - -} - -#endif - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/jabber_whiteboard/session-file-player.cpp b/src/jabber_whiteboard/session-file-player.cpp deleted file mode 100644 index cc4842e5b..000000000 --- a/src/jabber_whiteboard/session-file-player.cpp +++ /dev/null @@ -1,176 +0,0 @@ -/** - * Whiteboard session file playback mechanism - * - * Authors: - * David Yip - * - * Copyright (c) 2005 Authors - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - - -#include -#include - -#include - -#include "desktop-handles.h" -#include "document.h" - -#include "jabber_whiteboard/defines.h" -#include "jabber_whiteboard/session-file.h" -#include "jabber_whiteboard/session-file-player.h" -#include "jabber_whiteboard/session-manager.h" - -namespace Inkscape { - -namespace Whiteboard { - -SessionFilePlayer::SessionFilePlayer(unsigned int bufsz, SessionManager* sm) -{ - this->_sm = sm; - this->_delay = 100; - this->_playing = false; - this->_curdir = FORWARD; - - this->_current = this->_next = 0; - this->_sf = NULL; - - if (sm->session_file() != NULL) { - this->_sf = sm->session_file(); - } else { - g_warning("Cannot operate on NULL SessionFile."); - } -} - -SessionFilePlayer::~SessionFilePlayer() -{ - -} - -void -SessionFilePlayer::load(SessionFile* sm) -{ - this->stop(); - if (this->_sm != NULL) { - this->_sf = sm; - this->_current = this->_next = 0; - this->_visited.clear(); - } -} - -SessionFile* -SessionFilePlayer::unload() -{ - SessionFile* sf = this->_sf; - this->stop(); - this->_sf = NULL; - return sf; -} - -Glib::ustring const& -SessionFilePlayer::filename() -{ - return this->_sf->filename(); -} - -Glib::ustring const& -SessionFilePlayer::curmsg() -{ - return this->_curmsg; -} - -void -SessionFilePlayer::start() -{ - this->_playback_dispatcher = Glib::signal_timeout().connect(sigc::bind< 0 > (sigc::mem_fun(*(this), &SessionFilePlayer::step), this->_curdir), this->_delay); - this->_playing = true; -} - -void -SessionFilePlayer::stop() -{ - this->_playback_dispatcher.disconnect(); - this->_playing = false; -} - -void -SessionFilePlayer::setDelay(unsigned int delay) -{ - this->_delay = delay; - if (this->_playing) { - this->stop(); - this->start(); - } -} - -void -SessionFilePlayer::setMessageOutputWidget(Glib::RefPtr const& widgetptr) -{ - this->_outputwidget = widgetptr; -} - -bool -SessionFilePlayer::step(unsigned short dir) -{ - switch (dir) { - case FORWARD: { - // Glib::ustring buf; - this->_current = this->_next; - this->_next = this->_sf->nextMessageFrom(this->_current, this->_curmsg); - if (this->_next == this->_current) { - return false; - } else { - this->_visited.push_front(std::make_pair< gint64, gint64 >(this->_current, this->_curmsg.bytes())); - this->_outputMessageToWidget(); - this->_sm->receiveChange(this->_curmsg); - sp_document_done(sp_desktop_document(this->_sm->desktop())); - this->_curdir = FORWARD; - return true; - } - break; - } - case BACKWARD: - if (this->_current == 0) { - return false; - } else { - this->_visited.pop_front(); - std::pair< gint64, gint64 > last = this->_visited.front(); - this->_current = last.first; - this->_next = last.first + last.second; - this->_sf->nextMessageFrom(this->_current, this->_curmsg); - this->_outputMessageToWidget(); - sp_document_undo(sp_desktop_document(this->_sm->desktop())); - this->_curdir = BACKWARD; - return true; - } - break; - default: - return true; - break; - } -} - -void -SessionFilePlayer::_outputMessageToWidget() -{ - if (this->_outputwidget) { - this->_outputwidget->set_text(this->_curmsg); - } -} - -} - -} - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/jabber_whiteboard/session-file-player.h b/src/jabber_whiteboard/session-file-player.h deleted file mode 100644 index aa2e2b4c1..000000000 --- a/src/jabber_whiteboard/session-file-player.h +++ /dev/null @@ -1,99 +0,0 @@ -/** - * Whiteboard session file playback mechanism - * - * Authors: - * David Yip - * - * Copyright (c) 2005 Authors - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#ifndef __WHITEBOARD_SESSION_FILE_PLAYER_H__ -#define __WHITEBOARD_SESSION_FILE_PLAYER_H__ - -#include -#include -#include -#include -#include - -struct SPDesktop; - -namespace Inkscape { - namespace UI { - namespace Dialog { - class SessionPlaybackDialogImpl; - } - } - namespace Whiteboard { - -class SessionFile; -class SessionManager; - -class SessionFilePlayer { -friend class UI::Dialog::SessionPlaybackDialogImpl; - -public: - SessionFilePlayer(unsigned int bufsz, SessionManager* sm); - ~SessionFilePlayer(); - - void load(SessionFile* sm); - SessionFile* unload(); - - Glib::ustring const& filename(); - Glib::ustring const& curmsg(); - - void start(); - void stop(); - void setDelay(unsigned int delay); - void setMessageOutputWidget(Glib::RefPtr const& widgetptr); - - static unsigned short const BACKWARD = 0; - static unsigned short const FORWARD = 1; - -private: - bool step(unsigned short dir); - void _outputMessageToWidget(); - - SessionManager* _sm; - SessionFile* _sf; - - // Output widget refptr - Glib::RefPtr _outputwidget; - - // Playback signal - sigc::connection _playback_dispatcher; - - // trackers - unsigned int _delay; - unsigned short _curdir; - bool _playing; - Glib::ustring _curmsg; - - // (position, msgsize) - std::list< std::pair< gint64, gint64 > > _visited; - gint64 _current; - gint64 _next; - - // noncopyable, nonassignable - SessionFilePlayer(SessionFilePlayer const&); - void operator=(SessionFilePlayer const&); -}; - -} - -} - -#endif - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/jabber_whiteboard/session-file-selector.cpp b/src/jabber_whiteboard/session-file-selector.cpp index 85a3a3ec1..854d61d10 100644 --- a/src/jabber_whiteboard/session-file-selector.cpp +++ b/src/jabber_whiteboard/session-file-selector.cpp @@ -9,11 +9,12 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ +#include +#include + #include "session-file-selector.h" #include -#include -#include namespace Inkscape { diff --git a/src/jabber_whiteboard/session-file-selector.h b/src/jabber_whiteboard/session-file-selector.h index fe097e4ab..4b1f70375 100644 --- a/src/jabber_whiteboard/session-file-selector.h +++ b/src/jabber_whiteboard/session-file-selector.h @@ -12,10 +12,8 @@ #ifndef __WHITEBOARD_SESSION_FILE_SELECTOR_BOX_H__ #define __WHITEBOARD_SESSION_FILE_SELECTOR_BOX_H__ -#include -#include -#include -#include +#include +#include namespace Inkscape { diff --git a/src/jabber_whiteboard/session-file.cpp b/src/jabber_whiteboard/session-file.cpp deleted file mode 100644 index 137e56510..000000000 --- a/src/jabber_whiteboard/session-file.cpp +++ /dev/null @@ -1,140 +0,0 @@ -/** - * Whiteboard session file object - * - * Authors: - * David Yip - * - * Copyright (c) 2005 Authors - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#include -#include - -#include "util/list-container.h" - -#include "jabber_whiteboard/message-utilities.h" -#include "jabber_whiteboard/node-utilities.h" -#include "jabber_whiteboard/typedefs.h" - -#include "jabber_whiteboard/session-file.h" - - -namespace Inkscape { - -namespace Whiteboard { - -SessionFile::SessionFile(Glib::ustring const& filename, bool reading, bool compress) : _filename(filename), _compress(compress), _reading(reading) -{ - try { - - if (!reading) { - this->fptr = Glib::IOChannel::create_from_file(filename, "w+"); - } else { - this->fptr = Glib::IOChannel::create_from_file(filename, "r"); - } - this->_ateof = false; - } catch (Glib::FileError) { - throw; - } -} - -SessionFile::~SessionFile() -{ - if (!this->_reading) { - this->commit(); - } - this->close(); -} - -gint64 -SessionFile::nextMessageFrom(gint64 from, Glib::ustring& buf) -{ - try { - Glib::ustring line; - Glib::IOStatus st; - Node part; - - gint64 accum = from; - buf = ""; - this->fptr->seek(accum, Glib::SEEK_TYPE_SET); - - while(part.tag != MESSAGE_COMMIT) { - st = this->fptr->read_line(line); - if (st == Glib::IO_STATUS_EOF) { - break; - } else { - accum += line.bytes(); - this->fptr->seek(accum); - MessageUtilities::getFirstMessageTag(part, line); - buf += line; - line.clear(); - } - } - - if (st == Glib::IO_STATUS_NORMAL) { - // reset eof flag if successful - this->_ateof = false; - return from + buf.bytes(); - } else { - if (st == Glib::IO_STATUS_EOF) { - this->_ateof = true; - } - return from; - } - } catch (Glib::IOChannelError e) { - g_warning("Could not read next message due to I/O error (error: %s)!", e.what().data()); - } catch (Glib::ConvertError e) { - g_warning("Could not read next message due to charset conversion error (error: %s)!", e.what().data()); - } - - return from; -} - -void -SessionFile::addMessage(Glib::ustring const& message) -{ - Glib::ustring msg = message; - this->changes.push_back(msg); -} - -void -SessionFile::commit() -{ - if (!this->_reading) { - SessionQueue::iterator i = changes.begin(); - for(; i != changes.end(); i++) { - try { - fptr->write(*i); - changes.erase(i); - } catch (Glib::IOChannelError e) { - g_warning("Caught I/O exception (error string: %s) while committing change to session file %s. Attempting to commit remaining changes; session file will be inconsistent with whiteboard session history.", e.what().c_str(), this->_filename.c_str()); - } catch (Glib::ConvertError e) { - g_warning("Caught character set conversion error (error string: %s) while committing change to session file %s. Attempting to commit remaining changes; session file will be inconsistent with whiteboard session history.", e.what().c_str(), this->_filename.c_str()); - } - } - fptr->write("\n"); - } -} - -void -SessionFile::close() -{ - fptr->close(true); -} - -} - -} - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/jabber_whiteboard/session-file.h b/src/jabber_whiteboard/session-file.h deleted file mode 100644 index 926d27af5..000000000 --- a/src/jabber_whiteboard/session-file.h +++ /dev/null @@ -1,78 +0,0 @@ -/** - * Whiteboard session file object - * - * Authors: - * David Yip - * - * Copyright (c) 2005 Authors - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#ifndef __WHITEBOARD_SESSION_FILE_H__ -#define __WHITEBOARD_SESSION_FILE_H__ - -#include -#include "util/list-container.h" - -struct SPDesktop; - -namespace Inkscape { - -namespace Whiteboard { - -typedef Glib::RefPtr< Glib::IOChannel > SessionFilePtr; -typedef Util::ListContainer< Glib::ustring const > SessionQueue; - -class SessionFile { -public: - SessionFile(Glib::ustring const& filename, bool reading, bool compress); - ~SessionFile(); - - gint64 nextMessageFrom(gint64 from, Glib::ustring& buf); - - void addMessage(Glib::ustring const& message); - void commit(); - void close(); - - Glib::ustring const& filename() - { - return this->_filename; - } - - bool isReadOnly() - { - return this->_reading; - } - - bool eof() - { - return this->_ateof; - } - -private: - SessionQueue changes; - SessionFilePtr fptr; - Glib::ustring _filename; - - bool _ateof; - bool _compress; - bool _reading; -}; - -} - -} -#endif - - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/jabber_whiteboard/session-manager.cpp b/src/jabber_whiteboard/session-manager.cpp index 9ead6b60b..f8ca94612 100644 --- a/src/jabber_whiteboard/session-manager.cpp +++ b/src/jabber_whiteboard/session-manager.cpp @@ -3,1230 +3,439 @@ * * Authors: * David Yip + * Bob Jamison (Pedro port) * * Copyright (c) 2005 Authors * * Released under GNU GPL, read the file 'COPYING' for more information */ -/* -#include "inkscape.h" -*/ - -#include +#include +#include +#include +#include #include -#include -#include -#include -#include - -#include "gc-anchored.h" -#include "prefs-utils.h" - -#include "xml/repr.h" #include "xml/node-observer.h" -#include "util/ucompose.hpp" - -#include "message-context.h" -#include "message-stack.h" -#include "desktop-handles.h" #include "document.h" -#include "document-private.h" -#include "verbs.h" +#include "desktop.h" +#include "desktop-handles.h" -#include "jabber_whiteboard/defines.h" -#include "jabber_whiteboard/typedefs.h" -#include "jabber_whiteboard/deserializer.h" -#include "jabber_whiteboard/message-utilities.h" -#include "jabber_whiteboard/message-handler.h" -#include "jabber_whiteboard/node-tracker.h" -#include "jabber_whiteboard/jabber-handlers.h" -#include "jabber_whiteboard/callbacks.h" -#include "jabber_whiteboard/chat-handler.h" -#include "jabber_whiteboard/session-file.h" -#include "jabber_whiteboard/session-file-player.h" +#include "jabber_whiteboard/message-verifier.h" #include "jabber_whiteboard/session-manager.h" -#include "jabber_whiteboard/message-aggregator.h" -#include "jabber_whiteboard/undo-stack-observer.h" -#include "jabber_whiteboard/serializer.h" - -//#include "jabber_whiteboard/pedro/pedroxmpp.h" +#include "jabber_whiteboard/inkboard-document.h" +#include "jabber_whiteboard/new-inkboard-document.h" -#include "jabber_whiteboard/message-node.h" -#include "jabber_whiteboard/message-queue.h" +#define INKBOARD_XMLNS "http://inkscape.org/inkboard" namespace Inkscape { namespace Whiteboard { -SessionData::SessionData(SessionManager *sm) -{ - this->_sm = sm; - this->recipient = NULL; - this->connection = NULL; - this->ssl = NULL; - this->ignoreFurtherSSLErrors = false; - this->send_queue = new SendMessageQueue(sm); - this->sequence_number = 1; -} +//######################################################################### +//# S E S S I O N M A N A G E R +//######################################################################### -SessionData::~SessionData() -{ - this->receive_queues.clear(); +SessionManager *sessionManagerInstance = NULL; - if (this->send_queue) { - delete this->send_queue; - } +void SessionManager::showClient() +{ + SessionManager::instance().gui.show(); } -SessionManager::SessionManager(::SPDesktop *desktop) +SessionManager& +SessionManager::instance() { - - // Initialize private members to NULL to facilitate deletion in destructor - this->_myDoc = NULL; - this->session_data = NULL; - this->_myCallbacks = NULL; - this->_myTracker = NULL; - this->_myChatHandler = NULL; - this->_mySessionFile = NULL; - this->_mySessionPlayer = NULL; - this->_myMessageHandler = NULL; - this->_myUndoObserver = NULL; - this->_mySerializer = NULL; - this->_myDeserializer = NULL; - - this->setDesktop(desktop); - - if (this->_myDoc == NULL) { - g_error("Initializing SessionManager on null document object!"); - } - - -#ifdef WIN32 - //# lm_initialize() must be called before any network code -/* - if (!lm_initialize_called) { - lm_initialize(); - lm_initialize_called = true; - } -*/ -#endif - - this->_setVerbSensitivity(INITIAL); + if (!sessionManagerInstance) + sessionManagerInstance = new SessionManager(); + return *sessionManagerInstance; } -SessionManager::~SessionManager() +SessionManager::SessionManager() { + sequenceNumber = 0L; + getClient().addXmppEventListener(*this); - if (this->session_data) { - if (this->session_data->status[IN_WHITEBOARD]) { - // also calls closeSession - this->disconnectFromDocument(); - } - this->disconnectFromServer(); - - if (this->session_data->status[LOGGED_IN]) { - // TODO: unref message handlers - } - } - - if (this->_mySessionFile) { - delete this->_mySessionPlayer; - delete this->_mySessionFile; - } - - delete this->_myChatHandler; - - - // Deletion of _myTracker is done in closeSession; - // no need to do it here. - - // Deletion is handled separately from session teardown and server disconnection - // because some teardown methods (e.g. closeSession) require access to members that we will - // be deleting. Separating deletion from teardown means that we do not have - // to worry (as much) about proper ordering of the teardown sequence. (We still need - // to ensure that destructors in each object being deleted have access to all the - // members they need, though.) - - // Stop dispatchers - if (this->_myCallbacks) { - this->stopSendQueueDispatch(); - this->stopReceiveQueueDispatch(); - delete this->_myCallbacks; - } - - delete this->_myMessageHandler; - - delete this->session_data; - - Inkscape::GC::release(this->_myDoc); - + this->_check_pending_invitations = Glib::signal_timeout().connect(sigc::mem_fun(*this, &SessionManager::_checkInvitationQueue), 50); + this->_check_invitation_responses = Glib::signal_timeout().connect(sigc::mem_fun(*this, &SessionManager::_checkInvitationResponseQueue), 50); } -void -SessionManager::setDesktop(::SPDesktop* desktop) +SessionManager::~SessionManager() { - this->_myDesktop = desktop; - if (this->_myDoc != NULL) { - Inkscape::GC::release(this->_myDoc); - } - if (sp_desktop_document(desktop) != NULL) { - this->_myDoc = sp_desktop_document(desktop); - Inkscape::GC::anchor(this->_myDoc); - } + getClient().removeXmppEventListener(*this); + getClient().disconnect(); } -int -SessionManager::initializeConnection(Glib::ustring const& server, Glib::ustring const& port, bool usessl) +unsigned long SessionManager::getSequenceNumber() { - GError* error = NULL; - - if (!this->session_data) { - this->session_data = new SessionData(this); - } - - if (!this->_myMessageHandler) { - this->_myMessageHandler = new MessageHandler(this); - } - - // Connect to server - // We need to check to see if this object already exists, because - // the user may be reusing an old connection that failed due to e.g. - // authentication failure. - if (this->session_data->connection) { - lm_connection_close(this->session_data->connection, &error); - lm_connection_unref(this->session_data->connection); - } - - this->session_data->connection = lm_connection_new(server.c_str()); - this->session_data->chat_server = server; - - lm_connection_set_port(this->session_data->connection, atoi(port.c_str())); - - g_log(NULL, G_LOG_LEVEL_DEBUG, "Opened connection to %s at port %s. Connecting...", - server.c_str(), port.c_str()); - - if (usessl) { - if (lm_ssl_is_supported()) { - this->session_data->ssl = lm_ssl_new(NULL, ssl_error_handler, reinterpret_cast< gpointer >(this), NULL); - - lm_ssl_ref(this->session_data->ssl); - } else { - return SSL_INITIALIZATION_ERROR; - } - lm_connection_set_ssl(this->session_data->connection, this->session_data->ssl); - } - - // Send authorization - //lm_connection_set_jid(this->session_data->connection, jid.c_str()); - - // TODO: - // Asynchronous connection and authentication would be nice, - // but it's a huge mess of mixing C callbacks and C++ method calls. - // I've tried to do it and only managed to severely destabilize the Jabber - // server connection routines. - // - // This, of course, is an invitation to anyone more capable than me - // to convert this from synchronous to asynchronous Loudmouth calls. - if (!lm_connection_open_and_block(this->session_data->connection, &error)) { - if (error != NULL) { - std::cout << "Failed to open: " << error->message << std::endl; - } - return FAILED_TO_CONNECT; - } - - //On successful connect, remember info - prefs_set_string_attribute("whiteboard.server", "name", server.c_str()); - prefs_set_string_attribute("whiteboard.server", "port", port.c_str()); - prefs_set_int_attribute("whiteboard.server", "ssl", (usessl) ? 1 : 0); - - return CONNECT_SUCCESS; + return sequenceNumber++; } -std::vector -SessionManager::getRegistrationInfo() -{ - GError* error = NULL; - xmlDoc *doc = NULL; - xmlNode *root_element = NULL; - xmlNode *cur_node = NULL; - - LmMessage *reply,*request; - LmMessageNode *n; - - std::vector registerelements; - - request = lm_message_new_with_sub_type(NULL,LM_MESSAGE_TYPE_IQ,LM_MESSAGE_SUB_TYPE_GET); - n = lm_message_node_add_child (request->node, "query", NULL); - lm_message_node_set_attributes (n, "xmlns", "jabber:iq:register", NULL); - - reply = lm_connection_send_with_reply_and_block(this->session_data->connection, request, &error); - if (error != NULL) { - return registerelements; - } - - n = lm_message_get_node(reply); - - Glib::ustring content = static_cast< Glib::ustring >(lm_message_node_to_string(lm_message_node_get_child(n,"query"))); - doc = xmlReadMemory(content.c_str(),content.size(), "noname.xml", NULL, 0); - - if (doc == NULL) { - g_warning("Failed to parse document\n"); - return registerelements; - } - - root_element = xmlDocGetRootElement(doc); - - for (cur_node = root_element->children; cur_node; cur_node = cur_node->next) { - Glib::ustring name = static_cast< Glib::ustring >((char const *)cur_node->name); - if (cur_node->type == XML_ELEMENT_NODE && name != "instructions" - && name != "username" && name != "password" ) { - registerelements.push_back(name); - } - } - - xmlFreeDoc(doc); - xmlCleanupParser(); - - return registerelements; +bool +SessionManager::send(const Glib::ustring &destJid, + const MessageType type, + const Glib::ustring &data) +{ + Pedro::DOMString xmlData = Pedro::Parser::encode(data); + char *fmt= + "" + "%s" + "" + ""; + if (!getClient().write(fmt, + getClient().getJid().c_str(), + destJid.c_str(), + getClient().getMsgId(), + INKBOARD_XMLNS, + 2, + (MessageType)type, + getSequenceNumber(), + xmlData.c_str() + )) + { + return false; + } + + return true; } -int -SessionManager::registerWithServer(Glib::ustring const& username, Glib::ustring const& pw, - std::vector key, std::vector val) -{ - - GError* error = NULL; - - LmMessage *request,*reply; - LmMessageNode *n; - - request = lm_message_new_with_sub_type(NULL,LM_MESSAGE_TYPE_IQ,LM_MESSAGE_SUB_TYPE_SET); - n = lm_message_node_add_child (request->node, "query", NULL); - lm_message_node_set_attributes (n, "xmlns", "jabber:iq:register", NULL); - - lm_message_node_add_child(n,"username",username.c_str()); - lm_message_node_add_child(n,"password",pw.c_str()); - - for(unsigned i=0;isession_data->connection, request, &error); - if (error != NULL || lm_message_get_type(reply) != LM_MESSAGE_SUB_TYPE_RESULT) { - return INVALID_AUTH; - } - - this->session_data->jid = username + "@" + (this->session_data->chat_server.c_str()) + "/" + RESOURCE_NAME; - - prefs_set_string_attribute("whiteboard.server", "username", username.c_str()); - - return this->finaliseConnection(); +bool +SessionManager::sendGroup(const Glib::ustring &groupJid, + const MessageType type, + const Glib::ustring &data) +{ + Pedro::DOMString xmlData = Pedro::Parser::encode(data); + char *fmt= + "" + "%s" + "" + ""; + if (!getClient().write(fmt, + getClient().getJid().c_str(), + groupJid.c_str(), + getClient().getMsgId(), + INKBOARD_XMLNS, + 2, + type, + getSequenceNumber(), + xmlData.c_str() + )) + { + return false; + } + + return true; } -int -SessionManager::connectToServer(Glib::ustring const& server, Glib::ustring const& port, - Glib::ustring const& entered_username, Glib::ustring const& pw, bool usessl) -{ - GError* error = NULL; - Glib::ustring username; - Glib::ustring jid; - - initializeConnection(server,port,usessl); - - Glib::ustring::size_type atPos = entered_username.find('@'); - - if (atPos != Glib::ustring::npos) { - jid += entered_username; - username = entered_username.substr(0, atPos); - } else { - jid += entered_username + "@" + server + "/" + RESOURCE_NAME; - username = entered_username; - } - - this->session_data->jid = jid; - - if (!lm_connection_authenticate_and_block(this->session_data->connection, username.c_str(), pw.c_str(), RESOURCE_NAME, &error)) { - if (error != NULL) { - g_warning("Failed to authenticate: %s", error->message); - } - lm_connection_close(this->session_data->connection, NULL); - lm_connection_unref(this->session_data->connection); - this->session_data->connection = NULL; - return INVALID_AUTH; - } - - g_log(NULL, G_LOG_LEVEL_DEBUG, "Successfully authenticated."); - - return this->finaliseConnection(); +void +SessionManager::processXmppEvent(const Pedro::XmppEvent &event) +{ + int type = event.getType(); + + switch (type) { + case Pedro::XmppEvent::EVENT_STATUS: + { + break; + } + case Pedro::XmppEvent::EVENT_ERROR: + { + break; + } + case Pedro::XmppEvent::EVENT_CONNECTED: + { + break; + } + case Pedro::XmppEvent::EVENT_DISCONNECTED: + { + break; + } + case Pedro::XmppEvent::EVENT_MESSAGE: + { + printf("## SM message:%s\n", event.getFrom().c_str()); + Pedro::Element *root = event.getDOM(); + + if (root) + { + if (root->getTagAttribute("inkboard", "xmlns") == + INKBOARD_XMLNS) + { + _processInkboardEvent(event); + } + } + break; + } + case Pedro::XmppEvent::EVENT_PRESENCE: + { + break; + } + case Pedro::XmppEvent::EVENT_MUC_MESSAGE: + { + printf("## SM MUC message:%s\n", event.getFrom().c_str()); + Pedro::Element *root = event.getDOM(); + if (root) + { + if (root->getTagAttribute("inkboard", "xmlns") == + INKBOARD_XMLNS) + { + _processInkboardEvent(event); + } + } + break; + } + case Pedro::XmppEvent::EVENT_MUC_JOIN: + { + break; + } + case Pedro::XmppEvent::EVENT_MUC_LEAVE: + { + break; + } + case Pedro::XmppEvent::EVENT_MUC_PRESENCE: + { + break; + } + default: + { + break; + } + } } -int -SessionManager::finaliseConnection() +/** + * Initiates a shared session with a user or conference room. + * + * \param to The recipient to which this desktop will be linked, specified as a JID. + * \param type Type of the session; i.e. private message or group chat. + */ +void +SessionManager::doShare(Glib::ustring const& to, SessionType type) { - - GError* error = NULL; - LmMessage* m; - LmMessageHandler* mh; - - // Register message handler for presence messages - mh = lm_message_handler_new((LmHandleMessageFunction)presence_handler, reinterpret_cast< gpointer >(this->_myMessageHandler), NULL); - lm_connection_register_message_handler(this->session_data->connection, mh, LM_MESSAGE_TYPE_PRESENCE, LM_HANDLER_PRIORITY_NORMAL); - - // Register message handler for stream error messages - mh = lm_message_handler_new((LmHandleMessageFunction)stream_error_handler, reinterpret_cast< gpointer >(this->_myMessageHandler), NULL); - lm_connection_register_message_handler(this->session_data->connection, mh, LM_MESSAGE_TYPE_STREAM_ERROR, LM_HANDLER_PRIORITY_NORMAL); - - // Register message handler for chat messages - mh = lm_message_handler_new((LmHandleMessageFunction)default_handler, reinterpret_cast< gpointer >(this->_myMessageHandler), NULL); - lm_connection_register_message_handler(this->session_data->connection, mh, LM_MESSAGE_TYPE_MESSAGE, LM_HANDLER_PRIORITY_NORMAL); - - // Send presence message to server - m = lm_message_new_with_sub_type(NULL, LM_MESSAGE_TYPE_PRESENCE, LM_MESSAGE_SUB_TYPE_NOT_SET); - if (!lm_connection_send(this->session_data->connection, m, &error)) { - if (error != NULL) { - g_warning("Presence message could not be sent: %s", error->message); + SPDesktop* dt = createInkboardDesktop(to, type); + if (dt != NULL) { + InkboardDocument* doc = dynamic_cast< InkboardDocument* >(sp_desktop_document(dt)->rdoc); + if (doc != NULL) { + doc->startSessionNegotiation(); } - lm_connection_close(this->session_data->connection, NULL); - lm_connection_unref(this->session_data->connection); - this->session_data->connection = NULL; - return FAILED_TO_CONNECT; } - - this->session_data->status.set(LOGGED_IN, 1); - - this->_myCallbacks = new Callbacks(this); - - lm_message_unref(m); - - this->_setVerbSensitivity(ESTABLISHED_CONNECTION); - - return CONNECT_SUCCESS; } -LmSSLResponse -SessionManager::handleSSLError(LmSSL* ssl, LmSSLStatus status) +/** + * Clone of sp_file_new and all related subroutines and functions, + * with appropriate modifications to use the Inkboard document class. + * + * \param to The JID to which this Inkboard document will be connected. + * \return A pointer to the created desktop, or NULL if a new desktop could not be created. + */ +SPDesktop* +SessionManager::createInkboardDesktop(Glib::ustring const& to, SessionType type) { - if (this->session_data->ignoreFurtherSSLErrors) { - return LM_SSL_RESPONSE_CONTINUE; - } - - Glib::ustring msg; - - // TODO: It'd be nice to provide the user with additional information in some cases, - // like fingerprints, hostname, etc. - switch(status) { - case LM_SSL_STATUS_NO_CERT_FOUND: - msg = _("No SSL certificate was found."); - break; - case LM_SSL_STATUS_UNTRUSTED_CERT: - msg = _("The SSL certificate provided by the Jabber server is untrusted."); - break; - case LM_SSL_STATUS_CERT_EXPIRED: - msg = _("The SSL certificate provided by the Jabber server is expired."); - break; - case LM_SSL_STATUS_CERT_NOT_ACTIVATED: - msg = _("The SSL certificate provided by the Jabber server has not been activated."); - break; - case LM_SSL_STATUS_CERT_HOSTNAME_MISMATCH: - msg = _("The SSL certificate provided by the Jabber server contains a hostname that does not match the Jabber server's hostname."); - break; - case LM_SSL_STATUS_CERT_FINGERPRINT_MISMATCH: - msg = _("The SSL certificate provided by the Jabber server contains an invalid fingerprint."); - break; - case LM_SSL_STATUS_GENERIC_ERROR: - msg = _("An unknown error occurred while setting up the SSL connection."); - break; - } +// Create document (sp_repr_document_new clone) + SPDocument* doc = makeInkboardDocument(g_quark_from_static_string("xml"), "svg:svg", type, to); + g_return_val_if_fail(doc != NULL, NULL); - // TRANSLATORS: %1 is the message that describes the specific error that occurred when - // establishing the SSL connection. - Glib::ustring mainmsg = String::ucompose(_("%1\n\nDo you wish to continue connecting to the Jabber server?"), msg); - - Gtk::MessageDialog dlg(mainmsg, true, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_NONE, false); - dlg.add_button(_("Continue connecting and ignore further errors"), 0); - dlg.add_button(_("Continue connecting, but warn me of further errors"), 1); - dlg.add_button(_("Cancel connection"), 2); - - switch(dlg.run()) { - case 0: - this->session_data->ignoreFurtherSSLErrors = true; - /* FALL-THROUGH */ - case 1: - return LM_SSL_RESPONSE_CONTINUE; + InkboardDocument* inkdoc = dynamic_cast< InkboardDocument* >(doc->rdoc); + if (inkdoc == NULL) { // this shouldn't ever happen... + return NULL; + } - default: - return LM_SSL_RESPONSE_STOP; - } +// Create desktop and attach document + SPDesktop *dt = makeInkboardDesktop(doc); + _inkboards.push_back(Inkboard_record_type(to, inkdoc)); + return dt; } void -SessionManager::disconnectFromServer() -{ - if (this->session_data->connection) - { - GError* error = NULL; - - LmMessage *m; - this->disconnectFromDocument(); - m = lm_message_new_with_sub_type(NULL, LM_MESSAGE_TYPE_PRESENCE, LM_MESSAGE_SUB_TYPE_UNAVAILABLE); - if (!lm_connection_send(this->session_data->connection, m, &error)) { - g_warning("Could not send unavailable presence message: %s", error->message); - } - - lm_message_unref(m); - lm_connection_close(this->session_data->connection, NULL); - lm_connection_unref(this->session_data->connection); - if (this->session_data->ssl) { - lm_ssl_unref(this->session_data->ssl); - } +SessionManager::terminateInkboardSession(Glib::ustring const& to) +{ + std::cout << "Terminating Inkboard session to " << to << std::endl; + Inkboards_type::iterator i = _inkboards.begin(); + for(; i != _inkboards.end(); ++i) { + if ((*i).first == to) { + break; + } + } - this->session_data->connection = NULL; - this->session_data->ssl = NULL; - this->_setVerbSensitivity(INITIAL); - } + if (i != _inkboards.end()) { + std::cout << "Erasing Inkboard session to " << to << std::endl; + (*i).second->terminateSession(); + _inkboards.erase(i); + } } -void -SessionManager::disconnectFromDocument() +InkboardDocument* +SessionManager::getInkboardSession(Glib::ustring const& to) { - if (this->session_data->status[IN_WHITEBOARD] || !this->session_data->status[IN_CHATROOM]) { - this->sendMessage(DISCONNECTED_FROM_USER_SIGNAL, 0, "", this->session_data->recipient, false); - } - this->closeSession(); - this->_setVerbSensitivity(DISCONNECTED_FROM_SESSION); + Inkboards_type::iterator i = _inkboards.begin(); + for(; i != _inkboards.end(); ++i) { + if ((*i).first == to) { + return (*i).second; + } + } + return NULL; } void -SessionManager::closeSession() +SessionManager::_processInkboardEvent(Pedro::XmppEvent const& event) { + Pedro::Element* root = event.getDOM(); - if (this->session_data->status[IN_WHITEBOARD]) { - this->session_data->status.set(IN_WHITEBOARD, 0); - this->session_data->receive_queues.clear(); - this->session_data->send_queue->clear(); - this->stopSendQueueDispatch(); - this->stopReceiveQueueDispatch(); - } - - if (this->_myUndoObserver) { - this->_myDoc->removeUndoObserver(*this->_myUndoObserver); + if (root == NULL) { + g_warning("Received null DOM; ignoring message."); + return; } - delete this->_myUndoObserver; - delete this->_mySerializer; - delete this->_myDeserializer; - - this->_myUndoObserver = NULL; - this->_mySerializer = NULL; - this->_myDeserializer = NULL; - - if (this->_myTracker) { - delete this->_myTracker; - this->_myTracker = NULL; - } + Pedro::DOMString type = root->getTagAttribute("inkboard", "type"); + Pedro::DOMString seq = root->getTagAttribute("inkboard", "seq"); + Pedro::DOMString protover = root->getTagAttribute("inkboard", "protocol"); + if (type.empty() || seq.empty() || protover.empty()) { + g_warning("Received incomplete Inkboard message (missing type, protocol, or sequence number); ignoring message."); + return; + } - this->setRecipient(NULL); -} + MessageType mtype = static_cast< MessageType >(atoi(type.c_str())); -void -SessionManager::setRecipient(char const* recipientJID) -{ - if (this->session_data->recipient) { - free(const_cast< gchar* >(this->session_data->recipient)); - } - - if (recipientJID == NULL) { - this->session_data->recipient = NULL; - } else { - this->session_data->recipient = g_strdup(recipientJID); - } -} + // Messages that deal with the creation and destruction of sessions should be handled + // here in the SessionManager. + // + // These events are listed below, along with rationale. + // + // - CONNECT_REQUEST_USER: when we begin to process this message, we will not have an + // Inkboard session available to send the message to. Therefore, this message needs + // to be handled by the SessionManager. + // + // - CONNECT_REQUEST_REFUSED_BY_PEER: this message means that the recipient of a + // private invitation refused the invitation. In this case, we need to destroy the + // Inkboard desktop, document, and session associated with that invitation. + // Destruction of these components seems to be more naturally done in the SessionManager + // than in the Inkboard document itself (especially since the document may be associated + // with multiple desktops). + // + // - UNSUPPORTED_PROTOCOL_VERSION: this message means that the recipient of an invitation + // does not support the version of the Inkboard protocol we are using. In this case, + // we have to destroy the Inkboard desktop, document, and session associated with that + // invitation. The rationale for doing it in the SessionManager is the same as that + // given above. + // + // - ALREADY_IN_SESSION: similar rationale to above. + // + // - DISCONNECTED_FROM_USER_SIGNAL: similar rationale to above. + // + // + // All other events can be handled inside an Inkboard session. + + // The message we are handling will have come from some Jabber ID. We need to verify + // that the Inkboard session associated with that JID is in the correct state for the + // incoming message (or, in some cases, that the session correctly exists / does not + // exist). + InkboardDocument* doc = getInkboardSession(event.getFrom()); -void -SessionManager::sendChange(Glib::ustring const& msg, MessageType type, std::string const& recipientJID, bool chatroom) -{ - if (!this->session_data->status[IN_WHITEBOARD]) { - return; - } +// NOTE: This line refers to a class that hasn't been written yet +// MessageValidityTestResult res = MessageVerifier::verifyMessageValidity(event, mtype, doc); - std::string& recipient = const_cast< std::string& >(recipientJID); - if (recipient.empty()) { - recipient = this->session_data->recipient; - } - + MessageValidityTestResult res = RESULT_INVALID; - switch (type) { - case DOCUMENT_BEGIN: - case DOCUMENT_END: - case CHANGE_NOT_REPEATABLE: - case CHANGE_REPEATABLE: - case CHANGE_COMMIT: + switch (res) { + case RESULT_VALID: { - MessageNode *newNode = new MessageNode(this->session_data->sequence_number++, this->session_data->jid, recipient, msg, type, false, chatroom); - this->session_data->send_queue->insert(newNode); - Inkscape::GC::release(newNode); + switch (mtype) { + case CONNECT_REQUEST_USER: + case CONNECT_REQUEST_REFUSED_BY_PEER: + case UNSUPPORTED_PROTOCOL_VERSION: + case ALREADY_IN_SESSION: + _handleSessionEvent(mtype, event); + break; + case DISCONNECTED_FROM_USER_SIGNAL: + break; + default: + if (doc != NULL) { + unsigned int seqnum = atoi(seq.c_str()); + doc->processInkboardEvent(mtype, seqnum, event.getData()); + } + break; + } break; } + case RESULT_INVALID: default: - g_warning("Cannot insert MessageNode with unknown change type into send queue; discarding message. This may lead to desynchronization!"); + // FIXME: better warning message + g_warning("Received message in invalid context."); break; } } - -// FIXME: -// This method needs a massive, massive, massive overhaul. -int -SessionManager::sendMessage(MessageType msgtype, unsigned int sequence, Glib::ustring const& msg, char const* recipientJID, bool chatroom) +void +SessionManager::_handleSessionEvent(MessageType mtype, Pedro::XmppEvent const& event) { - LmMessage* m; - GError* error = NULL; - char* type, * seq; - - if (recipientJID == NULL || recipientJID == "") { - g_warning("Null recipient JID specified; not sending message."); - return NO_RECIPIENT_JID; - } else { - } - - // create message - m = lm_message_new(recipientJID, LM_MESSAGE_TYPE_MESSAGE); - - // add sender - lm_message_node_set_attribute(m->node, "from", this->session_data->jid.c_str()); - - // set message subtype according to whether or not this is - // destined for a chatroom - if (chatroom) { - lm_message_node_set_attribute(m->node, "type", "groupchat"); - } else { - lm_message_node_set_attribute(m->node, "type", "chat"); - } - - // set protocol version; - // we are currently fixed at version 1 - lm_message_node_add_child(m->node, MESSAGE_PROTOCOL_VER, MESSAGE_PROTOCOL_V1); - - // add message type - type = (char *)calloc(TYPE_FIELD_SIZE, sizeof(char)); - snprintf(type, TYPE_FIELD_SIZE, "%i", msgtype); - lm_message_node_add_child(m->node, MESSAGE_TYPE, type); - free(type); - - // add message body - if (!msg.empty()) { - lm_message_node_add_child(m->node, MESSAGE_BODY, msg.c_str()); - } else { - } - - // add sequence number - switch(msgtype) { - case CHANGE_REPEATABLE: - case CHANGE_NOT_REPEATABLE: - case DUMMY_CHANGE: - case CHANGE_COMMIT: - case DOCUMENT_BEGIN: - case DOCUMENT_END: - case CONNECT_REQUEST_RESPONSE_CHAT: - case CONNECT_REQUEST_RESPONSE_USER: - case CHATROOM_SYNCHRONIZE_RESPONSE: - seq = (char* )calloc(SEQNUM_FIELD_SIZE, sizeof(char)); - sprintf(seq, "%u", sequence); - lm_message_node_add_child(m->node, MESSAGE_SEQNUM, seq); - free(seq); - break; - + switch (mtype) { case CONNECT_REQUEST_USER: - case CONNECTED_SIGNAL: - case DISCONNECTED_FROM_USER_SIGNAL: + _handleIncomingInvitation(event.getFrom()); break; - - // Error messages and synchronization requests do not need a sequence number - case CHATROOM_SYNCHRONIZE_REQUEST: case CONNECT_REQUEST_REFUSED_BY_PEER: - case UNSUPPORTED_PROTOCOL_VERSION: + _handleInvitationResponse(event.getFrom(), DECLINE_INVITATION); + break; case ALREADY_IN_SESSION: + _handleInvitationResponse(event.getFrom(), PEER_ALREADY_IN_SESSION); + break; + case UNSUPPORTED_PROTOCOL_VERSION: + _handleInvitationResponse(event.getFrom(), UNSUPPORTED_PROTOCOL); break; - default: - g_warning("Outgoing message type not recognized; not sending."); - lm_message_unref(m); - return UNKNOWN_OUTGOING_TYPE; - } - - // We want to log messages even if they were not successfully sent, - // since the user may opt to re-synchronize a session using the session - // file record. - if (!msg.empty()) { - this->_log(msg); - this->_commitLog(); - } - - // send message - - if (!lm_connection_send(this->session_data->connection, m, &error)) { - g_warning("Send failed: %s", error->message); - lm_message_unref(m); - return CONNECTION_ERROR; - } - - lm_message_unref(m); - return SEND_SUCCESS; -} - -void -SessionManager::connectionError(Glib::ustring const& errmsg) -{ - Gtk::MessageDialog dlg(errmsg, true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE); - dlg.run(); -// sp_whiteboard_connect_dialog(const_cast< gchar* >(errmsg)); -} - -void -SessionManager::resendDocument(char const* recipientJID, KeyToNodeMap& newidsbuf, NodeToKeyMap& newnodesbuf) -{ - Glib::ustring docbegin = MessageUtilities::makeTagWithContent(MESSAGE_DOCBEGIN, ""); - this->sendChange(docbegin, DOCUMENT_BEGIN, recipientJID, false); - - Inkscape::XML::Node* root = sp_document_repr_root(this->_myDoc); - - if(root == NULL) { - return; - } - - NewChildObjectMessageList newchildren; - MessageAggregator& agg = MessageAggregator::instance(); - Glib::ustring buf; - - for ( Inkscape::XML::Node *child = root->firstChild() ; child != NULL ; child = child->next() ) { - // TODO: replace with Serializer methods - MessageUtilities::newObjectMessage(&buf, newidsbuf, newnodesbuf, newchildren, this->_myTracker, child); - - NewChildObjectMessageList::iterator j = newchildren.begin(); - Glib::ustring aggbuf; - - for(; j != newchildren.end(); j++) { - if (!agg.addOne(*j, aggbuf)) { - this->sendChange(aggbuf, CHANGE_REPEATABLE, recipientJID, false); - aggbuf.clear(); - agg.addOne(*j, aggbuf); - } - } - - // send remaining changes - if (!aggbuf.empty()) { - this->sendChange(aggbuf, CHANGE_REPEATABLE, recipientJID, false); - aggbuf.clear(); - } - - newchildren.clear(); - buf.clear(); - } - - Glib::ustring commit = MessageUtilities::makeTagWithContent(MESSAGE_COMMIT, ""); - this->sendChange(commit, CHANGE_COMMIT, recipientJID, false); - Glib::ustring docend = MessageUtilities::makeTagWithContent(MESSAGE_DOCEND, ""); - this->sendChange(docend, DOCUMENT_END, recipientJID, false); -} - -void -SessionManager::receiveChange(Glib::ustring const& changemsg) -{ - - struct Node part; - - Glib::ustring msgcopy = changemsg.c_str(); - - - while(MessageUtilities::getFirstMessageTag(part, msgcopy) != false) { - // TODO: - // Yikes. This is ugly. - if (part.tag == MESSAGE_CHANGE) { - this->_myDeserializer->deserializeEventChgAttr(part.data); - msgcopy.erase(0, part.next_pos); - - } else if (part.tag == MESSAGE_NEWOBJ) { - this->_myDeserializer->deserializeEventAdd(part.data); - msgcopy.erase(0, part.next_pos); - - } else if (part.tag == MESSAGE_DELETE) { - this->_myDeserializer->deserializeEventDel(part.data); - msgcopy.erase(0, part.next_pos); - - } else if (part.tag == MESSAGE_DOCUMENT) { - // no special handler, just keep going with the rest of the message - msgcopy.erase(0, part.next_pos); - - } else if (part.tag == MESSAGE_NODECONTENT) { - this->_myDeserializer->deserializeEventChgContent(part.data); - msgcopy.erase(0, part.next_pos); - - } else if (part.tag == MESSAGE_ORDERCHANGE) { - this->_myDeserializer->deserializeEventChgOrder(part.data); - msgcopy.erase(0, part.next_pos); - - } else if (part.tag == MESSAGE_COMMIT) { - // Retrieve the deserialized event log, node actions, and nodes with updated attributes - XML::Event* log = this->_myDeserializer->getEventLog(); - KeyToNodeActionList& node_changes = this->_myDeserializer->getNodeTrackerActions(); - AttributesUpdatedSet& updated = this->_myDeserializer->getUpdatedAttributeNodeSet(); - - // Make document insensitive to undo - gboolean saved = sp_document_get_undo_sensitive(this->_myDoc); - sp_document_set_undo_sensitive(this->_myDoc, FALSE); - - // Replay the log and push it onto the undo stack - sp_repr_replay_log(log); - - // Call updateRepr on changed nodes - // This is required for some tools to function properly, i.e. text tool - // (TODO: we don't need to update _all_ changed nodes, just their parents) - AttributesUpdatedSet::iterator i = updated.begin(); - for(; i != updated.end(); i++) { - SPObject* updated = this->_myDoc->getObjectByRepr(*i); - if (updated) { - updated->updateRepr(); - } - } - - // merge the events generated by updateRepr - sp_repr_coalesce_log(this->_myDoc->priv->partial, log); - this->_myDoc->priv->partial = NULL; - - this->_myDoc->priv->undo = g_slist_prepend(this->_myDoc->priv->undo, log); - - // Restore undo sensitivity - sp_document_set_undo_sensitive(this->_myDoc, saved); - - // Add or delete nodes to/from the tracker - this->_myTracker->process(node_changes); - - // Reset deserializer state - this->_myDeserializer->reset(); break; - - } else if (part.tag == MESSAGE_UNDO) { - this->_myUndoObserver->lockObserverFromSending(UndoStackObserver::UNDO_EVENT); - sp_document_undo(this->_myDoc); - this->_myUndoObserver->unlockObserverFromSending(UndoStackObserver::UNDO_EVENT); - msgcopy.erase(0, part.next_pos); - - } else if (part.tag == MESSAGE_REDO) { - this->_myUndoObserver->lockObserverFromSending(UndoStackObserver::REDO_EVENT); - sp_document_redo(this->_myDoc); - this->_myUndoObserver->unlockObserverFromSending(UndoStackObserver::REDO_EVENT); - msgcopy.erase(0, part.next_pos); - - } else if (part.tag == MESSAGE_DOCBEGIN) { - msgcopy.erase(0, part.next_pos); - - } else if (part.tag == MESSAGE_DOCEND) { - // Set this to be the new original state of the document - sp_document_done(this->document()); - sp_document_clear_redo(this->document()); - sp_document_clear_undo(this->document()); - this->setupCommitListener(); - msgcopy.erase(0, part.next_pos); - - } else { - msgcopy.erase(0, part.next_pos); - - } - } - - this->_log(changemsg); - - this->_commitLog(); -} - -bool -SessionManager::isPlayingSessionFile() -{ - return this->session_data->status[PLAYING_SESSION_FILE]; -} - -void -SessionManager::loadSessionFile(Glib::ustring filename) -{ - if (!this->session_data || !this->session_data->status[IN_WHITEBOARD]) { - try { - if (this->_mySessionFile) { - delete this->_mySessionFile; - } - this->_mySessionFile = new SessionFile(filename, true, false); - - // Initialize objects needed for session playback - if (this->_mySessionPlayer == NULL) { - this->_mySessionPlayer = new SessionFilePlayer(16, this); - } else { - this->_mySessionPlayer->load(this->_mySessionFile); - } - - if (this->_myTracker == NULL) { - this->_myTracker = new XMLNodeTracker(this); - } else { - this->_myTracker->reset(); - } - - if (!this->session_data) { - this->session_data = new SessionData(this); - } - - if (!this->_myDeserializer) { - this->_myDeserializer = new Deserializer(this->node_tracker()); - } - - if (!this->_myUndoObserver) { - this->setupCommitListener(); - } - - this->session_data->status.set(PLAYING_SESSION_FILE, 1); - - - } catch (Glib::FileError e) { - g_warning("Could not load session file: %s", e.what().data()); - } - } -} - -void -SessionManager::userConnectedToWhiteboard(gchar const* JID) -{ - sp_desktop_message_stack(this->_myDesktop)->flashF(Inkscape::INFORMATION_MESSAGE, _("Established whiteboard session with %s."), JID); -} - - -void -SessionManager::userDisconnectedFromWhiteboard(std::string const& JID) -{ - - sp_desktop_message_stack(this->_myDesktop)->flashF(Inkscape::INFORMATION_MESSAGE, _("%s has left the whiteboard session."), JID.c_str()); - - // Inform the user - // TRANSLATORS: %1 is the name of the user that disconnected, %2 is the name of the user whom the disconnected user disconnected from. - // This message is not used in a chatroom context. - Glib::ustring primary = String::ucompose(_("The user %1 has left the whiteboard session.\n\n"), JID); - // TRANSLATORS: %1 and %2 are userids - Glib::ustring secondary = String::ucompose(_("You are still connected to a Jabber server as %2, and may establish a new session to %1 or a different user."), JID, this->session_data->jid); - - // TODO: parent this dialog to the active desktop - Gtk::MessageDialog dialog(primary + secondary, true, Gtk::MESSAGE_INFO, Gtk::BUTTONS_CLOSE, false); - /* - dialog.set_message(primary, true); - dialog.set_secondary_text(secondary, true); - */ - dialog.run(); -} - -void -SessionManager::startSendQueueDispatch() -{ - this->_send_queue_dispatcher = Glib::signal_timeout().connect(sigc::mem_fun(*(this->_myCallbacks), &Callbacks::dispatchSendQueue), SEND_TIMEOUT); -} - -void -SessionManager::stopSendQueueDispatch() -{ - if (this->_send_queue_dispatcher) { - this->_send_queue_dispatcher.disconnect(); - } -} - -void -SessionManager::startReceiveQueueDispatch() -{ - this->_receive_queue_dispatcher = Glib::signal_timeout().connect(sigc::mem_fun(*(this->_myCallbacks), &Callbacks::dispatchReceiveQueue), SEND_TIMEOUT); -} - -void -SessionManager::stopReceiveQueueDispatch() -{ - if (this->_receive_queue_dispatcher) { - this->_receive_queue_dispatcher.disconnect(); - } -} - -void -SessionManager::clearDocument() -{ - // clear all layers, definitions, and metadata - XML::Node* rroot = this->_myDoc->rroot; - - // clear definitions - XML::Node* defs = SP_OBJECT_REPR((SPDefs*)SP_DOCUMENT_DEFS(this->_myDoc)); - g_assert(SP_ROOT(this->_myDoc->root)->defs); - - for(XML::Node* child = defs->firstChild(); child; child = child->next()) { - defs->removeChild(child); - } - - // clear layers - for(XML::Node* child = rroot->firstChild(); child; child = child->next()) { - if (strcmp(child->name(), "svg:g") == 0) { - rroot->removeChild(child); - } } - - // clear metadata - for(XML::Node* child = rroot->firstChild(); child; child = child->next()) { - if (strcmp(child->name(), "svg:metadata") == 0) { - rroot->removeChild(child); - } - } - -// sp_document_done(this->_myDoc); } void -SessionManager::setupInkscapeInterface() +SessionManager::_handleIncomingInvitation(Glib::ustring const& from) { - this->session_data->status.set(IN_WHITEBOARD, 1); - this->startSendQueueDispatch(); - this->startReceiveQueueDispatch(); - if (!this->_myTracker) { - this->_myTracker = new XMLNodeTracker(this); - } - - this->_mySerializer = new Serializer(this->node_tracker()); - this->_myDeserializer = new Deserializer(this->node_tracker()); - - // We're in a whiteboard session now, so set verb sensitivity accordingly - this->_setVerbSensitivity(ESTABLISHED_SESSION); -} - -void -SessionManager::setupCommitListener() -{ - this->_myUndoObserver = new Whiteboard::UndoStackObserver(this); - this->_myDoc->addUndoObserver(*this->_myUndoObserver); -} - -::SPDesktop* -SessionManager::desktop() -{ - return this->_myDesktop; -} - -::SPDocument* -SessionManager::document() -{ - return this->_myDoc; -} - -Callbacks* -SessionManager::callbacks() -{ - return this->_myCallbacks; -} - -Whiteboard::UndoStackObserver* -SessionManager::undo_stack_observer() -{ - return this->_myUndoObserver; -} - -Serializer* -SessionManager::serializer() -{ - return this->_mySerializer; -} - -XMLNodeTracker* -SessionManager::node_tracker() -{ - return this->_myTracker; -} - - -ChatMessageHandler* -SessionManager::chat_handler() -{ - return this->_myChatHandler; -} - -SessionFilePlayer* -SessionManager::session_player() -{ - return this->_mySessionPlayer; -} - -SessionFile* -SessionManager::session_file() -{ - return this->_mySessionFile; -} - -void -SessionManager::_log(Glib::ustring const& message) -{ - if (this->_mySessionFile && !this->_mySessionFile->isReadOnly()) { - this->_mySessionFile->addMessage(message); - } -} - -void -SessionManager::_commitLog() -{ - if (this->_mySessionFile && !this->_mySessionFile->isReadOnly()) { - this->_mySessionFile->commit(); + // don't insert duplicate invitations + if (std::find(_pending_invitations.begin(), _pending_invitations.end(), from) != _pending_invitations.end()) { + return; } -} -void -SessionManager::_closeLog() -{ - if (this->_mySessionFile) { - this->_mySessionFile->close(); - } -} + // We need to do the invitation confirm/deny dialog elsewhere -- + // when this method is called, we're still executing in Pedro's context, + // which causes issues when we run a dialog main loop. + // + // The invitation handling is done in a poller timeout that executes approximately + // every 50ms. It calls _checkInvitationQueue. + _pending_invitations.push_back(from); -void -SessionManager::startLog(Glib::ustring filename) -{ - try { - this->_mySessionFile = new SessionFile(filename, false, false); - } catch (Glib::FileError e) { - g_warning("Caught I/O error %s while attemping to open file %s for session recording.", e.what().c_str(), filename.c_str()); - throw; - } } void -SessionManager::_tryToStartLog() +SessionManager::_handleInvitationResponse(Glib::ustring const& from, InvitationResponses resp) { - if (this->session_data) { - if (!this->session_data->sessionFile.empty()) { - bool undecided = true; - while(undecided) { - try { - this->startLog(this->session_data->sessionFile); - undecided = false; - } catch (Glib::FileError e) { - undecided = true; - Glib::ustring msg = String::ucompose(_("Could not open file %1 for session recording.\nThe error encountered was: %2.\n\nYou may select a different location to record the session, or you may opt to not record this session."), this->session_data->sessionFile, e.what()); - Gtk::MessageDialog dlg(msg, true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_NONE, false); - dlg.add_button(_("Choose a different location"), 0); - dlg.add_button(_("Skip session recording"), 1); - switch (dlg.run()) { - case 0: - { - Gtk::FileChooserDialog sessionfiledlg(_("Select a location and filename"), Gtk::FILE_CHOOSER_ACTION_SAVE); - sessionfiledlg.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); - sessionfiledlg.add_button(_("Set filename"), Gtk::RESPONSE_OK); - int result = sessionfiledlg.run(); - switch (result) { - case Gtk::RESPONSE_OK: - { - this->session_data->sessionFile = sessionfiledlg.get_filename(); - break; - } - case Gtk::RESPONSE_CANCEL: - default: - undecided = false; - break; - } - break; - } - case 1: - default: - undecided = false; - break; - } - } - } - } + // only handle one response per invitation sender + // + // TODO: this could have one huge bug: say that Alice sends an invite to Bob, but + // Bob is doing something else at the moment and doesn't want to get in an Inkboard + // session. Eve intercepts Bob's "reject invitation" message and passes a + // "accept invitation" message to Alice that comes before Bob's "reject invitation" + // message. + // + // Does XMPP prevent this sort of attack? Need to investigate that. + if (std::find_if(_invitation_responses.begin(), _invitation_responses.end(), CheckInvitationSender(from)) != _invitation_responses.end()) { + return; } -} - -void -SessionManager::_setVerbSensitivity(SensitivityMode mode) -{ - return; - - switch (mode) { - case ESTABLISHED_CONNECTION: - // Upon successful connection, we can disconnect from the server. - // We can also start sharing a document with a user or chatroom. - // We cannot, however, connect to a new server without first disconnecting. - Inkscape::Verb::get(SP_VERB_DIALOG_WHITEBOARD_CONNECT)->sensitive(this->_myDoc, false); - Inkscape::Verb::get(SP_VERB_DIALOG_WHITEBOARD_DISCONNECT_FROM_SERVER)->sensitive(this->_myDoc, true); - Inkscape::Verb::get(SP_VERB_DIALOG_WHITEBOARD_SHAREWITHUSER)->sensitive(this->_myDoc, true); - Inkscape::Verb::get(SP_VERB_DIALOG_WHITEBOARD_SHAREWITHCHAT)->sensitive(this->_myDoc, true); - break; - case ESTABLISHED_SESSION: - // When we have established a session, we should not permit the user to go and - // establish another session from the same document without first disconnecting. - // - // TODO: Well, actually, we probably _should_, but there's no real reconnection logic just yet. - Inkscape::Verb::get(SP_VERB_DIALOG_WHITEBOARD_SHAREWITHUSER)->sensitive(this->_myDoc, false); - Inkscape::Verb::get(SP_VERB_DIALOG_WHITEBOARD_SHAREWITHCHAT)->sensitive(this->_myDoc, false); - Inkscape::Verb::get(SP_VERB_DIALOG_WHITEBOARD_DISCONNECT_FROM_SESSION)->sensitive(this->_myDoc, true); - break; - case DISCONNECTED_FROM_SESSION: - // Upon disconnecting from a session, we can establish a new session and disconnect - // from the server, but we cannot disconnect from a session (since we just left it.) - Inkscape::Verb::get(SP_VERB_DIALOG_WHITEBOARD_DISCONNECT_FROM_SESSION)->sensitive(this->_myDoc, false); - Inkscape::Verb::get(SP_VERB_DIALOG_WHITEBOARD_SHAREWITHUSER)->sensitive(this->_myDoc, true); - Inkscape::Verb::get(SP_VERB_DIALOG_WHITEBOARD_SHAREWITHCHAT)->sensitive(this->_myDoc, true); - - case INITIAL: - default: - // Upon construction, there is no active connection, so we cannot do the following: - // (1) disconnect from a session - // (2) disconnect from a server - // (3) share with a user - // (4) share with a chatroom - Inkscape::Verb::get(SP_VERB_DIALOG_WHITEBOARD_CONNECT)->sensitive(this->_myDoc, true); - Inkscape::Verb::get(SP_VERB_DIALOG_WHITEBOARD_SHAREWITHUSER)->sensitive(this->_myDoc, false); - Inkscape::Verb::get(SP_VERB_DIALOG_WHITEBOARD_SHAREWITHCHAT)->sensitive(this->_myDoc, false); - Inkscape::Verb::get(SP_VERB_DIALOG_WHITEBOARD_DISCONNECT_FROM_SESSION)->sensitive(this->_myDoc, false); - Inkscape::Verb::get(SP_VERB_DIALOG_WHITEBOARD_DISCONNECT_FROM_SERVER)->sensitive(this->_myDoc, false); - break; - }; -} - -/* -void -SessionManager::Listener::processXmppEvent(Pedro::XmppEvent const& event) -{ - int type = event.getType(); - - switch (type) { - case Pedro::XmppEvent::EVENT_STATUS: - break; - case Pedro::XmppEvent::EVENT_ERROR: - break; - case Pedro::XmppEvent::EVENT_CONNECTED: - break; - case Pedro::XmppEvent::EVENT_DISCONNECTED: - break; - case Pedro::XmppEvent::EVENT_MESSAGE: - break; - case Pedro::XmppEvent::EVENT_PRESENCE: - break; - case Pedro::XmppEvent::EVENT_MUC_MESSAGE: - break; - case Pedro::XmppEvent::EVENT_MUC_JOIN: - break; - case Pedro::XmppEvent::EVENT_MUC_LEAVE: - break; - case Pedro::XmppEvent::EVENT_MUC_PRESENCE: - break; - } -} -*/ + // We need to do the invitation confirm/deny dialog elsewhere -- + // when this method is called, we're still executing in Pedro's context, + // which causes issues when we run a dialog main loop. + // + // The invitation handling is done in a poller timeout that executes approximately + // every 50ms. It calls _checkInvitationResponseQueue. + _invitation_responses.push_back(Invitation_response_type(from, resp)); } -} +} // namespace Whiteboard + +} // namespace Inkscape /* diff --git a/src/jabber_whiteboard/session-manager.h b/src/jabber_whiteboard/session-manager.h index a273fef4d..75fd84a44 100644 --- a/src/jabber_whiteboard/session-manager.h +++ b/src/jabber_whiteboard/session-manager.h @@ -3,599 +3,221 @@ * * Authors: * David Yip + * Bob Jamison (Pedro port) * * Copyright (c) 2005 Authors * * Released under GNU GPL, read the file 'COPYING' for more information */ -#ifndef __SESSION_MANAGER_H__ -#define __SESSION_MANAGER_H__ +#ifndef __INKSCAPE_WHITEBOARD_SESSION_MANAGER_H__ +#define __INKSCAPE_WHITEBOARD_SESSION_MANAGER_H__ -#include -#include -#include - -#include -#include +#include "pedro/pedrogui.h" -#include +#include -extern "C" { -#include -} +#include +#include -#include "jabber_whiteboard/typedefs.h" +#include "jabber_whiteboard/message-queue.h" #include "jabber_whiteboard/defines.h" -#include "jabber_whiteboard/buddy-list-manager.h" +#include "jabber_whiteboard/internal-constants.h" +#include "jabber_whiteboard/inkboard-session.h" #include "gc-alloc.h" -struct SPDesktop; -struct SPDocument; - -namespace Inkscape { -namespace XML { -class Node; -} -} +class SPDesktop; namespace Inkscape { namespace Whiteboard { -class ReceiveMessageQueue; -class SendMessageQueue; -class XMLNodeTracker; -class SessionManager; -class MessageHandler; -class ChatMessageHandler; -class Callbacks; -class SessionFile; -class SessionFilePlayer; -class UndoStackObserver; -class Serializer; -class Deserializer; - -/// Jabber resource name -#define RESOURCE_NAME "Inkboard" - -/// connectToServer return values -#define CONNECT_SUCCESS 0 -#define FAILED_TO_CONNECT 1 -#define INVALID_AUTH 2 -#define SSL_INITIALIZATION_ERROR 3 - -/// sendMessage return values -#define SEND_SUCCESS 0 -#define CONNECTION_ERROR 1 -#define UNKNOWN_OUTGOING_TYPE 2 -#define NO_RECIPIENT_JID 3 - -/** - * Structure grouping data items pertinent to a whiteboard session. - * - * SessionData holds all session data for both 1:1 and chatroom conferences. - * Access to members should be controlled by first querying the status bitset - * to see if useful data will actually exist in that member -- i.e. checking - * status[IN_CHATROOM] to see if the chatters set will contain anything. - * It usually won't hurt to do a straight query -- there are very few members - * that remain uninitialized for very long -- but it's a good idea to check. - */ -struct SessionData { -public: - /** - * Constructor. - * - * \param sm The SessionManager with which a SessionData instance should be - * associated with. - */ - SessionData(SessionManager *sm); - - ~SessionData(); - - /** - * The JID of the recipient: either another user JID or the JID of a chatroom. - */ - gchar const* recipient; - - /** - * Pointer to Loudmouth connection structure. - * Used for Loudmouth calls that require it. - */ - LmConnection* connection; - - /** - * SSL information structure for SSL connections. - */ - LmSSL* ssl; - - /** - * Flag indicating whether or not we should ignore further SSL errors for a given session. - */ - bool ignoreFurtherSSLErrors; - - - /** - * A user's handle in a Jabber chatroom. - */ - Glib::ustring chat_handle; - - /** - * The Users Jid. - */ - Glib::ustring jid; - - /** - * Name of the chatroom that a user in a chatroom is connected to. - */ - Glib::ustring chat_name; - - /** - * Name of the conference server. - */ - Glib::ustring chat_server; - - // Message queues - - /** - * Map associating senders to receive queues. - */ - RecipientToReceiveQueueMap receive_queues; - - /** - * Map associating senders to commit events sent by those committers. - */ - CommitsQueue recipients_committed_queue; - - /** - * Pointer to queue for messages to be sent. - */ - SendMessageQueue* send_queue; - - // Message sequence numbers - - /** - * The sequence number of the latest message sent by this client in a given session. - * Used for determining the sequence number of the next message. - */ - unsigned int sequence_number; - - //unsigned int latest_sent_transaction; - //RecipientToLatestTransactionMap latest_processed_transactions; - - - // Status tracking - /** - * Session state and status flags. - */ - std::bitset< NUM_FLAGS > status; - - /** - * Jabber buddy list data. - */ - BuddyListManager buddyList; - - /** - * List of participants in a Jabber chatroom. - */ - ChatterList chatters; - - /** - * Session file filename; blank if no session file is to be - * recorded. - */ - Glib::ustring sessionFile; - -private: - // access to containing class - SessionManager *_sm; - - // noncopyable, nonassignable - SessionData(SessionData const&); - SessionData& operator=(SessionData const&); +enum SessionType { + INKBOARD_PRIVATE, + INKBOARD_MUC }; +class SessionManager; +class InkboardDocument; -// TODO: This class is huge. It might be best to refactor it into smaller, -// more coherent chunks. -// -// TODO: convert to pass-by-reference where appropriate. In particular, a lot of the -// string buffers passed to methods in the argument list can be made into references -// appropriately and easily. - -/** - * Session management class for Inkboard. - * - * By "session management", we refer to the management of all events that an Inkboard - * session may need to handle: negotiating a connection to a Jabber server, negotiating - * sessions with users and chatrooms, sending, receiving, and parsing messages, and so - * forth. - * - * SessionManager instances are associated with Inkscape desktop objects on a 1:1 basis. - */ -class SessionManager { +class SessionManager : public Pedro::XmppEventListener { public: - /** - * Constructor. - * - * \param desktop The desktop with which this SessionManager is associated. */ - SessionManager(::SPDesktop *desktop); - ~SessionManager(); - - // Session tracking data - - /** - * Pointer to SessionData structure. - */ - struct SessionData *session_data; - - // Inkscape interface - - /** - * Set the desktop with which this SessionManager is associated. - * - * @param desktop the desktop with which this SessionManager should be associated - */ - void setDesktop(::SPDesktop* desktop); - - // Session management - - /** - * Connect to a Jabber server. - * - * @param server Jabber server URL - * @param entered_username Jabber username provided by user (may also be full JID) - * @param pw password for Jabber account - * @param usessl use SSL for connection - * - * @return CONNECT_SUCCESS if connection successful; FAILED_TO_CONNECT if connection failed or INVALID_AUTH - * if authentication invalid - */ - int connectToServer(Glib::ustring const& server, Glib::ustring const& port, Glib::ustring const& entered_username, Glib::ustring const& pw, bool usessl); - - /** - * Register with a Jabber server. - * - * @param username Jabber username - * @param pw password for Jabber account - * @param key A list of string elements required for registration - * @param val The respective list of value of elements required for registration - * @param usessl use SSL for connection - * - * @return CONNECT_SUCCESS if connection successful; FAILED_TO_CONNECT if connection failed or INVALID_AUTH - * if authentication invalid - */ - int registerWithServer(Glib::ustring const& username,Glib::ustring const& pw, std::vector key, std::vector val); - /** - * Query the Registration information required for a jabber server - * - * @param server Jabber server URL - * @param username Jabber username - * @param pw password for Jabber account - * @param key A list of string elements required for registration - * @param val The respective list of value of elements required for registration - * @param usessl use SSL for connection - * - * @return CONNECT_SUCCESS if connection successful; FAILED_TO_CONNECT if connection failed or INVALID_AUTH - * if authentication invalid - */ - std::vector getRegistrationInfo(); - - int finaliseConnection(); - int initializeConnection(Glib::ustring const& server, Glib::ustring const& port, bool usessl); - /** - * Handle an SSL error by prompting the user for feedback, and continuing or aborting the connection - * process based on that feedback. - * - * @param ssl pointer to LmSSL structure - * @param status The error message - * - * @return LM_SSL_RESPONSE_CONTINUE if user wishes to continue establishing the connection or LM_SSL_RESPONSE_STOP if user wishes to abort connection - */ - LmSSLResponse handleSSLError(LmSSL* ssl, LmSSLStatus status); + /** + * + */ + SessionManager(); + + /** + * + */ + virtual ~SessionManager(); + + + static void showClient(); + static SessionManager& instance(); + + /** + * + */ + unsigned long getSequenceNumber(); + + /** + * + */ + virtual Pedro::XmppClient &getClient() + { return gui.client; } + + /** + * + */ + virtual bool send(const Glib::ustring &destJid, + const MessageType type, + const Glib::ustring &data); + + /** + * + */ + virtual bool sendGroup(const Glib::ustring &destJid, + const MessageType type, + const Glib::ustring &data); + /** + * + */ + virtual void processXmppEvent(const Pedro::XmppEvent &event); + + /** + * The session handling has been broken out into a subclass of XML::Session. See + * Whiteboard::InkboardSession and Whiteboard::InkboardDocument, both of which + * are still under heavy construction. Don't expect them to work just yet. + * + * This (should) allow us to substitute an InkboardDocument for an + * XML::SimpleDocument (InkboardDocument uses InkboardSession), which, I think, should + * lead to a very clean way of integrating Inkboard. It should also + * give us a cleaner way of handling node tracking. Finally, + * it'll let us experiment with data models that may be more appropriate for Inkboard. + * + * SessionManager still manages sessions insofar as it receives XMPP data from Pedro and + * sends it off to the correct InkboardSession. I'd like to have it still manage + * user sessions, which is what the user sees; however, that can be confusing from + * a programmer's standpoint. This class might therefore need to be renamed + * or something. + * + * Creation of an Inkboard session should be handled in some fashion similar + * to this: + * + * (1) The user chooses a chat room or user with which she wants to share a whiteboard. + * + * (2) This invokes the appropriate doShare() method in Pedro's GUI. + * + * (3) doShare() invokes code to create a new Inkscape desktop with a blank document. + * This desktop will use InkboardDocument (and hence InkboardSession) for transaction + * management. + * + * (4) Inkboard setup and operation proceeds as it did in the Loudmouth-based code. + * + * (3) and (4) will probably need tweaking (for example, it's probably a bad idea to + * open up a new desktop if an invitation is refused). Actually, really, nothing + * here is set in stone. Feel free to modify. -- dwyip 2005-11-21 + * + */ + + /** + * Initiates a shared session with a user or conference room. + * + * \param to The recipient to which this desktop will be linked, specified as a JID. + * \param type Type of the session; i.e. private message or group chat. + */ + virtual void doShare(Glib::ustring const& to, SessionType type); + + /** + * Creates a new desktop with an InkboardDocument. + * + * An InkboardDocument (and hence desktop) + * is identified by the recipient of the document, be it a + * conference room or another user. If an existing document is found, it will be + * returned. + * + * \param to The recipient to which this desktop will be linked, specified as a JID. + * \param type Type of the session; i.e. private message or group chat. + * \return A pointer to the created SPDesktop. + */ + virtual SPDesktop* createInkboardDesktop(Glib::ustring const& to, SessionType type); + + /** + * Terminates an Inkboard session to a given recipient. If the session to be + * terminated does not exist, does nothing. + * + * \param to The recipient JID identifying the session to be terminated. + */ + virtual void terminateInkboardSession(Glib::ustring const& to); + + /** + * Locates an Inkboard session by recipient JID. + * + * \param to The recipient JID identifying the session to be located. + * \return A pointer to the InkboardDocument associated with the Inkboard session, + * or NULL if no such session exists. + */ + InkboardDocument* getInkboardSession(Glib::ustring const& to); + + void operator=(XmppEventListener const& other) { - /** - * Disconnect from a Jabber server. - * - * This invokes disconnectFromDocument(). - * - * \see Inkscape::Whiteboard::SessionManager::disconnectFromDocument - */ - void disconnectFromServer(); - - /** - * Disconnect from a document session. The connection to the Jabber server is not - * broken, and may be reused to connect to a new document session. - * - */ - void disconnectFromDocument(); - - /** - * Perform session teardown. This method by itself does not disconnect from a document or - * a Jabber server. - * - */ - void closeSession(); - - /** - * Set the recipient for Inkboard messages. - * - * @param recipientJID the recipient's JID - */ - void setRecipient(char const* recipientJID); - - // Message sending utilities - - /** - * Put an Inkboard message into the send queue. - * This method does not actually send anything to an Inkboard client. - * - * \see Inkscape::Whiteboard::SessionManager::sendMessage - * - * - * @param msg the message to send - * @param type the type of message (only CHANGE_* types permitted) - * @param chatroom whether or not this message is destined for a chatroom - */ - void sendChange(Glib::ustring const& msg, MessageType type, std::string const& recipientJID, bool chatroom); - - /** - * Send a message to an Inkboard client. - * - * - * @param msgtype the type of message to send - * @param sequence message sequence number - * @param msg the message to send - * @param recipientJID the JID of the recipient - * @param chatroom whether or not this message is destined for a chatroom - * - * @return SEND_SUCCESS if successful; otherwise: UNKNOWN_OUTGOING_TYPE if msgtype is not recognized, NO_RECIPIENT_JID if recipientJID is NULL or blank, CONNECTION_ERROR if Jabber connection error occurred - */ - int sendMessage(MessageType msgtype, unsigned int sequence, Glib::ustring const& msg, char const* recipientJID, bool chatroom); - - /** - * Inform the user of a connection error via a Gtk::MessageDialog. - * - * @param errmsg message to display - */ - void connectionError(Glib::ustring const& errmsg); - - /** - * Stream the contents of the document with which this SessionManager is associated with to the given recipient. - * - * @param recipientJID the JID of the recipient - * @param newidsbuf buffer to store IDs of new nodes - * @param newnodesbuf buffer to store address of new nodes - */ - void resendDocument(char const* recipientJID, KeyToNodeMap& newidsbuf, NodeToKeyMap& newnodesbuf); - - - /** - * Send a connection request to another Inkboard client. - * - * - * @param recipientJID the JID to connect to - * @param document document message to send - */ - void sendRequestToUser(std::string const& recipientJID); - - /** - * Send a connection request to chatroom. - * - * @param server server to connect to - * @param chatroom name of chatroom - * @param handle chatroom handle to use - * @param password chatroom password; leave NULL if no password - */ - void sendRequestToChatroom(Glib::ustring const& server, Glib::ustring const& chatroom, Glib::ustring const& handle, Glib::ustring const& password); - - /** - * Send a connection request response to a user who requested to connect to us. - * - * @param requesterJID the JID of the user whom sent us the request - * @param accepted_request whether or not we accepted the request - */ - void sendConnectRequestResponse(char const* requesterJID, gboolean accepted_request); - - /** - * Method called when a connection request is received. This method produces a dialog - * that asks the user whether or not s/he would like to accept the request. - * - * - * @param requesterJID the JID of the user whom sent us the request - * @param msg the message associated with this request - */ - void receiveConnectRequest(gchar const* requesterJID); - - /** - * Method called when a response to a connection request is received. - * This method performs any necessary session setup/teardown and user notification - * depending on the response received. - * - * - * @param msg the message associated with this request - * @param response the response code - * @param sender the JID of the user whom responded to our request - */ - void receiveConnectRequestResponse(InvitationResponses response, std::string& sender); - - /** - * Method called when a document synchronization request is received from a new conference - * member in a chatroom. - * - * \param recipient the recipient JID - */ - void receiveConnectRequestResponseChat(gchar const* recipient); - - // Message parsing and passing - - /** - * Processes a group of document change messages. - * - * \param changemsg The change message group to process. - */ - void receiveChange(Glib::ustring const& changemsg); - - // Logging and session file handling - /** - * Start a session log with the given filename. - * - * \param filename Full path to the file that the session log should be written to. - * \throw Glib::FileError Thrown if an exception is thrown during session file creation. - */ - void startLog(Glib::ustring filename); - - /** - * Load a session file for playback. - * - * \param filename Full path to the session file that is to be loaded. - */ - void loadSessionFile(Glib::ustring filename); - - /** - * Returns whether or not the session is in session file playback mode. - * - * \return Whether or not the session is in session file playback mode. - */ - bool isPlayingSessionFile(); - - // User event notification - - /** - * Method to notify the user that a whiteboard session to another user has been successfully - * established. - * - * \param JID The JID with whom the user established a session. - */ - void userConnectedToWhiteboard(gchar const* JID); - - /** - * Method to notify the user that the other user in a user-to-user whiteboard session - * has disconnected. - * - * \param JID The JID of the user who left the whiteboard session. - */ - void userDisconnectedFromWhiteboard(std::string const& JID); - - // Queue dispatching and UI setup - - /** - * Start the send queue for this session. - */ - void startSendQueueDispatch(); - - /** - * Stop the send queue for this session. - */ - void stopSendQueueDispatch(); - - /** - * Start the receive queue for this session. - */ - void startReceiveQueueDispatch(); - - /** - * Stop the receive queue for this session. - */ - void stopReceiveQueueDispatch(); - - /** - * Clear all layers, definitions, and metadata from the document with which a - * SessionManager instance is associated. - * - * Documents are cleared to assist synchronization between two clients - * or a client and a chatroom. - */ - void clearDocument(); - - /** - * Set up objects for handling actions generated by the user interacting with - * Inkscape. This includes marking the active session as being in a whiteboard session, - * starting send and receive queues, and creating an event serializer and deserializer. - * - * \see Inkscape::Whiteboard::SendMessageQueue - * \see Inkscape::Whiteboard::ReceiveMessageQueue - * \see Inkscape::Whiteboard::Serializer - * \see Inkscape::Whiteboard::Deserializer - */ - void setupInkscapeInterface(); - - /** - * Reset whiteboard verbs to INITIAL state. - */ - void setInitialVerbSensitivity() { - this->_setVerbSensitivity(INITIAL); } - - /** - * Set up the event commit listener. - * - * The event commit listener watches for events that are committed to the document's undo log, - * serializes those events, and then adds them to the message send queue. - * - * \see Inkscape::Whiteboard::SendMessageQueue - * \see Inkscape::Whiteboard::UndoStackObserver - */ - void setupCommitListener(); - - // Private object retrieval - ::SPDesktop* desktop(); - ::SPDocument* document(); - Callbacks* callbacks(); - Whiteboard::UndoStackObserver* undo_stack_observer(); - Serializer* serializer(); - XMLNodeTracker* node_tracker(); - Deserializer* deserializer(); - ChatMessageHandler* chat_handler(); - SessionFilePlayer* session_player(); - SessionFile* session_file(); - private: - // Internal logging methods - void _log(Glib::ustring const& message); - void _commitLog(); - void _closeLog(); - void _tryToStartLog(); - - enum SensitivityMode { - INITIAL, - ESTABLISHED_CONNECTION, - ESTABLISHED_SESSION, - DISCONNECTED_FROM_SESSION + // types + typedef std::pair< Glib::ustring, InkboardDocument* > Inkboard_record_type; + typedef std::vector< Inkboard_record_type, GC::Alloc< Inkboard_record_type, GC::MANUAL > > Inkboards_type; + + typedef std::list< Glib::ustring > Pending_invitations_type; + + typedef std::pair< Glib::ustring, InvitationResponses > Invitation_response_type; + typedef std::list< Invitation_response_type > Invitation_responses_type; + + // functors + struct CheckInvitationSender { + public: + CheckInvitationSender(Glib::ustring const& x) : x(x) { } + ~CheckInvitationSender() { } + + bool operator()(SessionManager::Invitation_response_type const& y) const { + return (x == y.first); + } + private: + Glib::ustring const& x; }; - void _setVerbSensitivity(SensitivityMode mode); - - bool _pollReceiveConnectRequest(Glib::ustring const recipient); - - ::SPDesktop* _myDesktop; - ::SPDocument* _myDoc; - Whiteboard::UndoStackObserver* _myUndoObserver; - XMLNodeTracker* _myTracker; - ChatMessageHandler* _myChatHandler; - Callbacks* _myCallbacks; - SessionFile* _mySessionFile; - SessionFilePlayer* _mySessionPlayer; - MessageHandler* _myMessageHandler; - Serializer* _mySerializer; - Deserializer* _myDeserializer; - - sigc::connection _send_queue_dispatcher; - sigc::connection _receive_queue_dispatcher; - sigc::connection _notify_incoming_request; - - // noncopyable, nonassignable - SessionManager(SessionManager const&); - SessionManager& operator=(SessionManager const&); + // objects + Pedro::PedroGui gui; + SendMessageQueue sendMessageQueue; + ReceiveMessageQueue receiveMessageQueue; + + // members + unsigned long sequenceNumber; + Inkboards_type _inkboards; + Pending_invitations_type _pending_invitations; + Invitation_responses_type _invitation_responses; + + sigc::connection _check_pending_invitations; + sigc::connection _check_invitation_responses; + + // methods + void _processInkboardEvent(Pedro::XmppEvent const& event); + void _handleSessionEvent(MessageType mtype, Pedro::XmppEvent const& event); + void _handleIncomingInvitation(Glib::ustring const& from); + void _handleInvitationResponse(Glib::ustring const& from, InvitationResponses resp); + + // methods handled externally + bool _checkInvitationQueue(); + bool _checkInvitationResponseQueue(); }; -} +} // namespace Whiteboard -} +} // namespace Inkscape -#endif +#endif /* __SESSION_MANAGER_H__ */ /* Local Variables: diff --git a/src/jabber_whiteboard/tracker-node.h b/src/jabber_whiteboard/tracker-node.h index bbaf527ce..120c4d00e 100644 --- a/src/jabber_whiteboard/tracker-node.h +++ b/src/jabber_whiteboard/tracker-node.h @@ -86,9 +86,9 @@ private: Local Variables: mode:c++ c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + c-file-offsets:((innamespace . 0)(inline-open . 0)) indent-tabs-mode:nil fill-column:99 End: */ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : +// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/jabber_whiteboard/typedefs.h b/src/jabber_whiteboard/typedefs.h index 10adbdaf8..363a68606 100644 --- a/src/jabber_whiteboard/typedefs.h +++ b/src/jabber_whiteboard/typedefs.h @@ -13,21 +13,19 @@ #ifndef __WHITEBOARD_TYPEDEFS_H__ #define __WHITEBOARD_TYPEDEFS_H__ -extern "C" { -#include -} - #include #include #include #include #include #include +#include #include #include #include "jabber_whiteboard/defines.h" +#include "jabber_whiteboard/keynode.h" #include "gc-alloc.h" @@ -87,11 +85,11 @@ namespace Whiteboard { /// Associates node keys to pointers to XML::Nodes. /// \see Inkscape::Whiteboard::XMLNodeTracker -typedef std::map< std::string, XML::Node*, std::less< std::string >, GC::Alloc< std::pair< const std::string, XML::Node* >, GC::MANUAL > > KeyToTrackerNodeMap; +typedef std::map< std::string, XML::Node*, std::less< std::string >, GC::Alloc< std::pair< std::string, XML::Node* >, GC::MANUAL > > KeyToTrackerNodeMap; /// Associates pointers to XML::Nodes with node keys. /// \see Inkscape::Whiteboard::XMLNodeTracker -typedef std::map< XML::Node*, std::string, std::less< XML::Node* >, GC::Alloc< std::pair< XML::Node* const, std::string >, GC::MANUAL > > TrackerNodeToKeyMap; +typedef std::map< XML::Node*, std::string, std::less< XML::Node* >, GC::Alloc< std::pair< XML::Node*, std::string >, GC::MANUAL > > TrackerNodeToKeyMap; // TODO: Clean up these typedefs. I'm sure quite a few of these aren't used anymore; additionally, @@ -100,7 +98,6 @@ typedef std::map< XML::Node*, std::string, std::less< XML::Node* >, GC::Alloc< s // Temporary storage of new object messages and new nodes in said messages typedef std::list< Glib::ustring > NewChildObjectMessageList; -typedef std::pair< std::string, XML::Node* > KeyNodePair; typedef std::pair< KeyNodePair, NodeTrackerAction > SerializedEventNodeAction; typedef std::list< SerializedEventNodeAction > KeyToNodeActionList; @@ -113,6 +110,7 @@ typedef std::set< XML::Node* > AttributesUpdatedSet; typedef std::map< std::string, XML::Node const* > KeyToNodeMap; typedef std::map< XML::Node const*, std::string > NodeToKeyMap; + // Buddy list management typedef std::set< std::string > BuddyList; typedef sigc::signal< void, std::string const& > BuddyListSignal; @@ -126,9 +124,9 @@ struct MessageProcessor; class ReceiveMessageQueue; typedef std::map< MessageType, std::bitset< NUM_FLAGS > > MessageContextMap; -typedef std::map< MessageType, MessageProcessor*, std::less< MessageType >, GC::Alloc< std::pair< const MessageType, MessageProcessor* >, GC::MANUAL > > MessageProcessorMap; +typedef std::map< MessageType, MessageProcessor*, std::less< MessageType >, GC::Alloc< std::pair< MessageType, MessageProcessor* >, GC::MANUAL > > MessageProcessorMap; -typedef std::map< std::string, ReceiveMessageQueue*, std::less< std::string >, GC::Alloc< std::pair< const std::string, ReceiveMessageQueue* >, GC::MANUAL > > RecipientToReceiveQueueMap; +typedef std::map< std::string, ReceiveMessageQueue*, std::less< std::string >, GC::Alloc< std::pair< std::string, ReceiveMessageQueue* >, GC::MANUAL > > RecipientToReceiveQueueMap; typedef std::map< std::string, unsigned int > ReceipientToLatestTransactionMap; typedef std::string ReceivedCommitEvent; @@ -151,9 +149,9 @@ typedef std::list< Glib::ustring > SerializedEventList; Local Variables: mode:c++ c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + c-file-offsets:((innamespace . 0)(inline-open . 0)) indent-tabs-mode:nil fill-column:99 End: */ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : +// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/jabber_whiteboard/undo-stack-observer.cpp b/src/jabber_whiteboard/undo-stack-observer.cpp deleted file mode 100644 index 7750dc73c..000000000 --- a/src/jabber_whiteboard/undo-stack-observer.cpp +++ /dev/null @@ -1,181 +0,0 @@ -/** - * Undo / redo / undo log commit listener - * - * Authors: - * David Yip - * - * Copyright (c) 2005 Authors - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#include "document.h" -#include "document-private.h" - -#include "xml/event.h" -#include "xml/event-fns.h" -#include "undo-stack-observer.h" - -#include "util/list.h" -#include "util/reverse-list.h" - -#include "jabber_whiteboard/defines.h" -#include "jabber_whiteboard/session-manager.h" -#include "jabber_whiteboard/node-tracker.h" -#include "jabber_whiteboard/serializer.h" -#include "jabber_whiteboard/message-utilities.h" -#include "jabber_whiteboard/message-aggregator.h" -#include "jabber_whiteboard/message-tags.h" - - -#include - -namespace Inkscape { - -namespace Whiteboard { - -UndoStackObserver::UndoStackObserver(SessionManager* sm) : _sm(sm), _undoSendEventLocks(0), _redoSendEventLocks(0), _undoCommitSendEventLocks(0) { -} - -UndoStackObserver::~UndoStackObserver() { } - -void -UndoStackObserver::notifyUndoEvent(XML::Event* log) -{ - if (this->_undoSendEventLocks == 0) { - bool chatroom = this->_sm->session_data->status.test(IN_CHATROOM); - Glib::ustring commit = MessageUtilities::makeTagWithContent(MESSAGE_UNDO, ""); - this->_sm->sendChange(commit, CHANGE_COMMIT, "", chatroom); - } - - // Retrieve and process added/deleted nodes in the undo log - // TODO: re-enable; right now it doesn't work because we can't recover the names - // of deleted nodes (although perhaps creating a subclass of XML::Event that stored - // names of serialized nodes along with all other Event information would fix this) - /* - KeyToNodeActionMap node_actions = this->_action_observer.getNodeActionMap(); - this->_sm->node_tracker()->process(node_actions); - this->_action_observer.clearNodeBuffers(); - */ - -} - -void -UndoStackObserver::notifyRedoEvent(XML::Event* log) -{ - if (this->_redoSendEventLocks == 0) { - bool chatroom = this->_sm->session_data->status.test(IN_CHATROOM); - Glib::ustring commit = MessageUtilities::makeTagWithContent(MESSAGE_REDO, ""); - this->_sm->sendChange(commit, CHANGE_COMMIT, "", chatroom); - } - - // Retrieve and process added/deleted nodes in the redo log - /* - KeyToNodeActionMap node_actions = this->_action_observer.getNodeActionMap(); - this->_sm->node_tracker()->process(node_actions); - this->_action_observer.clearNodeBuffers(); - */ -} - -void -UndoStackObserver::notifyUndoCommitEvent(XML::Event* log) -{ - if (this->_undoCommitSendEventLocks == 0) { - this->_doAction(log); - } -} - -void -UndoStackObserver::lockObserverFromSending(ObserverType type) -{ - switch (type) { - case UNDO_EVENT: - ++this->_undoSendEventLocks; - break; - case REDO_EVENT: - ++this->_redoSendEventLocks; - break; - case UNDO_COMMIT_EVENT: - ++this->_undoCommitSendEventLocks; - break; - default: - break; - } -} - -void -UndoStackObserver::unlockObserverFromSending(ObserverType type) -{ - switch(type) { - case UNDO_EVENT: - if (this->_undoSendEventLocks) { - --this->_undoSendEventLocks; - } - break; - case REDO_EVENT: - if (this->_redoSendEventLocks) { - --this->_redoSendEventLocks; - } - break; - case UNDO_COMMIT_EVENT: - if (this->_undoCommitSendEventLocks) { - --this->_undoCommitSendEventLocks; - } - break; - default: - break; - } -} - -void -UndoStackObserver::_doAction(XML::Event* log) -{ - if (this->_sm->serializer()) { - bool chatroom = this->_sm->session_data->status.test(IN_CHATROOM); - XML::replay_log_to_observer(log, *this->_sm->serializer()); - - this->_sm->serializer()->synthesizeChildNodeAddEvents(); - - SerializedEventList& events = this->_sm->serializer()->getEventList(); - - SerializedEventList::iterator i = events.begin(); - MessageAggregator& agg = MessageAggregator::instance(); - Glib::ustring msgbuf; - - while(i != events.end()) { - while(agg.addOne(*i++, msgbuf)) { - if (i == events.end()) { - break; - } - } - - if (i != events.end()) { - i--; - } - - this->_sm->sendChange(msgbuf, CHANGE_REPEATABLE, "", chatroom); - msgbuf.clear(); - } - - KeyToNodeActionList& node_actions = this->_sm->serializer()->getNodeTrackerActions(); - this->_sm->node_tracker()->process(node_actions); - this->_sm->serializer()->reset(); - Glib::ustring commit = MessageUtilities::makeTagWithContent(MESSAGE_COMMIT, ""); - this->_sm->sendChange(commit, CHANGE_COMMIT, "", chatroom); - } -} - -} - -} - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/jabber_whiteboard/undo-stack-observer.h b/src/jabber_whiteboard/undo-stack-observer.h deleted file mode 100644 index 3b3884780..000000000 --- a/src/jabber_whiteboard/undo-stack-observer.h +++ /dev/null @@ -1,75 +0,0 @@ -/** - * Undo / redo / undo log commit listener - * - * Authors: - * David Yip - * - * Copyright (c) 2005 Authors - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#ifndef __WHITEBOARD_UNDO_COMMIT_OBSERVER_H__ -#define __WHITEBOARD_UNDO_COMMIT_OBSERVER_H__ - -#include -#include "../undo-stack-observer.h" -#include "jabber_whiteboard/typedefs.h" - -namespace Inkscape { - -namespace Whiteboard { - -class SessionManager; - -/** - * Inkboard implementation of Inkscape::UndoStackObserver. - */ -class UndoStackObserver : public Inkscape::UndoStackObserver { -public: - enum ObserverType { - UNDO_EVENT, - REDO_EVENT, - UNDO_COMMIT_EVENT - }; - - UndoStackObserver(SessionManager* sm); - ~UndoStackObserver(); - void notifyUndoEvent(XML::Event* log); - void notifyRedoEvent(XML::Event* log); - void notifyUndoCommitEvent(XML::Event* log); - - void lockObserverFromSending(ObserverType type); - void unlockObserverFromSending(ObserverType type); - -private: - SessionManager* _sm; - - // common action handler - void _doAction(XML::Event* log); - - // noncopyable, nonassignable - UndoStackObserver(UndoStackObserver const& other); - UndoStackObserver& operator=(UndoStackObserver const& other); - - unsigned int _undoSendEventLocks; - unsigned int _redoSendEventLocks; - unsigned int _undoCommitSendEventLocks; -}; - -} - -} - -#endif - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/menus-skeleton.h b/src/menus-skeleton.h index 986b36edf..66d1acb89 100644 --- a/src/menus-skeleton.h +++ b/src/menus-skeleton.h @@ -228,16 +228,7 @@ static char const menus_skeleton[] = " \n" #ifdef WITH_INKBOARD " \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" +" \n" " \n" #endif " \n" diff --git a/src/ui/dialog/Makefile_insert b/src/ui/dialog/Makefile_insert index 7ab87c7d3..4e40b645d 100644 --- a/src/ui/dialog/Makefile_insert +++ b/src/ui/dialog/Makefile_insert @@ -5,18 +5,6 @@ ui/dialog/all: ui/dialog/libuidialog.a ui/dialog/clean: rm -f ui/dialog/libuidialog.a $(ui_libuidialog_a_OBJECTS) -if WITH_INKBOARD -inkboard_dialogs = \ - ui/dialog/session-player.cpp \ - ui/dialog/session-player.h \ - ui/dialog/whiteboard-connect.cpp \ - ui/dialog/whiteboard-connect.h \ - ui/dialog/whiteboard-sharewithuser.cpp \ - ui/dialog/whiteboard-sharewithuser.h \ - ui/dialog/whiteboard-sharewithchat.cpp \ - ui/dialog/whiteboard-sharewithchat.h -endif - ui_dialog_libuidialog_a_SOURCES = \ ui/dialog/dialog-manager.cpp \ ui/dialog/dialog-manager.h \ @@ -54,7 +42,6 @@ ui_dialog_libuidialog_a_SOURCES = \ ui/dialog/transformation.h \ ui/dialog/tree-editor.cpp \ ui/dialog/tree-editor.h \ - $(inkboard_dialogs) \ ui/dialog/xml-editor.cpp \ ui/dialog/xml-editor.h \ ui/dialog/aboutbox.cpp \ diff --git a/src/ui/dialog/dialog-manager.cpp b/src/ui/dialog/dialog-manager.cpp index 80fae2c92..f4099b050 100644 --- a/src/ui/dialog/dialog-manager.cpp +++ b/src/ui/dialog/dialog-manager.cpp @@ -33,13 +33,6 @@ #include "ui/dialog/tracedialog.h" #include "ui/dialog/transformation.h" -#ifdef WITH_INKBOARD -#include "ui/dialog/whiteboard-sharewithchat.h" -#include "ui/dialog/whiteboard-sharewithuser.h" -#include "ui/dialog/whiteboard-connect.h" -#include "ui/dialog/session-player.h" -#endif - #include "ui/dialog/xml-editor.h" #include "dialogs/tiledialog.h" @@ -92,12 +85,6 @@ DialogManager::DialogManager() { registerFactory("TileDialog", &create); registerFactory("Trace", &create); registerFactory("Transformation", &create); -#ifdef WITH_INKBOARD - registerFactory("SessionPlayer", &create); - registerFactory("WhiteboardConnect", &create); - registerFactory("WhiteboardShareWithUser", &create); - registerFactory("WhiteboardShareWithChat", &create); -#endif registerFactory("XmlEditor", &create); } diff --git a/src/ui/view/edit-widget.cpp b/src/ui/view/edit-widget.cpp index c42f44749..55f63b443 100644 --- a/src/ui/view/edit-widget.cpp +++ b/src/ui/view/edit-widget.cpp @@ -59,12 +59,6 @@ #include "interface.h" #include "extension/db.h" -#ifdef WITH_INKBOARD -#include "ui/dialog/whiteboard-connect.h" -#include "ui/dialog/whiteboard-sharewithuser.h" -#include "ui/dialog/whiteboard-sharewithchat.h" -#endif - using namespace Inkscape::UI; using namespace Inkscape::UI::Widget; @@ -302,45 +296,6 @@ EditWidget::onDialogXmlEditor() _dlg_mgr.showDialog("XmlEditor"); } -#ifdef WITH_INKBOARD -void -EditWidget::onDialogWhiteboardConnect() -{ - Dialog::WhiteboardConnectDialogImpl* dlg = dynamic_cast< Dialog::WhiteboardConnectDialogImpl* >(_dlg_mgr.getDialog("WhiteboardConnect")); - dlg->setSessionManager(); - _dlg_mgr.showDialog("WhiteboardConnect"); -} - -void -EditWidget::onDialogWhiteboardShareWithUser() -{ - Dialog::WhiteboardShareWithUserDialogImpl* dlg = dynamic_cast< Dialog::WhiteboardShareWithUserDialogImpl* >(_dlg_mgr.getDialog("WhiteboardShareWithUser")); - dlg->setSessionManager(); - _dlg_mgr.showDialog("WhiteboardShareWithUser"); -} - -void -EditWidget::onDialogWhiteboardShareWithChat() -{ - Dialog::WhiteboardShareWithChatroomDialogImpl* dlg = dynamic_cast< Dialog::WhiteboardShareWithChatroomDialogImpl* >(_dlg_mgr.getDialog("WhiteboardShareWithChat")); - dlg->setSessionManager(); - _dlg_mgr.showDialog("WhiteboardShareWithChat"); -} - -void -EditWidget::onDialogOpenSessionFile() -{ - g_log(NULL, G_LOG_LEVEL_DEBUG, "not reimplemented yet"); -} - -void -EditWidget::onDumpXMLTracker() -{ - g_log(NULL, G_LOG_LEVEL_DEBUG, "not reimplemented yet"); -} - -#endif - void EditWidget::onUriChanged() { @@ -361,9 +316,6 @@ EditWidget::initMenuActions() // _act_grp->add(Gtk::Action::create("MenuObject", _("PLACEHOLDER, do not translate"))); // _act_grp->add(Gtk::Action::create("MenuPath", _("PLACEHOLDER, do not translate"))); // _act_grp->add(Gtk::Action::create("MenuText", _("PLACEHOLDER, do not translate"))); -#ifdef WITH_INKBOARD -// _act_grp->add(Gtk::Action::create("MenuWhiteboard", _("PLACEHOLDER, do not translate"))); -#endif // _act_grp->add(Gtk::Action::create("MenuHelp", _("PLACEHOLDER, do not translate"))); // temporarily replaced with non-gettext version to have a well-sized menu // for testing: @@ -375,9 +327,6 @@ EditWidget::initMenuActions() _act_grp->add(Gtk::Action::create("MenuObject", "Object")); _act_grp->add(Gtk::Action::create("MenuPath", "Path")); _act_grp->add(Gtk::Action::create("MenuText", "Text")); -#ifdef WITH_INKBOARD - _act_grp->add(Gtk::Action::create("MenuWhiteboard", "Whiteboard")); -#endif _act_grp->add(Gtk::Action::create("MenuHelp", "Help")); // File menu @@ -821,30 +770,6 @@ EditWidget::initMenuActions() // Whiteboard menu #ifdef WITH_INKBOARD - _act_grp->add(Gtk::Action::create("DialogWhiteboardConnect", - Gtk::Stock::CLEAR, Glib::ustring(), - _("PLACEHOLDER, do not translate")), - sigc::mem_fun(*this, &EditWidget::onDialogWhiteboardConnect)); - - _act_grp->add(Gtk::Action::create("DialogWhiteboardShareWithUser", - Gtk::Stock::CLEAR, Glib::ustring(), - _("PLACEHOLDER, do not translate")), - sigc::mem_fun(*this, &EditWidget::onDialogWhiteboardShareWithUser)); - - _act_grp->add(Gtk::Action::create("DialogWhiteboardShareWithChat", - Gtk::Stock::CLEAR, Glib::ustring(), - _("PLACEHOLDER, do not translate")), - sigc::mem_fun(*this, &EditWidget::onDialogWhiteboardShareWithChat)); - - _act_grp->add(Gtk::Action::create("WhiteboardOpenSessionFile", - Gtk::Stock::CLEAR, Glib::ustring(), - _("PLACEHOLDER, do not translate")), - sigc::mem_fun(*this, &EditWidget::onDialogOpenSessionFile)); - - _act_grp->add(Gtk::Action::create("WhiteboardDumpXMLTracker", - Gtk::Stock::CLEAR, Glib::ustring(), - _("PLACEHOLDER, do not translate")), - sigc::mem_fun(*this, &EditWidget::onDumpXMLTracker)); #endif // About menu diff --git a/src/verbs.cpp b/src/verbs.cpp index 9458d2d17..5649d0895 100644 --- a/src/verbs.cpp +++ b/src/verbs.cpp @@ -49,11 +49,7 @@ #include "dialogs/input.h" #ifdef WITH_INKBOARD -#include "ui/dialog/whiteboard-connect.h" -#include "ui/dialog/whiteboard-sharewithuser.h" -#include "ui/dialog/whiteboard-sharewithchat.h" #include "jabber_whiteboard/session-manager.h" -#include "jabber_whiteboard/node-tracker.h" #endif #include "extension/effect.h" @@ -1576,90 +1572,9 @@ DialogVerb::perform(SPAction *action, void *data, void *pdata) sp_item_dialog(); break; #ifdef WITH_INKBOARD - case SP_VERB_DIALOG_WHITEBOARD_CONNECT: { - // We need to ensure that this dialog is associated with the correct SessionManager, - // since the user may have opened a new document (and hence swapped SessionManager - // instances) sometime before this dialog invocation - Inkscape::UI::Dialog::WhiteboardConnectDialogImpl *dlg = dynamic_cast< Inkscape::UI::Dialog::WhiteboardConnectDialogImpl *>(dt->_dlg_mgr->getDialog("WhiteboardConnect")); - dlg->setSessionManager(); - dt->_dlg_mgr->showDialog("WhiteboardConnect"); - break; - } - case SP_VERB_DIALOG_WHITEBOARD_SHAREWITHUSER: { - //sp_whiteboard_sharewithuser_dialog(NULL); - Inkscape::Whiteboard::SessionManager *sm = SP_ACTIVE_DESKTOP->whiteboard_session_manager(); - if (sm->session_data && sm->session_data->status[Inkscape::Whiteboard::LOGGED_IN]) { - // We need to ensure that this dialog is associated with the correct SessionManager, - // since the user may have opened a new document (and hence swapped SessionManager - // instances) sometime before this dialog invocation - Inkscape::UI::Dialog::WhiteboardShareWithUserDialogImpl *dlg = dynamic_cast< Inkscape::UI::Dialog::WhiteboardShareWithUserDialogImpl *>(dt->_dlg_mgr->getDialog("WhiteboardShareWithUser")); - dlg->setSessionManager(); - dt->_dlg_mgr->showDialog("WhiteboardShareWithUser"); - } else { - Gtk::MessageDialog dlg(_("You need to connect to a Jabber server before sharing a document with another user."), true, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE); - dlg.run(); - } - break; - } - case SP_VERB_DIALOG_WHITEBOARD_SHAREWITHCHAT: { - Inkscape::Whiteboard::SessionManager *sm = SP_ACTIVE_DESKTOP->whiteboard_session_manager(); - if (sm->session_data && sm->session_data->status[Inkscape::Whiteboard::LOGGED_IN]) { - // We need to ensure that this dialog is associated with the correct SessionManager, - // since the user may have opened a new document (and hence swapped SessionManager - // instances) sometime before this dialog invocation - Inkscape::UI::Dialog::WhiteboardShareWithChatroomDialogImpl *dlg = dynamic_cast< Inkscape::UI::Dialog::WhiteboardShareWithChatroomDialogImpl *>(dt->_dlg_mgr->getDialog("WhiteboardShareWithChat")); - dlg->setSessionManager(); - dt->_dlg_mgr->showDialog("WhiteboardShareWithChat"); - } else { - Gtk::MessageDialog dlg(_("You need to connect to a Jabber server before sharing a document with a chatroom."), true, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE); - dlg.run(); - } - break; - } - - case SP_VERB_DIALOG_WHITEBOARD_DUMPXMLTRACKER: - if (SP_ACTIVE_DESKTOP->whiteboard_session_manager()->node_tracker()) { - SP_ACTIVE_DESKTOP->whiteboard_session_manager()->node_tracker()->dump(); - } else { - g_log(NULL, G_LOG_LEVEL_DEBUG, _("XML node tracker has not been initialized; nothing to dump")); - } - break; - case SP_VERB_DIALOG_WHITEBOARD_OPENSESSIONFILE: { - Gtk::FileChooserDialog sessionfiledlg(_("Open session file"), Gtk::FILE_CHOOSER_ACTION_OPEN); - sessionfiledlg.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); - sessionfiledlg.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK); - - int result = sessionfiledlg.run(); - switch (result) { - case Gtk::RESPONSE_OK: - { - SP_ACTIVE_DESKTOP->whiteboard_session_manager()->clearDocument(); - SP_ACTIVE_DESKTOP->whiteboard_session_manager()->loadSessionFile(sessionfiledlg.get_filename()); - dt->_dlg_mgr->showDialog("SessionPlayer"); - //SP_ACTIVE_DESKTOP->whiteboard_session_manager()->session_player()->start(); - break; - } - case Gtk::RESPONSE_CANCEL: - default: - break; - } - break; - } - - case SP_VERB_DIALOG_WHITEBOARD_DISCONNECT_FROM_SESSION: - { - Inkscape::Whiteboard::SessionManager *sm = SP_ACTIVE_DESKTOP->whiteboard_session_manager(); - if (sm->session_data && sm->session_data->status[Inkscape::Whiteboard::IN_WHITEBOARD]) { - SP_ACTIVE_DESKTOP->whiteboard_session_manager()->disconnectFromDocument(); - } - break; - } - case SP_VERB_DIALOG_WHITEBOARD_DISCONNECT_FROM_SERVER: + case SP_VERB_XMPP_CLIENT: { - Inkscape::Whiteboard::SessionManager *sm = SP_ACTIVE_DESKTOP->whiteboard_session_manager(); - if (sm->session_data && sm->session_data->status[Inkscape::Whiteboard::LOGGED_IN]) { - SP_ACTIVE_DESKTOP->whiteboard_session_manager()->disconnectFromServer(); - } + Inkscape::Whiteboard::SessionManager::showClient(); break; } #endif @@ -2345,22 +2260,8 @@ Verb *Verb::_base_verbs[] = { new DialogVerb(SP_VERB_DIALOG_ITEM, "DialogObjectProperties", N_("_Object Properties..."), N_("Edit the ID, locked and visible status, and other object properties"), "dialog_item_properties"), #ifdef WITH_INKBOARD - new DialogVerb(SP_VERB_DIALOG_WHITEBOARD_CONNECT, "DialogWhiteboardConnect", - N_("_Connect to Jabber server..."), N_("Connect to a Jabber server"), NULL), - new DialogVerb(SP_VERB_DIALOG_WHITEBOARD_SHAREWITHUSER, "DialogWhiteboardShareWithUser", - N_("Share with _user..."), N_("Establish a whiteboard session with another Jabber user"), NULL), - new DialogVerb(SP_VERB_DIALOG_WHITEBOARD_SHAREWITHCHAT, "DialogWhiteboardShareWithChat", - N_("Share with _chatroom..."), N_("Join a chatroom to start a new whiteboard session or join one in progress"), NULL), - new DialogVerb(SP_VERB_DIALOG_WHITEBOARD_DUMPXMLTRACKER, "DialogWhiteboardDumpXMLTracker", - N_("_Dump XML node tracker"), N_("Dump the contents of the XML tracker to the console"), NULL), - new DialogVerb(SP_VERB_DIALOG_WHITEBOARD_OPENSESSIONFILE, "DialogWhiteboardOpenSessionFile", - N_("_Open session file..."), N_("Open and browse through records of past whiteboard sessions"), NULL), - new DialogVerb(SP_VERB_DIALOG_WHITEBOARD_SESSIONPLAYBACK, "DialogWhiteboardSessionPlayback", - N_("Session file playback"), "", NULL), - new DialogVerb(SP_VERB_DIALOG_WHITEBOARD_DISCONNECT_FROM_SESSION, "DialogWhiteboardDisconnectSession", - N_("_Disconnect from session"), "", NULL), - new DialogVerb(SP_VERB_DIALOG_WHITEBOARD_DISCONNECT_FROM_SERVER, "DialogWhiteboardDisconnectServer", - N_("Disconnect from _server"), "", NULL), + new DialogVerb(SP_VERB_XMPP_CLIENT, "DialogXmppClient", + N_("_Instant Messaging..."), N_("Jabber Instant Messaging Client"), NULL), #endif new DialogVerb(SP_VERB_DIALOG_INPUT, "DialogInput", N_("_Input Devices..."), N_("Configure extended input devices, such as a graphics tablet"), NULL), diff --git a/src/verbs.h b/src/verbs.h index 5d364c53b..37f6f424b 100644 --- a/src/verbs.h +++ b/src/verbs.h @@ -196,14 +196,7 @@ enum { SP_VERB_DIALOG_CLONETILER, SP_VERB_DIALOG_ITEM, #ifdef WITH_INKBOARD - SP_VERB_DIALOG_WHITEBOARD_CONNECT, - SP_VERB_DIALOG_WHITEBOARD_SHAREWITHUSER, - SP_VERB_DIALOG_WHITEBOARD_SHAREWITHCHAT, - SP_VERB_DIALOG_WHITEBOARD_DUMPXMLTRACKER, - SP_VERB_DIALOG_WHITEBOARD_OPENSESSIONFILE, - SP_VERB_DIALOG_WHITEBOARD_SESSIONPLAYBACK, - SP_VERB_DIALOG_WHITEBOARD_DISCONNECT_FROM_SESSION, - SP_VERB_DIALOG_WHITEBOARD_DISCONNECT_FROM_SERVER, + SP_VERB_XMPP_CLIENT, #endif SP_VERB_DIALOG_INPUT, SP_VERB_DIALOG_EXTENSIONEDITOR,