Enable crypto by default in example call app, add MUC lookup code, and fix a few minor bugs.

git-svn-id: http://libjingle.googlecode.com/svn/trunk@62 dd674b97-3498-5ee5-1854-bdd07cd0ff33
diff --git a/talk/base/linux.cc b/talk/base/linux.cc
index 056e0a0..514ab94 100644
--- a/talk/base/linux.cc
+++ b/talk/base/linux.cc
@@ -25,11 +25,14 @@
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifdef LINUX
+#if defined(LINUX) || defined(ANDROID)
 #include "talk/base/linux.h"
 
+#include <ctype.h>
+
 #include <errno.h>
 #include <sys/utsname.h>
+#include <sys/wait.h>
 
 #include <cstdio>
 #include <set>
@@ -342,4 +345,4 @@
 
 }  // namespace talk_base
 
-#endif  // LINUX
+#endif  // defined(LINUX) || defined(ANDROID)
diff --git a/talk/base/linux.h b/talk/base/linux.h
index c6151a4..ee028c7 100644
--- a/talk/base/linux.h
+++ b/talk/base/linux.h
@@ -28,7 +28,7 @@
 #ifndef TALK_BASE_LINUX_H_
 #define TALK_BASE_LINUX_H_
 
-#ifdef LINUX
+#if defined(LINUX) || defined(ANDROID)
 #include <string>
 #include <map>
 #include <vector>
@@ -134,5 +134,5 @@
 
 }  // namespace talk_base
 
-#endif  // LINUX
+#endif  // defined(LINUX) || defined(ANDROID)
 #endif  // TALK_BASE_LINUX_H_
diff --git a/talk/examples/call/call_main.cc b/talk/examples/call/call_main.cc
index e0cc2cd..69d66f8 100644
--- a/talk/examples/call/call_main.cc
+++ b/talk/examples/call/call_main.cc
@@ -220,7 +220,7 @@
       protocol, "hybrid",
       "Initial signaling protocol to use: jingle, gingle, or hybrid.");
   DEFINE_string(
-      secure, "disable",
+      secure, "enable",
       "Disable or enable encryption: disable, enable, require.");
   DEFINE_bool(testserver, false, "Use test server");
   DEFINE_bool(plainserver, false, "Turn off tls and allow plain password.");
diff --git a/talk/examples/call/callclient.cc b/talk/examples/call/callclient.cc
index 895b58b..02abc0e 100644
--- a/talk/examples/call/callclient.cc
+++ b/talk/examples/call/callclient.cc
@@ -742,8 +742,7 @@
 
   // Look up this muc.
   MucMap::iterator elem = mucs_.find(jid);
-  ASSERT(elem != mucs_.end() &&
-         elem->second->state() == buzz::Muc::MUC_JOINED);
+  ASSERT(elem != mucs_.end());
 
   buzz::Muc* muc = elem->second;
 
diff --git a/talk/session/phone/channel.cc b/talk/session/phone/channel.cc
index d670bf1..bd5ec30 100644
--- a/talk/session/phone/channel.cc
+++ b/talk/session/phone/channel.cc
@@ -88,6 +88,7 @@
       rtcp_transport_channel_(NULL),
       enabled_(false),
       writable_(false),
+      was_ever_writable_(false),
       has_codec_(false),
       muted_(false) {
   ASSERT(worker_thread_ == talk_base::Thread::Current());
@@ -238,6 +239,11 @@
 }
 
 bool BaseChannel::SendPacket(bool rtcp, talk_base::Buffer* packet) {
+  // Ensure we have a path capable of sending packets.
+  if (!writable_) {
+    return false;
+  }
+
   // SendPacket gets called from MediaEngine, typically on an encoder thread.
   // If the thread is not our worker thread, we will post to our worker
   // so that the real work happens on our worker. This avoids us having to
@@ -254,12 +260,13 @@
     return true;
   }
 
-  // Make sure we have a place to send this packet before doing anything.
-  // (We might get RTCP packets that we don't intend to send.)
-  // If we've negotiated RTCP mux, send RTCP over the RTP transport.
+  // Now that we are on the correct thread, ensure we have a place to send this
+  // packet before doing anything. (We might get RTCP packets that we don't
+  // intend to send.) If we've negotiated RTCP mux, send RTCP over the RTP
+  // transport.
   TransportChannel* channel = (!rtcp || rtcp_mux_filter_.IsActive()) ?
       transport_channel_ : rtcp_transport_channel_;
-  if (!channel) {
+  if (!channel || !channel->writable()) {
     return false;
   }
 
@@ -465,7 +472,9 @@
   if (writable_)
     return;
   LOG(LS_INFO) << "Channel socket writable ("
-               << transport_channel_->name().c_str() << ")";
+               << transport_channel_->name().c_str() << ")"
+               << (was_ever_writable_ ? "" : " for the first time");
+  was_ever_writable_ = true;
   writable_ = true;
   ChangeState();
 }
@@ -739,10 +748,9 @@
     SendLastMediaError();
   }
 
-  // send outgoing data if we are the active call, have the
-  // remote party's codec, and have a writable transport
-  // we only send data on the default channel
-  bool send = enabled() && has_codec() && writable();
+  // Send outgoing data if we are the active call and we know their codec, and
+  // we have had some form of connectivity.
+  bool send = enabled() && has_codec() && was_ever_writable();
   SendFlags send_flag = send ? SEND_MICROPHONE : SEND_NOTHING;
   if (!media_channel()->SetSend(send_flag)) {
     LOG(LS_ERROR) << "Failed to SetSend " << send_flag << " on voice channel";
@@ -1037,10 +1045,9 @@
     // TODO: Report error back to server.
   }
 
-  // send outgoing data if we are the active call, have the
-  // remote party's codec, and have a writable transport
-  // we only send data on the default channel
-  bool send = enabled() && has_codec() && writable();
+  // Send outgoing data if we are the active call and we know their codec, and
+  // we have had some form of connectivity.
+  bool send = enabled() && has_codec() && was_ever_writable();
   if (!media_channel()->SetSend(send)) {
     LOG(LS_ERROR) << "Failed to SetSend on video channel";
     // TODO: Report error back to server.
diff --git a/talk/session/phone/channel.h b/talk/session/phone/channel.h
index 8b33386..9378a0f 100644
--- a/talk/session/phone/channel.h
+++ b/talk/session/phone/channel.h
@@ -144,6 +144,7 @@
   virtual MediaChannel* media_channel() const { return media_channel_; }
   void set_rtcp_transport_channel(TransportChannel* transport);
   bool writable() const { return writable_; }
+  bool was_ever_writable() const { return was_ever_writable_; }
   bool has_codec() const { return has_codec_; }
   void set_has_codec(bool has_codec) { has_codec_ = has_codec; }
   bool muted() const { return muted_; }
@@ -254,6 +255,7 @@
   talk_base::scoped_ptr<SocketMonitor> socket_monitor_;
   bool enabled_;
   bool writable_;
+  bool was_ever_writable_;
   bool has_codec_;
   bool muted_;
 };
diff --git a/talk/xmpp/mucroomlookuptask.cc b/talk/xmpp/mucroomlookuptask.cc
new file mode 100644
index 0000000..62b4b73
--- /dev/null
+++ b/talk/xmpp/mucroomlookuptask.cc
@@ -0,0 +1,157 @@
+/*
+ * libjingle
+ * Copyright 2011, 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/xmpp/mucroomlookuptask.h"
+
+#include "talk/base/logging.h"
+#include "talk/base/scoped_ptr.h"
+#include "talk/xmpp/constants.h"
+
+
+namespace buzz {
+
+static const int kLookupTimeout = 15;
+
+MucRoomLookupTask::MucRoomLookupTask(Task* parent,
+                                     const std::string& room_name,
+                                     const std::string& organizer_domain)
+    : XmppTask(parent, XmppEngine::HL_SINGLE),
+      room_name_(room_name),
+      organizer_domain_(organizer_domain) {
+  set_timeout_seconds(kLookupTimeout);
+}
+
+MucRoomLookupTask::MucRoomLookupTask(Task* parent,
+                                     const Jid& room_jid)
+    : XmppTask(parent, XmppEngine::HL_SINGLE), room_jid_(room_jid) {
+  set_timeout_seconds(kLookupTimeout);
+}
+
+int MucRoomLookupTask::ProcessStart() {
+  talk_base::scoped_ptr<XmlElement> lookup(MakeIq(STR_SET,
+      Jid(STR_MUC_LOOKUP_DOMAIN), task_id()));
+  if (room_jid_ != JID_EMPTY) {
+    // TODO: need to test the jid query calling code below.
+    XmlElement* query_elem = MakeJidQuery(room_jid_.Str());
+    lookup->AddElement(query_elem);
+  } else {
+    // We do room query if room jid is unknown.
+    XmlElement* query_elem = MakeRoomQuery(room_name_, organizer_domain_);
+    lookup->AddElement(query_elem);
+  }
+
+  if (SendStanza(lookup.get()) != XMPP_RETURN_OK) {
+    SignalRoomLookupError(NULL);
+    return STATE_ERROR;
+  }
+  return STATE_RESPONSE;
+}
+
+int MucRoomLookupTask::ProcessResponse() {
+  const XmlElement* stanza = NextStanza();
+
+  if (stanza == NULL)
+    return STATE_BLOCKED;
+
+  if (stanza->Attr(QN_TYPE) == STR_ERROR) {
+    SignalRoomLookupError(stanza->FirstNamed(QN_ERROR));
+    return STATE_DONE;
+  }
+
+  const XmlElement* query_elem = stanza->FirstNamed(QN_SEARCH_QUERY);
+  if (query_elem != NULL) {
+    const XmlElement* item_elem =
+        query_elem->FirstNamed(QN_SEARCH_ITEM);
+    if (item_elem != NULL && item_elem->HasAttr(QN_JID)) {
+      MucRoomInfo room_info;
+      if (GetRoomInfoFromResponse(item_elem, &room_info)) {
+        SignalRoomLookupResponse(room_info);
+        return STATE_DONE;
+      }
+    }
+  }
+
+  SignalRoomLookupError(NULL);
+  return STATE_DONE;
+}
+
+int MucRoomLookupTask::OnTimeout() {
+  SignalRoomLookupError(NULL);
+  return XmppTask::OnTimeout();
+}
+
+bool MucRoomLookupTask::HandleStanza(const XmlElement* stanza) {
+  if (MatchResponseIq(stanza, Jid(STR_MUC_LOOKUP_DOMAIN), task_id())) {
+    QueueStanza(stanza);
+    return true;
+  }
+  return false;
+}
+
+XmlElement* MucRoomLookupTask::MakeRoomQuery(const std::string& room_name,
+    const std::string& org_domain) {
+  XmlElement* room_elem = new XmlElement(QN_SEARCH_ROOM_NAME, false);
+  room_elem->SetBodyText(room_name);
+
+  XmlElement* domain_elem = new XmlElement(QN_SEARCH_ORGANIZERS_DOMAIN, false);
+  domain_elem->SetBodyText(org_domain);
+
+  XmlElement* query = new XmlElement(QN_SEARCH_QUERY, true);
+  query->AddElement(room_elem);
+  query->AddElement(domain_elem);
+
+  return query;
+}
+
+XmlElement* MucRoomLookupTask::MakeJidQuery(const std::string& room_jid) {
+  XmlElement* jid_elem = new XmlElement(QN_SEARCH_ROOM_JID);
+  jid_elem->SetBodyText(room_jid);
+
+  XmlElement* query = new XmlElement(QN_SEARCH_QUERY);
+  query->AddElement(jid_elem);
+
+  return query;
+}
+
+bool MucRoomLookupTask::GetRoomInfoFromResponse(
+    const XmlElement* stanza, MucRoomInfo* info) {
+
+  info->room_jid = Jid(stanza->Attr(buzz::QN_JID));
+  if (!info->room_jid.IsValid()) return false;
+
+  const XmlElement* room_name_elem = stanza->FirstNamed(QN_SEARCH_ROOM_NAME);
+  const XmlElement* org_domain_elem =
+      stanza->FirstNamed(QN_SEARCH_ORGANIZERS_DOMAIN);
+
+  if (room_name_elem != NULL)
+    info->room_name = room_name_elem->BodyText();
+  if (org_domain_elem != NULL)
+    info->organizer_domain = org_domain_elem->BodyText();
+
+  return true;
+}
+}  // namespace buzz
diff --git a/talk/xmpp/mucroomlookuptask.h b/talk/xmpp/mucroomlookuptask.h
new file mode 100644
index 0000000..ca56b3b
--- /dev/null
+++ b/talk/xmpp/mucroomlookuptask.h
@@ -0,0 +1,69 @@
+/*
+ * libjingle
+ * Copyright 2011, 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_XMPP_MUCROOMLOOKUPTASK_H_
+#define TALK_XMPP_MUCROOMLOOKUPTASK_H_
+
+#include <string>
+#include "talk/xmpp/xmpptask.h"
+
+namespace buzz {
+
+struct MucRoomInfo {
+  buzz::Jid room_jid;
+  std::string room_name;
+  std::string organizer_domain;
+};
+
+class MucRoomLookupTask : public XmppTask {
+ public:
+  MucRoomLookupTask(Task* parent, const std::string& room_name,
+      const std::string& organizer_domain);
+  MucRoomLookupTask(Task* parent, const Jid& room_jid);
+
+  sigslot::signal1<const MucRoomInfo&> SignalRoomLookupResponse;
+  sigslot::signal1<const XmlElement*> SignalRoomLookupError;
+
+ protected:
+  virtual bool HandleStanza(const XmlElement* stanza);
+  virtual int ProcessStart();
+  virtual int ProcessResponse();
+  virtual int OnTimeout();
+
+ private:
+  XmlElement* MakeRoomQuery(const std::string& room_name,
+      const std::string& org_domain);
+  XmlElement* MakeJidQuery(const std::string& room_jid);
+  bool GetRoomInfoFromResponse(const XmlElement* stanza, MucRoomInfo* info);
+  const std::string room_name_;
+  const std::string organizer_domain_;
+  const Jid room_jid_;
+};
+
+}  // namespace buzz
+
+#endif  // TALK_XMPP_MUCROOMLOOKUPTASK_H_