<commit_before>// Copyright (c) 2010 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 "chrome/browser/chromeos/login/google_authenticator.h"

#include <string>
#include <vector>

#include "base/file_path.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/sha2.h"
#include "base/string_util.h"
#include "base/third_party/nss/blapi.h"
#include "base/third_party/nss/sha256.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/chromeos/cros/cryptohome_library.h"
#include "chrome/browser/chromeos/login/auth_response_handler.h"
#include "chrome/browser/chromeos/login/authentication_notification_details.h"
#include "chrome/browser/chromeos/login/login_status_consumer.h"
#include "chrome/browser/net/chrome_url_request_context.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/profile_manager.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/net/url_fetcher.h"
#include "chrome/common/notification_service.h"
#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
#include "net/url_request/url_request_status.h"
#include "third_party/libjingle/source/talk/base/urlencode.h"

using base::Time;
using base::TimeDelta;
using file_util::GetFileSize;
using file_util::PathExists;
using file_util::ReadFile;
using file_util::ReadFileToString;

namespace chromeos {

// static
const char GoogleAuthenticator::kCookiePersistence[] = "true";
// static
const char GoogleAuthenticator::kAccountType[] = "HOSTED_OR_GOOGLE";
// static
const char GoogleAuthenticator::kSource[] = "chromeos";
// static
// Service name for Google Contacts API. API is used to get user's image.
const char GoogleAuthenticator::kService[] = "cp";
// static
const char GoogleAuthenticator::kFormat[] =
    "Email=%s&"
    "Passwd=%s&"
    "PersistentCookie=%s&"
    "accountType=%s&"
    "source=%s&"
    "service=%s";
// static
const char GoogleAuthenticator::kFormatCaptcha[] =
    "Email=%s&"
    "Passwd=%s&"
    "PersistentCookie=%s&"
    "accountType=%s&"
    "source=%s&"
    "service=%s&"
    "logintoken=%s&"
    "logincaptcha=%s";
// static
const char GoogleAuthenticator::kSecondFactor[] = "Info=InvalidSecondFactor";

// static
const char GoogleAuthenticator::kSystemSalt[] = "/home/.shadow/salt";
// static
const char GoogleAuthenticator::kOpenSSLMagic[] = "Salted__";
// static
const char GoogleAuthenticator::kLocalaccountFile[] = "localaccount";
// static
const char GoogleAuthenticator::kTmpfsTrigger[] = "incognito";

// static
const int GoogleAuthenticator::kClientLoginTimeoutMs = 5000;

const int kPassHashLen = 32;

GoogleAuthenticator::GoogleAuthenticator(LoginStatusConsumer* consumer)
    : Authenticator(consumer),
      fetcher_(NULL),
      getter_(NULL),
      checked_for_localaccount_(false),
      unlock_(false),
      try_again_(true),
      fetch_completed_(false) {
  CHECK(chromeos::CrosLibrary::Get()->EnsureLoaded());
}

GoogleAuthenticator::~GoogleAuthenticator() {
  delete fetcher_;
}

// static
URLFetcher* GoogleAuthenticator::CreateClientLoginFetcher(
    URLRequestContextGetter* getter,
    const std::string& body,
    URLFetcher::Delegate* delegate) {
  URLFetcher* to_return =
      URLFetcher::Create(0,
                         GURL(AuthResponseHandler::kClientLoginUrl),
                         URLFetcher::POST,
                         delegate);
  to_return->set_request_context(getter);
  to_return->set_load_flags(net::LOAD_DO_NOT_SEND_COOKIES);
  to_return->set_upload_data("application/x-www-form-urlencoded", body);
  return to_return;
}

bool GoogleAuthenticator::AuthenticateToLogin(
    Profile* profile,
    const std::string& username,
    const std::string& password,
    const std::string& login_token,
    const std::string& login_captcha) {
  unlock_ = false;
  getter_ = profile->GetRequestContext();

  // TODO(cmasone): be more careful about zeroing memory that stores
  // the user's password.
  if (login_token.empty() || login_captcha.empty()) {
    request_body_ = StringPrintf(kFormat,
                                 UrlEncodeString(username).c_str(),
                                 UrlEncodeString(password).c_str(),
                                 kCookiePersistence,
                                 kAccountType,
                                 kSource,
                                 kService);
  } else {
    request_body_ = StringPrintf(kFormatCaptcha,
                                 UrlEncodeString(username).c_str(),
                                 UrlEncodeString(password).c_str(),
                                 kCookiePersistence,
                                 kAccountType,
                                 kSource,
                                 kService,
                                 UrlEncodeString(login_token).c_str(),
                                 UrlEncodeString(login_captcha).c_str());
  }
  // TODO(cmasone): Figure out how to parallelize fetch, username/password
  // processing without impacting testability.
  username_.assign(Canonicalize(username));
  StoreHashedPassword(password);
  TryClientLogin();
  return true;
}

bool GoogleAuthenticator::AuthenticateToUnlock(const std::string& username,
                                               const std::string& password) {
  username_.assign(Canonicalize(username));
  StoreHashedPassword(password);
  unlock_ = true;
  ChromeThread::PostTask(
      ChromeThread::UI, FROM_HERE,
      NewRunnableMethod(this, &GoogleAuthenticator::CheckOffline,
                        std::string("unlock failed")));
  return true;
}

void GoogleAuthenticator::LoginOffTheRecord() {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
  if (CrosLibrary::Get()->GetCryptohomeLibrary()->Mount(kTmpfsTrigger, "")) {
    AuthenticationNotificationDetails details(true);
    NotificationService::current()->Notify(
        NotificationType::LOGIN_AUTHENTICATION,
        NotificationService::AllSources(),
        Details<AuthenticationNotificationDetails>(&details));
    consumer_->OnOffTheRecordLoginSuccess();
  } else {
    consumer_->OnLoginFailure("Could not mount tmpfs cryptohome");
  }
}

void GoogleAuthenticator::OnURLFetchComplete(const URLFetcher* source,
                                             const GURL& url,
                                             const URLRequestStatus& status,
                                             int response_code,
                                             const ResponseCookies& cookies,
                                             const std::string& data) {
  fetch_completed_ = true;
  if (status.is_success() && response_code == kHttpSuccess) {
    LOG(INFO) << "Online login successful!";
    ChromeThread::PostTask(
        ChromeThread::UI, FROM_HERE,
        NewRunnableMethod(this, &GoogleAuthenticator::OnLoginSuccess, data));
  } else if (!status.is_success()) {
    if (status.status() == URLRequestStatus::CANCELED) {
      if (try_again_) {
        try_again_ = false;
        LOG(ERROR) << "Login attempt canceled!?!?  Trying again.";
        TryClientLogin();
        fetch_completed_ = false;
        return;
      }
      LOG(ERROR) << "Login attempt canceled again?  Already retried...";
    }
    LOG(WARNING) << "Could not reach Google Accounts servers: errno "
              << status.os_error();
    // The fetch failed for network reasons, try offline login.
    LoadLocalaccount(kLocalaccountFile);
    ChromeThread::PostTask(
        ChromeThread::UI, FROM_HERE,
        NewRunnableMethod(this, &GoogleAuthenticator::CheckOffline,
                          net::ErrorToString(status.os_error())));
  } else {
    if (IsSecondFactorSuccess(data)) {
      ChromeThread::PostTask(
          ChromeThread::UI, FROM_HERE,
          NewRunnableMethod(this,
                            &GoogleAuthenticator::OnLoginSuccess,
                            std::string()));
    } else {
      // The fetch succeeded, but ClientLogin said no.
      LoadLocalaccount(kLocalaccountFile);
      ChromeThread::PostTask(
          ChromeThread::UI, FROM_HERE,
          NewRunnableMethod(this,
                            &GoogleAuthenticator::CheckLocalaccount,
                            data));
    }
  }
}

void GoogleAuthenticator::OnLoginSuccess(const std::string& data) {
  // Send notification of success
  AuthenticationNotificationDetails details(true);
  NotificationService::current()->Notify(
      NotificationType::LOGIN_AUTHENTICATION,
      NotificationService::AllSources(),
      Details<AuthenticationNotificationDetails>(&details));

  if (unlock_ ||
      CrosLibrary::Get()->GetCryptohomeLibrary()->Mount(username_.c_str(),
                                                        ascii_hash_.c_str())) {
    consumer_->OnLoginSuccess(username_, data);
  } else {
    OnLoginFailure("Could not mount cryptohome");
  }
}

void GoogleAuthenticator::CheckOffline(const std::string& error) {
  LOG(INFO) << "Attempting offline login";
  if (CrosLibrary::Get()->GetCryptohomeLibrary()->CheckKey(
          username_.c_str(),
          ascii_hash_.c_str())) {
    // The fetch didn't succeed, but offline login did.
    LOG(INFO) << "Offline login successful!";
    OnLoginSuccess(std::string());
  } else {
    // We couldn't hit the network, and offline login failed.
    GoogleAuthenticator::CheckLocalaccount(error);
  }
}

void GoogleAuthenticator::CheckLocalaccount(const std::string& error) {
  if (!localaccount_.empty() && localaccount_ == username_ &&
      CrosLibrary::Get()->GetCryptohomeLibrary()->Mount(kTmpfsTrigger, "")) {
    LOG(WARNING) << "Logging in with localaccount: " << localaccount_;
    consumer_->OnLoginSuccess(username_, std::string());
  } else {
    OnLoginFailure(error);
  }
}

void GoogleAuthenticator::OnLoginFailure(const std::string& data) {
  // Send notification of failure
  AuthenticationNotificationDetails details(false);
  NotificationService::current()->Notify(
      NotificationType::LOGIN_AUTHENTICATION,
      NotificationService::AllSources(),
      Details<AuthenticationNotificationDetails>(&details));
  LOG(WARNING) << "Login failed: " << data;
  // TODO(cmasone): what can we do to expose these OS/server-side error strings
  // in an internationalizable way?
  consumer_->OnLoginFailure(data);
}

void GoogleAuthenticator::LoadSystemSalt() {
  if (!system_salt_.empty())
    return;
  system_salt_ = CrosLibrary::Get()->GetCryptohomeLibrary()->GetSystemSalt();
  CHECK(!system_salt_.empty());
  CHECK_EQ(system_salt_.size() % 2, 0U);
}

void GoogleAuthenticator::LoadLocalaccount(const std::string& filename) {
  if (checked_for_localaccount_)
    return;
  FilePath localaccount_file;
  std::string localaccount;
  if (PathService::Get(base::DIR_EXE, &localaccount_file)) {
    localaccount_file = localaccount_file.Append(filename);
    LOG(INFO) << "looking for localaccount in " << localaccount_file.value();

    ReadFileToString(localaccount_file, &localaccount);
    TrimWhitespaceASCII(localaccount, TRIM_TRAILING, &localaccount);
    LOG(INFO) << "Loading localaccount: " << localaccount;
  } else {
    LOG(INFO) << "Assuming no localaccount";
  }
  set_localaccount(localaccount);
}

void GoogleAuthenticator::StoreHashedPassword(const std::string& password) {
  // Get salt, ascii encode, update sha with that, then update with ascii
  // of password, then end.
  std::string ascii_salt = SaltAsAscii();
  unsigned char passhash_buf[kPassHashLen];
  char ascii_buf[kPassHashLen + 1];

  // Hash salt and password
  SHA256Context ctx;
  SHA256_Begin(&ctx);
  SHA256_Update(&ctx,
                reinterpret_cast<const unsigned char*>(ascii_salt.data()),
                static_cast<unsigned int>(ascii_salt.length()));
  SHA256_Update(&ctx,
                reinterpret_cast<const unsigned char*>(password.data()),
                static_cast<unsigned int>(password.length()));
  SHA256_End(&ctx,
             passhash_buf,
             NULL,
             static_cast<unsigned int>(sizeof(passhash_buf)));

  std::vector<unsigned char> passhash(passhash_buf,
                                      passhash_buf + sizeof(passhash_buf));
  BinaryToHex(passhash,
              passhash.size() / 2,  // only want top half, at least for now.
              ascii_buf,
              sizeof(ascii_buf));
  ascii_hash_.assign(ascii_buf, sizeof(ascii_buf) - 1);
}

std::string GoogleAuthenticator::SaltAsAscii() {
  LoadSystemSalt();  // no-op if it's already loaded.
  unsigned int salt_len = system_salt_.size();
  char ascii_salt[2 * salt_len + 1];
  if (GoogleAuthenticator::BinaryToHex(system_salt_,
                                       salt_len,
                                       ascii_salt,
                                       sizeof(ascii_salt))) {
    return std::string(ascii_salt, sizeof(ascii_salt) - 1);
  } else {
    return std::string();
  }
}

void GoogleAuthenticator::Cancel() {
  if (!fetch_completed_ && fetcher_) {
    delete fetcher_;
    fetcher_ = NULL;
  }
  OnLoginFailure("Login has timed out; please try again!");
}

void GoogleAuthenticator::TryClientLogin() {
  if (fetcher_)
    delete fetcher_;
  fetcher_ = CreateClientLoginFetcher(getter_, request_body_, this);
  fetcher_->Start();
  ChromeThread::PostDelayedTask(
      ChromeThread::UI, FROM_HERE,
      NewRunnableMethod(this,
                        &GoogleAuthenticator::Cancel), kClientLoginTimeoutMs);
}

// static
bool GoogleAuthenticator::IsSecondFactorSuccess(
    const std::string& alleged_error) {
  return alleged_error.find(GoogleAuthenticator::kSecondFactor) !=
      std::string::npos;
}

// static
bool GoogleAuthenticator::BinaryToHex(const std::vector<unsigned char>& binary,
                                      const unsigned int binary_len,
                                      char* hex_string,
                                      const unsigned int len) {
  if (len < 2*binary_len)
    return false;
  memset(hex_string, 0, len);
  for (uint i = 0, j = 0; i < binary_len; i++, j+=2)
    snprintf(hex_string + j, len - j, "%02x", binary[i]);
  return true;
}

// static
std::string GoogleAuthenticator::Canonicalize(
    const std::string& email_address) {
  std::vector<std::string> parts;
  char at = '@';
  SplitString(email_address, at, &parts);
  DCHECK_EQ(parts.size(), 2U) << "email_address should have only one @";
  RemoveChars(parts[0], ".", &parts[0]);
  if (parts[0].find('+') != std::string::npos)
    parts[0].erase(parts[0].find('+'));
  std::string new_email = StringToLowerASCII(JoinString(parts, at));
  LOG(INFO) << "Canonicalized " << email_address << " to " << new_email;
  return new_email;
}

}  // namespace chromeos
<commit_msg>In case of successful login attempt do nothing in Cancel task. Fixes crash introduced in http://codereview.chromium.org/2867012<commit_after>// Copyright (c) 2010 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 "chrome/browser/chromeos/login/google_authenticator.h"

#include <string>
#include <vector>

#include "base/file_path.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/sha2.h"
#include "base/string_util.h"
#include "base/third_party/nss/blapi.h"
#include "base/third_party/nss/sha256.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/chromeos/cros/cryptohome_library.h"
#include "chrome/browser/chromeos/login/auth_response_handler.h"
#include "chrome/browser/chromeos/login/authentication_notification_details.h"
#include "chrome/browser/chromeos/login/login_status_consumer.h"
#include "chrome/browser/net/chrome_url_request_context.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/profile_manager.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/net/url_fetcher.h"
#include "chrome/common/notification_service.h"
#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
#include "net/url_request/url_request_status.h"
#include "third_party/libjingle/source/talk/base/urlencode.h"

using base::Time;
using base::TimeDelta;
using file_util::GetFileSize;
using file_util::PathExists;
using file_util::ReadFile;
using file_util::ReadFileToString;

namespace chromeos {

// static
const char GoogleAuthenticator::kCookiePersistence[] = "true";
// static
const char GoogleAuthenticator::kAccountType[] = "HOSTED_OR_GOOGLE";
// static
const char GoogleAuthenticator::kSource[] = "chromeos";
// static
// Service name for Google Contacts API. API is used to get user's image.
const char GoogleAuthenticator::kService[] = "cp";
// static
const char GoogleAuthenticator::kFormat[] =
    "Email=%s&"
    "Passwd=%s&"
    "PersistentCookie=%s&"
    "accountType=%s&"
    "source=%s&"
    "service=%s";
// static
const char GoogleAuthenticator::kFormatCaptcha[] =
    "Email=%s&"
    "Passwd=%s&"
    "PersistentCookie=%s&"
    "accountType=%s&"
    "source=%s&"
    "service=%s&"
    "logintoken=%s&"
    "logincaptcha=%s";
// static
const char GoogleAuthenticator::kSecondFactor[] = "Info=InvalidSecondFactor";

// static
const char GoogleAuthenticator::kSystemSalt[] = "/home/.shadow/salt";
// static
const char GoogleAuthenticator::kOpenSSLMagic[] = "Salted__";
// static
const char GoogleAuthenticator::kLocalaccountFile[] = "localaccount";
// static
const char GoogleAuthenticator::kTmpfsTrigger[] = "incognito";

// static
const int GoogleAuthenticator::kClientLoginTimeoutMs = 5000;

const int kPassHashLen = 32;

GoogleAuthenticator::GoogleAuthenticator(LoginStatusConsumer* consumer)
    : Authenticator(consumer),
      fetcher_(NULL),
      getter_(NULL),
      checked_for_localaccount_(false),
      unlock_(false),
      try_again_(true),
      fetch_completed_(false) {
  CHECK(chromeos::CrosLibrary::Get()->EnsureLoaded());
}

GoogleAuthenticator::~GoogleAuthenticator() {
  delete fetcher_;
}

// static
URLFetcher* GoogleAuthenticator::CreateClientLoginFetcher(
    URLRequestContextGetter* getter,
    const std::string& body,
    URLFetcher::Delegate* delegate) {
  URLFetcher* to_return =
      URLFetcher::Create(0,
                         GURL(AuthResponseHandler::kClientLoginUrl),
                         URLFetcher::POST,
                         delegate);
  to_return->set_request_context(getter);
  to_return->set_load_flags(net::LOAD_DO_NOT_SEND_COOKIES);
  to_return->set_upload_data("application/x-www-form-urlencoded", body);
  return to_return;
}

bool GoogleAuthenticator::AuthenticateToLogin(
    Profile* profile,
    const std::string& username,
    const std::string& password,
    const std::string& login_token,
    const std::string& login_captcha) {
  unlock_ = false;
  getter_ = profile->GetRequestContext();

  // TODO(cmasone): be more careful about zeroing memory that stores
  // the user's password.
  if (login_token.empty() || login_captcha.empty()) {
    request_body_ = StringPrintf(kFormat,
                                 UrlEncodeString(username).c_str(),
                                 UrlEncodeString(password).c_str(),
                                 kCookiePersistence,
                                 kAccountType,
                                 kSource,
                                 kService);
  } else {
    request_body_ = StringPrintf(kFormatCaptcha,
                                 UrlEncodeString(username).c_str(),
                                 UrlEncodeString(password).c_str(),
                                 kCookiePersistence,
                                 kAccountType,
                                 kSource,
                                 kService,
                                 UrlEncodeString(login_token).c_str(),
                                 UrlEncodeString(login_captcha).c_str());
  }
  // TODO(cmasone): Figure out how to parallelize fetch, username/password
  // processing without impacting testability.
  username_.assign(Canonicalize(username));
  StoreHashedPassword(password);
  TryClientLogin();
  return true;
}

bool GoogleAuthenticator::AuthenticateToUnlock(const std::string& username,
                                               const std::string& password) {
  username_.assign(Canonicalize(username));
  StoreHashedPassword(password);
  unlock_ = true;
  ChromeThread::PostTask(
      ChromeThread::UI, FROM_HERE,
      NewRunnableMethod(this, &GoogleAuthenticator::CheckOffline,
                        std::string("unlock failed")));
  return true;
}

void GoogleAuthenticator::LoginOffTheRecord() {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
  if (CrosLibrary::Get()->GetCryptohomeLibrary()->Mount(kTmpfsTrigger, "")) {
    AuthenticationNotificationDetails details(true);
    NotificationService::current()->Notify(
        NotificationType::LOGIN_AUTHENTICATION,
        NotificationService::AllSources(),
        Details<AuthenticationNotificationDetails>(&details));
    consumer_->OnOffTheRecordLoginSuccess();
  } else {
    consumer_->OnLoginFailure("Could not mount tmpfs cryptohome");
  }
}

void GoogleAuthenticator::OnURLFetchComplete(const URLFetcher* source,
                                             const GURL& url,
                                             const URLRequestStatus& status,
                                             int response_code,
                                             const ResponseCookies& cookies,
                                             const std::string& data) {
  fetch_completed_ = true;
  if (status.is_success() && response_code == kHttpSuccess) {
    LOG(INFO) << "Online login successful!";
    ChromeThread::PostTask(
        ChromeThread::UI, FROM_HERE,
        NewRunnableMethod(this, &GoogleAuthenticator::OnLoginSuccess, data));
  } else if (!status.is_success()) {
    if (status.status() == URLRequestStatus::CANCELED) {
      if (try_again_) {
        try_again_ = false;
        LOG(ERROR) << "Login attempt canceled!?!?  Trying again.";
        TryClientLogin();
        fetch_completed_ = false;
        return;
      }
      LOG(ERROR) << "Login attempt canceled again?  Already retried...";
    }
    LOG(WARNING) << "Could not reach Google Accounts servers: errno "
              << status.os_error();
    // The fetch failed for network reasons, try offline login.
    LoadLocalaccount(kLocalaccountFile);
    ChromeThread::PostTask(
        ChromeThread::UI, FROM_HERE,
        NewRunnableMethod(this, &GoogleAuthenticator::CheckOffline,
                          net::ErrorToString(status.os_error())));
  } else {
    if (IsSecondFactorSuccess(data)) {
      ChromeThread::PostTask(
          ChromeThread::UI, FROM_HERE,
          NewRunnableMethod(this,
                            &GoogleAuthenticator::OnLoginSuccess,
                            std::string()));
    } else {
      // The fetch succeeded, but ClientLogin said no.
      LoadLocalaccount(kLocalaccountFile);
      ChromeThread::PostTask(
          ChromeThread::UI, FROM_HERE,
          NewRunnableMethod(this,
                            &GoogleAuthenticator::CheckLocalaccount,
                            data));
    }
  }
}

void GoogleAuthenticator::OnLoginSuccess(const std::string& data) {
  // Send notification of success
  AuthenticationNotificationDetails details(true);
  NotificationService::current()->Notify(
      NotificationType::LOGIN_AUTHENTICATION,
      NotificationService::AllSources(),
      Details<AuthenticationNotificationDetails>(&details));

  if (unlock_ ||
      CrosLibrary::Get()->GetCryptohomeLibrary()->Mount(username_.c_str(),
                                                        ascii_hash_.c_str())) {
    consumer_->OnLoginSuccess(username_, data);
  } else {
    OnLoginFailure("Could not mount cryptohome");
  }
}

void GoogleAuthenticator::CheckOffline(const std::string& error) {
  LOG(INFO) << "Attempting offline login";
  if (CrosLibrary::Get()->GetCryptohomeLibrary()->CheckKey(
          username_.c_str(),
          ascii_hash_.c_str())) {
    // The fetch didn't succeed, but offline login did.
    LOG(INFO) << "Offline login successful!";
    OnLoginSuccess(std::string());
  } else {
    // We couldn't hit the network, and offline login failed.
    GoogleAuthenticator::CheckLocalaccount(error);
  }
}

void GoogleAuthenticator::CheckLocalaccount(const std::string& error) {
  if (!localaccount_.empty() && localaccount_ == username_ &&
      CrosLibrary::Get()->GetCryptohomeLibrary()->Mount(kTmpfsTrigger, "")) {
    LOG(WARNING) << "Logging in with localaccount: " << localaccount_;
    consumer_->OnLoginSuccess(username_, std::string());
  } else {
    OnLoginFailure(error);
  }
}

void GoogleAuthenticator::OnLoginFailure(const std::string& data) {
  // Send notification of failure
  AuthenticationNotificationDetails details(false);
  NotificationService::current()->Notify(
      NotificationType::LOGIN_AUTHENTICATION,
      NotificationService::AllSources(),
      Details<AuthenticationNotificationDetails>(&details));
  LOG(WARNING) << "Login failed: " << data;
  // TODO(cmasone): what can we do to expose these OS/server-side error strings
  // in an internationalizable way?
  consumer_->OnLoginFailure(data);
}

void GoogleAuthenticator::LoadSystemSalt() {
  if (!system_salt_.empty())
    return;
  system_salt_ = CrosLibrary::Get()->GetCryptohomeLibrary()->GetSystemSalt();
  CHECK(!system_salt_.empty());
  CHECK_EQ(system_salt_.size() % 2, 0U);
}

void GoogleAuthenticator::LoadLocalaccount(const std::string& filename) {
  if (checked_for_localaccount_)
    return;
  FilePath localaccount_file;
  std::string localaccount;
  if (PathService::Get(base::DIR_EXE, &localaccount_file)) {
    localaccount_file = localaccount_file.Append(filename);
    LOG(INFO) << "looking for localaccount in " << localaccount_file.value();

    ReadFileToString(localaccount_file, &localaccount);
    TrimWhitespaceASCII(localaccount, TRIM_TRAILING, &localaccount);
    LOG(INFO) << "Loading localaccount: " << localaccount;
  } else {
    LOG(INFO) << "Assuming no localaccount";
  }
  set_localaccount(localaccount);
}

void GoogleAuthenticator::StoreHashedPassword(const std::string& password) {
  // Get salt, ascii encode, update sha with that, then update with ascii
  // of password, then end.
  std::string ascii_salt = SaltAsAscii();
  unsigned char passhash_buf[kPassHashLen];
  char ascii_buf[kPassHashLen + 1];

  // Hash salt and password
  SHA256Context ctx;
  SHA256_Begin(&ctx);
  SHA256_Update(&ctx,
                reinterpret_cast<const unsigned char*>(ascii_salt.data()),
                static_cast<unsigned int>(ascii_salt.length()));
  SHA256_Update(&ctx,
                reinterpret_cast<const unsigned char*>(password.data()),
                static_cast<unsigned int>(password.length()));
  SHA256_End(&ctx,
             passhash_buf,
             NULL,
             static_cast<unsigned int>(sizeof(passhash_buf)));

  std::vector<unsigned char> passhash(passhash_buf,
                                      passhash_buf + sizeof(passhash_buf));
  BinaryToHex(passhash,
              passhash.size() / 2,  // only want top half, at least for now.
              ascii_buf,
              sizeof(ascii_buf));
  ascii_hash_.assign(ascii_buf, sizeof(ascii_buf) - 1);
}

std::string GoogleAuthenticator::SaltAsAscii() {
  LoadSystemSalt();  // no-op if it's already loaded.
  unsigned int salt_len = system_salt_.size();
  char ascii_salt[2 * salt_len + 1];
  if (GoogleAuthenticator::BinaryToHex(system_salt_,
                                       salt_len,
                                       ascii_salt,
                                       sizeof(ascii_salt))) {
    return std::string(ascii_salt, sizeof(ascii_salt) - 1);
  } else {
    return std::string();
  }
}

void GoogleAuthenticator::Cancel() {
  if (fetch_completed_)
   return;

  if (fetcher_) {
    delete fetcher_;
    fetcher_ = NULL;
  }
  OnLoginFailure("Login has timed out; please try again!");
}

void GoogleAuthenticator::TryClientLogin() {
  if (fetcher_)
    delete fetcher_;
  fetcher_ = CreateClientLoginFetcher(getter_, request_body_, this);
  fetcher_->Start();
  ChromeThread::PostDelayedTask(
      ChromeThread::UI, FROM_HERE,
      NewRunnableMethod(this,
                        &GoogleAuthenticator::Cancel), kClientLoginTimeoutMs);
}

// static
bool GoogleAuthenticator::IsSecondFactorSuccess(
    const std::string& alleged_error) {
  return alleged_error.find(GoogleAuthenticator::kSecondFactor) !=
      std::string::npos;
}

// static
bool GoogleAuthenticator::BinaryToHex(const std::vector<unsigned char>& binary,
                                      const unsigned int binary_len,
                                      char* hex_string,
                                      const unsigned int len) {
  if (len < 2*binary_len)
    return false;
  memset(hex_string, 0, len);
  for (uint i = 0, j = 0; i < binary_len; i++, j+=2)
    snprintf(hex_string + j, len - j, "%02x", binary[i]);
  return true;
}

// static
std::string GoogleAuthenticator::Canonicalize(
    const std::string& email_address) {
  std::vector<std::string> parts;
  char at = '@';
  SplitString(email_address, at, &parts);
  DCHECK_EQ(parts.size(), 2U) << "email_address should have only one @";
  RemoveChars(parts[0], ".", &parts[0]);
  if (parts[0].find('+') != std::string::npos)
    parts[0].erase(parts[0].find('+'));
  std::string new_email = StringToLowerASCII(JoinString(parts, at));
  LOG(INFO) << "Canonicalized " << email_address << " to " << new_email;
  return new_email;
}

}  // namespace chromeos
<|endoftext|>


<commit_before>// 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 "chrome/browser/chromeos/login/rounded_rect_painter.h"

#include "base/logging.h"
#include "chrome/browser/chromeos/login/helper.h"
#include "third_party/skia/include/effects/SkBlurMaskFilter.h"
#include "third_party/skia/include/effects/SkGradientShader.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/skia_util.h"
#include "ui/views/border.h"
#include "ui/views/painter.h"

namespace chromeos {

namespace {

const SkColor kScreenTopColor = SkColorSetRGB(250, 251, 251);
const SkColor kScreenBottomColor = SkColorSetRGB(204, 209, 212);
const SkColor kScreenShadowColor = SkColorSetARGB(64, 34, 54, 115);
const int kScreenShadow = 10;

void DrawRoundedRect(gfx::Canvas* canvas,
                     const SkRect& rect,
                     int corner_radius,
                     SkColor top_color,
                     SkColor bottom_color) {
  SkPath path;
  path.addRoundRect(rect,
                    SkIntToScalar(corner_radius), SkIntToScalar(corner_radius));
  SkPaint paint;
  paint.setStyle(SkPaint::kFill_Style);
  paint.setFlags(SkPaint::kAntiAlias_Flag);
  if (top_color != bottom_color) {
    SkPoint p[2];
    p[0].set(SkIntToScalar(rect.left()), SkIntToScalar(rect.top()));
    p[1].set(SkIntToScalar(rect.left()), SkIntToScalar(rect.bottom()));
    SkColor colors[2] = { top_color, bottom_color };
    SkShader* s = SkGradientShader::CreateLinear(p, colors, NULL, 2,
        SkShader::kClamp_TileMode, NULL);
    paint.setShader(s);
    // Need to unref shader, otherwise never deleted.
    s->unref();
  } else {
    paint.setColor(top_color);
  }

  canvas->DrawPath(path, paint);
}

void DrawRoundedRectShadow(gfx::Canvas* canvas,
                           const SkRect& rect,
                           int corner_radius,
                           int shadow,
                           SkColor color) {
  SkPaint paint;
  paint.setFlags(SkPaint::kAntiAlias_Flag);
  paint.setStyle(SkPaint::kFill_Style);
  paint.setColor(color);
  SkMaskFilter* filter = SkBlurMaskFilter::Create(
      shadow / 2, SkBlurMaskFilter::kNormal_BlurStyle);
  paint.setMaskFilter(filter)->unref();
  SkRect inset_rect(rect);
  inset_rect.inset(SkIntToScalar(shadow / 2), SkIntToScalar(shadow / 2));
  canvas->sk_canvas()->drawRoundRect(
      inset_rect,
      SkIntToScalar(corner_radius), SkIntToScalar(corner_radius),
      paint);
  paint.setMaskFilter(NULL);
}

void DrawRectWithBorder(gfx::Canvas* canvas,
                        const gfx::Size& size,
                        const BorderDefinition* const border) {
  SkRect rect(gfx::RectToSkRect(gfx::Rect(size)));
  if (border->padding > 0) {
    SkPaint paint;
    paint.setColor(border->padding_color);
    canvas->sk_canvas()->drawRect(rect, paint);
    rect.inset(SkIntToScalar(border->padding), SkIntToScalar(border->padding));
  }
  if (border->shadow > 0) {
    DrawRoundedRectShadow(canvas, rect, border->corner_radius, border->shadow,
                          border->shadow_color);
    rect.inset(SkIntToScalar(border->shadow), SkIntToScalar(border->shadow));
    rect.offset(0, SkIntToScalar(-border->shadow / 3));
  }
  DrawRoundedRect(canvas, rect, border->corner_radius, border->top_color,
                  border->bottom_color);
}

// This Painter can be used to draw a background consistent cross all login
// screens. It draws a rect with padding, shadow and rounded corners.
class RoundedRectPainter : public views::Painter {
 public:
  explicit RoundedRectPainter(const BorderDefinition* const border)
      : border_(border) {
  }

  // Overridden from views::Painter:
  virtual void Paint(gfx::Canvas* canvas, const gfx::Size& size) OVERRIDE {
    DrawRectWithBorder(canvas, size, border_);
  }

 private:
  const BorderDefinition* const border_;

  DISALLOW_COPY_AND_ASSIGN(RoundedRectPainter);
};

// This border can be used to draw shadow and rounded corners across all
// login screens.
class RoundedRectBorder : public views::Border {
 public:
  explicit RoundedRectBorder(const BorderDefinition* const border)
      : border_(border) {
  }

  virtual void Paint(const views::View& view, gfx::Canvas* canvas) const;
  virtual void GetInsets(gfx::Insets* insets) const;

 private:
  const BorderDefinition* const border_;

  DISALLOW_COPY_AND_ASSIGN(RoundedRectBorder);
};

void RoundedRectBorder::Paint(const views::View& view,
                              gfx::Canvas* canvas) const {
  // Don't paint anything. RoundedRectBorder is used to provide insets only.
}

void RoundedRectBorder::GetInsets(gfx::Insets* insets) const {
  DCHECK(insets);
  int shadow = border_->shadow;
  int inset = border_->corner_radius / 2 + border_->padding + shadow;
  insets->Set(inset - shadow / 3, inset, inset + shadow / 3, inset);
}

// Simple solid round background.
class RoundedBackground : public views::Background {
 public:
  RoundedBackground(int corner_radius,
                    int stroke_width,
                    const SkColor& background_color,
                    const SkColor& stroke_color)
      : corner_radius_(corner_radius),
        stroke_width_(stroke_width),
        stroke_color_(stroke_color) {
    SetNativeControlColor(background_color);
  }

  virtual void Paint(gfx::Canvas* canvas, views::View* view) const {
    SkRect rect;
    rect.iset(0, 0, view->width(), view->height());
    SkPath path;
    path.addRoundRect(rect,
                      SkIntToScalar(corner_radius_),
                      SkIntToScalar(corner_radius_));
    // Draw interior.
    SkPaint paint;
    paint.setStyle(SkPaint::kFill_Style);
    paint.setFlags(SkPaint::kAntiAlias_Flag);
    paint.setColor(get_color());
    canvas->DrawPath(path, paint);
    // Redraw boundary region with correspoinding color.
    paint.setStyle(SkPaint::kStroke_Style);
    paint.setStrokeWidth(SkIntToScalar(stroke_width_));
    paint.setColor(stroke_color_);
    canvas->DrawPath(path, paint);
  }

 private:
  int corner_radius_;
  int stroke_width_;
  SkColor stroke_color_;

  DISALLOW_COPY_AND_ASSIGN(RoundedBackground);
};

}  // namespace

// static
const BorderDefinition BorderDefinition::kScreenBorder = {
  0,
  SK_ColorBLACK,
  kScreenShadow,
  kScreenShadowColor,
  login::kScreenCornerRadius,
  kScreenTopColor,
  kScreenBottomColor
};

const BorderDefinition BorderDefinition::kUserBorder = {
  0,
  SK_ColorBLACK,
  0,
  kScreenShadowColor,
  login::kUserCornerRadius,
  kScreenTopColor,
  kScreenBottomColor
};

views::Painter* CreateWizardPainter(const BorderDefinition* const border) {
  return new RoundedRectPainter(border);
}

views::Border* CreateWizardBorder(const BorderDefinition* const border) {
  return new RoundedRectBorder(border);
}

views::Background* CreateRoundedBackground(int corner_radius,
                                           int stroke_width,
                                           SkColor background_color,
                                           SkColor stroke_color) {
  return new RoundedBackground(
      corner_radius, stroke_width, background_color, stroke_color);
}

}  // namespace chromeos
<commit_msg>chromeos: Do not pass SkColor by const-reference as it's defined as POD(integer).<commit_after>// 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 "chrome/browser/chromeos/login/rounded_rect_painter.h"

#include "base/logging.h"
#include "chrome/browser/chromeos/login/helper.h"
#include "third_party/skia/include/effects/SkBlurMaskFilter.h"
#include "third_party/skia/include/effects/SkGradientShader.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/skia_util.h"
#include "ui/views/border.h"
#include "ui/views/painter.h"

namespace chromeos {

namespace {

const SkColor kScreenTopColor = SkColorSetRGB(250, 251, 251);
const SkColor kScreenBottomColor = SkColorSetRGB(204, 209, 212);
const SkColor kScreenShadowColor = SkColorSetARGB(64, 34, 54, 115);
const int kScreenShadow = 10;

void DrawRoundedRect(gfx::Canvas* canvas,
                     const SkRect& rect,
                     int corner_radius,
                     SkColor top_color,
                     SkColor bottom_color) {
  SkPath path;
  path.addRoundRect(rect,
                    SkIntToScalar(corner_radius), SkIntToScalar(corner_radius));
  SkPaint paint;
  paint.setStyle(SkPaint::kFill_Style);
  paint.setFlags(SkPaint::kAntiAlias_Flag);
  if (top_color != bottom_color) {
    SkPoint p[2];
    p[0].set(SkIntToScalar(rect.left()), SkIntToScalar(rect.top()));
    p[1].set(SkIntToScalar(rect.left()), SkIntToScalar(rect.bottom()));
    SkColor colors[2] = { top_color, bottom_color };
    SkShader* s = SkGradientShader::CreateLinear(p, colors, NULL, 2,
        SkShader::kClamp_TileMode, NULL);
    paint.setShader(s);
    // Need to unref shader, otherwise never deleted.
    s->unref();
  } else {
    paint.setColor(top_color);
  }

  canvas->DrawPath(path, paint);
}

void DrawRoundedRectShadow(gfx::Canvas* canvas,
                           const SkRect& rect,
                           int corner_radius,
                           int shadow,
                           SkColor color) {
  SkPaint paint;
  paint.setFlags(SkPaint::kAntiAlias_Flag);
  paint.setStyle(SkPaint::kFill_Style);
  paint.setColor(color);
  SkMaskFilter* filter = SkBlurMaskFilter::Create(
      shadow / 2, SkBlurMaskFilter::kNormal_BlurStyle);
  paint.setMaskFilter(filter)->unref();
  SkRect inset_rect(rect);
  inset_rect.inset(SkIntToScalar(shadow / 2), SkIntToScalar(shadow / 2));
  canvas->sk_canvas()->drawRoundRect(
      inset_rect,
      SkIntToScalar(corner_radius), SkIntToScalar(corner_radius),
      paint);
  paint.setMaskFilter(NULL);
}

void DrawRectWithBorder(gfx::Canvas* canvas,
                        const gfx::Size& size,
                        const BorderDefinition* const border) {
  SkRect rect(gfx::RectToSkRect(gfx::Rect(size)));
  if (border->padding > 0) {
    SkPaint paint;
    paint.setColor(border->padding_color);
    canvas->sk_canvas()->drawRect(rect, paint);
    rect.inset(SkIntToScalar(border->padding), SkIntToScalar(border->padding));
  }
  if (border->shadow > 0) {
    DrawRoundedRectShadow(canvas, rect, border->corner_radius, border->shadow,
                          border->shadow_color);
    rect.inset(SkIntToScalar(border->shadow), SkIntToScalar(border->shadow));
    rect.offset(0, SkIntToScalar(-border->shadow / 3));
  }
  DrawRoundedRect(canvas, rect, border->corner_radius, border->top_color,
                  border->bottom_color);
}

// This Painter can be used to draw a background consistent cross all login
// screens. It draws a rect with padding, shadow and rounded corners.
class RoundedRectPainter : public views::Painter {
 public:
  explicit RoundedRectPainter(const BorderDefinition* const border)
      : border_(border) {
  }

  // Overridden from views::Painter:
  virtual void Paint(gfx::Canvas* canvas, const gfx::Size& size) OVERRIDE {
    DrawRectWithBorder(canvas, size, border_);
  }

 private:
  const BorderDefinition* const border_;

  DISALLOW_COPY_AND_ASSIGN(RoundedRectPainter);
};

// This border can be used to draw shadow and rounded corners across all
// login screens.
class RoundedRectBorder : public views::Border {
 public:
  explicit RoundedRectBorder(const BorderDefinition* const border)
      : border_(border) {
  }

  virtual void Paint(const views::View& view, gfx::Canvas* canvas) const;
  virtual void GetInsets(gfx::Insets* insets) const;

 private:
  const BorderDefinition* const border_;

  DISALLOW_COPY_AND_ASSIGN(RoundedRectBorder);
};

void RoundedRectBorder::Paint(const views::View& view,
                              gfx::Canvas* canvas) const {
  // Don't paint anything. RoundedRectBorder is used to provide insets only.
}

void RoundedRectBorder::GetInsets(gfx::Insets* insets) const {
  DCHECK(insets);
  int shadow = border_->shadow;
  int inset = border_->corner_radius / 2 + border_->padding + shadow;
  insets->Set(inset - shadow / 3, inset, inset + shadow / 3, inset);
}

// Simple solid round background.
class RoundedBackground : public views::Background {
 public:
  RoundedBackground(int corner_radius,
                    int stroke_width,
                    SkColor background_color,
                    SkColor stroke_color)
      : corner_radius_(corner_radius),
        stroke_width_(stroke_width),
        stroke_color_(stroke_color) {
    SetNativeControlColor(background_color);
  }

  virtual void Paint(gfx::Canvas* canvas, views::View* view) const {
    SkRect rect;
    rect.iset(0, 0, view->width(), view->height());
    SkPath path;
    path.addRoundRect(rect,
                      SkIntToScalar(corner_radius_),
                      SkIntToScalar(corner_radius_));
    // Draw interior.
    SkPaint paint;
    paint.setStyle(SkPaint::kFill_Style);
    paint.setFlags(SkPaint::kAntiAlias_Flag);
    paint.setColor(get_color());
    canvas->DrawPath(path, paint);
    // Redraw boundary region with correspoinding color.
    paint.setStyle(SkPaint::kStroke_Style);
    paint.setStrokeWidth(SkIntToScalar(stroke_width_));
    paint.setColor(stroke_color_);
    canvas->DrawPath(path, paint);
  }

 private:
  int corner_radius_;
  int stroke_width_;
  SkColor stroke_color_;

  DISALLOW_COPY_AND_ASSIGN(RoundedBackground);
};

}  // namespace

// static
const BorderDefinition BorderDefinition::kScreenBorder = {
  0,
  SK_ColorBLACK,
  kScreenShadow,
  kScreenShadowColor,
  login::kScreenCornerRadius,
  kScreenTopColor,
  kScreenBottomColor
};

const BorderDefinition BorderDefinition::kUserBorder = {
  0,
  SK_ColorBLACK,
  0,
  kScreenShadowColor,
  login::kUserCornerRadius,
  kScreenTopColor,
  kScreenBottomColor
};

views::Painter* CreateWizardPainter(const BorderDefinition* const border) {
  return new RoundedRectPainter(border);
}

views::Border* CreateWizardBorder(const BorderDefinition* const border) {
  return new RoundedRectBorder(border);
}

views::Background* CreateRoundedBackground(int corner_radius,
                                           int stroke_width,
                                           SkColor background_color,
                                           SkColor stroke_color) {
  return new RoundedBackground(
      corner_radius, stroke_width, background_color, stroke_color);
}

}  // namespace chromeos
<|endoftext|>


<commit_before>/*
 * Copyright 2013 by Philip N. Garner
 *
 * See the file COPYING for the licence associated with this software.
 *
 * Author(s):
 *   Phil Garner, October 2013
 */

#include <fstream>
#include <stdexcept>
#include <var.h>

#include "expat.h"

namespace libvar
{
    /**
     * Class to wrap the expat library and callbacks.
     */
    class Expat : public varfile
    {
    public:
        Expat();
        ~Expat();
        var parse(const char* iFile);
        void startElementHandler(const XML_Char *iName, const XML_Char **iAtts);
        void endElementHandler(const XML_Char *iName);
        void characterDataHandler(const XML_Char *iStr, int iLen);
        virtual var read(const char* iFile);
        virtual void write(const char* iFile, var iVar);

    private:
        var mVar;            ///< Var to populate during parse
        var mStack;          ///< Parse stack
        XML_Parser mParser;  ///< The expat parser

        var element();
    };
}

using namespace libvar;

void libvar::factory(varfile** oFile)
{
    *oFile = new Expat;
}

/**
 * In principle this is unnecessary; in practice it's useful to catch
 * errors (of the form "dude, you forgot to implement...").
 */
static void DefaultHandler(
    void *iUserData, const XML_Char *iStr, int iLen
)
{
    var str(iLen, iStr);
    std::cout << "expat::DefaultHandler: " << str << std::endl;
    throw std::runtime_error("xmlfile: default handler called");
}

/**
 * We don't do anything with the XML declaration, but need to handle
 * it so the the default handler doesn't.
 */
static void XmlDeclHandler(
    void *iUserData,
    const XML_Char *version,
    const XML_Char *encoding,
    int standalone
)
{
    //std::cout << "xml: " << version << std::endl;
}

static void StartElementHandler(
    void *iUserData, const XML_Char *iName, const XML_Char **iAtts
)
{
    return ((Expat*)iUserData)->startElementHandler(iName, iAtts);
}

static void EndElementHandler(
    void *iUserData, const XML_Char *iName
)
{
    return ((Expat*)iUserData)->endElementHandler(iName);
}

static void CharacterDataHandler(
    void *iUserData, const XML_Char *iStr, int iLen
)
{
    return ((Expat*)iUserData)->characterDataHandler(iStr, iLen);
}

/**
 * Parser constructor.  Points the callbacks to the static functions;
 * those functions convert the UserData field into the class pointer
 * and pass the callback to the appropriate method.
 */
Expat::Expat()
{
    // Create the parser
    mParser = XML_ParserCreate(0);

    // Set the callbacks to the static functions
    XML_SetUserData(mParser, this);
    XML_SetDefaultHandler(mParser, DefaultHandler);
    XML_SetXmlDeclHandler(mParser, XmlDeclHandler);
    XML_SetStartElementHandler(mParser, StartElementHandler);
    XML_SetEndElementHandler(mParser, EndElementHandler);
    XML_SetCharacterDataHandler(mParser, CharacterDataHandler);
}

Expat::~Expat()
{
    XML_ParserFree(mParser);
}

var Expat::parse(const char* iFile)
{
    std::ifstream is(iFile, std::ifstream::in);
    if (is.fail())
        throw std::runtime_error("xmlfile::read(): Open failed");

    var f;
    XML_Status s;
    while (f.getline(is))
    {
        s = XML_Parse(mParser, f.str(), f.size(), 0);
        if (!s)
            throw std::runtime_error("xmlfile::parse(): Error!");
    }
    s = XML_Parse(mParser, f.str(), 0, 0);
    if (!s)
        throw std::runtime_error("xmlfile::parse(): Error!");
    if (mStack.size() != 0)
        throw std::runtime_error("xmlfile::parse(): Short file?");

    return mVar;
}

var Expat::element()
{
    static var elem;
    if (!elem)
    {
        var nil;
        elem["name"] = nil;
        elem["attr"] = nil;
        elem["data"] = nil;
    }
    return elem.copy();
}

void Expat::startElementHandler(const XML_Char *iName, const XML_Char **iAtts)
{
    var elem = element();
    if (mStack)
        mStack.top()["data"].push(elem);
    else
        mVar = elem;
    mStack.push(elem);
    elem["name"] = iName;
    while (*iAtts)
    {
        elem["attr"][iAtts[0]] = iAtts[1];
        iAtts += 2;
    }
}

void Expat::endElementHandler(const XML_Char *iName)
{
    if (mStack.top()["name"] != iName)
        throw std::runtime_error("Expat::endElementHandler: malformed xml");
    mStack.pop();
}

void Expat::characterDataHandler(const XML_Char *iStr, int iLen)
{
    var str(iLen, iStr);
    mStack.top()["data"].push(str);
}

var Expat::read(const char* iFile)
{
    return parse(iFile);
}

void Expat::write(const char* iFile, var iVar)
{
}
<commit_msg>Handle DOS line ends in XML files<commit_after>/*
 * Copyright 2013 by Philip N. Garner
 *
 * See the file COPYING for the licence associated with this software.
 *
 * Author(s):
 *   Phil Garner, October 2013
 */

#include <fstream>
#include <stdexcept>
#include <var.h>

#include "expat.h"

namespace libvar
{
    /**
     * Class to wrap the expat library and callbacks.
     */
    class Expat : public varfile
    {
    public:
        Expat();
        ~Expat();
        var parse(const char* iFile);
        void startElementHandler(const XML_Char *iName, const XML_Char **iAtts);
        void endElementHandler(const XML_Char *iName);
        void characterDataHandler(const XML_Char *iStr, int iLen);
        virtual var read(const char* iFile);
        virtual void write(const char* iFile, var iVar);

    private:
        var mVar;            ///< Var to populate during parse
        var mStack;          ///< Parse stack
        XML_Parser mParser;  ///< The expat parser

        var element();
    };
}

using namespace libvar;

void libvar::factory(varfile** oFile)
{
    *oFile = new Expat;
}

/**
 * In principle this is unnecessary; in practice it's useful to catch
 * errors (of the form "dude, you forgot to implement...").
 */
static void DefaultHandler(
    void *iUserData, const XML_Char *iStr, int iLen
)
{
    // DOS line ends find their way here.  Why?
    if ((iLen == 1) && (*iStr == '\r'))
        return;

    var str(iLen, iStr);
    std::cout << "expat::DefaultHandler: " << str << std::endl;
    throw std::runtime_error("xmlfile: default handler called");
}

/**
 * We don't do anything with the XML declaration, but need to handle
 * it so the the default handler doesn't.
 */
static void XmlDeclHandler(
    void *iUserData,
    const XML_Char *version,
    const XML_Char *encoding,
    int standalone
)
{
    //std::cout << "xml: " << version << std::endl;
}

static void StartElementHandler(
    void *iUserData, const XML_Char *iName, const XML_Char **iAtts
)
{
    return ((Expat*)iUserData)->startElementHandler(iName, iAtts);
}

static void EndElementHandler(
    void *iUserData, const XML_Char *iName
)
{
    return ((Expat*)iUserData)->endElementHandler(iName);
}

static void CharacterDataHandler(
    void *iUserData, const XML_Char *iStr, int iLen
)
{
    return ((Expat*)iUserData)->characterDataHandler(iStr, iLen);
}

/**
 * Parser constructor.  Points the callbacks to the static functions;
 * those functions convert the UserData field into the class pointer
 * and pass the callback to the appropriate method.
 */
Expat::Expat()
{
    // Create the parser
    mParser = XML_ParserCreate(0);

    // Set the callbacks to the static functions
    XML_SetUserData(mParser, this);
    XML_SetDefaultHandler(mParser, DefaultHandler);
    XML_SetXmlDeclHandler(mParser, XmlDeclHandler);
    XML_SetStartElementHandler(mParser, StartElementHandler);
    XML_SetEndElementHandler(mParser, EndElementHandler);
    XML_SetCharacterDataHandler(mParser, CharacterDataHandler);
}

Expat::~Expat()
{
    XML_ParserFree(mParser);
}

var Expat::parse(const char* iFile)
{
    std::ifstream is(iFile, std::ifstream::in);
    if (is.fail())
        throw std::runtime_error("xmlfile::read(): Open failed");

    var f;
    XML_Status s;
    while (f.getline(is))
    {
        s = XML_Parse(mParser, f.str(), f.size(), 0);
        if (!s)
            throw std::runtime_error("xmlfile::parse(): Error!");
    }
    s = XML_Parse(mParser, f.str(), 0, 0);
    if (!s)
        throw std::runtime_error("xmlfile::parse(): Error!");
    if (mStack.size() != 0)
        throw std::runtime_error("xmlfile::parse(): Short file?");

    return mVar;
}

var Expat::element()
{
    static var elem;
    if (!elem)
    {
        var nil;
        elem["name"] = nil;
        elem["attr"] = nil;
        elem["data"] = nil;
    }
    return elem.copy();
}

void Expat::startElementHandler(const XML_Char *iName, const XML_Char **iAtts)
{
    var elem = element();
    if (mStack)
        mStack.top()["data"].push(elem);
    else
        mVar = elem;
    mStack.push(elem);
    elem["name"] = iName;
    while (*iAtts)
    {
        elem["attr"][iAtts[0]] = iAtts[1];
        iAtts += 2;
    }
}

void Expat::endElementHandler(const XML_Char *iName)
{
    if (mStack.top()["name"] != iName)
        throw std::runtime_error("Expat::endElementHandler: malformed xml");
    mStack.pop();
}

void Expat::characterDataHandler(const XML_Char *iStr, int iLen)
{
    var str(iLen, iStr);
    mStack.top()["data"].push(str);
}

var Expat::read(const char* iFile)
{
    return parse(iFile);
}

void Expat::write(const char* iFile, var iVar)
{
}
<|endoftext|>


<commit_before>// --------------------------------------------------------------------------
#include <sstream>
#include <cstdio>
#include <UniSetTypes.h>
#include "PostgreSQLInterface.h"
// --------------------------------------------------------------------------
using namespace std;
using namespace UniSetTypes;
using namespace pqxx;
// --------------------------------------------------------------------------

PostgreSQLInterface::PostgreSQLInterface():
	lastQ(""),
	lastE(""),
	last_inserted_id(0)
{
	//db = make_shared<pqxx::connection>();
}

PostgreSQLInterface::~PostgreSQLInterface()
{
	close();
}

// -----------------------------------------------------------------------------------------
bool PostgreSQLInterface::ping()
{
	return db && db->is_open();
}
// -----------------------------------------------------------------------------------------
bool PostgreSQLInterface::connect( const string& host, const string& user, const string& pswd, const string& dbname)
{
	if( db )
		return true;

	std::string conninfo = "dbname=" + dbname + " host=" + host + " user=" + user + " password=" + pswd;

	try
	{
		db = make_shared<pqxx::connection>(conninfo);
		return db->is_open();

	}
	catch( const std::exception& e )
	{
		cerr << e.what() << std::endl;
	}

	return false;
}
// -----------------------------------------------------------------------------------------
bool PostgreSQLInterface::close()
{
	if( db )
	{
		db->disconnect();
		db.reset();
	}

	return true;
}
// -----------------------------------------------------------------------------------------
bool PostgreSQLInterface::insert( const string& q )
{
	if( !db )
		return false;

	try
	{
		work w( *(db.get()) );
		w.exec(q);
		w.commit();
		return true;
	}
	catch( const std::exception& e )
	{
		//cerr << e.what() << std::endl;
		lastE = string(e.what());
	}

	return false;
}
// -----------------------------------------------------------------------------------------
bool PostgreSQLInterface::insertAndSaveRowid( const string& q )
{
	if( !db )
		return false;

	std::string qplus = q + " RETURNING id";

	try
	{
		work w( *(db.get()) );
		pqxx::result res = w.exec(qplus);
		w.commit();
		save_inserted_id(res);
		return true;
	}
	catch( const std::exception& e )
	{
		//cerr << e.what() << std::endl;
		lastE = string(e.what());
	}

	return false;
}
// -----------------------------------------------------------------------------------------
PostgreSQLResult PostgreSQLInterface::query( const string& q )
{
	if( !db )
		return PostgreSQLResult();

	try
	{
		nontransaction n(*(db.get()));

		/* Execute SQL query */
		result res( n.exec(q) );
		return PostgreSQLResult(res);
	}
	catch( const std::exception& e )
	{
		lastE = string(e.what());
	}

	return PostgreSQLResult();
}
// -----------------------------------------------------------------------------------------
string PostgreSQLInterface::error()
{
	return lastE;
}
// -----------------------------------------------------------------------------------------
const string PostgreSQLInterface::lastQuery()
{
	return lastQ;
}
// -----------------------------------------------------------------------------------------
double PostgreSQLInterface::insert_id()
{
	return last_inserted_id;
}
// -----------------------------------------------------------------------------------------
void PostgreSQLInterface::save_inserted_id( const pqxx::result& res )
{
	if( res.size() > 0 && res[0].size() > 0 )
		last_inserted_id = res[0][0].as<int>();
}
// -----------------------------------------------------------------------------------------
bool PostgreSQLInterface::isConnection()
{
	return (db && db->is_open());
}
// -----------------------------------------------------------------------------------------
int PostgreSQLResult::num_cols( const PostgreSQLResult::iterator& it )
{
	return it->size();
}
// -----------------------------------------------------------------------------------------
int PostgreSQLResult::as_int( const PostgreSQLResult::iterator& it, int col )
{
	//    if( col<0 || col >it->size() )
	//        return 0;
	return uni_atoi( (*it)[col] );
}
// -----------------------------------------------------------------------------------------
double PostgreSQLResult::as_double( const PostgreSQLResult::iterator& it, int col )
{
	return atof( ((*it)[col]).c_str() );
}
// -----------------------------------------------------------------------------------------
std::string PostgreSQLResult::as_string( const PostgreSQLResult::iterator& it, int col )
{
	return ((*it)[col]);
}
// -----------------------------------------------------------------------------------------
int PostgreSQLResult::as_int( const PostgreSQLResult::COL::iterator& it )
{
	return uni_atoi( (*it) );
}
// -----------------------------------------------------------------------------------------
double PostgreSQLResult::as_double( const PostgreSQLResult::COL::iterator& it )
{
	return atof( (*it).c_str() );
}
// -----------------------------------------------------------------------------------------
std::string PostgreSQLResult::as_string( const PostgreSQLResult::COL::iterator& it )
{
	return (*it);
}
// -----------------------------------------------------------------------------------------
#if 0
PostgreSQLResult::COL PostgreSQLResult::get_col( const PostgreSQLResult::ROW::iterator& it )
{
	return (*it);
}
#endif
// -----------------------------------------------------------------------------------------
PostgreSQLResult::~PostgreSQLResult()
{

}
// -----------------------------------------------------------------------------------------
PostgreSQLResult::PostgreSQLResult( const pqxx::result& res )
{
	for( result::const_iterator c = res.begin(); c != res.end(); ++c )
	{
		COL col;

		for( auto i = 0; i < c.size(); i++ )
			col.push_back( c[i].as<string>() );

		row.push_back(col);
	}
}
// -----------------------------------------------------------------------------------------
<commit_msg>minor fix:<commit_after>// --------------------------------------------------------------------------
#include <sstream>
#include <cstdio>
#include <UniSetTypes.h>
#include "PostgreSQLInterface.h"
// --------------------------------------------------------------------------
using namespace std;
using namespace UniSetTypes;
using namespace pqxx;
// --------------------------------------------------------------------------

PostgreSQLInterface::PostgreSQLInterface():
	lastQ(""),
	lastE(""),
	last_inserted_id(0)
{
	//db = make_shared<pqxx::connection>();
}

PostgreSQLInterface::~PostgreSQLInterface()
{
	close();
}

// -----------------------------------------------------------------------------------------
bool PostgreSQLInterface::ping()
{
	return db && db->is_open();
}
// -----------------------------------------------------------------------------------------
bool PostgreSQLInterface::connect( const string& host, const string& user, const string& pswd, const string& dbname)
{
	if( db )
		return true;

	std::string conninfo = "dbname=" + dbname + " host=" + host + " user=" + user + " password=" + pswd;

	try
	{
		db = make_shared<pqxx::connection>(conninfo);
		return db->is_open();

	}
	catch( const std::exception& e )
	{
		cerr << e.what() << std::endl;
	}

	return false;
}
// -----------------------------------------------------------------------------------------
bool PostgreSQLInterface::close()
{
	if( db )
	{
		db->disconnect();
		db.reset();
	}

	return true;
}
// -----------------------------------------------------------------------------------------
bool PostgreSQLInterface::insert( const string& q )
{
	if( !db )
		return false;

	try
	{
		work w( *(db.get()) );
		w.exec(q);
		w.commit();
		return true;
	}
	catch( const std::exception& e )
	{
		//cerr << e.what() << std::endl;
		lastE = string(e.what());
	}

	return false;
}
// -----------------------------------------------------------------------------------------
bool PostgreSQLInterface::insertAndSaveRowid( const string& q )
{
	if( !db )
		return false;

	std::string qplus = q + " RETURNING id";

	try
	{
		work w( *(db.get()) );
		pqxx::result res = w.exec(qplus);
		w.commit();
		save_inserted_id(res);
		return true;
	}
	catch( const std::exception& e )
	{
		//cerr << e.what() << std::endl;
		lastE = string(e.what());
	}

	return false;
}
// -----------------------------------------------------------------------------------------
PostgreSQLResult PostgreSQLInterface::query( const string& q )
{
	if( !db )
		return PostgreSQLResult();

	try
	{
		nontransaction n(*(db.get()));

		/* Execute SQL query */
		result res( n.exec(q) );
		return PostgreSQLResult(res);
	}
	catch( const std::exception& e )
	{
		lastE = string(e.what());
	}

	return PostgreSQLResult();
}
// -----------------------------------------------------------------------------------------
string PostgreSQLInterface::error()
{
	return lastE;
}
// -----------------------------------------------------------------------------------------
const string PostgreSQLInterface::lastQuery()
{
	return lastQ;
}
// -----------------------------------------------------------------------------------------
double PostgreSQLInterface::insert_id()
{
	return last_inserted_id;
}
// -----------------------------------------------------------------------------------------
void PostgreSQLInterface::save_inserted_id( const pqxx::result& res )
{
	if( res.size() > 0 && res[0].size() > 0 )
		last_inserted_id = res[0][0].as<int>();
}
// -----------------------------------------------------------------------------------------
bool PostgreSQLInterface::isConnection()
{
	return (db && db->is_open());
}
// -----------------------------------------------------------------------------------------
int PostgreSQLResult::num_cols( const PostgreSQLResult::iterator& it )
{
	return it->size();
}
// -----------------------------------------------------------------------------------------
int PostgreSQLResult::as_int( const PostgreSQLResult::iterator& it, int col )
{
	//    if( col<0 || col >it->size() )
	//        return 0;
	return uni_atoi( (*it)[col] );
}
// -----------------------------------------------------------------------------------------
double PostgreSQLResult::as_double( const PostgreSQLResult::iterator& it, int col )
{
	return atof( ((*it)[col]).c_str() );
}
// -----------------------------------------------------------------------------------------
std::string PostgreSQLResult::as_string( const PostgreSQLResult::iterator& it, int col )
{
	return ((*it)[col]);
}
// -----------------------------------------------------------------------------------------
int PostgreSQLResult::as_int( const PostgreSQLResult::COL::iterator& it )
{
	return uni_atoi( (*it) );
}
// -----------------------------------------------------------------------------------------
double PostgreSQLResult::as_double( const PostgreSQLResult::COL::iterator& it )
{
	return atof( (*it).c_str() );
}
// -----------------------------------------------------------------------------------------
std::string PostgreSQLResult::as_string( const PostgreSQLResult::COL::iterator& it )
{
	return (*it);
}
// -----------------------------------------------------------------------------------------
#if 0
PostgreSQLResult::COL PostgreSQLResult::get_col( const PostgreSQLResult::ROW::iterator& it )
{
	return (*it);
}
#endif
// -----------------------------------------------------------------------------------------
PostgreSQLResult::~PostgreSQLResult()
{

}
// -----------------------------------------------------------------------------------------
PostgreSQLResult::PostgreSQLResult( const pqxx::result& res )
{
	for( result::const_iterator c = res.begin(); c != res.end(); ++c )
	{
		COL col;

		for( pqxx::result::tuple::size_type i = 0; i < c.size(); i++ )
			col.push_back( c[i].as<string>() );

		row.push_back(col);
	}
}
// -----------------------------------------------------------------------------------------
<|endoftext|>


<commit_before>/**
  ******************************************************************************
  * @file    voodoospark.cpp
  * @author  Chris Williams
  * @version V1.0.0
  * @date    24-January-2014
  * @brief   Exposes the firmware level API through a TCP Connection intiated
  *          via the spark cloud service
  ******************************************************************************
  Copyright (c) 2014 Chris Williams  All rights reserved.

  Permission is hereby granted, free of charge, to any person
  obtaining a copy of this software and associated documentation
  files (the "Software"), to deal in the Software without
  restriction, including without limitation the rights to use,
  copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the
  Software is furnished to do so, subject to the following
  conditions:

  The above copyright notice and this permission notice shall be
  included in all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  OTHER DEALINGS IN THE SOFTWARE.
  ******************************************************************************
  */

#define DEBUG 0
TCPClient client;

byte reading[20];
byte previous[20];

Servo servos[20];

long SerialSpeed[] = {  600, 1200, 2400, 4800, 9600, 14400, 19200, 28800, 38400, 57600, 115200 };

void ipArrayFromString(byte ipArray[], String ipString) {
  int dot1 = ipString.indexOf('.');
  ipArray[0] = ipString.substring(0, dot1).toInt();
  int dot2 = ipString.indexOf('.', dot1 + 1);
  ipArray[1] = ipString.substring(dot1 + 1, dot2).toInt();
  dot1 = ipString.indexOf('.', dot2 + 1);
  ipArray[2] = ipString.substring(dot2 + 1, dot1).toInt();
  ipArray[3] = ipString.substring(dot1 + 1).toInt();
}

int connectToMyServer(String params) {
  //parse data
  int colonIndex = params.indexOf(":");
  String ip = params.substring(0, colonIndex);
  String port = params.substring(colonIndex+1, params.length());
  if(DEBUG)
    Serial.println("Attempting to connect to server: "+ip+":"+port);

  byte serverAddress[4];
  ipArrayFromString(serverAddress, ip);
  int serverPort = port.toInt();
  if (client.connect(serverAddress, serverPort)) {

    reset();

    if (DEBUG)
      Serial.println("Connected to server: "+ip+":"+port);
    return 1; // successfully connected

  } else {
    if(DEBUG)
      Serial.println("Unable to connect to server: "+ip+":"+port);
    return -1; // failed to connect
  }
}

void reset() {
  for (int i = 0; i < 20; i++) {
    reading[i] = 0;
    previous[i] = 0;
  }
}

void send(int action, int pin, int value) {
  if (previous[pin] != value) {
    client.write(action);
    client.write(pin);
    client.write(value);
  }
  previous[pin] = value;
}

void report() {
  for (int i = 0; i < 20; i++) {
    if (reading[i]) {
      int dr = (reading[i] & 1);
      int ar = (reading[i] & 2);

      if (i < 10 && dr) {
        send(0x03, i, digitalRead(i));
      } else {
        if (dr) {
          send(0x03, i, digitalRead(i));
        } else {
          if (ar) {
            send(0x04, i, analogRead(i));
          }
        }
      }
    }
  }
}

void setup() {
  Spark.function("connect", connectToMyServer);
  if (DEBUG)
    Serial.begin(115200);
}

void loop() {
  report();

  if (client.connected()) {
    if (client.available()) {
      // parse and execute commands

      int action = client.read();
      if(DEBUG)
        Serial.println("Action received: "+('0'+action));
      int pin, mode, val, type, speed, address, stop, len, i;
      switch (action) {
        case 0x00:  // pinMode
          pin = client.read();
          mode = client.read();
          //mode is modeled after Standard Firmata
          if (mode == 0x00) {
            pinMode(pin, INPUT);
          } else if (mode == 0x02) {
            pinMode(pin, INPUT_PULLUP);
          } else if (mode == 0x03) {
            pinMode(pin, INPUT_PULLDOWN);
          } else if (mode == 0x01) {
            pinMode(pin, OUTPUT);
          }
          break;
        case 0x01:  // digitalWrite
          pin = client.read();
          val = client.read();
          digitalWrite(pin, val);
          break;
        case 0x02:  // analogWrite
          pin = client.read();
          val = client.read();
          analogWrite(pin, val);
          break;
        case 0x03:  // digitalRead
          pin = client.read();
          val = digitalRead(pin);
          client.write(0x03);
          client.write(pin);
          client.write(val);
          break;
        case 0x04:  // analogRead
          pin = client.read();
          val = analogRead(pin);
          client.write(0x04);
          client.write(pin);
          client.write(val);
          break;
        case 0x05: // set always send bit
          pin = client.read();
          val = client.read();
          reading[pin] = val;
          break;

      if(DEBUG)
        Serial.println("Action received: "+('0'+action));

      int pin, mode, val;

      // These are used in the commented code below there are warnings there that need to be resolved
      // otherwise spark.io will not compile and flash
      // int type, speed, len, i;

      switch (action) {
        case 0x00:  // pinMode
          pin = client.read();
          mode = client.read();
          //mode is modeled after Standard Firmata
          if (mode == 0x00) {
            pinMode(pin, INPUT);
          } else if (mode == 0x02) {
            pinMode(pin, INPUT_PULLUP);
          } else if (mode == 0x03) {
            pinMode(pin, INPUT_PULLDOWN);
          } else if (mode == 0x01) {
            pinMode(pin, OUTPUT);
          }
          break;
        case 0x01:  // digitalWrite
          pin = client.read();
          val = client.read();
          digitalWrite(pin, val);
          break;
        case 0x02:  // analogWrite
          pin = client.read();
          val = client.read();
          analogWrite(pin, val);
          break;
        case 0x03:  // digitalRead
          pin = client.read();
          val = digitalRead(pin);
          client.write(0x03);
          client.write(pin);
          client.write(val);
          break;
        case 0x04:  // analogRead
          pin = client.read();
          val = analogRead(pin);
          client.write(0x04);
          client.write(pin);
          client.write(val);
          break;
        case 0x05:
          pin = client.read();
          val = client.read();
          reading[pin] = val;
          break;

        // Serial API
        case 0x10:  // serial.begin
           type = client.read();
           speed = client.read();
          if (type == 0) {
            Serial.begin(SerialSpeed[speed]);
          } else {
            Serial1.begin(SerialSpeed[speed]);
          }
          break;
        case 0x11:  // serial.end
          type = client.read();
          if (type == 0) {
            Serial.end();
          } else {
            Serial1.end();
          }
          break;
        case 0x12:  // serial.peek
          type = client.read();
          if (type == 0) {
            val = Serial.peek();
          } else {
            val = Serial1.peek();
          }
          client.write(0x07);
          client.write(type);
          client.write(val);
          break;
        case 0x13:  // serial.available()
          type = client.read();
          if (type == 0) {
            val = Serial.available();
          } else {
            val = Serial1.available();
          }
          client.write(0x07);
          client.write(type);
          client.write(val);
          break;
        case 0x14:  // serial.write
          type = client.read();
          len = client.read();
          for (i = 0; i < len; i++) {
            if (type ==0) {
              Serial.write(client.read());
            } else {
              Serial1.write(client.read());
            }
          }
          break;
        case 0x15: // serial.read
          type = client.read();
          if (type == 0) {
            val = Serial.read();
          } else {
            val = Serial1.read();
          }
          client.write(0x16);
          client.write(type);
          client.write(val);
          break;
        case 0x16: // serial.flush
          type = client.read();
          if (type == 0) {
            Serial.flush();
          } else {
            Serial1.flush();
          }
          break;

        // SPI API
        case 0x20:  // SPI.begin
          SPI.begin();
          break;
        case 0x21:  // SPI.end
          SPI.end();
          break;
        case 0x22:  // SPI.setBitOrder
          type = client.read();
          SPI.setBitOrder((type ? MSBFIRST : LSBFIRST));
          break;
        case 0x23:  // SPI.setClockDivider
          val = client.read();
          if (val == 0) {
            SPI.setClockDivider(SPI_CLOCK_DIV2);
          } else if (val == 1) {
            SPI.setClockDivider(SPI_CLOCK_DIV4);
          } else if (val == 2) {
            SPI.setClockDivider(SPI_CLOCK_DIV8);
          } else if (val == 3) {
            SPI.setClockDivider(SPI_CLOCK_DIV16);
          } else if (val == 4) {
            SPI.setClockDivider(SPI_CLOCK_DIV32);
          } else if (val == 5) {
            SPI.setClockDivider(SPI_CLOCK_DIV64);
          } else if (val == 6) {
            SPI.setClockDivider(SPI_CLOCK_DIV128);
          } else if (val == 7) {
            SPI.setClockDivider(SPI_CLOCK_DIV256);
          }
          break;

        case 0x24:  // SPI.setDataMode
          val = client.read();
          if (val == 0) {
            SPI.setDataMode(SPI_MODE0);
          } else if (val == 1) {
            SPI.setDataMode(SPI_MODE1);
          } else if (val == 2) {
            SPI.setDataMode(SPI_MODE2);
          } else if (val == 3) {
            SPI.setDataMode(SPI_MODE3);
          }
          break;

        case 0x25:  // SPI.transfer
          val = client.read();
          val = SPI.transfer(val);
          client.write(0x24);
          client.write(val);
          break;

        // Wire API
        case 0x30:  // Wire.begin
          address = client.read();
          if (address == 0) {
            Wire.begin();
          } else {
            Wire.begin(address);
          }
          break;
        case 0x31:  // Wire.requestFrom
          address = client.read();
          val = client.read();
          stop = client.read();

          Wire.requestFrom(address, val, stop);
          break;
        case 0x32:  // Wire.beginTransmission
          address = client.read();
          Wire.beginTransmission(address);
          break;
        case 0x33:  // Wire.endTransmission
          stop = client.read();
          val = Wire.endTransmission(stop);
          client.write(0x33);
          client.write(val);
          break;
        case 0x34:  // Wire.write
          len = client.read();
          uint8_t wireData[len];
          for (i = 0; i< len; i++) {
            wireData[i] = client.read();
          }
          val = Wire.write(wireData, len);
          client.write(0x34);
          client.write(val);
          break;
        case 0x35:  // Wire.available
          val = Wire.available();
          client.write(0x35);
          client.write(val);
          break;
        case 0x36:  // Wire.read
          val = Wire.read();
          client.write(0x36);
          client.write(val);
          break;

        case 0x40:
          pin = client.read();
          servos[pin].attach(pin);
          break;

        case 0x41:
          pin = client.read();
          val = client.read();
          servos[pin].write(val);
          break;

        case 0x42:
          pin = client.read();
          val = client.read();
          servos[pin].writeMicroseconds(val);
          break;

        case 0x43:
          pin = client.read();
          val = servos[pin].read();
          client.write(0x42);
          client.write(pin);
          client.write(val);

          break;

        case 0x44:
          pin = client.read();
          val = servos[pin].attached();
          client.write(0x44);
          client.write(pin);
          client.write(val);
          break;

        case 0x45:
          pin = client.read();
          servos[pin].detach();
          break;

        default: // noop
          break;
        }
      }
    }
  }
}
<commit_msg>Fix copy pasta that resulted from a bad merge conflict resolution in 4abb82b1233d3abc9a319dc9714600d0ddd86183<commit_after>/**
  ******************************************************************************
  * @file    voodoospark.cpp
  * @author  Chris Williams
  * @version V1.0.0
  * @date    24-January-2014
  * @brief   Exposes the firmware level API through a TCP Connection intiated
  *          via the spark cloud service
  ******************************************************************************
  Copyright (c) 2014 Chris Williams  All rights reserved.

  Permission is hereby granted, free of charge, to any person
  obtaining a copy of this software and associated documentation
  files (the "Software"), to deal in the Software without
  restriction, including without limitation the rights to use,
  copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the
  Software is furnished to do so, subject to the following
  conditions:

  The above copyright notice and this permission notice shall be
  included in all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  OTHER DEALINGS IN THE SOFTWARE.
  ******************************************************************************
  */

#define DEBUG 0
TCPClient client;

byte reading[20];
byte previous[20];

Servo servos[20];

long SerialSpeed[] = {  600, 1200, 2400, 4800, 9600, 14400, 19200, 28800, 38400, 57600, 115200 };

void ipArrayFromString(byte ipArray[], String ipString) {
  int dot1 = ipString.indexOf('.');
  ipArray[0] = ipString.substring(0, dot1).toInt();
  int dot2 = ipString.indexOf('.', dot1 + 1);
  ipArray[1] = ipString.substring(dot1 + 1, dot2).toInt();
  dot1 = ipString.indexOf('.', dot2 + 1);
  ipArray[2] = ipString.substring(dot2 + 1, dot1).toInt();
  ipArray[3] = ipString.substring(dot1 + 1).toInt();
}

int connectToMyServer(String params) {
  //parse data
  int colonIndex = params.indexOf(":");
  String ip = params.substring(0, colonIndex);
  String port = params.substring(colonIndex+1, params.length());
  if(DEBUG)
    Serial.println("Attempting to connect to server: "+ip+":"+port);

  byte serverAddress[4];
  ipArrayFromString(serverAddress, ip);
  int serverPort = port.toInt();
  if (client.connect(serverAddress, serverPort)) {

    reset();

    if (DEBUG)
      Serial.println("Connected to server: "+ip+":"+port);
    return 1; // successfully connected

  } else {
    if(DEBUG)
      Serial.println("Unable to connect to server: "+ip+":"+port);
    return -1; // failed to connect
  }
}

void reset() {
  for (int i = 0; i < 20; i++) {
    reading[i] = 0;
    previous[i] = 0;
  }
}

void send(int action, int pin, int value) {
  if (previous[pin] != value) {
    client.write(action);
    client.write(pin);
    client.write(value);
  }
  previous[pin] = value;
}

void report() {
  for (int i = 0; i < 20; i++) {
    if (reading[i]) {
      int dr = (reading[i] & 1);
      int ar = (reading[i] & 2);

      if (i < 10 && dr) {
        send(0x03, i, digitalRead(i));
      } else {
        if (dr) {
          send(0x03, i, digitalRead(i));
        } else {
          if (ar) {
            send(0x04, i, analogRead(i));
          }
        }
      }
    }
  }
}

void setup() {
  Spark.function("connect", connectToMyServer);
  if (DEBUG)
    Serial.begin(115200);
}

void loop() {
  report();

  if (client.connected()) {
    if (client.available()) {
      // parse and execute commands

      int action = client.read();
      if(DEBUG)
        Serial.println("Action received: "+('0'+action));
      int pin, mode, val, type, speed, address, stop, len, i;
      switch (action) {
        case 0x00:  // pinMode
          pin = client.read();
          mode = client.read();
          //mode is modeled after Standard Firmata
          if (mode == 0x00) {
            pinMode(pin, INPUT);
          } else if (mode == 0x02) {
            pinMode(pin, INPUT_PULLUP);
          } else if (mode == 0x03) {
            pinMode(pin, INPUT_PULLDOWN);
          } else if (mode == 0x01) {
            pinMode(pin, OUTPUT);
          }
          break;
        case 0x01:  // digitalWrite
          pin = client.read();
          val = client.read();
          digitalWrite(pin, val);
          break;
        case 0x02:  // analogWrite
          pin = client.read();
          val = client.read();
          analogWrite(pin, val);
          break;
        case 0x03:  // digitalRead
          pin = client.read();
          val = digitalRead(pin);
          client.write(0x03);
          client.write(pin);
          client.write(val);
          break;
        case 0x04:  // analogRead
          pin = client.read();
          val = analogRead(pin);
          client.write(0x04);
          client.write(pin);
          client.write(val);
          break;
        case 0x05: // set always send bit
          pin = client.read();
          val = client.read();
          reading[pin] = val;
          break;

        // Serial API
        case 0x10:  // serial.begin
           type = client.read();
           speed = client.read();
          if (type == 0) {
            Serial.begin(SerialSpeed[speed]);
          } else {
            Serial1.begin(SerialSpeed[speed]);
          }
          break;
        case 0x11:  // serial.end
          type = client.read();
          if (type == 0) {
            Serial.end();
          } else {
            Serial1.end();
          }
          break;
        case 0x12:  // serial.peek
          type = client.read();
          if (type == 0) {
            val = Serial.peek();
          } else {
            val = Serial1.peek();
          }
          client.write(0x07);
          client.write(type);
          client.write(val);
          break;
        case 0x13:  // serial.available()
          type = client.read();
          if (type == 0) {
            val = Serial.available();
          } else {
            val = Serial1.available();
          }
          client.write(0x07);
          client.write(type);
          client.write(val);
          break;
        case 0x14:  // serial.write
          type = client.read();
          len = client.read();
          for (i = 0; i < len; i++) {
            if (type ==0) {
              Serial.write(client.read());
            } else {
              Serial1.write(client.read());
            }
          }
          break;
        case 0x15: // serial.read
          type = client.read();
          if (type == 0) {
            val = Serial.read();
          } else {
            val = Serial1.read();
          }
          client.write(0x16);
          client.write(type);
          client.write(val);
          break;
        case 0x16: // serial.flush
          type = client.read();
          if (type == 0) {
            Serial.flush();
          } else {
            Serial1.flush();
          }
          break;

        // SPI API
        case 0x20:  // SPI.begin
          SPI.begin();
          break;
        case 0x21:  // SPI.end
          SPI.end();
          break;
        case 0x22:  // SPI.setBitOrder
          type = client.read();
          SPI.setBitOrder((type ? MSBFIRST : LSBFIRST));
          break;
        case 0x23:  // SPI.setClockDivider
          val = client.read();
          if (val == 0) {
            SPI.setClockDivider(SPI_CLOCK_DIV2);
          } else if (val == 1) {
            SPI.setClockDivider(SPI_CLOCK_DIV4);
          } else if (val == 2) {
            SPI.setClockDivider(SPI_CLOCK_DIV8);
          } else if (val == 3) {
            SPI.setClockDivider(SPI_CLOCK_DIV16);
          } else if (val == 4) {
            SPI.setClockDivider(SPI_CLOCK_DIV32);
          } else if (val == 5) {
            SPI.setClockDivider(SPI_CLOCK_DIV64);
          } else if (val == 6) {
            SPI.setClockDivider(SPI_CLOCK_DIV128);
          } else if (val == 7) {
            SPI.setClockDivider(SPI_CLOCK_DIV256);
          }
          break;

        case 0x24:  // SPI.setDataMode
          val = client.read();
          if (val == 0) {
            SPI.setDataMode(SPI_MODE0);
          } else if (val == 1) {
            SPI.setDataMode(SPI_MODE1);
          } else if (val == 2) {
            SPI.setDataMode(SPI_MODE2);
          } else if (val == 3) {
            SPI.setDataMode(SPI_MODE3);
          }
          break;

        case 0x25:  // SPI.transfer
          val = client.read();
          val = SPI.transfer(val);
          client.write(0x24);
          client.write(val);
          break;

        // Wire API
        case 0x30:  // Wire.begin
          address = client.read();
          if (address == 0) {
            Wire.begin();
          } else {
            Wire.begin(address);
          }
          break;
        case 0x31:  // Wire.requestFrom
          address = client.read();
          val = client.read();
          stop = client.read();

          Wire.requestFrom(address, val, stop);
          break;
        case 0x32:  // Wire.beginTransmission
          address = client.read();
          Wire.beginTransmission(address);
          break;
        case 0x33:  // Wire.endTransmission
          stop = client.read();
          val = Wire.endTransmission(stop);
          client.write(0x33);
          client.write(val);
          break;
        case 0x34:  // Wire.write
          len = client.read();
          uint8_t wireData[len];
          for (i = 0; i< len; i++) {
            wireData[i] = client.read();
          }
          val = Wire.write(wireData, len);
          client.write(0x34);
          client.write(val);
          break;
        case 0x35:  // Wire.available
          val = Wire.available();
          client.write(0x35);
          client.write(val);
          break;
        case 0x36:  // Wire.read
          val = Wire.read();
          client.write(0x36);
          client.write(val);
          break;

        case 0x40:
          pin = client.read();
          servos[pin].attach(pin);
          break;
        case 0x41:
          pin = client.read();
          val = client.read();
          servos[pin].write(val);
          break;
        case 0x42:
          pin = client.read();
          val = client.read();
          servos[pin].writeMicroseconds(val);
          break;
        case 0x43:
          pin = client.read();
          val = servos[pin].read();
          client.write(0x43);
          client.write(pin);
          client.write(val);
          break;
        case 0x44:
          pin = client.read();
          val = servos[pin].attached();
          client.write(0x44);
          client.write(pin);
          client.write(val);
          break;
        case 0x45:
          pin = client.read();
          servos[pin].detach();
          break;

        default: // noop
          break;

      } // <-- This is the end of the switch
    }
  }
}
<|endoftext|>


<commit_before>#include "extensions.h"
#include "extensions/accelerometer.h"
#include "extensions/debugconsole.h"
#include "extensions/deviceinfo.h"
#include "extensions/hash.h"
#include "extensions/notification.h"

#ifdef Q_WS_S60
#include "extensions/camera.h"
#include "extensions/memorywatcher.h"
#endif

#include <QWebFrame>

Extensions::Extensions(QWebView *webView) :
    QObject(webView) {

    m_frame = webView->page()->mainFrame();
    connect(m_frame, SIGNAL(javaScriptWindowObjectCleared()), SLOT(attachExtensions()));

    m_extensions["GapAccelerometer"] = new Accelerometer(this);
    m_extensions["GapDebugConsole"] = new DebugConsole(this);
    m_extensions["GapDeviceInfo"] = new DeviceInfo(this);
    m_extensions["GapHash"] = new Hash(this);
    m_extensions["GapNotification"] = new Notification(this);

#ifdef Q_WS_S60
    m_extensions["GapCamera"] = new Camera(this);
    m_extensions["GapMemoryWatcher"] = new MemoryWatcher(this);
#endif

    attachExtensions();
}

void Extensions::attachExtensions() {

    foreach (QString name, m_extensions.keys()) {
        m_frame->addToJavaScriptWindowObject(name, m_extensions[name]);
    }
}
<commit_msg>Add Geolocation to exported APIs.<commit_after>#include "extensions.h"
#include "extensions/accelerometer.h"
#include "extensions/debugconsole.h"
#include "extensions/deviceinfo.h"
#include "extensions/geolocation.h"
#include "extensions/hash.h"
#include "extensions/notification.h"

#ifdef Q_WS_S60
#include "extensions/camera.h"
#include "extensions/memorywatcher.h"
#endif

#include <QWebFrame>

Extensions::Extensions(QWebView *webView) :
    QObject(webView) {

    m_frame = webView->page()->mainFrame();
    connect(m_frame, SIGNAL(javaScriptWindowObjectCleared()), SLOT(attachExtensions()));

    m_extensions["GapAccelerometer"] = new Accelerometer(this);
    m_extensions["GapDebugConsole"] = new DebugConsole(this);
    m_extensions["GapDeviceInfo"] = new DeviceInfo(this);
    m_extensions["GapGeolocation"] = new Geolocation(this);
    m_extensions["GapHash"] = new Hash(this);
    m_extensions["GapNotification"] = new Notification(this);

#ifdef Q_WS_S60
    m_extensions["GapCamera"] = new Camera(this);
    m_extensions["GapMemoryWatcher"] = new MemoryWatcher(this);
#endif

    attachExtensions();
}

void Extensions::attachExtensions() {

    foreach (QString name, m_extensions.keys()) {
        m_frame->addToJavaScriptWindowObject(name, m_extensions[name]);
    }
}
<|endoftext|>


<commit_before>#include "opencv2/opencv.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include<fstream>
#include<iostream>
using namespace std;
using namespace cv;
struct data
{
  int img[20][20];
} s1;
int main()
{
  int r,s;
  Point p,q;
  Mat img=imread("5.jpg",CV_8UC3);
  GaussianBlur(img, img, Size(3,3), 1, 0, 2);
  Mat mserOutMask(img.size(),CV_8UC1,Scalar(0));
  Ptr<MSER> mserExtractor  = MSER::create();

  vector<vector<Point> > mserContours;
  vector<KeyPoint> mserKeypoint;
  vector<Rect> mserBbox;
  mserExtractor->detectRegions(img, mserContours,  mserBbox);

  for (int i=0; i<mserContours.size(); ++i){
      for (int j=0; j<mserContours[i].size(); ++j){
        Point p =  mserContours[i][j];
          // cout << p.x << ", " << p.y << endl;
          mserOutMask.at<uchar>(p.y, p.x) = 255;
      }
  }
  imshow("",mserOutMask);
  Mat threshold_output;
    vector<vector<Point> > contours;
    vector<Vec4i> hierarchy;
    threshold(mserOutMask, threshold_output, 100, 255, THRESH_BINARY );
  imshow(" ",threshold_output);
    findContours( threshold_output, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0) );
    vector<vector<Point> > contours_poly( contours.size() );
    vector<Rect> boundRect( contours.size() );
    for( size_t i = 0; i < contours.size(); i++ )
       { approxPolyDP( Mat(contours[i]), contours_poly[i], 3, true );
         boundRect[i] = boundingRect( Mat(contours_poly[i]) );
       }
ofstream f("segments.dat",ios::binary);
Mat m1(20,20,CV_8UC1);
for(size_t j=0;j<contours.size();j++)
{

      cv::Mat crop = img(boundRect[j]);
resize(crop,m1,m1.size());
for(int x=0;x<20;x++)
for(int y=0;y<20;y++)
s1.img[y][x]=m1.at<uchar>(y,x);
f.write((char*)&s1,sizeof(s1));
}
f.close();
  imshow("mser", img);
waitKey(0);
  return 0;
}
<commit_msg>Delete charsegment.cpp<commit_after><|endoftext|>