/* * libjingle * Copyright 2006, Google Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include "libjingleplus.h" #ifdef WIN32 #include "talk/base/win32socketserver.h" #endif #include "talk/base/physicalsocketserver.h" #include "talk/base/logging.h" #include "talk/examples/login/xmppauth.h" #include "talk/examples/login/xmppsocket.h" #include "talk/examples/login/xmpppump.h" #include "presencepushtask.h" #include "talk/app/status.h" #include "talk/app/message.h" #include "rostertask.h" #include "talk/app/iqtask.h" #include "talk/app/presenceouttask.h" #include "talk/app/receivemessagetask.h" #include "talk/app/rostersettask.h" #include "talk/app/sendmessagetask.h" enum { MSG_START, // main thread to worker MSG_LOGIN, MSG_DISCONNECT, MSG_SEND_PRESENCE, MSG_SEND_DIRECTED_PRESENCE, MSG_SEND_DIRECTED_MUC_PRESENCE, MSG_SEND_XMPP_MESSAGE, MSG_SEND_XMPP_IQ, MSG_UPDATE_ROSTER_ITEM, MSG_REMOVE_ROSTER_ITEM, // worker thread to main thread MSG_STATE_CHANGE, MSG_STATUS_UPDATE, MSG_STATUS_ERROR, MSG_ROSTER_REFRESH_STARTED, MSG_ROSTER_REFRESH_FINISHED, MSG_ROSTER_ITEM_UPDATED, MSG_ROSTER_ITEM_REMOVED, MSG_ROSTER_SUBSCRIBE, MSG_ROSTER_UNSUBSCRIBE, MSG_ROSTER_SUBSCRIBED, MSG_ROSTER_UNSUBSCRIBED, MSG_INCOMING_MESSAGE, MSG_IQ_COMPLETE, MSG_XMPP_INPUT, MSG_XMPP_OUTPUT }; class LibjinglePlusWorker : public talk_base::MessageHandler, public XmppPumpNotify, public sigslot::has_slots<> { public: LibjinglePlusWorker(LibjinglePlus *ljp, LibjinglePlusNotify *notify) : worker_thread_(NULL), ljp_(ljp), notify_(notify), ppt_(NULL), rmt_(NULL), rt_(NULL), is_test_login_(false) { main_thread_.reset(new talk_base::AutoThread()); #ifdef WIN32 ss_.reset(new talk_base::Win32SocketServer(main_thread_.get())); main_thread_->set_socketserver(ss_.get()); #endif pump_.reset(new XmppPump(this)); pump_->client()->SignalLogInput.connect(this, &LibjinglePlusWorker::OnInputDebug); pump_->client()->SignalLogOutput.connect(this, &LibjinglePlusWorker::OnOutputDebug); //pump_->client()->SignalStateChange.connect(this, &LibjinglePlusWorker::OnStateChange); } ~LibjinglePlusWorker() { if (worker_thread_) { worker_thread_->Send(this, MSG_DISCONNECT); delete worker_thread_; } } virtual void OnMessage(talk_base::Message *msg) { switch (msg->message_id) { case MSG_START: LoginW(); break; case MSG_DISCONNECT: DisconnectW(); break; case MSG_SEND_XMPP_MESSAGE: SendXmppMessageW(static_cast(msg->pdata)->m_); delete msg->pdata; break; case MSG_SEND_XMPP_IQ: SendXmppIqW(static_cast(msg->pdata)->to_jid_, static_cast(msg->pdata)->is_get_, static_cast(msg->pdata)->xml_element_); delete msg->pdata; break; case MSG_SEND_PRESENCE: SendPresenceW(static_cast(msg->pdata)->s_); delete msg->pdata; break; case MSG_SEND_DIRECTED_PRESENCE: SendDirectedPresenceW(static_cast(msg->pdata)->j_, static_cast(msg->pdata)->s_); delete msg->pdata; break; case MSG_SEND_DIRECTED_MUC_PRESENCE: SendDirectedMUCPresenceW(static_cast(msg->pdata)->j_, static_cast(msg->pdata)->s_, static_cast(msg->pdata)->un_, static_cast(msg->pdata)->ac_, static_cast(msg->pdata)->am_, static_cast(msg->pdata)->role_); delete msg->pdata; break; case MSG_UPDATE_ROSTER_ITEM: UpdateRosterItemW(static_cast(msg->pdata)->jid_, static_cast(msg->pdata)->n_, static_cast(msg->pdata)->g_, static_cast(msg->pdata)->grt_); delete msg->pdata; break; case MSG_REMOVE_ROSTER_ITEM: RemoveRosterItemW(static_cast(msg->pdata)->jid_); delete msg->pdata; break; case MSG_STATUS_UPDATE: OnStatusUpdateW(static_cast(msg->pdata)->s_); delete msg->pdata; break; case MSG_STATUS_ERROR: OnStatusErrorW(static_cast(msg->pdata)->stanza_); delete msg->pdata; break; case MSG_STATE_CHANGE: OnStateChangeW(static_cast(msg->pdata)->s_); delete msg->pdata; break; case MSG_ROSTER_REFRESH_STARTED: OnRosterRefreshStartedW(); break; case MSG_ROSTER_REFRESH_FINISHED: OnRosterRefreshFinishedW(); break; case MSG_ROSTER_ITEM_UPDATED: OnRosterItemUpdatedW(static_cast(msg->pdata)->ri_); delete msg->pdata; break; case MSG_ROSTER_ITEM_REMOVED: OnRosterItemRemovedW(static_cast(msg->pdata)->ri_); delete msg->pdata; break; case MSG_ROSTER_SUBSCRIBE: OnRosterSubscribeW(static_cast(msg->pdata)->jid_); delete msg->pdata; break; case MSG_ROSTER_UNSUBSCRIBE: OnRosterUnsubscribeW(static_cast(msg->pdata)->jid_); delete msg->pdata; break; case MSG_ROSTER_SUBSCRIBED: OnRosterSubscribedW(static_cast(msg->pdata)->jid_); delete msg->pdata; break; case MSG_ROSTER_UNSUBSCRIBED: OnRosterUnsubscribedW(static_cast(msg->pdata)->jid_); delete msg->pdata; break; case MSG_INCOMING_MESSAGE: OnIncomingMessageW(static_cast(msg->pdata)->m_); delete msg->pdata; break; case MSG_IQ_COMPLETE: OnIqCompleteW(static_cast(msg->pdata)->success_, static_cast(msg->pdata)->stanza_); delete msg->pdata; break; case MSG_XMPP_OUTPUT: OnOutputDebugW(static_cast(msg->pdata)->s_); delete msg->pdata; break; case MSG_XMPP_INPUT: OnInputDebugW(static_cast(msg->pdata)->s_); delete msg->pdata; break; } } void Login(const std::string &jid, const std::string &password, const std::string &machine_address, bool is_test, bool cookie_auth) { is_test_login_ = is_test; xcs_.set_user(jid); if (cookie_auth) { xcs_.set_auth_cookie(password); } else { talk_base::InsecureCryptStringImpl pass; pass.password() = password; xcs_.set_pass(talk_base::CryptString(pass)); } xcs_.set_host(is_test ? "google.com" : "gmail.com"); xcs_.set_resource("libjingleplus"); xcs_.set_server(talk_base::SocketAddress(machine_address, 5222)); xcs_.set_use_tls(!is_test); if (is_test) { xcs_.set_allow_plain(true); } worker_thread_ = new talk_base::Thread(&pss_); worker_thread_->Start(); worker_thread_->Send(this, MSG_START); } void SendXmppMessage(const buzz::XmppMessage &m) { assert(talk_base::ThreadManager::CurrentThread() != worker_thread_); worker_thread_->Post(this, MSG_SEND_XMPP_MESSAGE, new SendMessageData(m)); } void SendXmppIq(const buzz::Jid &to_jid, bool is_get, const buzz::XmlElement *xml_element) { assert(talk_base::ThreadManager::CurrentThread() != worker_thread_); worker_thread_->Post(this, MSG_SEND_XMPP_IQ, new SendIqData(to_jid, is_get, xml_element)); } void SendPresence(const buzz::Status & s) { assert(talk_base::ThreadManager::CurrentThread() != worker_thread_); worker_thread_->Post(this, MSG_SEND_PRESENCE, new SendPresenceData(s)); } void SendDirectedPresence (const buzz::Jid &j, const buzz::Status &s) { assert(talk_base::ThreadManager::CurrentThread() != worker_thread_); worker_thread_->Post(this, MSG_SEND_DIRECTED_PRESENCE, new SendDirectedPresenceData(j,s)); } void SendDirectedMUCPresence(const buzz::Jid &j, const buzz::Status &s, const std::string &un, const std::string &ac, const std::string &am, const std::string &role) { assert(talk_base::ThreadManager::CurrentThread() != worker_thread_); worker_thread_->Post(this, MSG_SEND_DIRECTED_MUC_PRESENCE, new SendDirectedMUCPresenceData(j,s,un,ac,am, role)); } void UpdateRosterItem(const buzz::Jid & jid, const std::string & name, const std::vector & groups, buzz::GrType grt) { assert(talk_base::ThreadManager::CurrentThread() != worker_thread_); worker_thread_->Post(this, MSG_UPDATE_ROSTER_ITEM, new UpdateRosterItemData(jid,name,groups,grt)); } void RemoveRosterItemW(const buzz::Jid &jid) { buzz::RosterSetTask *rst = new buzz::RosterSetTask(pump_.get()->client()); rst->Remove(jid); rst->Start(); } void RemoveRosterItem(const buzz::Jid &jid) { assert(talk_base::ThreadManager::CurrentThread() != worker_thread_); worker_thread_->Post(this, MSG_REMOVE_ROSTER_ITEM, new JidData(jid)); } void DoCallbacks() { assert(talk_base::ThreadManager::CurrentThread() != worker_thread_); talk_base::Message m; while (main_thread_->Get(&m, 0)) { main_thread_->Dispatch(&m); } } private: struct UpdateRosterItemData : public talk_base::MessageData { UpdateRosterItemData(const buzz::Jid &jid, const std::string &name, const std::vector &groups, buzz::GrType grt) : jid_(jid), n_(name), g_(groups), grt_(grt) {} buzz::Jid jid_; std::string n_; std::vector g_; buzz::GrType grt_; }; void UpdateRosterItemW(const buzz::Jid &jid, const std::string &name, const std::vector &groups, buzz::GrType grt) { assert (talk_base::ThreadManager::CurrentThread() == worker_thread_); buzz::RosterSetTask *rst = new buzz::RosterSetTask(pump_.get()->client()); rst->Update(jid, name, groups, grt); rst->Start(); } struct StringData : public talk_base::MessageData { StringData(std::string s) : s_(s) {} std::string s_; }; void OnInputDebugW(const std::string &data) { assert(talk_base::ThreadManager::CurrentThread() != worker_thread_); if (notify_) notify_->OnXmppInput(data); } void OnInputDebug(const char *data, int len) { assert (talk_base::ThreadManager::CurrentThread() == worker_thread_); main_thread_->Post(this, MSG_XMPP_INPUT, new StringData(std::string(data,len))); if (notify_) notify_->WakeupMainThread(); } void OnOutputDebugW(const std::string &data) { assert(talk_base::ThreadManager::CurrentThread() != worker_thread_); if (notify_) notify_->OnXmppOutput(data); } void OnOutputDebug(const char *data, int len) { assert (talk_base::ThreadManager::CurrentThread() == worker_thread_); main_thread_->Post(this, MSG_XMPP_OUTPUT, new StringData(std::string(data,len))); if (notify_) notify_->WakeupMainThread(); } struct StateChangeData : public talk_base::MessageData { StateChangeData(buzz::XmppEngine::State state) : s_(state) {} buzz::XmppEngine::State s_; }; void OnStateChange(buzz::XmppEngine::State state) { assert (talk_base::ThreadManager::CurrentThread() == worker_thread_); switch (state) { case buzz::XmppEngine::STATE_OPEN: ppt_ = new buzz::PresencePushTask(pump_.get()->client()); ppt_->SignalStatusUpdate.connect(this, &LibjinglePlusWorker::OnStatusUpdate); ppt_->SignalStatusError.connect(this, &LibjinglePlusWorker::OnStatusError); ppt_->Start(); rmt_ = new buzz::ReceiveMessageTask(pump_.get()->client(), buzz::XmppEngine::HL_ALL); rmt_->SignalIncomingMessage.connect(this, &LibjinglePlusWorker::OnIncomingMessage); rmt_->Start(); rt_ = new buzz::RosterTask(pump_.get()->client()); rt_->SignalRosterItemUpdated.connect(this, &LibjinglePlusWorker::OnRosterItemUpdated); rt_->SignalRosterItemRemoved.connect(this, &LibjinglePlusWorker::OnRosterItemRemoved); rt_->SignalSubscribe.connect(this, &LibjinglePlusWorker::OnRosterSubscribe); rt_->SignalUnsubscribe.connect(this, &LibjinglePlusWorker::OnRosterUnsubscribe); rt_->SignalSubscribed.connect(this, &LibjinglePlusWorker::OnRosterSubscribed); rt_->SignalUnsubscribed.connect(this, &LibjinglePlusWorker::OnRosterUnsubscribed); rt_->SignalRosterRefreshStarted.connect(this, &LibjinglePlusWorker::OnRosterRefreshStarted); rt_->SignalRosterRefreshFinished.connect(this, &LibjinglePlusWorker::OnRosterRefreshFinished); rt_->Start(); rt_->RefreshRosterNow(); break; } main_thread_->Post(this, MSG_STATE_CHANGE, new StateChangeData(state)); if (notify_) notify_->WakeupMainThread(); } void OnStateChangeW(buzz::XmppEngine::State state) { assert(talk_base::ThreadManager::CurrentThread() != worker_thread_); if (notify_) notify_->OnStateChange(state); } struct RosterItemData : public talk_base::MessageData { RosterItemData(const buzz::RosterItem &ri) : ri_(ri) {} buzz::RosterItem ri_; }; void OnRosterItemUpdatedW(const buzz::RosterItem &ri) { assert(talk_base::ThreadManager::CurrentThread() != worker_thread_); if (notify_) notify_->OnRosterItemUpdated(ri); } void OnRosterItemUpdated(const buzz::RosterItem &ri, bool huh) { assert (talk_base::ThreadManager::CurrentThread() == worker_thread_); main_thread_->Post(this, MSG_ROSTER_ITEM_UPDATED, new RosterItemData(ri)); if (notify_) notify_->WakeupMainThread(); } void OnRosterItemRemovedW(const buzz::RosterItem &ri) { assert(talk_base::ThreadManager::CurrentThread() != worker_thread_); if (notify_) notify_->OnRosterItemRemoved(ri); } void OnRosterItemRemoved(const buzz::RosterItem &ri) { assert (talk_base::ThreadManager::CurrentThread() == worker_thread_); main_thread_->Post(this, MSG_ROSTER_ITEM_REMOVED, new RosterItemData(ri)); if (notify_) notify_->WakeupMainThread(); } struct JidData : public talk_base::MessageData { JidData(const buzz::Jid& jid) : jid_(jid) {} const buzz::Jid jid_; }; void OnRosterSubscribeW(const buzz::Jid& jid) { assert(talk_base::ThreadManager::CurrentThread() != worker_thread_); if (notify_) notify_->OnRosterSubscribe(jid); } void OnRosterSubscribe(const buzz::Jid& jid) { assert (talk_base::ThreadManager::CurrentThread() == worker_thread_); main_thread_->Post(this, MSG_ROSTER_SUBSCRIBE, new JidData(jid)); if (notify_) notify_->WakeupMainThread(); } void OnRosterUnsubscribeW(const buzz::Jid &jid) { assert(talk_base::ThreadManager::CurrentThread() != worker_thread_); if (notify_) notify_->OnRosterUnsubscribe(jid); } void OnRosterUnsubscribe(const buzz::Jid &jid) { assert (talk_base::ThreadManager::CurrentThread() == worker_thread_); main_thread_->Post(this, MSG_ROSTER_UNSUBSCRIBE, new JidData(jid)); if (notify_) notify_->WakeupMainThread(); } void OnRosterSubscribedW(const buzz::Jid &jid) { assert(talk_base::ThreadManager::CurrentThread() != worker_thread_); if (notify_) notify_->OnRosterSubscribed(jid); } void OnRosterSubscribed(const buzz::Jid &jid) { assert (talk_base::ThreadManager::CurrentThread() == worker_thread_); main_thread_->Post(this, MSG_ROSTER_SUBSCRIBED, new JidData(jid)); if (notify_) notify_->WakeupMainThread(); } void OnRosterUnsubscribedW(const buzz::Jid &jid) { assert(talk_base::ThreadManager::CurrentThread() != worker_thread_); if (notify_) notify_->OnRosterUnsubscribed(jid); } void OnRosterUnsubscribed(const buzz::Jid &jid) { assert (talk_base::ThreadManager::CurrentThread() == worker_thread_); main_thread_->Post(this, MSG_ROSTER_UNSUBSCRIBED, new JidData(jid)); if (notify_) notify_->WakeupMainThread(); } void OnRosterRefreshStartedW() { assert(talk_base::ThreadManager::CurrentThread() != worker_thread_); if (notify_) notify_->OnRosterRefreshStarted(); } void OnRosterRefreshStarted() { assert (talk_base::ThreadManager::CurrentThread() == worker_thread_); main_thread_->Post(this, MSG_ROSTER_REFRESH_STARTED); if (notify_) notify_->WakeupMainThread(); } void OnRosterRefreshFinishedW() { assert(talk_base::ThreadManager::CurrentThread() != worker_thread_); if (notify_) notify_->OnRosterRefreshFinished(); } void OnRosterRefreshFinished() { assert (talk_base::ThreadManager::CurrentThread() == worker_thread_); main_thread_->Post(this, MSG_ROSTER_REFRESH_FINISHED); if (notify_) notify_->WakeupMainThread(); } struct XmppMessageData : talk_base::MessageData { XmppMessageData(const buzz::XmppMessage &m) : m_(m) {} buzz::XmppMessage m_; }; void OnIncomingMessageW(const buzz::XmppMessage &msg) { assert(talk_base::ThreadManager::CurrentThread() != worker_thread_); if (notify_) notify_->OnMessage(msg); } void OnIncomingMessage(const buzz::XmppMessage &msg) { assert (talk_base::ThreadManager::CurrentThread() == worker_thread_); main_thread_->Post(this, MSG_INCOMING_MESSAGE, new XmppMessageData(msg)); if (notify_) notify_->WakeupMainThread(); } void OnStatusUpdateW (const buzz::Status &status) { assert(talk_base::ThreadManager::CurrentThread() != worker_thread_); if (notify_) notify_->OnStatusUpdate(status); } void OnStatusUpdate (const buzz::Status &status) { assert (talk_base::ThreadManager::CurrentThread() == worker_thread_); main_thread_->Post(this, MSG_STATUS_UPDATE, new SendPresenceData(status)); if (notify_) notify_->WakeupMainThread(); } struct StatusErrorData : talk_base::MessageData { StatusErrorData(const buzz::XmlElement &stanza) : stanza_(stanza) {} buzz::XmlElement stanza_; }; void OnStatusErrorW (const buzz::XmlElement &stanza) { assert(talk_base::ThreadManager::CurrentThread() != worker_thread_); if (notify_) notify_->OnStatusError(stanza); } void OnStatusError (const buzz::XmlElement &stanza) { assert (talk_base::ThreadManager::CurrentThread() == worker_thread_); main_thread_->Post(this, MSG_STATUS_ERROR, new StatusErrorData(stanza)); if (notify_) notify_->WakeupMainThread(); } void LoginW() { assert (talk_base::ThreadManager::CurrentThread() == worker_thread_); XmppSocket* socket = new XmppSocket(true); pump_->DoLogin(xcs_, socket, is_test_login_ ? NULL : new XmppAuth()); socket->SignalCloseEvent.connect(this, &LibjinglePlusWorker::OnXmppSocketClose); } void DisconnectW() { assert(talk_base::ThreadManager::CurrentThread() == worker_thread_); pump_->DoDisconnect(); } void SendXmppMessageW(const buzz::XmppMessage &m) { assert (talk_base::ThreadManager::CurrentThread() == worker_thread_); buzz::SendMessageTask * smt = new buzz::SendMessageTask(pump_.get()->client()); smt->Send(m); smt->Start(); } void SendXmppIqW(const buzz::Jid &to_jid, bool is_get, const buzz::XmlElement *xml_element) { assert (talk_base::ThreadManager::CurrentThread() == worker_thread_); buzz::IqTask *iq_task = new buzz::IqTask(pump_.get()->client(), is_get, to_jid, const_cast(xml_element)); iq_task->SignalDone.connect(this, &LibjinglePlusWorker::OnIqComplete); iq_task->Start(); } struct IqCompleteData : public talk_base::MessageData { IqCompleteData(bool success, const buzz::XmlElement *stanza) : success_(success), stanza_(*stanza) {} bool success_; buzz::XmlElement stanza_; }; void OnIqCompleteW(bool success, const buzz::XmlElement& stanza) { assert(talk_base::ThreadManager::CurrentThread() != worker_thread_); if (notify_) notify_->OnIqDone(success, stanza); } void OnIqComplete(bool success, const buzz::XmlElement *stanza) { assert(talk_base::ThreadManager::CurrentThread() == worker_thread_); main_thread_->Post(this, MSG_IQ_COMPLETE, new IqCompleteData(success, stanza)); if (notify_) notify_->WakeupMainThread(); } void SendPresenceW(const buzz::Status & s) { assert (talk_base::ThreadManager::CurrentThread() == worker_thread_); buzz::PresenceOutTask *pot = new buzz::PresenceOutTask(pump_.get()->client()); pot->Send(s); pot->Start(); } void SendDirectedMUCPresenceW(const buzz::Jid & j, const buzz::Status & s, const std::string &user_nick, const std::string &api_capability, const std::string &api_message, const std::string &role) { assert (talk_base::ThreadManager::CurrentThread() == worker_thread_); buzz::PresenceOutTask *pot = new buzz::PresenceOutTask(pump_.get()->client()); pot->SendDirectedMUC(j,s,user_nick,api_capability,api_message, role); pot->Start(); } void SendDirectedPresenceW(const buzz::Jid & j, const buzz::Status & s) { assert (talk_base::ThreadManager::CurrentThread() == worker_thread_); buzz::PresenceOutTask *pot = new buzz::PresenceOutTask(pump_.get()->client()); pot->SendDirected(j,s); pot->Start(); } void OnXmppSocketClose(int error) { notify_->OnSocketClose(error); } struct SendMessageData : public talk_base::MessageData { SendMessageData(const buzz::XmppMessage &m) : m_(m) {} buzz::XmppMessage m_; }; struct SendIqData : public talk_base::MessageData { SendIqData(const buzz::Jid &jid, bool is_get, const buzz::XmlElement *m) : to_jid_(jid), is_get_(is_get), xml_element_(m) {} buzz::Jid to_jid_; bool is_get_; const buzz::XmlElement *xml_element_; }; struct SendPresenceData : public talk_base::MessageData { SendPresenceData(const buzz::Status &s) : s_(s) {} buzz::Status s_; }; struct SendDirectedPresenceData : public talk_base::MessageData { SendDirectedPresenceData(const buzz::Jid &j, const buzz::Status &s) : j_(j), s_(s) {} buzz::Jid j_; buzz::Status s_; }; struct SendDirectedMUCPresenceData : public talk_base::MessageData { SendDirectedMUCPresenceData(const buzz::Jid &j, const buzz::Status &s, const std::string &un, const std::string &ac, const std::string &am, const std::string &role) : j_(j), s_(s), un_(un), ac_(ac), am_(am), role_(role) {} buzz::Jid j_; buzz::Status s_; std::string un_; std::string ac_; std::string am_; std::string role_; }; talk_base::scoped_ptr ss_; talk_base::scoped_ptr main_thread_; talk_base::Thread *worker_thread_; LibjinglePlus *ljp_; LibjinglePlusNotify *notify_; buzz::XmppClientSettings xcs_; talk_base::PhysicalSocketServer pss_; talk_base::scoped_ptr pump_; buzz::PresencePushTask * ppt_; buzz::ReceiveMessageTask * rmt_; buzz::RosterTask * rt_; bool is_test_login_; }; LibjinglePlus::LibjinglePlus(LibjinglePlusNotify *notify) { worker_ = new LibjinglePlusWorker(this, notify); } LibjinglePlus::~LibjinglePlus() { delete worker_; worker_ = NULL; } void LibjinglePlus::Login(const std::string &jid, const std::string &password, const std::string &machine_address, bool is_test, bool cookie_auth) { worker_->Login(jid, password, machine_address, is_test, cookie_auth); } void LibjinglePlus::SendPresence(const buzz::Status & s) { worker_->SendPresence(s); } void LibjinglePlus::SendDirectedPresence(const buzz::Jid & j, const buzz::Status & s) { worker_->SendDirectedPresence(j,s); } void LibjinglePlus::SendDirectedMUCPresence(const buzz::Jid & j, const buzz::Status & s, const std::string &user_nick, const std::string &api_capability, const std::string &api_message, const std::string &role) { worker_->SendDirectedMUCPresence(j,s,user_nick,api_capability,api_message, role); } void LibjinglePlus::SendXmppMessage(const buzz::XmppMessage & m) { worker_->SendXmppMessage(m); } void LibjinglePlus::SendXmppIq(const buzz::Jid &to_jid, bool is_get, const buzz::XmlElement *iq_element) { worker_->SendXmppIq(to_jid, is_get, iq_element); } void LibjinglePlus::DoCallbacks() { worker_->DoCallbacks(); }