Talk: Removes deprecated example apps and moves the server apps to trunk/talk/examples.
BUG=12545067 R=mallinath@webrtc.org Review URL: https://webrtc-codereview.appspot.com/7159004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@5397 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
0af1ffa84d
commit
2ce9a64b75
@ -1,11 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.google.call</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>chat</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
@ -1,159 +0,0 @@
|
||||
/*
|
||||
* libjingle
|
||||
* Copyright 2004--2013, 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.
|
||||
*/
|
||||
|
||||
//
|
||||
// A simple text chat application, largely copied from examples/call.
|
||||
//
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "talk/base/logging.h"
|
||||
#include "talk/base/ssladapter.h"
|
||||
|
||||
#ifdef OSX
|
||||
#include "talk/base/maccocoasocketserver.h"
|
||||
#elif defined(WIN32)
|
||||
#include "talk/base/win32socketserver.h"
|
||||
#else
|
||||
#include "talk/base/physicalsocketserver.h"
|
||||
#endif
|
||||
|
||||
#include "talk/xmpp/constants.h"
|
||||
#include "talk/xmpp/xmppauth.h"
|
||||
#include "talk/xmpp/xmppclientsettings.h"
|
||||
#include "talk/xmpp/xmpppump.h"
|
||||
#include "talk/xmpp/xmppsocket.h"
|
||||
|
||||
#include "talk/examples/chat/chatapp.h"
|
||||
#include "talk/examples/chat/consoletask.h"
|
||||
|
||||
static const int kDefaultPort = 5222;
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
// TODO(pmclean): Remove duplication of code with examples/call.
|
||||
// Set up debugging.
|
||||
bool debug = true;
|
||||
if (debug) {
|
||||
talk_base::LogMessage::LogToDebug(talk_base::LS_VERBOSE);
|
||||
}
|
||||
|
||||
// Set up the crypto subsystem.
|
||||
talk_base::InitializeSSL();
|
||||
|
||||
// Parse username and password, if present.
|
||||
buzz::Jid jid;
|
||||
std::string username;
|
||||
talk_base::InsecureCryptStringImpl pass;
|
||||
if (argc > 1) {
|
||||
username = argv[1];
|
||||
if (argc > 2) {
|
||||
pass.password() = argv[2];
|
||||
}
|
||||
}
|
||||
|
||||
// ... else prompt for them
|
||||
if (username.empty()) {
|
||||
printf("JID: ");
|
||||
std::cin >> username;
|
||||
}
|
||||
if (username.find('@') == std::string::npos) {
|
||||
username.append("@localhost");
|
||||
}
|
||||
|
||||
jid = buzz::Jid(username);
|
||||
if (!jid.IsValid() || jid.node() == "") {
|
||||
printf("Invalid JID. JIDs should be in the form user@domain\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (pass.password().empty()) {
|
||||
buzz::ConsoleTask::SetEcho(false);
|
||||
printf("Password: ");
|
||||
std::cin >> pass.password();
|
||||
buzz::ConsoleTask::SetEcho(true);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
// OTP (this can be skipped)
|
||||
std::string otp_token;
|
||||
printf("OTP: ");
|
||||
fflush(stdin);
|
||||
std::getline(std::cin, otp_token);
|
||||
|
||||
// Setup the connection settings.
|
||||
buzz::XmppClientSettings xcs;
|
||||
xcs.set_user(jid.node());
|
||||
xcs.set_resource("chat");
|
||||
xcs.set_host(jid.domain());
|
||||
bool allow_plain = false;
|
||||
xcs.set_allow_plain(allow_plain);
|
||||
xcs.set_use_tls(buzz::TLS_REQUIRED);
|
||||
xcs.set_pass(talk_base::CryptString(pass));
|
||||
if (!otp_token.empty() && *otp_token.c_str() != '\n') {
|
||||
xcs.set_auth_token(buzz::AUTH_MECHANISM_OAUTH2, otp_token);
|
||||
}
|
||||
|
||||
// Build the server spec
|
||||
std::string host;
|
||||
int port;
|
||||
|
||||
std::string server = "talk.google.com";
|
||||
int colon = server.find(':');
|
||||
if (colon == -1) {
|
||||
host = server;
|
||||
port = kDefaultPort;
|
||||
} else {
|
||||
host = server.substr(0, colon);
|
||||
port = atoi(server.substr(colon + 1).c_str());
|
||||
}
|
||||
xcs.set_server(talk_base::SocketAddress(host, port));
|
||||
|
||||
talk_base::Thread* main_thread = talk_base::Thread::Current();
|
||||
#if WIN32
|
||||
// Need to pump messages on our main thread on Windows.
|
||||
talk_base::Win32Thread w32_thread;
|
||||
talk_base::ThreadManager::Instance()->SetCurrentThread(&w32_thread);
|
||||
#elif defined(OSX)
|
||||
talk_base::MacCocoaSocketServer ss;
|
||||
talk_base::SocketServerScope ss_scope(&ss);
|
||||
#else
|
||||
talk_base::PhysicalSocketServer ss;
|
||||
#endif
|
||||
|
||||
buzz::XmppPump* pump = new buzz::XmppPump();
|
||||
ChatApp *client = new ChatApp(pump->client(), main_thread);
|
||||
|
||||
// Start pumping messages!
|
||||
pump->DoLogin(xcs, new buzz::XmppSocket(buzz::TLS_REQUIRED), new XmppAuth());
|
||||
|
||||
main_thread->Run();
|
||||
pump->DoDisconnect();
|
||||
|
||||
delete client;
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,252 +0,0 @@
|
||||
/*
|
||||
* libjingle
|
||||
* Copyright 2004--2013, 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 "talk/examples/chat/chatapp.h"
|
||||
|
||||
#include "talk/base/stringencode.h"
|
||||
#include "talk/examples/chat/consoletask.h"
|
||||
#include "talk/examples/chat/textchatsendtask.h"
|
||||
#include "talk/examples/chat/textchatreceivetask.h"
|
||||
#include "talk/xmpp/presenceouttask.h"
|
||||
#include "talk/xmpp/presencereceivetask.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
ChatApp::ChatApp(buzz::XmppClient* xmpp_client, talk_base::Thread* main_thread)
|
||||
: xmpp_client_(xmpp_client),
|
||||
presence_out_task_(),
|
||||
presence_receive_task_(),
|
||||
message_send_task_(),
|
||||
message_received_task_(),
|
||||
console_task_(new buzz::ConsoleTask(main_thread)),
|
||||
ui_state_(STATE_BASE) {
|
||||
xmpp_client_->SignalStateChange.connect(this, &ChatApp::OnStateChange);
|
||||
|
||||
console_task_->TextInputHandler.connect(this, &ChatApp::OnConsoleMessage);
|
||||
console_task_->Start();
|
||||
}
|
||||
|
||||
ChatApp::~ChatApp() {
|
||||
if (presence_out_task_ != NULL) {
|
||||
// Check out
|
||||
BroadcastPresence(away);
|
||||
}
|
||||
}
|
||||
|
||||
void ChatApp::Quit() {
|
||||
talk_base::Thread::Current()->Quit();
|
||||
}
|
||||
|
||||
void ChatApp::OnXmppOpen() {
|
||||
presence_out_task_.reset(new buzz::PresenceOutTask(xmpp_client_));
|
||||
presence_receive_task_.reset(new buzz::PresenceReceiveTask(xmpp_client_));
|
||||
presence_receive_task_->PresenceUpdate.connect(this,
|
||||
&ChatApp::OnPresenceUpdate);
|
||||
message_send_task_.reset(new buzz::TextChatSendTask(xmpp_client_));
|
||||
message_received_task_.reset(new buzz::TextChatReceiveTask(xmpp_client_));
|
||||
message_received_task_->SignalTextChatReceived.connect(
|
||||
this, &ChatApp::OnTextMessage);
|
||||
|
||||
presence_out_task_->Start();
|
||||
presence_receive_task_->Start();
|
||||
message_send_task_->Start();
|
||||
message_received_task_->Start();
|
||||
}
|
||||
|
||||
void ChatApp::BroadcastPresence(PresenceState state) {
|
||||
buzz::PresenceStatus status;
|
||||
status.set_jid(xmpp_client_->jid());
|
||||
status.set_available(state == online);
|
||||
status.set_show(state == online ? buzz::PresenceStatus::SHOW_ONLINE
|
||||
: buzz::PresenceStatus::SHOW_AWAY);
|
||||
presence_out_task_->Send(status);
|
||||
}
|
||||
|
||||
// UI Stuff
|
||||
static const char* kMenuChoiceQuit = "0";
|
||||
static const char* kMenuChoiceRoster = "1";
|
||||
static const char* kMenuChoiceChat = "2";
|
||||
|
||||
static const char* kUIStrings[3][2] = {
|
||||
{kMenuChoiceQuit, "Quit"},
|
||||
{kMenuChoiceRoster, "Roster"},
|
||||
{kMenuChoiceChat, "Send"}};
|
||||
|
||||
void ChatApp::PrintMenu() {
|
||||
char buff[128];
|
||||
int numMenuItems = sizeof(kUIStrings) / sizeof(kUIStrings[0]);
|
||||
for (int index = 0; index < numMenuItems; ++index) {
|
||||
snprintf(buff, sizeof(buff), "%s) %s\n", kUIStrings[index][0],
|
||||
kUIStrings[index][1]);
|
||||
console_task_->Print(buff);
|
||||
}
|
||||
console_task_->Print("choice:");
|
||||
}
|
||||
|
||||
void ChatApp::PrintRoster() {
|
||||
int index = 0;
|
||||
for (RosterList::iterator iter = roster_list_.begin();
|
||||
iter != roster_list_.end(); ++iter) {
|
||||
const buzz::Jid& jid = iter->second.jid();
|
||||
console_task_->Print(
|
||||
"%d: (*) %s@%s [%s] \n",
|
||||
index++,
|
||||
jid.node().c_str(),
|
||||
jid.domain().c_str(),
|
||||
jid.resource().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void ChatApp::PromptJid() {
|
||||
PrintRoster();
|
||||
console_task_->Print("choice:");
|
||||
}
|
||||
|
||||
void ChatApp::PromptChatMessage() {
|
||||
console_task_->Print(":");
|
||||
}
|
||||
|
||||
bool ChatApp::GetRosterItem(int index, buzz::PresenceStatus* status) {
|
||||
int found_index = 0;
|
||||
for (RosterList::iterator iter = roster_list_.begin();
|
||||
iter != roster_list_.end() && found_index <= index; ++iter) {
|
||||
if (found_index == index) {
|
||||
*status = iter->second;
|
||||
return true;
|
||||
}
|
||||
found_index++;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ChatApp::HandleBaseInput(const std::string& message) {
|
||||
if (message == kMenuChoiceQuit) {
|
||||
Quit();
|
||||
} else if (message == kMenuChoiceRoster) {
|
||||
PrintRoster();
|
||||
} else if (message == kMenuChoiceChat) {
|
||||
ui_state_ = STATE_PROMPTJID;
|
||||
PromptJid();
|
||||
} else if (message == "") {
|
||||
PrintMenu();
|
||||
}
|
||||
}
|
||||
|
||||
void ChatApp::HandleJidInput(const std::string& message) {
|
||||
if (isdigit(message[0])) {
|
||||
// It's an index-based roster choice.
|
||||
int index = 0;
|
||||
buzz::PresenceStatus status;
|
||||
if (!talk_base::FromString(message, &index) ||
|
||||
!GetRosterItem(index, &status)) {
|
||||
// fail, so drop back
|
||||
ui_state_ = STATE_BASE;
|
||||
return;
|
||||
}
|
||||
|
||||
chat_dest_jid_ = status.jid();
|
||||
} else {
|
||||
// It's an explicit address.
|
||||
chat_dest_jid_ = buzz::Jid(message.c_str());
|
||||
}
|
||||
ui_state_ = STATE_CHATTING;
|
||||
PromptChatMessage();
|
||||
}
|
||||
|
||||
void ChatApp::HandleChatInput(const std::string& message) {
|
||||
if (message == "") {
|
||||
ui_state_ = STATE_BASE;
|
||||
PrintMenu();
|
||||
} else {
|
||||
message_send_task_->Send(chat_dest_jid_, message);
|
||||
PromptChatMessage();
|
||||
}
|
||||
}
|
||||
|
||||
// Connection state notifications
|
||||
void ChatApp::OnStateChange(buzz::XmppEngine::State state) {
|
||||
switch (state) {
|
||||
// Nonexistent state
|
||||
case buzz::XmppEngine::STATE_NONE:
|
||||
break;
|
||||
|
||||
// Nonexistent state
|
||||
case buzz::XmppEngine::STATE_START:
|
||||
break;
|
||||
|
||||
// Exchanging stream headers, authenticating and so on.
|
||||
case buzz::XmppEngine::STATE_OPENING:
|
||||
break;
|
||||
|
||||
// Authenticated and bound.
|
||||
case buzz::XmppEngine::STATE_OPEN:
|
||||
OnXmppOpen();
|
||||
BroadcastPresence(online);
|
||||
PrintMenu();
|
||||
break;
|
||||
|
||||
// Session closed, possibly due to error.
|
||||
case buzz::XmppEngine::STATE_CLOSED:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Presence Notifications
|
||||
void ChatApp::OnPresenceUpdate(const buzz::PresenceStatus& status) {
|
||||
if (status.available()) {
|
||||
roster_list_[status.jid().Str()] = status;
|
||||
} else {
|
||||
RosterList::iterator iter = roster_list_.find(status.jid().Str());
|
||||
if (iter != roster_list_.end()) {
|
||||
roster_list_.erase(iter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Text message handlers
|
||||
void ChatApp::OnTextMessage(const buzz::Jid& from, const buzz::Jid& to,
|
||||
const std::string& message) {
|
||||
console_task_->Print("%s says: %s\n", from.node().c_str(), message.c_str());
|
||||
}
|
||||
|
||||
void ChatApp::OnConsoleMessage(const std::string &message) {
|
||||
switch (ui_state_) {
|
||||
case STATE_BASE:
|
||||
HandleBaseInput(message);
|
||||
break;
|
||||
|
||||
case STATE_PROMPTJID:
|
||||
HandleJidInput(message);
|
||||
break;
|
||||
|
||||
case STATE_CHATTING:
|
||||
HandleChatInput(message);
|
||||
break;
|
||||
}
|
||||
}
|
@ -1,171 +0,0 @@
|
||||
/*
|
||||
* libjingle
|
||||
* Copyright 2004--2013, 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.
|
||||
*/
|
||||
|
||||
#ifndef TALK_EXAMPLES_CHAT_CHATAPP_H_
|
||||
#define TALK_EXAMPLES_CHAT_CHATAPP_H_
|
||||
|
||||
#include "talk/base/thread.h"
|
||||
#include "talk/base/scoped_ptr.h"
|
||||
|
||||
#include "talk/xmpp/jid.h"
|
||||
#include "talk/xmpp/xmppclient.h"
|
||||
|
||||
namespace buzz {
|
||||
class XmppClient;
|
||||
class PresenceOutTask;
|
||||
class PresenceReceiveTask;
|
||||
class TextChatSendTask;
|
||||
class TextChatReceiveTask;
|
||||
class ConsoleTask;
|
||||
class PresenceStatus;
|
||||
}
|
||||
|
||||
// This is an example chat app for libjingle, showing how to use xmpp tasks,
|
||||
// data, callbacks, etc. It has a simple text-based UI for logging in,
|
||||
// sending and receiving messages, and printing the roster.
|
||||
class ChatApp: public sigslot::has_slots<> {
|
||||
public:
|
||||
// Arguments:
|
||||
// xmpp_client Points to the XmppClient for the communication channel
|
||||
// (typically created by the XmppPump object).
|
||||
// main_thread Wraps the application's main thread. Subsidiary threads
|
||||
// for the various tasks will be forked off of this.
|
||||
ChatApp(buzz::XmppClient* xmpp_client, talk_base::Thread* main_thread);
|
||||
|
||||
// Shuts down and releases all of the contained tasks/threads
|
||||
~ChatApp();
|
||||
|
||||
// Shuts down the current thread and quits
|
||||
void Quit();
|
||||
|
||||
private:
|
||||
//
|
||||
// Initialization
|
||||
//
|
||||
// Called explicitly after the connection to the chat server is established.
|
||||
void OnXmppOpen();
|
||||
|
||||
//
|
||||
// UI Stuff
|
||||
//
|
||||
// Prints the app main menu on the console.
|
||||
// Called when ui_state_ == STATE_BASE.
|
||||
void PrintMenu();
|
||||
|
||||
// Prints a numbered list of the logged-in user's roster on the console.
|
||||
void PrintRoster();
|
||||
|
||||
// Prints a prompt for the user to enter either the index from the
|
||||
// roster list of the user they wish to chat with, or a fully-qualified
|
||||
// (user@server.ext) jid.
|
||||
// Called when when ui_state_ == STATE_PROMPTJID.
|
||||
void PromptJid();
|
||||
|
||||
// Prints a prompt on the console for the user to enter a message to send.
|
||||
// Called when when ui_state_ == STATE_CHATTING.
|
||||
void PromptChatMessage();
|
||||
|
||||
// Sends our presence state to the chat server (and on to your roster list).
|
||||
// Arguments:
|
||||
// state Specifies the presence state to show.
|
||||
enum PresenceState {online, away};
|
||||
void BroadcastPresence(PresenceState state);
|
||||
|
||||
// Returns the RosterItem associated with the specified index.
|
||||
// Just a helper to select a roster item from a numbered list in the UI.
|
||||
bool GetRosterItem(int index, buzz::PresenceStatus* status);
|
||||
|
||||
//
|
||||
// Input Handling
|
||||
//
|
||||
// Receives input when ui_state_ == STATE_BASE. Handles choices from the
|
||||
// main menu.
|
||||
void HandleBaseInput(const std::string& message);
|
||||
|
||||
// Receives input when ui_state_ == STATE_PROMPTJID. Handles selection
|
||||
// of a JID to chat to.
|
||||
void HandleJidInput(const std::string& message);
|
||||
|
||||
// Receives input when ui_state_ == STATE_CHATTING. Handles text messages.
|
||||
void HandleChatInput(const std::string& message);
|
||||
|
||||
//
|
||||
// signal/slot Callbacks
|
||||
//
|
||||
// Connected to the XmppClient::SignalStateChange slot. Receives
|
||||
// notifications of state changes of the connection.
|
||||
void OnStateChange(buzz::XmppEngine::State state);
|
||||
|
||||
// Connected to the PresenceReceiveTask::PresenceUpdate slot.
|
||||
// Receives status messages for the logged-in user's roster (i.e.
|
||||
// an initial list from the server and people coming/going).
|
||||
void OnPresenceUpdate(const buzz::PresenceStatus& status);
|
||||
|
||||
// Connected to the TextChatReceiveTask::SignalTextChatReceived slot.
|
||||
// Called when we receive a text chat from someone else.
|
||||
void OnTextMessage(const buzz::Jid& from, const buzz::Jid& to,
|
||||
const std::string& message);
|
||||
|
||||
// Receives text input from the console task. This is where any input
|
||||
// from the user comes in.
|
||||
// Arguments:
|
||||
// message What the user typed.
|
||||
void OnConsoleMessage(const std::string &message);
|
||||
|
||||
// The XmppClient object associated with this chat application instance.
|
||||
buzz::XmppClient* xmpp_client_;
|
||||
|
||||
// We send presence information through this object.
|
||||
talk_base::scoped_ptr<buzz::PresenceOutTask> presence_out_task_;
|
||||
|
||||
// We receive others presence information through this object.
|
||||
talk_base::scoped_ptr<buzz::PresenceReceiveTask> presence_receive_task_;
|
||||
|
||||
// We send text messages though this object.
|
||||
talk_base::scoped_ptr<buzz::TextChatSendTask> message_send_task_;
|
||||
|
||||
// We receive messages through this object.
|
||||
talk_base::scoped_ptr<buzz::TextChatReceiveTask> message_received_task_;
|
||||
|
||||
// UI gets drawn and receives input through this task.
|
||||
talk_base::scoped_ptr< buzz::ConsoleTask> console_task_;
|
||||
|
||||
// The list of JIDs for the people in the logged-in users roster.
|
||||
// RosterList roster_list_;
|
||||
typedef std::map<std::string, buzz::PresenceStatus> RosterList;
|
||||
RosterList roster_list_;
|
||||
|
||||
// The JID of the user currently being chatted with.
|
||||
buzz::Jid chat_dest_jid_;
|
||||
|
||||
// UI State constants
|
||||
enum UIState { STATE_BASE, STATE_PROMPTJID, STATE_CHATTING };
|
||||
UIState ui_state_;
|
||||
};
|
||||
|
||||
#endif // TALK_EXAMPLES_CHAT_CHATAPP_H_
|
||||
|
@ -1,177 +0,0 @@
|
||||
/*
|
||||
* libjingle
|
||||
* Copyright 2004--2013, 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.
|
||||
*/
|
||||
|
||||
// TODO(pmclean): Perhaps this should be unified with examples/call/console.cc
|
||||
// and refactor to talk/base.
|
||||
#include "talk/examples/chat/consoletask.h"
|
||||
|
||||
#define _CRT_SECURE_NO_DEPRECATE 1
|
||||
|
||||
#include <stdarg.h>
|
||||
#ifdef POSIX
|
||||
#include <signal.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
#endif // POSIX
|
||||
#include <cassert>
|
||||
|
||||
#include "talk/base/logging.h"
|
||||
|
||||
#ifdef POSIX
|
||||
static void DoNothing(int unused) {}
|
||||
#endif
|
||||
|
||||
namespace buzz {
|
||||
|
||||
ConsoleTask::ConsoleTask(talk_base::Thread *thread) :
|
||||
client_thread_(thread),
|
||||
console_thread_(new talk_base::Thread()) {
|
||||
}
|
||||
|
||||
ConsoleTask::~ConsoleTask() {
|
||||
Stop();
|
||||
}
|
||||
|
||||
void ConsoleTask::Start() {
|
||||
if (!console_thread_) {
|
||||
// stdin was closed in Stop(), so we can't restart.
|
||||
LOG(LS_ERROR) << "Cannot re-start";
|
||||
return;
|
||||
}
|
||||
if (console_thread_->started()) {
|
||||
LOG(LS_WARNING) << "Already started";
|
||||
return;
|
||||
}
|
||||
console_thread_->Start();
|
||||
console_thread_->Post(this, MSG_START);
|
||||
}
|
||||
|
||||
void ConsoleTask::Stop() {
|
||||
if (console_thread_ && console_thread_->started()) {
|
||||
#ifdef WIN32
|
||||
CloseHandle(GetStdHandle(STD_INPUT_HANDLE));
|
||||
#else
|
||||
close(fileno(stdin));
|
||||
// This forces the read() in fgets() to return with errno = EINTR. fgets()
|
||||
// will retry the read() and fail, thus returning.
|
||||
pthread_kill(console_thread_->GetPThread(), SIGUSR1);
|
||||
#endif
|
||||
console_thread_->Stop();
|
||||
console_thread_.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void ConsoleTask::SetEcho(bool on) {
|
||||
#ifdef WIN32
|
||||
HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE);
|
||||
if ((hIn == INVALID_HANDLE_VALUE) || (hIn == NULL))
|
||||
return;
|
||||
|
||||
DWORD mode;
|
||||
if (!GetConsoleMode(hIn, &mode))
|
||||
return;
|
||||
|
||||
if (on) {
|
||||
mode = mode | ENABLE_ECHO_INPUT;
|
||||
} else {
|
||||
mode = mode & ~ENABLE_ECHO_INPUT;
|
||||
}
|
||||
|
||||
SetConsoleMode(hIn, mode);
|
||||
#else // MAC & LINUX
|
||||
const int fd = fileno(stdin);
|
||||
if (fd == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct termios tcflags;
|
||||
if (tcgetattr(fd, &tcflags) == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (on) {
|
||||
tcflags.c_lflag |= ECHO;
|
||||
} else {
|
||||
tcflags.c_lflag &= ~ECHO;
|
||||
}
|
||||
|
||||
tcsetattr(fd, TCSANOW, &tcflags);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ConsoleTask::Print(const char* format, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
|
||||
char buf[4096];
|
||||
int size = vsnprintf(buf, sizeof(buf), format, ap);
|
||||
assert(size >= 0);
|
||||
assert(size < static_cast<int>(sizeof(buf)));
|
||||
buf[size] = '\0';
|
||||
printf("%s", buf);
|
||||
fflush(stdout);
|
||||
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void ConsoleTask::RunConsole() {
|
||||
char input_buffer[128];
|
||||
while (fgets(input_buffer, sizeof(input_buffer), stdin) != NULL) {
|
||||
client_thread_->Post(this, MSG_INPUT,
|
||||
new talk_base::TypedMessageData<std::string>(input_buffer));
|
||||
}
|
||||
}
|
||||
|
||||
void ConsoleTask::OnMessage(talk_base::Message *msg) {
|
||||
switch (msg->message_id) {
|
||||
case MSG_START:
|
||||
#ifdef POSIX
|
||||
// Install a no-op signal so that we can abort RunConsole() by raising
|
||||
// SIGUSR1.
|
||||
struct sigaction act;
|
||||
act.sa_handler = &DoNothing;
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_flags = 0;
|
||||
if (sigaction(SIGUSR1, &act, NULL) < 0) {
|
||||
LOG(LS_WARNING) << "Can't install signal";
|
||||
}
|
||||
#endif
|
||||
RunConsole();
|
||||
break;
|
||||
|
||||
case MSG_INPUT:
|
||||
talk_base::TypedMessageData<std::string> *data =
|
||||
static_cast<talk_base::TypedMessageData<std::string>*>(msg->pdata);
|
||||
// Trim off the .line-terminator to make processing easier.
|
||||
std::string parsed_message =
|
||||
data->data().substr(0, data->data().length() - 1);
|
||||
TextInputHandler(parsed_message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace buzz
|
@ -1,92 +0,0 @@
|
||||
/*
|
||||
* libjingle
|
||||
* Copyright 2004--2013, 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.
|
||||
*/
|
||||
|
||||
#ifndef TALK_EXAMPLES_CHAT_CONSOLETASK_H_
|
||||
#define TALK_EXAMPLES_CHAT_CONSOLETASK_H_
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
#include "talk/base/thread.h"
|
||||
#include "talk/base/sigslot.h"
|
||||
|
||||
namespace buzz {
|
||||
|
||||
//
|
||||
// Provides properly threaded console I/O.
|
||||
//
|
||||
class ConsoleTask : public talk_base::MessageHandler {
|
||||
public:
|
||||
// Arguments:
|
||||
// thread The main application thread. Input messages get posted through
|
||||
// this.
|
||||
explicit ConsoleTask(talk_base::Thread *thread);
|
||||
|
||||
// Shuts down the thread associated with this task.
|
||||
~ConsoleTask();
|
||||
|
||||
// Slot for text inputs handler.
|
||||
sigslot::signal1<const std::string&> TextInputHandler;
|
||||
|
||||
// Starts reading lines from the console and passes them to the
|
||||
// TextInputHandler.
|
||||
void Start();
|
||||
|
||||
// Stops reading lines and shuts down the thread. Cannot be restarted.
|
||||
void Stop();
|
||||
|
||||
// Thread messages (especialy text-input messages) come in through here.
|
||||
virtual void OnMessage(talk_base::Message *msg);
|
||||
|
||||
// printf() style output to the console.
|
||||
void Print(const char* format, ...);
|
||||
|
||||
// Turns on/off the echo of input characters on the console.
|
||||
// Arguments:
|
||||
// on If true turns echo on, off otherwise.
|
||||
static void SetEcho(bool on);
|
||||
|
||||
private:
|
||||
/** Message IDs (for OnMessage()). */
|
||||
enum {
|
||||
MSG_START,
|
||||
MSG_INPUT,
|
||||
};
|
||||
|
||||
// Starts up polling for console input
|
||||
void RunConsole();
|
||||
|
||||
// The main application thread
|
||||
talk_base::Thread *client_thread_;
|
||||
|
||||
// The tread associated with this console object
|
||||
talk_base::scoped_ptr<talk_base::Thread> console_thread_;
|
||||
};
|
||||
|
||||
} // namespace buzz
|
||||
|
||||
#endif // TALK_EXAMPLES_CHAT_CONSOLETASK_H_
|
||||
|
@ -1,66 +0,0 @@
|
||||
/*
|
||||
* libjingle
|
||||
* Copyright 2004--2013, 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 "talk/examples/chat/textchatreceivetask.h"
|
||||
|
||||
#include "talk/xmpp/constants.h"
|
||||
|
||||
namespace buzz {
|
||||
|
||||
TextChatReceiveTask::TextChatReceiveTask(XmppTaskParentInterface* parent)
|
||||
: XmppTask(parent, XmppEngine::HL_TYPE) {
|
||||
}
|
||||
|
||||
TextChatReceiveTask::~TextChatReceiveTask() {
|
||||
Stop();
|
||||
}
|
||||
|
||||
bool TextChatReceiveTask::HandleStanza(const XmlElement* stanza) {
|
||||
// Make sure that this stanza is a message
|
||||
if (stanza->Name() != QN_MESSAGE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// see if there is any body
|
||||
const XmlElement* message_body = stanza->FirstNamed(QN_BODY);
|
||||
if (message_body == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Looks good, so send the message text along.
|
||||
SignalTextChatReceived(Jid(stanza->Attr(QN_FROM)), Jid(stanza->Attr(QN_TO)),
|
||||
message_body->BodyText());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int TextChatReceiveTask::ProcessStart() {
|
||||
// not queuing messages, so just block.
|
||||
return STATE_BLOCKED;
|
||||
}
|
||||
|
||||
} // namespace buzz
|
@ -1,63 +0,0 @@
|
||||
/*
|
||||
* libjingle
|
||||
* Copyright 2004--2013, 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.
|
||||
*/
|
||||
|
||||
#ifndef TALK_EXAMPLES_CHAT_TEXTCHATRECEIVETASK_H_
|
||||
#define TALK_EXAMPLES_CHAT_TEXTCHATRECEIVETASK_H_
|
||||
|
||||
#include "talk/base/sigslot.h"
|
||||
#include "talk/xmpp/xmpptask.h"
|
||||
|
||||
namespace buzz {
|
||||
|
||||
// A class to receive chat messages from the XMPP server.
|
||||
class TextChatReceiveTask : public XmppTask {
|
||||
public:
|
||||
// Arguments:
|
||||
// parent a reference to task interface associated withe the XMPP client.
|
||||
explicit TextChatReceiveTask(XmppTaskParentInterface* parent);
|
||||
|
||||
// Shuts down the thread associated with this task.
|
||||
virtual ~TextChatReceiveTask();
|
||||
|
||||
// Starts pulling queued status messages and dispatching them to the
|
||||
// PresenceUpdate() callback.
|
||||
virtual int ProcessStart();
|
||||
|
||||
// Slot for chat message callbacks
|
||||
sigslot::signal3<const Jid&, const Jid&, const std::string&>
|
||||
SignalTextChatReceived;
|
||||
|
||||
protected:
|
||||
// Called by the XMPP client when chat stanzas arrive. We pull out the
|
||||
// interesting parts and send them to the SignalTextCharReceived() slot.
|
||||
virtual bool HandleStanza(const XmlElement* stanza);
|
||||
};
|
||||
|
||||
} // namespace buzz
|
||||
|
||||
#endif // TALK_EXAMPLES_CHAT_TEXTCHATRECEIVETASK_H_
|
||||
|
@ -1,81 +0,0 @@
|
||||
/*
|
||||
* libjingle
|
||||
* Copyright 2004--2013, 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 "talk/examples/chat/textchatsendtask.h"
|
||||
|
||||
#include "talk/xmpp/constants.h"
|
||||
#include "talk/xmpp/xmppclient.h"
|
||||
|
||||
namespace buzz {
|
||||
TextChatSendTask::TextChatSendTask(XmppTaskParentInterface* parent)
|
||||
: XmppTask(parent) {
|
||||
}
|
||||
|
||||
TextChatSendTask::~TextChatSendTask() {
|
||||
Stop();
|
||||
}
|
||||
|
||||
XmppReturnStatus TextChatSendTask::Send(const Jid& to,
|
||||
const std::string& textmessage) {
|
||||
// Make sure we are actually connected.
|
||||
if (GetState() != STATE_INIT && GetState() != STATE_START) {
|
||||
return XMPP_RETURN_BADSTATE;
|
||||
}
|
||||
|
||||
// Put together the chat stanza...
|
||||
XmlElement* message_stanza = new XmlElement(QN_MESSAGE);
|
||||
|
||||
// ... and specify the required attributes...
|
||||
message_stanza->AddAttr(QN_TO, to.Str());
|
||||
message_stanza->AddAttr(QN_TYPE, "chat");
|
||||
message_stanza->AddAttr(QN_LANG, "en");
|
||||
|
||||
// ... and fill out the body.
|
||||
XmlElement* message_body = new XmlElement(QN_BODY);
|
||||
message_body->AddText(textmessage);
|
||||
message_stanza->AddElement(message_body);
|
||||
|
||||
// Now queue it up.
|
||||
QueueStanza(message_stanza);
|
||||
|
||||
return XMPP_RETURN_OK;
|
||||
}
|
||||
|
||||
int TextChatSendTask::ProcessStart() {
|
||||
const XmlElement* stanza = NextStanza();
|
||||
if (stanza == NULL) {
|
||||
return STATE_BLOCKED;
|
||||
}
|
||||
|
||||
if (SendStanza(stanza) != XMPP_RETURN_OK) {
|
||||
return STATE_ERROR;
|
||||
}
|
||||
|
||||
return STATE_START;
|
||||
}
|
||||
|
||||
} // namespace buzz
|
@ -1,56 +0,0 @@
|
||||
/*
|
||||
* libjingle
|
||||
* Copyright 2004--2013, 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.
|
||||
*/
|
||||
|
||||
#ifndef TALK_EXAMPLES_CHAT_TEXTCHATSENDTASK_H_
|
||||
#define TALK_EXAMPLES_CHAT_TEXTCHATSENDTASK_H_
|
||||
|
||||
#include "talk/xmpp/xmpptask.h"
|
||||
|
||||
namespace buzz {
|
||||
|
||||
// A class to send chat messages to the XMPP server.
|
||||
class TextChatSendTask : public XmppTask {
|
||||
public:
|
||||
// Arguments:
|
||||
// parent a reference to task interface associated withe the XMPP client.
|
||||
explicit TextChatSendTask(XmppTaskParentInterface* parent);
|
||||
|
||||
// Shuts down the thread associated with this task.
|
||||
virtual ~TextChatSendTask();
|
||||
|
||||
// Forms the XMPP "chat" stanza with the specified receipient and message
|
||||
// and queues it up.
|
||||
XmppReturnStatus Send(const Jid& to, const std::string& message);
|
||||
|
||||
// Picks up any "chat" stanzas from our queue and sends them to the server.
|
||||
virtual int ProcessStart();
|
||||
};
|
||||
|
||||
} // namespace buzz
|
||||
|
||||
#endif // TALK_EXAMPLES_CHAT_TEXTCHATSENDTASK_H_
|
||||
|
@ -1,715 +0,0 @@
|
||||
#define _CRT_SECURE_NO_DEPRECATE 1
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#if defined(POSIX)
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#if HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif // HAVE_CONFIG_H
|
||||
|
||||
#include "talk/base/sslconfig.h" // For SSL_USE_*
|
||||
|
||||
#if SSL_USE_OPENSSL
|
||||
#define USE_SSL_TUNNEL
|
||||
#endif
|
||||
|
||||
#include "talk/base/basicdefs.h"
|
||||
#include "talk/base/common.h"
|
||||
#include "talk/base/helpers.h"
|
||||
#include "talk/base/logging.h"
|
||||
#include "talk/base/ssladapter.h"
|
||||
#include "talk/base/stringutils.h"
|
||||
#include "talk/base/thread.h"
|
||||
#include "talk/p2p/base/sessionmanager.h"
|
||||
#include "talk/p2p/client/autoportallocator.h"
|
||||
#include "talk/p2p/client/sessionmanagertask.h"
|
||||
#include "talk/xmpp/xmppengine.h"
|
||||
#ifdef USE_SSL_TUNNEL
|
||||
#include "talk/session/tunnel/securetunnelsessionclient.h"
|
||||
#endif
|
||||
#include "talk/session/tunnel/tunnelsessionclient.h"
|
||||
#include "talk/xmpp/xmppclient.h"
|
||||
#include "talk/xmpp/xmppclientsettings.h"
|
||||
#include "talk/xmpp/xmpppump.h"
|
||||
#include "talk/xmpp/xmppsocket.h"
|
||||
|
||||
#ifndef MAX_PATH
|
||||
#define MAX_PATH 256
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER < 1400)
|
||||
// The following are necessary to properly link when compiling STL without
|
||||
// /EHsc, otherwise known as C++ exceptions.
|
||||
void __cdecl std::_Throw(const std::exception &) {}
|
||||
std::_Prhand std::_Raise_handler = 0;
|
||||
#endif
|
||||
|
||||
enum {
|
||||
MSG_LOGIN_COMPLETE = 1,
|
||||
MSG_LOGIN_FAILED,
|
||||
MSG_DONE,
|
||||
};
|
||||
|
||||
buzz::Jid gUserJid;
|
||||
talk_base::InsecureCryptStringImpl gUserPass;
|
||||
std::string gXmppHost = "talk.google.com";
|
||||
int gXmppPort = 5222;
|
||||
buzz::TlsOptions gXmppUseTls = buzz::TLS_REQUIRED;
|
||||
|
||||
class DebugLog : public sigslot::has_slots<> {
|
||||
public:
|
||||
DebugLog() :
|
||||
debug_input_buf_(NULL), debug_input_len_(0), debug_input_alloc_(0),
|
||||
debug_output_buf_(NULL), debug_output_len_(0), debug_output_alloc_(0),
|
||||
censor_password_(false)
|
||||
{}
|
||||
char * debug_input_buf_;
|
||||
int debug_input_len_;
|
||||
int debug_input_alloc_;
|
||||
char * debug_output_buf_;
|
||||
int debug_output_len_;
|
||||
int debug_output_alloc_;
|
||||
bool censor_password_;
|
||||
|
||||
void Input(const char * data, int len) {
|
||||
if (debug_input_len_ + len > debug_input_alloc_) {
|
||||
char * old_buf = debug_input_buf_;
|
||||
debug_input_alloc_ = 4096;
|
||||
while (debug_input_alloc_ < debug_input_len_ + len) {
|
||||
debug_input_alloc_ *= 2;
|
||||
}
|
||||
debug_input_buf_ = new char[debug_input_alloc_];
|
||||
memcpy(debug_input_buf_, old_buf, debug_input_len_);
|
||||
delete[] old_buf;
|
||||
}
|
||||
memcpy(debug_input_buf_ + debug_input_len_, data, len);
|
||||
debug_input_len_ += len;
|
||||
DebugPrint(debug_input_buf_, &debug_input_len_, false);
|
||||
}
|
||||
|
||||
void Output(const char * data, int len) {
|
||||
if (debug_output_len_ + len > debug_output_alloc_) {
|
||||
char * old_buf = debug_output_buf_;
|
||||
debug_output_alloc_ = 4096;
|
||||
while (debug_output_alloc_ < debug_output_len_ + len) {
|
||||
debug_output_alloc_ *= 2;
|
||||
}
|
||||
debug_output_buf_ = new char[debug_output_alloc_];
|
||||
memcpy(debug_output_buf_, old_buf, debug_output_len_);
|
||||
delete[] old_buf;
|
||||
}
|
||||
memcpy(debug_output_buf_ + debug_output_len_, data, len);
|
||||
debug_output_len_ += len;
|
||||
DebugPrint(debug_output_buf_, &debug_output_len_, true);
|
||||
}
|
||||
|
||||
static bool
|
||||
IsAuthTag(const char * str, size_t len) {
|
||||
if (str[0] == '<' && str[1] == 'a' &&
|
||||
str[2] == 'u' &&
|
||||
str[3] == 't' &&
|
||||
str[4] == 'h' &&
|
||||
str[5] <= ' ') {
|
||||
std::string tag(str, len);
|
||||
|
||||
if (tag.find("mechanism") != std::string::npos)
|
||||
return true;
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
DebugPrint(char * buf, int * plen, bool output) {
|
||||
int len = *plen;
|
||||
if (len > 0) {
|
||||
time_t tim = time(NULL);
|
||||
struct tm * now = localtime(&tim);
|
||||
char *time_string = asctime(now);
|
||||
if (time_string) {
|
||||
size_t time_len = strlen(time_string);
|
||||
if (time_len > 0) {
|
||||
time_string[time_len-1] = 0; // trim off terminating \n
|
||||
}
|
||||
}
|
||||
LOG(INFO) << (output ? "SEND >>>>>>>>>>>>>>>>>>>>>>>>>" : "RECV <<<<<<<<<<<<<<<<<<<<<<<<<")
|
||||
<< " : " << time_string;
|
||||
|
||||
bool indent;
|
||||
int start = 0, nest = 3;
|
||||
for (int i = 0; i < len; i += 1) {
|
||||
if (buf[i] == '>') {
|
||||
if ((i > 0) && (buf[i-1] == '/')) {
|
||||
indent = false;
|
||||
} else if ((start + 1 < len) && (buf[start + 1] == '/')) {
|
||||
indent = false;
|
||||
nest -= 2;
|
||||
} else {
|
||||
indent = true;
|
||||
}
|
||||
|
||||
// Output a tag
|
||||
LOG(INFO) << std::setw(nest) << " " << std::string(buf + start, i + 1 - start);
|
||||
|
||||
if (indent)
|
||||
nest += 2;
|
||||
|
||||
// Note if it's a PLAIN auth tag
|
||||
if (IsAuthTag(buf + start, i + 1 - start)) {
|
||||
censor_password_ = true;
|
||||
}
|
||||
|
||||
// incr
|
||||
start = i + 1;
|
||||
}
|
||||
|
||||
if (buf[i] == '<' && start < i) {
|
||||
if (censor_password_) {
|
||||
LOG(INFO) << std::setw(nest) << " " << "## TEXT REMOVED ##";
|
||||
censor_password_ = false;
|
||||
}
|
||||
else {
|
||||
LOG(INFO) << std::setw(nest) << " " << std::string(buf + start, i - start);
|
||||
}
|
||||
start = i;
|
||||
}
|
||||
}
|
||||
len = len - start;
|
||||
memcpy(buf, buf + start, len);
|
||||
*plen = len;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
static DebugLog debug_log_;
|
||||
|
||||
// Prints out a usage message then exits.
|
||||
void Usage() {
|
||||
std::cerr << "Usage:" << std::endl;
|
||||
std::cerr << " pcp [options] <my_jid> (server mode)" << std::endl;
|
||||
std::cerr << " pcp [options] <my_jid> <src_file> <dst_full_jid>:<dst_file> (client sending)" << std::endl;
|
||||
std::cerr << " pcp [options] <my_jid> <src_full_jid>:<src_file> <dst_file> (client rcv'ing)" << std::endl;
|
||||
std::cerr << " --verbose" << std::endl;
|
||||
std::cerr << " --xmpp-host=<host>" << std::endl;
|
||||
std::cerr << " --xmpp-port=<port>" << std::endl;
|
||||
std::cerr << " --xmpp-use-tls=(true|false)" << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Prints out an error message, a usage message, then exits.
|
||||
void Error(const std::string& msg) {
|
||||
std::cerr << "error: " << msg << std::endl;
|
||||
std::cerr << std::endl;
|
||||
Usage();
|
||||
}
|
||||
|
||||
void FatalError(const std::string& msg) {
|
||||
std::cerr << "error: " << msg << std::endl;
|
||||
std::cerr << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Determines whether the given string is an option. If so, the name and
|
||||
// value are appended to the given strings.
|
||||
bool ParseArg(const char* arg, std::string* name, std::string* value) {
|
||||
if (strncmp(arg, "--", 2) != 0)
|
||||
return false;
|
||||
|
||||
const char* eq = strchr(arg + 2, '=');
|
||||
if (eq) {
|
||||
if (name)
|
||||
name->append(arg + 2, eq);
|
||||
if (value)
|
||||
value->append(eq + 1, arg + strlen(arg));
|
||||
} else {
|
||||
if (name)
|
||||
name->append(arg + 2, arg + strlen(arg));
|
||||
if (value)
|
||||
value->clear();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int ParseIntArg(const std::string& name, const std::string& value) {
|
||||
char* end;
|
||||
long val = strtol(value.c_str(), &end, 10);
|
||||
if (*end != '\0')
|
||||
Error(std::string("value of option ") + name + " must be an integer");
|
||||
return static_cast<int>(val);
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
#pragma warning(push)
|
||||
// disable "unreachable code" warning b/c it varies between dbg and opt
|
||||
#pragma warning(disable: 4702)
|
||||
#endif
|
||||
bool ParseBoolArg(const std::string& name, const std::string& value) {
|
||||
if (value == "true")
|
||||
return true;
|
||||
else if (value == "false")
|
||||
return false;
|
||||
else {
|
||||
Error(std::string("value of option ") + name + " must be true or false");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#ifdef WIN32
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
void ParseFileArg(const char* arg, buzz::Jid* jid, std::string* file) {
|
||||
const char* sep = strchr(arg, ':');
|
||||
if (!sep) {
|
||||
*file = arg;
|
||||
} else {
|
||||
buzz::Jid jid_arg(std::string(arg, sep-arg));
|
||||
if (jid_arg.IsBare())
|
||||
Error("A full JID is required for the source or destination arguments.");
|
||||
*jid = jid_arg;
|
||||
*file = std::string(sep+1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SetConsoleEcho(bool on) {
|
||||
#ifdef WIN32
|
||||
HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE);
|
||||
if ((hIn == INVALID_HANDLE_VALUE) || (hIn == NULL))
|
||||
return;
|
||||
|
||||
DWORD mode;
|
||||
if (!GetConsoleMode(hIn, &mode))
|
||||
return;
|
||||
|
||||
if (on) {
|
||||
mode = mode | ENABLE_ECHO_INPUT;
|
||||
} else {
|
||||
mode = mode & ~ENABLE_ECHO_INPUT;
|
||||
}
|
||||
|
||||
SetConsoleMode(hIn, mode);
|
||||
#else
|
||||
int re;
|
||||
if (on)
|
||||
re = system("stty echo");
|
||||
else
|
||||
re = system("stty -echo");
|
||||
if (-1 == re)
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Fills in a settings object with the values from the arguments.
|
||||
buzz::XmppClientSettings LoginSettings() {
|
||||
buzz::XmppClientSettings xcs;
|
||||
xcs.set_user(gUserJid.node());
|
||||
xcs.set_host(gUserJid.domain());
|
||||
xcs.set_resource("pcp");
|
||||
xcs.set_pass(talk_base::CryptString(gUserPass));
|
||||
talk_base::SocketAddress server(gXmppHost, gXmppPort);
|
||||
xcs.set_server(server);
|
||||
xcs.set_use_tls(gXmppUseTls);
|
||||
return xcs;
|
||||
}
|
||||
|
||||
// Runs the current thread until a message with the given ID is seen.
|
||||
uint32 Loop(const std::vector<uint32>& ids) {
|
||||
talk_base::Message msg;
|
||||
while (talk_base::Thread::Current()->Get(&msg)) {
|
||||
if (msg.phandler == NULL) {
|
||||
if (std::find(ids.begin(), ids.end(), msg.message_id) != ids.end())
|
||||
return msg.message_id;
|
||||
std::cout << "orphaned message: " << msg.message_id;
|
||||
continue;
|
||||
}
|
||||
talk_base::Thread::Current()->Dispatch(&msg);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
#pragma warning(disable:4355)
|
||||
#endif
|
||||
|
||||
class CustomXmppPump : public buzz::XmppPumpNotify, public buzz::XmppPump {
|
||||
public:
|
||||
CustomXmppPump() : XmppPump(this), server_(false) { }
|
||||
|
||||
void Serve(cricket::TunnelSessionClient* client) {
|
||||
client->SignalIncomingTunnel.connect(this,
|
||||
&CustomXmppPump::OnIncomingTunnel);
|
||||
server_ = true;
|
||||
}
|
||||
|
||||
void OnStateChange(buzz::XmppEngine::State state) {
|
||||
switch (state) {
|
||||
case buzz::XmppEngine::STATE_START:
|
||||
std::cout << "connecting..." << std::endl;
|
||||
break;
|
||||
case buzz::XmppEngine::STATE_OPENING:
|
||||
std::cout << "logging in..." << std::endl;
|
||||
break;
|
||||
case buzz::XmppEngine::STATE_OPEN:
|
||||
std::cout << "logged in..." << std::endl;
|
||||
talk_base::Thread::Current()->Post(NULL, MSG_LOGIN_COMPLETE);
|
||||
break;
|
||||
case buzz::XmppEngine::STATE_CLOSED:
|
||||
std::cout << "logged out..." << std::endl;
|
||||
talk_base::Thread::Current()->Post(NULL, MSG_LOGIN_FAILED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void OnIncomingTunnel(cricket::TunnelSessionClient* client, buzz::Jid jid,
|
||||
std::string description, cricket::Session* session) {
|
||||
std::cout << "IncomingTunnel from " << jid.Str()
|
||||
<< ": " << description << std::endl;
|
||||
if (!server_ || file_) {
|
||||
client->DeclineTunnel(session);
|
||||
return;
|
||||
}
|
||||
std::string filename;
|
||||
bool send;
|
||||
if (strncmp(description.c_str(), "send:", 5) == 0) {
|
||||
send = true;
|
||||
} else if (strncmp(description.c_str(), "recv:", 5) == 0) {
|
||||
send = false;
|
||||
} else {
|
||||
client->DeclineTunnel(session);
|
||||
return;
|
||||
}
|
||||
filename = description.substr(5);
|
||||
talk_base::StreamInterface* stream = client->AcceptTunnel(session);
|
||||
if (!ProcessStream(stream, filename, send))
|
||||
talk_base::Thread::Current()->Post(NULL, MSG_DONE);
|
||||
|
||||
// TODO: There is a potential memory leak, however, since the PCP
|
||||
// app doesn't work right now, I can't verify the fix actually works, so
|
||||
// comment out the following line until we fix the PCP app.
|
||||
|
||||
// delete stream;
|
||||
}
|
||||
|
||||
bool ProcessStream(talk_base::StreamInterface* stream,
|
||||
const std::string& filename, bool send) {
|
||||
ASSERT(file_);
|
||||
sending_ = send;
|
||||
file_.reset(new talk_base::FileStream);
|
||||
buffer_len_ = 0;
|
||||
int err;
|
||||
if (!file_->Open(filename.c_str(), sending_ ? "rb" : "wb", &err)) {
|
||||
std::cerr << "Error opening <" << filename << ">: "
|
||||
<< std::strerror(err) << std::endl;
|
||||
return false;
|
||||
}
|
||||
stream->SignalEvent.connect(this, &CustomXmppPump::OnStreamEvent);
|
||||
if (stream->GetState() == talk_base::SS_CLOSED) {
|
||||
std::cerr << "Failed to establish P2P tunnel" << std::endl;
|
||||
return false;
|
||||
}
|
||||
if (stream->GetState() == talk_base::SS_OPEN) {
|
||||
OnStreamEvent(stream,
|
||||
talk_base::SE_OPEN | talk_base::SE_READ | talk_base::SE_WRITE, 0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void OnStreamEvent(talk_base::StreamInterface* stream, int events,
|
||||
int error) {
|
||||
if (events & talk_base::SE_CLOSE) {
|
||||
if (error == 0) {
|
||||
std::cout << "Tunnel closed normally" << std::endl;
|
||||
} else {
|
||||
std::cout << "Tunnel closed with error: " << error << std::endl;
|
||||
}
|
||||
Cleanup(stream);
|
||||
return;
|
||||
}
|
||||
if (events & talk_base::SE_OPEN) {
|
||||
std::cout << "Tunnel connected" << std::endl;
|
||||
}
|
||||
talk_base::StreamResult result;
|
||||
size_t count;
|
||||
if (sending_ && (events & talk_base::SE_WRITE)) {
|
||||
LOG(LS_VERBOSE) << "Tunnel SE_WRITE";
|
||||
while (true) {
|
||||
size_t write_pos = 0;
|
||||
while (write_pos < buffer_len_) {
|
||||
result = stream->Write(buffer_ + write_pos, buffer_len_ - write_pos,
|
||||
&count, &error);
|
||||
if (result == talk_base::SR_SUCCESS) {
|
||||
write_pos += count;
|
||||
continue;
|
||||
}
|
||||
if (result == talk_base::SR_BLOCK) {
|
||||
buffer_len_ -= write_pos;
|
||||
memmove(buffer_, buffer_ + write_pos, buffer_len_);
|
||||
LOG(LS_VERBOSE) << "Tunnel write block";
|
||||
return;
|
||||
}
|
||||
if (result == talk_base::SR_EOS) {
|
||||
std::cout << "Tunnel closed unexpectedly on write" << std::endl;
|
||||
} else {
|
||||
std::cout << "Tunnel write error: " << error << std::endl;
|
||||
}
|
||||
Cleanup(stream);
|
||||
return;
|
||||
}
|
||||
buffer_len_ = 0;
|
||||
while (buffer_len_ < sizeof(buffer_)) {
|
||||
result = file_->Read(buffer_ + buffer_len_,
|
||||
sizeof(buffer_) - buffer_len_,
|
||||
&count, &error);
|
||||
if (result == talk_base::SR_SUCCESS) {
|
||||
buffer_len_ += count;
|
||||
continue;
|
||||
}
|
||||
if (result == talk_base::SR_EOS) {
|
||||
if (buffer_len_ > 0)
|
||||
break;
|
||||
std::cout << "End of file" << std::endl;
|
||||
// A hack until we have friendly shutdown
|
||||
Cleanup(stream, true);
|
||||
return;
|
||||
} else if (result == talk_base::SR_BLOCK) {
|
||||
std::cout << "File blocked unexpectedly on read" << std::endl;
|
||||
} else {
|
||||
std::cout << "File read error: " << error << std::endl;
|
||||
}
|
||||
Cleanup(stream);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!sending_ && (events & talk_base::SE_READ)) {
|
||||
LOG(LS_VERBOSE) << "Tunnel SE_READ";
|
||||
while (true) {
|
||||
buffer_len_ = 0;
|
||||
while (buffer_len_ < sizeof(buffer_)) {
|
||||
result = stream->Read(buffer_ + buffer_len_,
|
||||
sizeof(buffer_) - buffer_len_,
|
||||
&count, &error);
|
||||
if (result == talk_base::SR_SUCCESS) {
|
||||
buffer_len_ += count;
|
||||
continue;
|
||||
}
|
||||
if (result == talk_base::SR_BLOCK) {
|
||||
if (buffer_len_ > 0)
|
||||
break;
|
||||
LOG(LS_VERBOSE) << "Tunnel read block";
|
||||
return;
|
||||
}
|
||||
if (result == talk_base::SR_EOS) {
|
||||
std::cout << "Tunnel closed unexpectedly on read" << std::endl;
|
||||
} else {
|
||||
std::cout << "Tunnel read error: " << error << std::endl;
|
||||
}
|
||||
Cleanup(stream);
|
||||
return;
|
||||
}
|
||||
size_t write_pos = 0;
|
||||
while (write_pos < buffer_len_) {
|
||||
result = file_->Write(buffer_ + write_pos, buffer_len_ - write_pos,
|
||||
&count, &error);
|
||||
if (result == talk_base::SR_SUCCESS) {
|
||||
write_pos += count;
|
||||
continue;
|
||||
}
|
||||
if (result == talk_base::SR_EOS) {
|
||||
std::cout << "File closed unexpectedly on write" << std::endl;
|
||||
} else if (result == talk_base::SR_BLOCK) {
|
||||
std::cout << "File blocked unexpectedly on write" << std::endl;
|
||||
} else {
|
||||
std::cout << "File write error: " << error << std::endl;
|
||||
}
|
||||
Cleanup(stream);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Cleanup(talk_base::StreamInterface* stream, bool delay = false) {
|
||||
LOG(LS_VERBOSE) << "Closing";
|
||||
stream->Close();
|
||||
file_.reset();
|
||||
if (!server_) {
|
||||
if (delay)
|
||||
talk_base::Thread::Current()->PostDelayed(2000, NULL, MSG_DONE);
|
||||
else
|
||||
talk_base::Thread::Current()->Post(NULL, MSG_DONE);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool server_, sending_;
|
||||
talk_base::scoped_ptr<talk_base::FileStream> file_;
|
||||
char buffer_[1024 * 64];
|
||||
size_t buffer_len_;
|
||||
};
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
talk_base::LogMessage::LogThreads();
|
||||
talk_base::LogMessage::LogTimestamps();
|
||||
|
||||
// TODO: Default the username to the current users's name.
|
||||
|
||||
// Parse the arguments.
|
||||
|
||||
int index = 1;
|
||||
while (index < argc) {
|
||||
std::string name, value;
|
||||
if (!ParseArg(argv[index], &name, &value))
|
||||
break;
|
||||
|
||||
if (name == "help") {
|
||||
Usage();
|
||||
} else if (name == "verbose") {
|
||||
talk_base::LogMessage::LogToDebug(talk_base::LS_VERBOSE);
|
||||
} else if (name == "xmpp-host") {
|
||||
gXmppHost = value;
|
||||
} else if (name == "xmpp-port") {
|
||||
gXmppPort = ParseIntArg(name, value);
|
||||
} else if (name == "xmpp-use-tls") {
|
||||
gXmppUseTls = ParseBoolArg(name, value)?
|
||||
buzz::TLS_REQUIRED : buzz::TLS_DISABLED;
|
||||
} else {
|
||||
Error(std::string("unknown option: ") + name);
|
||||
}
|
||||
|
||||
index += 1;
|
||||
}
|
||||
|
||||
if (index >= argc)
|
||||
Error("bad arguments");
|
||||
gUserJid = buzz::Jid(argv[index++]);
|
||||
if (!gUserJid.IsValid())
|
||||
Error("bad arguments");
|
||||
|
||||
char path[MAX_PATH];
|
||||
#if WIN32
|
||||
GetCurrentDirectoryA(MAX_PATH, path);
|
||||
#else
|
||||
if (NULL == getcwd(path, MAX_PATH))
|
||||
Error("Unable to get current path");
|
||||
#endif
|
||||
|
||||
std::cout << "Directory: " << std::string(path) << std::endl;
|
||||
|
||||
buzz::Jid gSrcJid;
|
||||
buzz::Jid gDstJid;
|
||||
std::string gSrcFile;
|
||||
std::string gDstFile;
|
||||
|
||||
bool as_server = true;
|
||||
if (index + 2 == argc) {
|
||||
ParseFileArg(argv[index], &gSrcJid, &gSrcFile);
|
||||
ParseFileArg(argv[index+1], &gDstJid, &gDstFile);
|
||||
if(gSrcJid.Str().empty() == gDstJid.Str().empty())
|
||||
Error("Exactly one of source JID or destination JID must be empty.");
|
||||
as_server = false;
|
||||
} else if (index != argc) {
|
||||
Error("bad arguments");
|
||||
}
|
||||
|
||||
std::cout << "Password: ";
|
||||
SetConsoleEcho(false);
|
||||
std::cin >> gUserPass.password();
|
||||
SetConsoleEcho(true);
|
||||
std::cout << std::endl;
|
||||
|
||||
talk_base::InitializeSSL();
|
||||
// Log in.
|
||||
CustomXmppPump pump;
|
||||
pump.client()->SignalLogInput.connect(&debug_log_, &DebugLog::Input);
|
||||
pump.client()->SignalLogOutput.connect(&debug_log_, &DebugLog::Output);
|
||||
pump.DoLogin(LoginSettings(), new buzz::XmppSocket(gXmppUseTls), 0);
|
||||
//new XmppAuth());
|
||||
|
||||
// Wait until login succeeds.
|
||||
std::vector<uint32> ids;
|
||||
ids.push_back(MSG_LOGIN_COMPLETE);
|
||||
ids.push_back(MSG_LOGIN_FAILED);
|
||||
if (MSG_LOGIN_FAILED == Loop(ids))
|
||||
FatalError("Failed to connect");
|
||||
|
||||
{
|
||||
talk_base::scoped_ptr<buzz::XmlElement> presence(
|
||||
new buzz::XmlElement(buzz::QN_PRESENCE));
|
||||
presence->AddElement(new buzz::XmlElement(buzz::QN_PRIORITY));
|
||||
presence->AddText("-1", 1);
|
||||
pump.SendStanza(presence.get());
|
||||
}
|
||||
|
||||
std::string user_jid_str = pump.client()->jid().Str();
|
||||
std::cout << "Logged in as " << user_jid_str << std::endl;
|
||||
|
||||
// Prepare the random number generator.
|
||||
talk_base::InitRandom(user_jid_str.c_str(), user_jid_str.size());
|
||||
|
||||
// Create the P2P session manager.
|
||||
talk_base::BasicNetworkManager network_manager;
|
||||
AutoPortAllocator allocator(&network_manager, "pcp_agent");
|
||||
allocator.SetXmppClient(pump.client());
|
||||
cricket::SessionManager session_manager(&allocator);
|
||||
#ifdef USE_SSL_TUNNEL
|
||||
cricket::SecureTunnelSessionClient session_client(pump.client()->jid(),
|
||||
&session_manager);
|
||||
if (!session_client.GenerateIdentity())
|
||||
FatalError("Failed to generate SSL identity");
|
||||
#else // !USE_SSL_TUNNEL
|
||||
cricket::TunnelSessionClient session_client(pump.client()->jid(),
|
||||
&session_manager);
|
||||
#endif // USE_SSL_TUNNEL
|
||||
cricket::SessionManagerTask *receiver =
|
||||
new cricket::SessionManagerTask(pump.client(), &session_manager);
|
||||
receiver->EnableOutgoingMessages();
|
||||
receiver->Start();
|
||||
|
||||
bool success = true;
|
||||
|
||||
// Establish the appropriate connection.
|
||||
if (as_server) {
|
||||
pump.Serve(&session_client);
|
||||
} else {
|
||||
talk_base::StreamInterface* stream = NULL;
|
||||
std::string filename;
|
||||
bool sending;
|
||||
if (gSrcJid.Str().empty()) {
|
||||
std::string message("recv:");
|
||||
message.append(gDstFile);
|
||||
stream = session_client.CreateTunnel(gDstJid, message);
|
||||
filename = gSrcFile;
|
||||
sending = true;
|
||||
} else {
|
||||
std::string message("send:");
|
||||
message.append(gSrcFile);
|
||||
stream = session_client.CreateTunnel(gSrcJid, message);
|
||||
filename = gDstFile;
|
||||
sending = false;
|
||||
}
|
||||
success = pump.ProcessStream(stream, filename, sending);
|
||||
}
|
||||
|
||||
if (success) {
|
||||
// Wait until the copy is done.
|
||||
ids.clear();
|
||||
ids.push_back(MSG_DONE);
|
||||
ids.push_back(MSG_LOGIN_FAILED);
|
||||
Loop(ids);
|
||||
}
|
||||
|
||||
// Log out.
|
||||
pump.DoDisconnect();
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,736 +0,0 @@
|
||||
/*
|
||||
* 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 <iostream>
|
||||
#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<SendMessageData*>(msg->pdata)->m_);
|
||||
delete msg->pdata;
|
||||
break;
|
||||
case MSG_SEND_XMPP_IQ:
|
||||
SendXmppIqW(static_cast<SendIqData*>(msg->pdata)->to_jid_,
|
||||
static_cast<SendIqData*>(msg->pdata)->is_get_,
|
||||
static_cast<SendIqData*>(msg->pdata)->xml_element_);
|
||||
delete msg->pdata;
|
||||
break;
|
||||
case MSG_SEND_PRESENCE:
|
||||
SendPresenceW(static_cast<SendPresenceData*>(msg->pdata)->s_);
|
||||
delete msg->pdata;
|
||||
break;
|
||||
case MSG_SEND_DIRECTED_PRESENCE:
|
||||
SendDirectedPresenceW(static_cast<SendDirectedPresenceData*>(msg->pdata)->j_,
|
||||
static_cast<SendDirectedPresenceData*>(msg->pdata)->s_);
|
||||
delete msg->pdata;
|
||||
break;
|
||||
case MSG_SEND_DIRECTED_MUC_PRESENCE:
|
||||
SendDirectedMUCPresenceW(static_cast<SendDirectedMUCPresenceData*>(msg->pdata)->j_,
|
||||
static_cast<SendDirectedMUCPresenceData*>(msg->pdata)->s_,
|
||||
static_cast<SendDirectedMUCPresenceData*>(msg->pdata)->un_,
|
||||
static_cast<SendDirectedMUCPresenceData*>(msg->pdata)->ac_,
|
||||
static_cast<SendDirectedMUCPresenceData*>(msg->pdata)->am_,
|
||||
static_cast<SendDirectedMUCPresenceData*>(msg->pdata)->role_);
|
||||
delete msg->pdata;
|
||||
break;
|
||||
case MSG_UPDATE_ROSTER_ITEM:
|
||||
UpdateRosterItemW(static_cast<UpdateRosterItemData*>(msg->pdata)->jid_,
|
||||
static_cast<UpdateRosterItemData*>(msg->pdata)->n_,
|
||||
static_cast<UpdateRosterItemData*>(msg->pdata)->g_,
|
||||
static_cast<UpdateRosterItemData*>(msg->pdata)->grt_);
|
||||
delete msg->pdata;
|
||||
break;
|
||||
case MSG_REMOVE_ROSTER_ITEM:
|
||||
RemoveRosterItemW(static_cast<JidData*>(msg->pdata)->jid_);
|
||||
delete msg->pdata;
|
||||
break;
|
||||
|
||||
|
||||
|
||||
|
||||
case MSG_STATUS_UPDATE:
|
||||
OnStatusUpdateW(static_cast<SendPresenceData*>(msg->pdata)->s_);
|
||||
delete msg->pdata;
|
||||
break;
|
||||
case MSG_STATUS_ERROR:
|
||||
OnStatusErrorW(static_cast<StatusErrorData*>(msg->pdata)->stanza_);
|
||||
delete msg->pdata;
|
||||
break;
|
||||
case MSG_STATE_CHANGE:
|
||||
OnStateChangeW(static_cast<StateChangeData*>(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<RosterItemData*>(msg->pdata)->ri_);
|
||||
delete msg->pdata;
|
||||
break;
|
||||
case MSG_ROSTER_ITEM_REMOVED:
|
||||
OnRosterItemRemovedW(static_cast<RosterItemData*>(msg->pdata)->ri_);
|
||||
delete msg->pdata;
|
||||
break;
|
||||
case MSG_ROSTER_SUBSCRIBE:
|
||||
OnRosterSubscribeW(static_cast<JidData*>(msg->pdata)->jid_);
|
||||
delete msg->pdata;
|
||||
break;
|
||||
case MSG_ROSTER_UNSUBSCRIBE:
|
||||
OnRosterUnsubscribeW(static_cast<JidData*>(msg->pdata)->jid_);
|
||||
delete msg->pdata;
|
||||
break;
|
||||
case MSG_ROSTER_SUBSCRIBED:
|
||||
OnRosterSubscribedW(static_cast<JidData*>(msg->pdata)->jid_);
|
||||
delete msg->pdata;
|
||||
break;
|
||||
case MSG_ROSTER_UNSUBSCRIBED:
|
||||
OnRosterUnsubscribedW(static_cast<JidData*>(msg->pdata)->jid_);
|
||||
delete msg->pdata;
|
||||
break;
|
||||
case MSG_INCOMING_MESSAGE:
|
||||
OnIncomingMessageW(static_cast<XmppMessageData*>(msg->pdata)->m_);
|
||||
delete msg->pdata;
|
||||
break;
|
||||
case MSG_IQ_COMPLETE:
|
||||
OnIqCompleteW(static_cast<IqCompleteData*>(msg->pdata)->success_,
|
||||
static_cast<IqCompleteData*>(msg->pdata)->stanza_);
|
||||
delete msg->pdata;
|
||||
break;
|
||||
case MSG_XMPP_OUTPUT:
|
||||
OnOutputDebugW(static_cast<StringData*>(msg->pdata)->s_);
|
||||
delete msg->pdata;
|
||||
break;
|
||||
case MSG_XMPP_INPUT:
|
||||
OnInputDebugW(static_cast<StringData*>(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<std::string> & 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<std::string> &groups, buzz::GrType grt) :
|
||||
jid_(jid), n_(name), g_(groups), grt_(grt) {}
|
||||
buzz::Jid jid_;
|
||||
std::string n_;
|
||||
std::vector<std::string> g_;
|
||||
buzz::GrType grt_;
|
||||
};
|
||||
|
||||
void UpdateRosterItemW(const buzz::Jid &jid, const std::string &name,
|
||||
const std::vector<std::string> &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<buzz::XmlElement *>(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<talk_base::Win32SocketServer> ss_;
|
||||
talk_base::scoped_ptr<talk_base::Thread> main_thread_;
|
||||
talk_base::Thread *worker_thread_;
|
||||
|
||||
LibjinglePlus *ljp_;
|
||||
LibjinglePlusNotify *notify_;
|
||||
buzz::XmppClientSettings xcs_;
|
||||
talk_base::PhysicalSocketServer pss_;
|
||||
|
||||
talk_base::scoped_ptr<XmppPump> 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();
|
||||
}
|
@ -1,154 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// LibjinglePlus is a class that connects to Google Talk, creates
|
||||
// some common tasks, and emits signals when things change
|
||||
|
||||
#ifndef LIBJINGLEPLUS_H__
|
||||
#define LIBJINGLEPLUS_H__
|
||||
|
||||
#include "talk/base/basicdefs.h"
|
||||
#include "talk/app/rosteritem.h"
|
||||
#include "talk/app/message.h"
|
||||
#include "talk/app/status.h"
|
||||
#include "talk/xmpp/xmppengine.h"
|
||||
#include "talk/base/scoped_ptr.h"
|
||||
|
||||
|
||||
class LibjinglePlusWorker;
|
||||
|
||||
class LibjinglePlusNotify {
|
||||
public:
|
||||
virtual ~LibjinglePlusNotify() {}
|
||||
|
||||
/* Libjingle+ works on its own thread. It will call WakeupMainThread
|
||||
* when it has something to report. The main thread should then wake up,
|
||||
* and call DoCallbacks on the LibjinglePlus object.
|
||||
*
|
||||
* This function gets called from libjingle+'s worker thread. All other
|
||||
* methods in LibjinglePlusNotify get called from the thread you call
|
||||
* DoCallbacks() on.
|
||||
*
|
||||
* If running on Windows, libjingle+ will use Windows messages to generate
|
||||
* callbacks from the main thread, and you don't need to do anything here.
|
||||
*/
|
||||
virtual void WakeupMainThread() = 0;
|
||||
|
||||
/* Connection */
|
||||
/* Called when the connection state changes */
|
||||
virtual void OnStateChange(buzz::XmppEngine::State) = 0;
|
||||
|
||||
/* Called when the socket closes */
|
||||
virtual void OnSocketClose(int error_code) = 0;
|
||||
|
||||
/* Called when XMPP is being sent or received. Used for debugging */
|
||||
virtual void OnXmppOutput(const std::string &output) = 0;
|
||||
virtual void OnXmppInput(const std::string &input) = 0;
|
||||
|
||||
/* Presence */
|
||||
/* Called when someone's Status is updated */
|
||||
virtual void OnStatusUpdate(const buzz::Status &status) = 0;
|
||||
|
||||
/* Called when a status update results in an error */
|
||||
virtual void OnStatusError(const buzz::XmlElement &stanza) = 0;
|
||||
|
||||
/* Called with an IQ return code */
|
||||
virtual void OnIqDone(bool success, const buzz::XmlElement &stanza) = 0;
|
||||
|
||||
/* Message */
|
||||
/* Called when a message comes in. */
|
||||
virtual void OnMessage(const buzz::XmppMessage &message) = 0;
|
||||
|
||||
/* Roster */
|
||||
|
||||
/* Called when we start refreshing the roster */
|
||||
virtual void OnRosterRefreshStarted() = 0;
|
||||
/* Called when we have the entire roster */
|
||||
virtual void OnRosterRefreshFinished() = 0;
|
||||
/* Called when an item on the roster is created or updated */
|
||||
virtual void OnRosterItemUpdated(const buzz::RosterItem &ri) = 0;
|
||||
/* Called when an item on the roster is removed */
|
||||
virtual void OnRosterItemRemoved(const buzz::RosterItem &ri) = 0;
|
||||
|
||||
/* Subscriptions */
|
||||
virtual void OnRosterSubscribe(const buzz::Jid &jid) = 0;
|
||||
virtual void OnRosterUnsubscribe(const buzz::Jid &jid) = 0;
|
||||
virtual void OnRosterSubscribed(const buzz::Jid &jid) = 0;
|
||||
virtual void OnRosterUnsubscribed(const buzz::Jid &jid) = 0;
|
||||
|
||||
};
|
||||
|
||||
class LibjinglePlus
|
||||
{
|
||||
public:
|
||||
/* Provide the constructor with your interface. */
|
||||
LibjinglePlus(LibjinglePlusNotify *notify);
|
||||
~LibjinglePlus();
|
||||
|
||||
/* Logs in and starts doing stuff
|
||||
*
|
||||
* If cookie_auth is true, password must be a Gaia SID. Otherwise,
|
||||
* it should be the user's password
|
||||
*/
|
||||
void Login(const std::string &username, const std::string &password,
|
||||
const std::string &machine_address, bool is_test, bool cookie_auth);
|
||||
|
||||
/* Set Presence */
|
||||
void SendPresence(const buzz::Status & s);
|
||||
void SendDirectedPresence(const buzz::Jid & j, const buzz::Status & s);
|
||||
void 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);
|
||||
|
||||
/* Send Message */
|
||||
void SendXmppMessage(const buzz::XmppMessage & m);
|
||||
|
||||
/* Send IQ */
|
||||
void SendXmppIq(const buzz::Jid &to_jid, bool is_get,
|
||||
const buzz::XmlElement *iq_element);
|
||||
|
||||
/* Set Roster */
|
||||
void UpdateRosterItem(const buzz::Jid & jid, const std::string & name,
|
||||
const std::vector<std::string> & groups, buzz::GrType grt);
|
||||
void RemoveRosterItem(const buzz::Jid &jid);
|
||||
|
||||
/* Call this from the thread you want to receive callbacks on. Typically, this will be called
|
||||
* after your WakeupMainThread() notify function is called.
|
||||
*
|
||||
* On Windows, libjingle+ will trigger its callback from the Windows message loop, and
|
||||
* you needn't call this yourself.
|
||||
*/
|
||||
void DoCallbacks();
|
||||
|
||||
private:
|
||||
void LoginInternal(const std::string &jid, const std::string &password,
|
||||
const std::string &machine_address, bool is_test);
|
||||
|
||||
LibjinglePlusWorker *worker_;
|
||||
};
|
||||
|
||||
#endif // LIBJINGLE_PLUS_H__
|
@ -1,201 +0,0 @@
|
||||
/*
|
||||
* libjingle
|
||||
* Copyright 2004--2005, 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 "talk/base/stringencode.h"
|
||||
#include "presencepushtask.h"
|
||||
#include "talk/xmpp/constants.h"
|
||||
#include <sstream>
|
||||
|
||||
|
||||
namespace buzz {
|
||||
|
||||
// string helper functions -----------------------------------------------------
|
||||
|
||||
static bool
|
||||
IsXmlSpace(int ch) {
|
||||
return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t';
|
||||
}
|
||||
|
||||
static bool
|
||||
ListContainsToken(const std::string & list, const std::string & token) {
|
||||
size_t i = list.find(token);
|
||||
if (i == std::string::npos || token.empty())
|
||||
return false;
|
||||
bool boundary_before = (i == 0 || IsXmlSpace(list[i - 1]));
|
||||
bool boundary_after = (i == list.length() - token.length() || IsXmlSpace(list[i + token.length()]));
|
||||
return boundary_before && boundary_after;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
PresencePushTask::HandleStanza(const XmlElement * stanza) {
|
||||
if (stanza->Name() != QN_PRESENCE)
|
||||
return false;
|
||||
if (stanza->HasAttr(QN_TYPE) && stanza->Attr(QN_TYPE) != STR_UNAVAILABLE) {
|
||||
if (stanza->Attr(QN_TYPE) == STR_ERROR) {
|
||||
// Pass on the error.
|
||||
const XmlElement* error_xml_elem = stanza->FirstNamed(QN_ERROR);
|
||||
if (!error_xml_elem) {
|
||||
return false;
|
||||
}
|
||||
SignalStatusError(*error_xml_elem);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
QueueStanza(stanza);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool IsUtf8FirstByte(int c) {
|
||||
return (((c)&0x80)==0) || // is single byte
|
||||
((unsigned char)((c)-0xc0)<0x3e); // or is lead byte
|
||||
}
|
||||
|
||||
int
|
||||
PresencePushTask::ProcessStart() {
|
||||
const XmlElement * stanza = NextStanza();
|
||||
if (stanza == NULL)
|
||||
return STATE_BLOCKED;
|
||||
Status s;
|
||||
|
||||
s.set_jid(Jid(stanza->Attr(QN_FROM)));
|
||||
|
||||
if (stanza->Attr(QN_TYPE) == STR_UNAVAILABLE) {
|
||||
s.set_available(false);
|
||||
SignalStatusUpdate(s);
|
||||
}
|
||||
else {
|
||||
s.set_available(true);
|
||||
const XmlElement * status = stanza->FirstNamed(QN_STATUS);
|
||||
if (status != NULL) {
|
||||
s.set_status(status->BodyText());
|
||||
|
||||
// Truncate status messages longer than 300 bytes
|
||||
if (s.status().length() > 300) {
|
||||
size_t len = 300;
|
||||
|
||||
// Be careful not to split legal utf-8 chars in half
|
||||
while (!IsUtf8FirstByte(s.status()[len]) && len > 0) {
|
||||
len -= 1;
|
||||
}
|
||||
std::string truncated(s.status(), 0, len);
|
||||
s.set_status(truncated);
|
||||
}
|
||||
}
|
||||
|
||||
const XmlElement * priority = stanza->FirstNamed(QN_PRIORITY);
|
||||
if (priority != NULL) {
|
||||
int pri;
|
||||
if (talk_base::FromString(priority->BodyText(), &pri)) {
|
||||
s.set_priority(pri);
|
||||
}
|
||||
}
|
||||
|
||||
const XmlElement * show = stanza->FirstNamed(QN_SHOW);
|
||||
if (show == NULL || show->FirstChild() == NULL) {
|
||||
s.set_show(Status::SHOW_ONLINE);
|
||||
}
|
||||
else {
|
||||
if (show->BodyText() == "away") {
|
||||
s.set_show(Status::SHOW_AWAY);
|
||||
}
|
||||
else if (show->BodyText() == "xa") {
|
||||
s.set_show(Status::SHOW_XA);
|
||||
}
|
||||
else if (show->BodyText() == "dnd") {
|
||||
s.set_show(Status::SHOW_DND);
|
||||
}
|
||||
else if (show->BodyText() == "chat") {
|
||||
s.set_show(Status::SHOW_CHAT);
|
||||
}
|
||||
else {
|
||||
s.set_show(Status::SHOW_ONLINE);
|
||||
}
|
||||
}
|
||||
|
||||
const XmlElement * caps = stanza->FirstNamed(QN_CAPS_C);
|
||||
if (caps != NULL) {
|
||||
std::string node = caps->Attr(QN_NODE);
|
||||
std::string ver = caps->Attr(QN_VER);
|
||||
std::string exts = caps->Attr(QN_EXT);
|
||||
|
||||
s.set_know_capabilities(true);
|
||||
std::string capability;
|
||||
std::stringstream ss(exts);
|
||||
while (ss >> capability) {
|
||||
s.AddCapability(capability);
|
||||
}
|
||||
|
||||
s->set_caps_node(node);
|
||||
s->set_version(ver);
|
||||
}
|
||||
|
||||
const XmlElement* delay = stanza->FirstNamed(kQnDelayX);
|
||||
if (delay != NULL) {
|
||||
// Ideally we would parse this according to the Psuedo ISO-8601 rules
|
||||
// that are laid out in JEP-0082:
|
||||
// http://www.jabber.org/jeps/jep-0082.html
|
||||
std::string stamp = delay->Attr(kQnStamp);
|
||||
s.set_sent_time(stamp);
|
||||
}
|
||||
|
||||
const XmlElement *nick = stanza->FirstNamed(kQnNickname);
|
||||
if (nick) {
|
||||
std::string user_nick = nick->BodyText();
|
||||
s.set_user_nick(user_nick);
|
||||
}
|
||||
|
||||
const XmlElement *plugin = stanza->FirstNamed(QN_PLUGIN);
|
||||
if (plugin) {
|
||||
const XmlElement *api_cap = plugin->FirstNamed(QN_CAPABILITY);
|
||||
if (api_cap) {
|
||||
const std::string &api_capability = api_cap->BodyText();
|
||||
s.set_api_capability(api_capability);
|
||||
}
|
||||
const XmlElement *api_msg = plugin->FirstNamed(QN_DATA);
|
||||
if (api_msg) {
|
||||
const std::string &api_message = api_msg->BodyText();
|
||||
s.set_api_message(api_message);
|
||||
}
|
||||
}
|
||||
|
||||
const XmlElement* data_x = stanza->FirstNamed(QN_MUC_USER_X);
|
||||
if (data_x != NULL) {
|
||||
const XmlElement* item = data_x->FirstNamed(QN_MUC_USER_ITEM);
|
||||
if (item != NULL) {
|
||||
s.set_muc_role(item->Attr(QN_ROLE));
|
||||
}
|
||||
}
|
||||
|
||||
SignalStatusUpdate(s);
|
||||
}
|
||||
|
||||
return STATE_START;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
/*
|
||||
* libjingle
|
||||
* Copyright 2004--2005, 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.
|
||||
*/
|
||||
|
||||
#ifndef _PRESENCEPUSHTASK_H_
|
||||
#define _PRESENCEPUSHTASK_H_
|
||||
|
||||
#include "talk/xmpp/xmppengine.h"
|
||||
#include "talk/xmpp/xmpptask.h"
|
||||
#include "talk/base/sigslot.h"
|
||||
#include "talk/app/status.h"
|
||||
|
||||
namespace buzz {
|
||||
|
||||
class PresencePushTask : public XmppTask {
|
||||
|
||||
public:
|
||||
PresencePushTask(Task * parent) : XmppTask(parent, XmppEngine::HL_TYPE) {}
|
||||
virtual int ProcessStart();
|
||||
sigslot::signal1<const Status &>SignalStatusUpdate;
|
||||
sigslot::signal1<const XmlElement &> SignalStatusError;
|
||||
|
||||
protected:
|
||||
virtual bool HandleStanza(const XmlElement * stanza);
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -1,218 +0,0 @@
|
||||
/*
|
||||
* libjingle
|
||||
* Copyright 2004--2005, 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 "rostertask.h"
|
||||
#include "talk/xmpp/constants.h"
|
||||
#include "talk/base/stream.h"
|
||||
|
||||
#undef WIN32
|
||||
#ifdef WIN32
|
||||
#include "talk/app/win32/offlineroster.h"
|
||||
#endif
|
||||
|
||||
namespace buzz {
|
||||
|
||||
class RosterTask::RosterGetTask : public XmppTask {
|
||||
public:
|
||||
RosterGetTask(Task * parent) : XmppTask(parent, XmppEngine::HL_SINGLE),
|
||||
done_(false) {}
|
||||
|
||||
virtual int ProcessStart();
|
||||
virtual int ProcessResponse();
|
||||
|
||||
protected:
|
||||
virtual bool HandleStanza(const XmlElement * stanza);
|
||||
|
||||
bool done_;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
// RosterTask
|
||||
//==============================================================================
|
||||
void RosterTask::RefreshRosterNow() {
|
||||
RosterGetTask* get_task = new RosterGetTask(this);
|
||||
ResumeTimeout();
|
||||
get_task->Start();
|
||||
}
|
||||
|
||||
void RosterTask::TranslateItems(const XmlElement * rosterQueryResult) {
|
||||
#if defined(FEATURE_ENABLE_PSTN)
|
||||
#ifdef WIN32
|
||||
// We build up a list of contacts which have had information persisted offline.
|
||||
// we'll remove items from this list if we get a buzz::SUBSCRIBE_REMOVE
|
||||
// subscription. After updating all the items from the server, we'll then
|
||||
// update (and merge) any roster items left in our map of offline items
|
||||
XmlElement *el_local = OfflineRoster::RetrieveOfflineRoster(GetClient()->jid());
|
||||
std::map<buzz::Jid, RosterItem> jid_to_item;
|
||||
if (el_local) {
|
||||
for (XmlElement *el_item = el_local->FirstNamed(QN_ROSTER_ITEM);
|
||||
el_item != NULL;
|
||||
el_item = el_item->NextNamed(QN_ROSTER_ITEM)) {
|
||||
RosterItem roster_item;
|
||||
roster_item.FromXml(el_item);
|
||||
|
||||
jid_to_item[roster_item.jid()] = roster_item;
|
||||
}
|
||||
}
|
||||
#endif // WIN32
|
||||
#endif // FEATURE_ENABLE_PSTN
|
||||
|
||||
const XmlElement * xml_item;
|
||||
for (xml_item = rosterQueryResult->FirstNamed(QN_ROSTER_ITEM);
|
||||
xml_item != NULL; xml_item = xml_item->NextNamed(QN_ROSTER_ITEM)) {
|
||||
RosterItem roster_item;
|
||||
roster_item.FromXml(xml_item);
|
||||
|
||||
if (roster_item.subscription() == buzz::SUBSCRIBE_REMOVE) {
|
||||
SignalRosterItemRemoved(roster_item);
|
||||
|
||||
#if defined(FEATURE_ENABLE_PSTN)
|
||||
#ifdef WIN32
|
||||
std::map<buzz::Jid, RosterItem>::iterator it =
|
||||
jid_to_item.find(roster_item.jid());
|
||||
|
||||
if (it != jid_to_item.end())
|
||||
jid_to_item.erase(it);
|
||||
#endif
|
||||
#endif
|
||||
} else {
|
||||
SignalRosterItemUpdated(roster_item, false);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(FEATURE_ENABLE_PSTN)
|
||||
#ifdef WIN32
|
||||
for (std::map<buzz::Jid, RosterItem>::iterator it = jid_to_item.begin();
|
||||
it != jid_to_item.end(); ++it) {
|
||||
SignalRosterItemUpdated(it->second, true);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
int RosterTask::ProcessStart() {
|
||||
const XmlElement * stanza = NextStanza();
|
||||
if (stanza == NULL)
|
||||
return STATE_BLOCKED;
|
||||
|
||||
if (stanza->Name() == QN_IQ) {
|
||||
SuspendTimeout();
|
||||
bool result = (stanza->Attr(QN_TYPE) == STR_RESULT);
|
||||
if (result)
|
||||
SignalRosterRefreshStarted();
|
||||
|
||||
TranslateItems(stanza->FirstNamed(QN_ROSTER_QUERY));
|
||||
|
||||
if (result)
|
||||
SignalRosterRefreshFinished();
|
||||
} else if (stanza->Name() == QN_PRESENCE) {
|
||||
Jid jid(stanza->Attr(QN_FROM));
|
||||
std::string type = stanza->Attr(QN_TYPE);
|
||||
if (type == "subscribe")
|
||||
SignalSubscribe(jid);
|
||||
else if (type == "unsubscribe")
|
||||
SignalUnsubscribe(jid);
|
||||
else if (type == "subscribed")
|
||||
SignalSubscribed(jid);
|
||||
else if (type == "unsubscribed")
|
||||
SignalUnsubscribed(jid);
|
||||
}
|
||||
|
||||
return STATE_START;
|
||||
}
|
||||
|
||||
bool RosterTask::HandleStanza(const XmlElement * stanza) {
|
||||
if (!MatchRequestIq(stanza, STR_SET, QN_ROSTER_QUERY)) {
|
||||
// Not a roster IQ. Look for a presence instead
|
||||
if (stanza->Name() != QN_PRESENCE)
|
||||
return false;
|
||||
if (!stanza->HasAttr(QN_TYPE))
|
||||
return false;
|
||||
std::string type = stanza->Attr(QN_TYPE);
|
||||
if (type == "subscribe" || type == "unsubscribe" ||
|
||||
type == "subscribed" || type == "unsubscribed") {
|
||||
QueueStanza(stanza);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// only respect roster push from the server
|
||||
Jid from(stanza->Attr(QN_FROM));
|
||||
if (from != JID_EMPTY &&
|
||||
!from.BareEquals(GetClient()->jid()) &&
|
||||
from != Jid(GetClient()->jid().domain()))
|
||||
return false;
|
||||
|
||||
XmlElement * result = MakeIqResult(stanza);
|
||||
result->AddElement(new XmlElement(QN_ROSTER_QUERY, true));
|
||||
SendStanza(result);
|
||||
|
||||
QueueStanza(stanza);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
// RosterTask::RosterGetTask
|
||||
//==============================================================================
|
||||
int RosterTask::RosterGetTask::ProcessStart() {
|
||||
talk_base::scoped_ptr<XmlElement> get(MakeIq(STR_GET, JID_EMPTY, task_id()));
|
||||
get->AddElement(new XmlElement(QN_ROSTER_QUERY, true));
|
||||
get->AddAttr(QN_XMLNS_GR, NS_GR, 1);
|
||||
get->AddAttr(QN_GR_EXT, "2", 1);
|
||||
get->AddAttr(QN_GR_INCLUDE, "all", 1);
|
||||
if (SendStanza(get.get()) != XMPP_RETURN_OK) {
|
||||
return STATE_ERROR;
|
||||
}
|
||||
return STATE_RESPONSE;
|
||||
}
|
||||
|
||||
int RosterTask::RosterGetTask::ProcessResponse() {
|
||||
if (done_)
|
||||
return STATE_DONE;
|
||||
return STATE_BLOCKED;
|
||||
}
|
||||
|
||||
bool RosterTask::RosterGetTask::HandleStanza(const XmlElement * stanza) {
|
||||
if (!MatchResponseIq(stanza, JID_EMPTY, task_id()))
|
||||
return false;
|
||||
|
||||
if (stanza->Attr(QN_TYPE) != STR_RESULT)
|
||||
return false;
|
||||
|
||||
// Queue the stanza with the parent so these don't get handled out of order
|
||||
RosterTask* parent = static_cast<RosterTask*>(GetParent());
|
||||
parent->QueueStanza(stanza);
|
||||
|
||||
// Wake ourselves so we can go into the done state
|
||||
done_ = true;
|
||||
Wake();
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@ -1,72 +0,0 @@
|
||||
/*
|
||||
* libjingle
|
||||
* Copyright 2004--2005, 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.
|
||||
*/
|
||||
|
||||
#ifndef _PHONE_CLIENT_ROSTERTASK_H_
|
||||
#define _PHONE_CLIENT_ROSTERTASK_H_
|
||||
|
||||
#include "talk/xmpp/xmppclient.h"
|
||||
#include "talk/xmpp/xmpptask.h"
|
||||
#include "talk/app/rosteritem.h"
|
||||
#include "talk/base/sigslot.h"
|
||||
|
||||
namespace buzz {
|
||||
|
||||
class RosterTask : public XmppTask {
|
||||
public:
|
||||
RosterTask(Task * parent) :
|
||||
XmppTask(parent, XmppEngine::HL_TYPE) {}
|
||||
|
||||
// Roster items removed or updated. This can come from a push or a get
|
||||
sigslot::signal2<const RosterItem &, bool> SignalRosterItemUpdated;
|
||||
sigslot::signal1<const RosterItem &> SignalRosterItemRemoved;
|
||||
|
||||
// Subscription messages
|
||||
sigslot::signal1<const Jid &> SignalSubscribe;
|
||||
sigslot::signal1<const Jid &> SignalUnsubscribe;
|
||||
sigslot::signal1<const Jid &> SignalSubscribed;
|
||||
sigslot::signal1<const Jid &> SignalUnsubscribed;
|
||||
|
||||
// Roster get
|
||||
void RefreshRosterNow();
|
||||
sigslot::signal0<> SignalRosterRefreshStarted;
|
||||
sigslot::signal0<> SignalRosterRefreshFinished;
|
||||
|
||||
virtual int ProcessStart();
|
||||
|
||||
protected:
|
||||
void TranslateItems(const XmlElement *rosterQueryResult);
|
||||
|
||||
virtual bool HandleStanza(const XmlElement * stanza);
|
||||
|
||||
// Inner class for doing the roster get
|
||||
class RosterGetTask;
|
||||
friend class RosterGetTask;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // _PHONE_CLIENT_ROSTERTASK_H_
|
@ -1,119 +0,0 @@
|
||||
/*
|
||||
* 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 <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "talk/base/thread.h"
|
||||
#include "talk/libjingle-plus/libjingleplus.h"
|
||||
#include "talk/libjingle-plus/testutil/libjingleplus_test_notifier.h"
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER < 1400)
|
||||
void __cdecl std::_Throw(const std::exception &) {}
|
||||
std::_Prhand std::_Raise_handler =0;
|
||||
#endif
|
||||
|
||||
|
||||
void SetConsoleEcho(bool on) {
|
||||
#ifdef WIN32
|
||||
HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE);
|
||||
if ((hIn == INVALID_HANDLE_VALUE) || (hIn == NULL))
|
||||
return;
|
||||
|
||||
DWORD mode;
|
||||
if (!GetConsoleMode(hIn, &mode))
|
||||
return;
|
||||
|
||||
if (on) {
|
||||
mode = mode | ENABLE_ECHO_INPUT;
|
||||
} else {
|
||||
mode = mode & ~ENABLE_ECHO_INPUT;
|
||||
}
|
||||
|
||||
SetConsoleMode(hIn, mode);
|
||||
#else
|
||||
if (on)
|
||||
system("stty echo");
|
||||
else
|
||||
system("stty -echo");
|
||||
#endif
|
||||
}
|
||||
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
std::string username;
|
||||
std::string password;
|
||||
|
||||
bool gaia = false;
|
||||
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (!strcmp(argv[i], "-gaia"))
|
||||
gaia = true;
|
||||
}
|
||||
|
||||
std::cout << "Username: ";
|
||||
std::cin >> username;
|
||||
std::cout << (gaia ? "Gaia cookie: " : "Password: ");
|
||||
SetConsoleEcho(false);
|
||||
std::cin >> password;
|
||||
SetConsoleEcho(true);
|
||||
|
||||
// Create a LibjinglePlus object and give it the notifier interface
|
||||
LibjinglePlus ljp(new Notifier);
|
||||
|
||||
// Login
|
||||
ljp.Login(username, password, "talk.google.com", false, gaia);
|
||||
|
||||
buzz::Status s;
|
||||
s.set_available(true);
|
||||
s.set_show(buzz::Status::SHOW_ONLINE);
|
||||
s.set_status("I'm online.");
|
||||
|
||||
buzz::XmppMessage m;
|
||||
m.set_to(buzz::Jid(username + "@gmail.com"));
|
||||
m.set_body("What's up?");
|
||||
|
||||
// Typically, you would wait for WakeupMainThread to be called, and then call
|
||||
// DoCallbacks. Because I have nothing else to do on the main thread, I'm just going
|
||||
// to do a few things after 10 seconds and then poll every 2ms.
|
||||
Sleep(10000);
|
||||
// ljp.DoCallbacks();
|
||||
ljp.SendPresence(s);
|
||||
ljp.SendXmppMessage(m);
|
||||
|
||||
#ifdef WIN32
|
||||
MSG msg;
|
||||
while (GetMessage(&msg, NULL, 0, 0)) {
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
#else
|
||||
for (;;) {
|
||||
ljp.DoCallbacks();
|
||||
Sleep(2);
|
||||
}
|
||||
#endif
|
||||
}
|
@ -1,101 +0,0 @@
|
||||
/*
|
||||
* 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 <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "talk/libjingle-plus/libjingleplus.h"
|
||||
|
||||
class Notifier : virtual public LibjinglePlusNotify {
|
||||
virtual void OnStateChange(buzz::XmppEngine::State state) {
|
||||
std::cout << "State change: " << state << std::endl;
|
||||
}
|
||||
|
||||
virtual void OnSocketClose(int error_code) {
|
||||
std::cout << "Socket close: " << error_code << std::endl;
|
||||
}
|
||||
|
||||
virtual void OnXmppOutput(const std::string &output) {
|
||||
std::cout << ">>>>>>>>" << std::endl << output << std::endl << ">>>>>>>>" << std::endl;
|
||||
}
|
||||
|
||||
virtual void OnXmppInput(const std::string &input) {
|
||||
std::cout << "<<<<<<<<" << std::endl << input << std::endl << "<<<<<<<<" << std::endl;
|
||||
}
|
||||
|
||||
|
||||
virtual void OnStatusUpdate(const buzz::Status &status) {
|
||||
std::string from = status.jid().Str();
|
||||
std::cout << from << " - " << status.status() << std::endl;
|
||||
}
|
||||
|
||||
virtual void OnStatusError(const buzz::XmlElement &stanza) {
|
||||
}
|
||||
|
||||
virtual void OnIqDone(bool success, const buzz::XmlElement &stanza) {
|
||||
}
|
||||
|
||||
virtual void OnMessage(const buzz::XmppMessage &m) {
|
||||
if (m.body() != "")
|
||||
std::cout << m.from().Str() << ": " << m.body() << std::endl;
|
||||
}
|
||||
|
||||
void OnRosterItemUpdated(const buzz::RosterItem &ri) {
|
||||
std::cout << "Roster item: " << ri.jid().Str() << std::endl;
|
||||
}
|
||||
|
||||
virtual void OnRosterItemRemoved(const buzz::RosterItem &ri) {
|
||||
std::cout << "Roster item removed: " << ri.jid().Str() << std::endl;
|
||||
}
|
||||
|
||||
virtual void OnRosterSubscribe(const buzz::Jid& jid) {
|
||||
std::cout << "Subscribing: " << jid.Str() << std::endl;
|
||||
}
|
||||
|
||||
virtual void OnRosterUnsubscribe(const buzz::Jid &jid) {
|
||||
std::cout << "Unsubscribing: " <<jid.Str() << std::endl;
|
||||
}
|
||||
|
||||
virtual void OnRosterSubscribed(const buzz::Jid &jid) {
|
||||
std::cout << "Subscribed: " << jid.Str() << std::endl;
|
||||
}
|
||||
|
||||
virtual void OnRosterUnsubscribed(const buzz::Jid &jid) {
|
||||
std::cout << "Unsubscribed: " << jid.Str() << std::endl;
|
||||
}
|
||||
|
||||
virtual void OnRosterRefreshStarted() {
|
||||
std::cout << "Refreshing roster." << std::endl;
|
||||
}
|
||||
|
||||
virtual void OnRosterRefreshFinished() {
|
||||
std::cout << "Roster refreshed." << std::endl;
|
||||
}
|
||||
|
||||
virtual void WakeupMainThread() {
|
||||
}
|
||||
};
|
@ -1,52 +0,0 @@
|
||||
/*
|
||||
* 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 "testing/base/gunit.h"
|
||||
#include "talk/libjingle-plus/libjingleplus.h"
|
||||
#include "talk/libjingle-plus/testutil/libjingleplus_test_notifier.h"
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER < 1400)
|
||||
void __cdecl std::_Throw(const std::exception &) {}
|
||||
std::_Prhand std::_Raise_handler =0;
|
||||
#endif
|
||||
|
||||
namespace talk_base {
|
||||
|
||||
TEST(LibjingleTest, ConstructDestruct) {
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
LibjinglePlus *libjingleplus = new LibjinglePlus(new Notifier);
|
||||
libjingleplus->Login("eaterleaver0", "Buzzt3st", "talk.google.com", false, false);
|
||||
|
||||
delete libjingleplus;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
testing::ParseGUnitFlags(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
@ -51,7 +51,7 @@
|
||||
'libjingle.gyp:libjingle_p2p',
|
||||
],
|
||||
'sources': [
|
||||
'p2p/base/relayserver_main.cc',
|
||||
'examples/relayserver/relayserver_main.cc',
|
||||
],
|
||||
}, # target relayserver
|
||||
{
|
||||
@ -62,7 +62,7 @@
|
||||
'libjingle.gyp:libjingle_p2p',
|
||||
],
|
||||
'sources': [
|
||||
'p2p/base/stunserver_main.cc',
|
||||
'examples/stunserver/stunserver_main.cc',
|
||||
],
|
||||
}, # target stunserver
|
||||
{
|
||||
@ -73,7 +73,7 @@
|
||||
'libjingle.gyp:libjingle_p2p',
|
||||
],
|
||||
'sources': [
|
||||
'p2p/base/turnserver_main.cc',
|
||||
'examples/turnserver/turnserver_main.cc',
|
||||
],
|
||||
}, # target turnserver
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user