Merge remote-tracking branch 'weave/dev' into 'weave/master'

ff46c93 Merge remote-tracking branch 'weave/master' into dev_review
08be74d Update libuweave/macaroon code
4efdf46 Fix GCC warning
4fe71e3 Make App ID a part of User ID
3cbb686 Update macaroon lib with version supporting empty strings
8585d30 Remove unused line
69dd2e1 Merge remote-tracking branch 'weave/master' into dev_dev
70c8642 Add kUwMacaroonDelegateeTypeService caveat
d5f7aab Add session ID validation
d7c6deb Remove crypto type "None"
d74a732 Update macaroon lib
a821f2e Integrate new macaroon library
7d29a5a Update macaroon lib
1c83377 Fix build errors introduced by
9ac4c6c Merge remote-tracking branch 'weave/master' into 'weave/dev'
5a7c4f5 Add black list manager implementation
484b6e4 Update AccessBlackListManager interface
81ac16e Add MockConfigStore argument to disabled default expectations
07bb755 Merge remote-tracking branch 'weave/master' into dev_dev2
7329b74 Fix unittest compilation on GCC
f533677 Implemented _accessControlBlackList trait
6741755 Merge remote-tracking branch 'weave/master' into dev_dev2
42e508f Add write callback into SaveSettings function
7ecdf95 Add |name| into LoadSettings/SaveSettings
8023b80 Merge remote-tracking branch 'weave/master' into dev_dev2
diff --git a/README.md b/README.md
index 211033c..fb8d092 100644
--- a/README.md
+++ b/README.md
@@ -77,16 +77,18 @@
 
 ### For tests
 
+  - cmake
   - gtest (included; see third_party/get_gtest.sh)
   - gmock (included; see third_party/get_gtest.sh)
 
 ### For examples
 
+  - cmake
   - hostapd
   - libavahi-client-dev
   - libcurl4-openssl-dev
-  - libevent 2.0.x
   - libevhtp (included; see third_party/get_libevhtp.sh)
+  - libevent-dev
 
 
 # Compiling
diff --git a/examples/prerequisites.sh b/examples/prerequisites.sh
index 489bb58..23d54d7 100755
--- a/examples/prerequisites.sh
+++ b/examples/prerequisites.sh
@@ -13,10 +13,12 @@
   autoconf \
   automake \
   binutils \
+  cmake \
   g++ \
   hostapd \
   libavahi-client-dev \
   libcurl4-openssl-dev \
+  libevent-dev \
   libexpat1-dev \
   libnl-3-dev \
   libnl-route-3-dev \
diff --git a/include/weave/settings.h b/include/weave/settings.h
index 741fff2..7cb798d 100644
--- a/include/weave/settings.h
+++ b/include/weave/settings.h
@@ -61,6 +61,7 @@
   // Optional cloud information. Can be used for testing or debugging.
   std::string oauth_url;
   std::string service_url;
+  std::string xmpp_endpoint;
 
   // Cloud ID of the registered device. Empty if device is not registered.
   std::string cloud_id;
diff --git a/src/config.cc b/src/config.cc
index 44d20dd..21a1c1f 100644
--- a/src/config.cc
+++ b/src/config.cc
@@ -33,6 +33,7 @@
 const char kApiKey[] = "api_key";
 const char kOAuthURL[] = "oauth_url";
 const char kServiceURL[] = "service_url";
+const char kXmppEndpoint[] = "xmpp_endpoint";
 const char kName[] = "name";
 const char kDescription[] = "description";
 const char kLocation[] = "location";
@@ -51,6 +52,7 @@
 
 const char kWeaveUrl[] = "https://www.googleapis.com/weave/v1/";
 const char kDeprecatedUrl[] = "https://www.googleapis.com/clouddevices/v1/";
+const char kXmppEndpoint[] = "talk.google.com:5223";
 
 namespace {
 
@@ -69,6 +71,7 @@
   Config::Settings result;
   result.oauth_url = "https://accounts.google.com/o/oauth2/";
   result.service_url = kWeaveUrl;
+  result.xmpp_endpoint = kXmppEndpoint;
   result.local_anonymous_access_role = AuthScope::kViewer;
   result.pairing_modes.insert(PairingType::kPinCode);
   result.device_id = base::GenerateGUID();
@@ -119,6 +122,7 @@
   CHECK(!settings_.api_key.empty());
   CHECK(!settings_.oauth_url.empty());
   CHECK(!settings_.service_url.empty());
+  CHECK(!settings_.xmpp_endpoint.empty());
   CHECK(!settings_.oem_name.empty());
   CHECK(!settings_.model_name.empty());
   CHECK(!settings_.model_id.empty());
@@ -190,6 +194,10 @@
     set_service_url(tmp);
   }
 
+  if (dict->GetString(config_keys::kXmppEndpoint, &tmp)) {
+    set_xmpp_endpoint(tmp);
+  }
+
   if (dict->GetString(config_keys::kName, &tmp))
     set_name(tmp);
 
@@ -249,6 +257,7 @@
   dict.SetString(config_keys::kApiKey, settings_.api_key);
   dict.SetString(config_keys::kOAuthURL, settings_.oauth_url);
   dict.SetString(config_keys::kServiceURL, settings_.service_url);
+  dict.SetString(config_keys::kXmppEndpoint, settings_.xmpp_endpoint);
   dict.SetString(config_keys::kRefreshToken, settings_.refresh_token);
   dict.SetString(config_keys::kCloudId, settings_.cloud_id);
   dict.SetString(config_keys::kDeviceId, settings_.device_id);
diff --git a/src/config.h b/src/config.h
index 6dc0a07..8e0a8f3 100644
--- a/src/config.h
+++ b/src/config.h
@@ -68,6 +68,9 @@
     void set_service_url(const std::string& url) {
       settings_->service_url = url;
     }
+    void set_xmpp_endpoint(const std::string& endpoint) {
+      settings_->xmpp_endpoint = endpoint;
+    }
     void set_name(const std::string& name) { settings_->name = name; }
     void set_description(const std::string& description) {
       settings_->description = description;
diff --git a/src/config_unittest.cc b/src/config_unittest.cc
index 4b0e5b4..bb2743a 100644
--- a/src/config_unittest.cc
+++ b/src/config_unittest.cc
@@ -62,6 +62,7 @@
   EXPECT_EQ("", GetSettings().api_key);
   EXPECT_EQ("https://accounts.google.com/o/oauth2/", GetSettings().oauth_url);
   EXPECT_EQ("https://www.googleapis.com/weave/v1/", GetSettings().service_url);
+  EXPECT_EQ("talk.google.com:5223", GetSettings().xmpp_endpoint);
   EXPECT_EQ("", GetSettings().oem_name);
   EXPECT_EQ("", GetSettings().model_name);
   EXPECT_EQ("", GetSettings().model_id);
@@ -146,7 +147,8 @@
     "refresh_token": "state_refresh_token",
     "robot_account": "state_robot_account",
     "secret": "c3RhdGVfc2VjcmV0",
-    "service_url": "state_service_url"
+    "service_url": "state_service_url",
+    "xmpp_endpoint": "state_xmpp_endpoint"
   })";
   EXPECT_CALL(config_store_, LoadSettings(kConfigName)).WillOnce(Return(state));
 
@@ -157,6 +159,7 @@
   EXPECT_EQ("state_api_key", GetSettings().api_key);
   EXPECT_EQ("state_oauth_url", GetSettings().oauth_url);
   EXPECT_EQ("state_service_url", GetSettings().service_url);
+  EXPECT_EQ("state_xmpp_endpoint", GetSettings().xmpp_endpoint);
   EXPECT_EQ(GetDefaultSettings().oem_name, GetSettings().oem_name);
   EXPECT_EQ(GetDefaultSettings().model_name, GetSettings().model_name);
   EXPECT_EQ(GetDefaultSettings().model_id, GetSettings().model_id);
@@ -200,6 +203,9 @@
   change.set_service_url("set_service_url");
   EXPECT_EQ("set_service_url", GetSettings().service_url);
 
+  change.set_xmpp_endpoint("set_xmpp_endpoint");
+  EXPECT_EQ("set_xmpp_endpoint", GetSettings().xmpp_endpoint);
+
   change.set_name("set_name");
   EXPECT_EQ("set_name", GetSettings().name);
 
@@ -277,7 +283,8 @@
           'refresh_token': 'set_token',
           'robot_account': 'set_account',
           'secret': 'AQIDBAU=',
-          'service_url': 'set_service_url'
+          'service_url': 'set_service_url',
+          'xmpp_endpoint': 'set_xmpp_endpoint'
         })";
             EXPECT_JSON_EQ(expected, *test::CreateValue(json));
             callback.Run(nullptr);
diff --git a/src/device_registration_info.cc b/src/device_registration_info.cc
index 7c20084..0dc1f54 100644
--- a/src/device_registration_info.cc
+++ b/src/device_registration_info.cc
@@ -463,8 +463,9 @@
   current_notification_channel_ = pull_channel_.get();
 
   notification_channel_starting_ = true;
-  primary_notification_channel_.reset(new XmppChannel{
-      GetSettings().robot_account, access_token_, task_runner_, network_});
+  primary_notification_channel_.reset(
+      new XmppChannel{GetSettings().robot_account, access_token_,
+                      GetSettings().xmpp_endpoint, task_runner_, network_});
   primary_notification_channel_->Start(this);
 }
 
@@ -833,17 +834,25 @@
     const std::string& api_key,
     const std::string& oauth_url,
     const std::string& service_url,
+    const std::string& xmpp_endpoint,
     ErrorPtr* error) {
   if (HaveRegistrationCredentials()) {
     return Error::AddTo(error, FROM_HERE, kErrorAlreayRegistered,
                         "Unable to change config for registered device");
   }
   Config::Transaction change{config_};
-  change.set_client_id(client_id);
-  change.set_client_secret(client_secret);
-  change.set_api_key(api_key);
-  change.set_oauth_url(oauth_url);
-  change.set_service_url(service_url);
+  if (!client_id.empty())
+    change.set_client_id(client_id);
+  if (!client_secret.empty())
+    change.set_client_secret(client_secret);
+  if (!api_key.empty())
+    change.set_api_key(api_key);
+  if (!oauth_url.empty())
+    change.set_oauth_url(oauth_url);
+  if (!service_url.empty())
+    change.set_service_url(service_url);
+  if (!xmpp_endpoint.empty())
+    change.set_xmpp_endpoint(xmpp_endpoint);
   return true;
 }
 
diff --git a/src/device_registration_info.h b/src/device_registration_info.h
index f670b68..a296258 100644
--- a/src/device_registration_info.h
+++ b/src/device_registration_info.h
@@ -78,6 +78,7 @@
                            const std::string& api_key,
                            const std::string& oauth_url,
                            const std::string& service_url,
+                           const std::string& xmpp_endpoint,
                            ErrorPtr* error);
 
   void GetDeviceInfo(const CloudRequestDoneCallback& callback);
diff --git a/src/device_registration_info_unittest.cc b/src/device_registration_info_unittest.cc
index 7908c8b..bbc167e 100644
--- a/src/device_registration_info_unittest.cc
+++ b/src/device_registration_info_unittest.cc
@@ -44,6 +44,7 @@
 
 namespace test_data {
 
+const char kXmppEndpoint[] = "xmpp.server.com:1234";
 const char kServiceURL[] = "http://gcd.server.com/";
 const char kOAuthURL[] = "http://oauth.server.com/";
 const char kApiKey[] = "GOadRdTf9FERf0k4w6EFOof56fUJ3kFDdFL3d7f";
@@ -144,6 +145,7 @@
           settings->model_id = "AAAAA";
           settings->oauth_url = test_data::kOAuthURL;
           settings->service_url = test_data::kServiceURL;
+          settings->xmpp_endpoint = test_data::kXmppEndpoint;
           return true;
         }));
     config_.reset(new Config{&config_store_});
diff --git a/src/notification/xmpp_channel.cc b/src/notification/xmpp_channel.cc
index ceb45ed..f9d7924 100644
--- a/src/notification/xmpp_channel.cc
+++ b/src/notification/xmpp_channel.cc
@@ -7,6 +7,7 @@
 #include <string>
 
 #include <base/bind.h>
+#include <base/strings/string_number_conversions.h>
 #include <weave/provider/network.h>
 #include <weave/provider/task_runner.h>
 
@@ -16,6 +17,7 @@
 #include "src/notification/notification_parser.h"
 #include "src/notification/xml_node.h"
 #include "src/privet/openssl_utils.h"
+#include "src/string_utils.h"
 #include "src/utils.h"
 
 namespace weave {
@@ -74,9 +76,6 @@
     false,
 };
 
-const char kDefaultXmppHost[] = "talk.google.com";
-const uint16_t kDefaultXmppPort = 5223;
-
 // Used for keeping connection alive.
 const int kRegularPingIntervalSeconds = 60;
 const int kRegularPingTimeoutSeconds = 30;
@@ -91,10 +90,12 @@
 
 XmppChannel::XmppChannel(const std::string& account,
                          const std::string& access_token,
+                         const std::string& xmpp_endpoint,
                          provider::TaskRunner* task_runner,
                          provider::Network* network)
     : account_{account},
       access_token_{access_token},
+      xmpp_endpoint_{xmpp_endpoint},
       network_{network},
       backoff_entry_{&kDefaultBackoffPolicy},
       task_runner_{task_runner},
@@ -285,10 +286,16 @@
 void XmppChannel::CreateSslSocket() {
   CHECK(!stream_);
   state_ = XmppState::kConnecting;
-  LOG(INFO) << "Starting XMPP connection to " << kDefaultXmppHost << ":"
-            << kDefaultXmppPort;
+  LOG(INFO) << "Starting XMPP connection to: " << xmpp_endpoint_;
 
-  network_->OpenSslSocket(kDefaultXmppHost, kDefaultXmppPort,
+  std::pair<std::string, std::string> host_port =
+      SplitAtFirst(xmpp_endpoint_, ":", true);
+  CHECK(!host_port.first.empty());
+  CHECK(!host_port.second.empty());
+  uint32_t port = 0;
+  CHECK(base::StringToUint(host_port.second, &port)) << xmpp_endpoint_;
+
+  network_->OpenSslSocket(host_port.first, port,
                           base::Bind(&XmppChannel::OnSslSocketReady,
                                      task_ptr_factory_.GetWeakPtr()));
 }
diff --git a/src/notification/xmpp_channel.h b/src/notification/xmpp_channel.h
index 50e84d2..b0a4468 100644
--- a/src/notification/xmpp_channel.h
+++ b/src/notification/xmpp_channel.h
@@ -45,6 +45,7 @@
   // so you will need to reset the XmppClient every time this happens.
   XmppChannel(const std::string& account,
               const std::string& access_token,
+              const std::string& xmpp_endpoint,
               provider::TaskRunner* task_runner,
               provider::Network* network);
   ~XmppChannel() override = default;
@@ -124,12 +125,15 @@
   // Robot account name for the device.
   std::string account_;
 
-  // Full JID of this device.
-  std::string jid_;
-
   // OAuth access token for the account. Expires fairly frequently.
   std::string access_token_;
 
+  // Xmpp endpoint.
+  std::string xmpp_endpoint_;
+
+  // Full JID of this device.
+  std::string jid_;
+
   provider::Network* network_{nullptr};
   std::unique_ptr<Stream> stream_;
 
diff --git a/src/notification/xmpp_channel_unittest.cc b/src/notification/xmpp_channel_unittest.cc
index 674fe22..dfa2a79 100644
--- a/src/notification/xmpp_channel_unittest.cc
+++ b/src/notification/xmpp_channel_unittest.cc
@@ -26,6 +26,7 @@
 
 constexpr char kAccountName[] = "Account@Name";
 constexpr char kAccessToken[] = "AccessToken";
+constexpr char kEndpoint[] = "endpoint:456";
 
 constexpr char kStartStreamMessage[] =
     "<stream:stream to='clouddevices.gserviceaccount.com' "
@@ -84,7 +85,8 @@
  public:
   explicit FakeXmppChannel(provider::TaskRunner* task_runner,
                            provider::Network* network)
-      : XmppChannel{kAccountName, kAccessToken, task_runner, network},
+      : XmppChannel{kAccountName, kAccessToken, kEndpoint, task_runner,
+                    network},
         stream_{new test::FakeStream{task_runner_}},
         fake_stream_{stream_.get()} {}
 
@@ -122,7 +124,7 @@
 class XmppChannelTest : public ::testing::Test {
  protected:
   XmppChannelTest() {
-    EXPECT_CALL(network_, OpenSslSocket("talk.google.com", 5223, _))
+    EXPECT_CALL(network_, OpenSslSocket("endpoint", 456, _))
         .WillOnce(
             WithArgs<2>(Invoke(&xmpp_client_, &FakeXmppChannel::Connect)));
   }