Index: cloud_print/service/win/service_state.cc |
diff --git a/cloud_print/service/win/service_state.cc b/cloud_print/service/win/service_state.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..864100001e3b75670e8cdccabd5e902b925e9a1a |
--- /dev/null |
+++ b/cloud_print/service/win/service_state.cc |
@@ -0,0 +1,211 @@ |
+// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "cloud_print/service/win/service_state.h" |
+ |
+#include "base/json/json_reader.h" |
+#include "base/json/json_writer.h" |
+#include "base/logging.h" |
+#include "base/message_loop.h" |
+#include "base/string_util.h" |
+#include "base/utf_string_conversions.h" |
+#include "net/base/escape.h" |
+#include "net/base/io_buffer.h" |
+#include "net/url_request/url_request.h" |
+#include "net/url_request/url_request_context.h" |
+#include "net/url_request/url_request_context_builder.h" |
+ |
+namespace { |
+ |
+const char kCloudPrintJsonName[] = "cloud_print"; |
+const char kEnabledOptionName[] = "enabled"; |
+ |
+const char kEmailOptionName[] = "email"; |
+const char kPasswordOptionName[] = "password"; |
+const char kProxyIdOptionName[] = "proxy_id"; |
+const char kRobotEmailOptionName[] = "robot_email"; |
+const char kRobotTokenOptionName[] = "robot_refresh_token"; |
+const char kAuthTokenOptionName[] = "auth_token"; |
+const char kXmppAuthTokenOptionName[] = "xmpp_auth_token"; |
+ |
+const char kClientLoginUrl[] = "https://www.google.com/accounts/ClientLogin"; |
+ |
+const int64 kRequestTimeoutMs = 10 * 1000; |
+ |
+class ServiceStateURLRequestDelegate : public net::URLRequest::Delegate { |
+ public: |
+ virtual void OnResponseStarted(net::URLRequest* request) { |
+ if (request->GetResponseCode() == 200) { |
+ Read(request); |
+ if (request->status().is_io_pending()) |
+ return; |
+ } |
+ request->Cancel(); |
+ }; |
+ |
+ virtual void OnReadCompleted(net::URLRequest* request, int bytes_read) { |
+ Read(request); |
+ if (!request->status().is_io_pending()) |
+ MessageLoop::current()->Quit(); |
+ }; |
+ |
+ const std::string& data() const { |
+ return data_; |
+ } |
+ |
+ private: |
+ void Read(net::URLRequest* request) { |
+ // Read as many bytes as are available synchronously. |
+ const int kBufSize = 100000; |
+ scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kBufSize)); |
+ int num_bytes = 0; |
+ while (request->Read(buf, kBufSize, &num_bytes)) { |
+ data_.append(buf->data(), buf->data() + num_bytes); |
+ } |
+ } |
+ std::string data_; |
+}; |
+ |
+ |
+void SetNotEmptyJsonString(base::DictionaryValue* dictionary, |
+ const std::string& name, |
+ const std::string& value) { |
+ if (!value.empty()) |
+ dictionary->SetString(name, value); |
+} |
+ |
+} // namespace |
+ |
+ServiceState::ServiceState() { |
+ Reset(); |
+} |
+ |
+ServiceState::~ServiceState() { |
+} |
+ |
+void ServiceState::Reset() { |
+ email_.clear(); |
+ proxy_id_.clear(); |
+ robot_email_.clear(); |
+ robot_token_.clear(); |
+ auth_token_.clear(); |
+ xmpp_auth_token_.clear(); |
+} |
+ |
+bool ServiceState::FromString(const std::string& json) { |
+ Reset(); |
+ scoped_ptr<base::Value> data(base::JSONReader::Read(json)); |
+ if (!data.get()) |
+ return false; |
+ |
+ const base::DictionaryValue* services = NULL; |
+ if (!data->GetAsDictionary(&services)) |
+ return false; |
+ |
+ base::DictionaryValue* cloud_print = NULL; |
+ if (!services->GetDictionary(kCloudPrintJsonName, &cloud_print)) |
+ return false; |
+ |
+ bool valid_file = true; |
+ // Don't exit on fail. Collect all data for re-use by user later. |
+ if (!cloud_print->GetBoolean(kEnabledOptionName, &valid_file)) |
+ valid_file = false; |
+ |
+ cloud_print->GetString(kEmailOptionName, &email_); |
+ cloud_print->GetString(kProxyIdOptionName, &proxy_id_); |
+ cloud_print->GetString(kRobotEmailOptionName, &robot_email_); |
+ cloud_print->GetString(kRobotTokenOptionName, &robot_token_); |
+ cloud_print->GetString(kAuthTokenOptionName, &auth_token_); |
+ cloud_print->GetString(kXmppAuthTokenOptionName, &xmpp_auth_token_); |
+ |
+ return valid_file && IsValid(); |
+} |
+ |
+bool ServiceState::IsValid() const { |
+ if (email_.empty() || proxy_id_.empty()) |
+ return false; |
+ bool valid_robot = !robot_email_.empty() && !robot_token_.empty(); |
+ bool valid_auth = !auth_token_.empty() && !xmpp_auth_token_.empty(); |
+ return valid_robot || valid_auth; |
+} |
+ |
+std::string ServiceState::ToString() { |
+ scoped_ptr<base::DictionaryValue> services(new DictionaryValue()); |
+ |
+ scoped_ptr<base::DictionaryValue> cloud_print(new DictionaryValue()); |
+ cloud_print->SetBoolean(kEnabledOptionName, true); |
+ |
+ SetNotEmptyJsonString(cloud_print.get(), kEmailOptionName, email_); |
+ SetNotEmptyJsonString(cloud_print.get(), kProxyIdOptionName, proxy_id_); |
+ SetNotEmptyJsonString(cloud_print.get(), kRobotEmailOptionName, robot_email_); |
+ SetNotEmptyJsonString(cloud_print.get(), kRobotTokenOptionName, robot_token_); |
+ SetNotEmptyJsonString(cloud_print.get(), kAuthTokenOptionName, auth_token_); |
+ SetNotEmptyJsonString(cloud_print.get(), kXmppAuthTokenOptionName, |
+ xmpp_auth_token_); |
+ |
+ services->Set(kCloudPrintJsonName, cloud_print.release()); |
+ |
+ std::string json; |
+ base::JSONWriter::WriteWithOptions(services.get(), |
+ base::JSONWriter::OPTIONS_PRETTY_PRINT, |
+ &json); |
+ return json; |
+} |
+ |
+std::string ServiceState::LoginToGoogle(const std::string& service, |
+ const std::string& email, |
+ const std::string& password) { |
+ MessageLoop loop(MessageLoop::TYPE_IO); |
+ |
+ net::URLRequestContextBuilder builder; |
+ scoped_ptr<net::URLRequestContext> context(builder.Build()); |
+ |
+ ServiceStateURLRequestDelegate fetcher_delegate; |
+ GURL url(kClientLoginUrl); |
+ |
+ std::string post_body; |
+ post_body += "accountType=GOOGLE"; |
+ post_body += "&Email=" + net::EscapeUrlEncodedData(email, true); |
+ post_body += "&Passwd=" + net::EscapeUrlEncodedData(password, true); |
+ post_body += "&source=" + net::EscapeUrlEncodedData("CP-Service", true); |
+ post_body += "&service=" + net::EscapeUrlEncodedData(service, true); |
+ |
+ net::URLRequest request(url, &fetcher_delegate); |
+ |
+ request.AppendBytesToUpload(post_body.c_str(), post_body.size()); |
+ request.SetExtraRequestHeaderByName( |
+ "Content-Type", "application/x-www-form-urlencoded", true); |
+ request.set_context(context.get()); |
+ request.set_method("POST"); |
+ request.Start(); |
+ |
+ MessageLoop::current()->PostDelayedTask( |
+ FROM_HERE, MessageLoop::QuitClosure(), kRequestTimeoutMs); |
+ |
+ MessageLoop::current()->Run(); |
+ |
+ const char kAuthStart[] = "Auth="; |
+ std::vector<std::string> lines; |
+ Tokenize(fetcher_delegate.data(), "\r\n", &lines); |
+ for (size_t i = 0; i < lines.size(); ++i) { |
+ std::vector<std::string> tokens; |
+ if (StartsWithASCII(lines[i], kAuthStart, false)) |
+ return lines[i].substr(arraysize(kAuthStart) - 1); |
+ } |
+ |
+ return std::string(); |
+} |
+ |
+bool ServiceState::Configure(const std::string& email, |
+ const std::string& password, |
+ const std::string& proxy_id) { |
+ robot_token_.clear(); |
+ robot_email_.clear(); |
+ email_ = email; |
+ proxy_id_ = proxy_id; |
+ auth_token_ = LoginToGoogle("cloudprint", email_, password); |
+ xmpp_auth_token_ = LoginToGoogle("chromiumsync", email_, password); |
+ return IsValid(); |
+} |
+ |