Adds trunk/talk folder of revision 359 from libjingles google code to
trunk/talk
git-svn-id: http://webrtc.googlecode.com/svn/trunk@4318 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/talk/examples/chat/Info.plist b/talk/examples/chat/Info.plist
new file mode 100644
index 0000000..ecd083a
--- /dev/null
+++ b/talk/examples/chat/Info.plist
@@ -0,0 +1,11 @@
+<?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>
+
diff --git a/talk/examples/chat/chat_main.cc b/talk/examples/chat/chat_main.cc
new file mode 100644
index 0000000..09a454e
--- /dev/null
+++ b/talk/examples/chat/chat_main.cc
@@ -0,0 +1,159 @@
+/*
+ * 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;
+}
diff --git a/talk/examples/chat/chatapp.cc b/talk/examples/chat/chatapp.cc
new file mode 100644
index 0000000..1b59910
--- /dev/null
+++ b/talk/examples/chat/chatapp.cc
@@ -0,0 +1,251 @@
+/*
+ * 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/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_(NULL),
+ presence_receive_task_(NULL),
+ message_send_task_(NULL),
+ message_received_task_(NULL),
+ 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;
+ }
+}
diff --git a/talk/examples/chat/chatapp.h b/talk/examples/chat/chatapp.h
new file mode 100644
index 0000000..cc032a6
--- /dev/null
+++ b/talk/examples/chat/chatapp.h
@@ -0,0 +1,171 @@
+/*
+ * 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_
+
diff --git a/talk/examples/chat/consoletask.cc b/talk/examples/chat/consoletask.cc
new file mode 100644
index 0000000..2577c79
--- /dev/null
+++ b/talk/examples/chat/consoletask.cc
@@ -0,0 +1,177 @@
+/*
+ * 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
diff --git a/talk/examples/chat/consoletask.h b/talk/examples/chat/consoletask.h
new file mode 100644
index 0000000..1d45b3a
--- /dev/null
+++ b/talk/examples/chat/consoletask.h
@@ -0,0 +1,92 @@
+/*
+ * 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_
+
diff --git a/talk/examples/chat/textchatreceivetask.cc b/talk/examples/chat/textchatreceivetask.cc
new file mode 100644
index 0000000..cbd019c
--- /dev/null
+++ b/talk/examples/chat/textchatreceivetask.cc
@@ -0,0 +1,66 @@
+/*
+ * 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
diff --git a/talk/examples/chat/textchatreceivetask.h b/talk/examples/chat/textchatreceivetask.h
new file mode 100644
index 0000000..e277692
--- /dev/null
+++ b/talk/examples/chat/textchatreceivetask.h
@@ -0,0 +1,63 @@
+/*
+ * 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_
+
diff --git a/talk/examples/chat/textchatsendtask.cc b/talk/examples/chat/textchatsendtask.cc
new file mode 100644
index 0000000..ba14453
--- /dev/null
+++ b/talk/examples/chat/textchatsendtask.cc
@@ -0,0 +1,81 @@
+/*
+ * 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
diff --git a/talk/examples/chat/textchatsendtask.h b/talk/examples/chat/textchatsendtask.h
new file mode 100644
index 0000000..9b18923
--- /dev/null
+++ b/talk/examples/chat/textchatsendtask.h
@@ -0,0 +1,56 @@
+/*
+ * 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_
+