<commit_before>#include <boost/tokenizer.hpp>
#include <iostream>
#include <unistd.h>
#include <string.h>
#include <cstdlib>
#include <errno.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string>
#include <sstream>
#include <vector>

//using namespace boost;
using namespace std;

int main()
{
	using namespace boost;
	string args;
	while(1 != 2)
	{
		cout << "$ ";
		getline(cin, args);

		char *argv[9];
		int i = 0;
		vector<string> arg_s;
		typedef tokenizer< char_separator<char> > tokenizer;
		char_separator<char> sep(" ", "-;||&&", drop_empty_tokens);
		tokenizer tokens(args, sep);

		for(tokenizer::iterator tok_iter=tokens.begin(); tok_iter != tokens.end();++tok_iter) {
			if(*tok_iter == "&&" || *tok_iter == "||" || *tok_iter == ";") {

	//			argv[i] = NULL;
	//			int pidb = fork();
	//			if(pidb == -1) {
	//				perror("fork");
	//			}
	//			if(pidb == 0) {
	//				int t = execvp(argv[0], argv);
	//				if(t == -1) {
	//					perror("execvp");
	//				}
	//			}
	//			else {
	//				if(-1 == waitpid(pidb, &pidb, 0)) {
	//					perror("waitpid");
	//				}
	//			}
			}
			else {
				cout << *tok_iter << endl;
				arg_s.push_back(*tok_iter);
				argv[i] = new char[12];
				strcpy(argv[i], const_cast<char*>(arg_s[i].c_str()));
				if(*tok_iter == "exit")
					exit(1);
				++i;
			}
		}
		argv[i] = NULL;
		int pid = fork();
		if(pid == -1) {
			perror("fork");
			exit(1);
		}
		if(pid == 0) {
			int r = execvp(argv[0], argv);
			if(r == -1) {
				perror("execvp");
				exit(1);
			}
		}
		else {
			if(-1 == waitpid(pid, &pid, 0)) {
				perror("waitpid");
			}
		}

//	int pid = fork();
//	if(pid == -1) {
//		perror("fork");
//		exit(1);
//	}
//	if(pid == 0)
//	{
		//char *argv2[4];
		//argv2[0] = new char[6];
		//strcpy(argv[0], "ls");
		//argv2[1] = new char[6];
		//strcpy(argv[1], "-a");
		//argv2[2] = new char [6];
		//strcpy(argv[2], "-l");

	//	int pid2 = fork();
	//	if(pid2 == -1) {
	//		perror("fork");
	//		exit(1);
	//	}
	//	if(pid2 == 0) {
	///		if(execvp(argv[0], argv) == -1) {
	//			perror("execvp");
	//			exit(1);
	//		}
	//	}
	//	else {
	//		if(-1 == waitpid(pid2,&pid2,0 ))
	//			perror("waitpid");
	//	}
	//
	  //      if(execvp(argv[1], argv) == -1) {
	//		perror("execvp");
	//		exit(1);
	//	}
//
//		cout << "after" << endl;
//	}
//	else {
//		if(-1 == waitpid(pid, &pid, 0))
//			perror("waitpid");
//	}

	}

	return 0;
}
<commit_msg>rshell.cpp updated<commit_after>#include <boost/tokenizer.hpp>
#include <iostream>
#include <unistd.h>
#include <string.h>
#include <cstdlib>
#include <errno.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string>
#include <sstream>
#include <vector>

//using namespace boost;
using namespace std;

int main()
{
	using namespace boost;
	string args;
	while(1 != 2)
	{
		cout << "$ ";
		getline(cin, args);

		char *argv[9];
		int i = 0;
		vector<string> arg_s;
		typedef tokenizer< char_separator<char> > tokenizer;
		char_separator<char> sep(" ", "-;||&&", drop_empty_tokens);
		tokenizer tokens(args, sep);

		for(tokenizer::iterator tok_iter=tokens.begin(); tok_iter != tokens.end();++tok_iter) {
			if(*tok_iter == "&&" || *tok_iter == "||" || *tok_iter == ";") {

	//			argv[i] = NULL;
	//			int pidb = fork();
	//			if(pidb == -1) {
	//				perror("fork");
	//			}
	//			if(pidb == 0) {
	//				int t = execvp(argv[0], argv);
	//				if(t == -1) {
	//					perror("execvp");
	//				}
	//			}
	//			else {
	//				if(-1 == waitpid(pidb, &pidb, 0)) {
	//					perror("waitpid");
	//				}
	//			}
			}
			else {

				arg_s.push_back(*tok_iter);
				argv[i] = new char[12];
				strcpy(argv[i], const_cast<char*>(arg_s[i].c_str()));
				if(*tok_iter == "exit")
					exit(1);
				++i;
			}
		}
		argv[i] = NULL;
		int pid = fork();
		if(pid == -1) {
			perror("fork");
			exit(1);
		}
		if(pid == 0) {
			int r = execvp(argv[0], argv);
			if(r == -1) {
				perror("execvp");
				exit(1);
			}
		}
		else {
			if(-1 == waitpid(pid, &pid, 0)) {
				perror("waitpid");
			}
		}

//	int pid = fork();
//	if(pid == -1) {
//		perror("fork");
//		exit(1);
//	}
//	if(pid == 0)
//	{
		//char *argv2[4];
		//argv2[0] = new char[6];
		//strcpy(argv[0], "ls");
		//argv2[1] = new char[6];
		//strcpy(argv[1], "-a");
		//argv2[2] = new char [6];
		//strcpy(argv[2], "-l");

	//	int pid2 = fork();
	//	if(pid2 == -1) {
	//		perror("fork");
	//		exit(1);
	//	}
	//	if(pid2 == 0) {
	///		if(execvp(argv[0], argv) == -1) {
	//			perror("execvp");
	//			exit(1);
	//		}
	//	}
	//	else {
	//		if(-1 == waitpid(pid2,&pid2,0 ))
	//			perror("waitpid");
	//	}
	//
	  //      if(execvp(argv[1], argv) == -1) {
	//		perror("execvp");
	//		exit(1);
	//	}
//
//		cout << "after" << endl;
//	}
//	else {
//		if(-1 == waitpid(pid, &pid, 0))
//			perror("waitpid");
//	}

	}

	return 0;
}
<|endoftext|>


<commit_before><commit_msg>Adding many of the features. Considering this a v0.1<commit_after>#include <iostream>
#include <string>
#include <queue>
#include <vector>
#include <algorithm>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

using namespace std;

const string cmd_delimiter = ";|&#";

void splice_input(queue<string> &cmds, queue<char> &conns, const string &input);
string get_input(const string &input, int &start, int &end);
int find_delimiter(const string &input, int &start);
bool run_command(string &input, char &conn);
void tokenize(vector<char*> &comms, string &input);

int main()
{
  string input;
  char logic;
  queue<string> commands;
  queue<char> connectors;
  bool running = true;

  while(1)
  {
    cout << "$ ";
    getline(cin, input);
    splice_input(commands, connectors, input);

    while(!commands.empty() && running)
    {
      input = commands.front();
      commands.pop();

      if(!connectors.empty())
      {
        logic = connectors.front();
        connectors.pop();
      }

      if(input.find("exit") == string::npos)
        running = run_command(input, logic);
      else
        exit(1);

      if(!running)
      {
        connectors = queue<char>();
        commands = queue<string>();
      }
    }
    running = true;

  }

  return 0;
}

void splice_input(queue<string> &cmds, queue<char> &conns, const string &input)
{
  int pos = 0;
  char logic;
  string new_cmd;
  string parse = input;

  while(pos != -1)
  {
    pos = parse.find_first_of(cmd_delimiter);
    new_cmd = parse.substr(0, pos);
    logic = parse[pos];

    while(new_cmd[0] == ' ')
      new_cmd = new_cmd.substr(1, new_cmd.length());

    if(logic == '&' || logic == '|')
    {
      cmds.push(new_cmd);
      parse.erase(0, pos + 2);
    }
    else if(logic == ';')
    {
      cmds.push(new_cmd);
      parse.erase(0, pos + 1);
    }
    else
      cmds.push(new_cmd);

    if(logic == '#')
      return;

    conns.push(logic);
  }

}

bool run_command(string &input, char &conn)
{
  pid_t pid = fork();
  vector<char*> tokens;
  int status = 0;

  if(pid == -1)
  {
    perror("Error with fork()");
    exit(1);
  }
  else if(pid == 0)
  {
    tokenize(tokens, input);
    char **cmds = &tokens[0];
    execvp(cmds[0], cmds);
    perror("Execvp failed!");
    exit(1);
  }
  else
  {
    wait(&status);

    if(conn == '&')
    {
      if(status > 0)
        return false;
    }
  }

  return true;
}

void tokenize(vector<char*> &comms, string &input)
{
  string convert;
  string tokenizer = input;
  size_t pos = 0;

  while(pos != string::npos)
  {
    pos = tokenizer.find(' ');
    convert = pos == string::npos ? tokenizer \
                                  : tokenizer.substr(0, pos);
    convert.erase(std::remove_if(convert.begin(), convert.end(), ::isspace), convert.end());
    if(!convert.empty())
    {
      char *tmp = new char[convert.length() + 1];
      strcpy(tmp, convert.c_str());
      comms.push_back(tmp);
      tokenizer.erase(0, pos + 1);
    }
  }

  comms.push_back(NULL);

  return;
}

<|endoftext|>


<commit_before>// Copyright (c) 2011 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/automation/testing_automation_provider.h"

#include <windows.h>

#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/automation/automation_browser_tracker.h"
#include "chrome/browser/automation/automation_window_tracker.h"
#include "chrome/browser/ui/browser_window.h"

void TestingAutomationProvider::ActivateWindow(int handle) {
  if (window_tracker_->ContainsHandle(handle)) {
    ::SetActiveWindow(window_tracker_->GetResource(handle));
  }
}

void TestingAutomationProvider::IsWindowMaximized(int handle,
                                                  bool* is_maximized,
                                                  bool* success) {
  *success = false;

  HWND hwnd = window_tracker_->GetResource(handle);
  if (hwnd) {
    *success = true;
    WINDOWPLACEMENT window_placement;
    GetWindowPlacement(hwnd, &window_placement);
    *is_maximized = (window_placement.showCmd == SW_MAXIMIZE);
  }
}

void TestingAutomationProvider::TerminateSession(int handle, bool* success) {
  *success = false;

  if (browser_tracker_->ContainsHandle(handle)) {
    Browser* browser = browser_tracker_->GetResource(handle);
    HWND window = browser->window()->GetNativeHandle();
    *success = (::PostMessageW(window, WM_ENDSESSION, 0, 0) == TRUE);
  }
}

void TestingAutomationProvider::GetWindowBounds(int handle,
                                                gfx::Rect* bounds,
                                                bool* success) {
  *success = false;
  HWND hwnd = window_tracker_->GetResource(handle);
  if (hwnd) {
    *success = true;
    WINDOWPLACEMENT window_placement;
    GetWindowPlacement(hwnd, &window_placement);
    *bounds = window_placement.rcNormalPosition;
  }
}

void TestingAutomationProvider::SetWindowBounds(int handle,
                                                const gfx::Rect& bounds,
                                                bool* success) {
  *success = false;
  if (window_tracker_->ContainsHandle(handle)) {
    HWND hwnd = window_tracker_->GetResource(handle);
    if (::MoveWindow(hwnd, bounds.x(), bounds.y(), bounds.width(),
                     bounds.height(), true)) {
      *success = true;
    }
  }
}

void TestingAutomationProvider::SetWindowVisible(int handle,
                                                 bool visible,
                                                 bool* result) {
  if (window_tracker_->ContainsHandle(handle)) {
    HWND hwnd = window_tracker_->GetResource(handle);
    ::ShowWindow(hwnd, visible ? SW_SHOW : SW_HIDE);
    *result = true;
  } else {
    *result = false;
  }
}

void TestingAutomationProvider::GetWindowTitle(int handle, string16* text) {
  gfx::NativeWindow window = window_tracker_->GetResource(handle);
  std::wstring result;
  int length = ::GetWindowTextLength(window) + 1;
  ::GetWindowText(window, WriteInto(&result, length), length);
  text->assign(WideToUTF16(result));
}

<commit_msg>Set WINDOWPLACEMENT.length before calling GetWindowPlacement() Also check return value of GetWindowPlacement()<commit_after>// Copyright (c) 2011 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/automation/testing_automation_provider.h"

#include <windows.h>

#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/automation/automation_browser_tracker.h"
#include "chrome/browser/automation/automation_window_tracker.h"
#include "chrome/browser/ui/browser_window.h"

void TestingAutomationProvider::ActivateWindow(int handle) {
  if (window_tracker_->ContainsHandle(handle)) {
    ::SetActiveWindow(window_tracker_->GetResource(handle));
  }
}

void TestingAutomationProvider::IsWindowMaximized(int handle,
                                                  bool* is_maximized,
                                                  bool* success) {
  *success = false;

  HWND hwnd = window_tracker_->GetResource(handle);
  if (hwnd) {
    WINDOWPLACEMENT window_placement;
    window_placement.length = sizeof(window_placement);
    if (GetWindowPlacement(hwnd, &window_placement)) {
      *success = true;
      *is_maximized = (window_placement.showCmd == SW_MAXIMIZE);
    }
  }
}

void TestingAutomationProvider::TerminateSession(int handle, bool* success) {
  *success = false;

  if (browser_tracker_->ContainsHandle(handle)) {
    Browser* browser = browser_tracker_->GetResource(handle);
    HWND window = browser->window()->GetNativeHandle();
    *success = (::PostMessageW(window, WM_ENDSESSION, 0, 0) == TRUE);
  }
}

void TestingAutomationProvider::GetWindowBounds(int handle,
                                                gfx::Rect* bounds,
                                                bool* success) {
  *success = false;
  HWND hwnd = window_tracker_->GetResource(handle);
  if (hwnd) {
    WINDOWPLACEMENT window_placement;
    window_placement.length = sizeof(window_placement);
    if (GetWindowPlacement(hwnd, &window_placement)) {
      *success = true;
      *bounds = window_placement.rcNormalPosition;
    }
  }
}

void TestingAutomationProvider::SetWindowBounds(int handle,
                                                const gfx::Rect& bounds,
                                                bool* success) {
  *success = false;
  if (window_tracker_->ContainsHandle(handle)) {
    HWND hwnd = window_tracker_->GetResource(handle);
    if (::MoveWindow(hwnd, bounds.x(), bounds.y(), bounds.width(),
                     bounds.height(), true)) {
      *success = true;
    }
  }
}

void TestingAutomationProvider::SetWindowVisible(int handle,
                                                 bool visible,
                                                 bool* result) {
  if (window_tracker_->ContainsHandle(handle)) {
    HWND hwnd = window_tracker_->GetResource(handle);
    ::ShowWindow(hwnd, visible ? SW_SHOW : SW_HIDE);
    *result = true;
  } else {
    *result = false;
  }
}

void TestingAutomationProvider::GetWindowTitle(int handle, string16* text) {
  gfx::NativeWindow window = window_tracker_->GetResource(handle);
  std::wstring result;
  int length = ::GetWindowTextLength(window) + 1;
  ::GetWindowText(window, WriteInto(&result, length), length);
  text->assign(WideToUTF16(result));
}

<|endoftext|>


<commit_before>// Copyright 2013 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/drive/change_list_loader.h"

#include "base/files/scoped_temp_dir.h"
#include "base/memory/scoped_ptr.h"
#include "base/prefs/testing_pref_service.h"
#include "base/run_loop.h"
#include "chrome/browser/chromeos/drive/change_list_loader_observer.h"
#include "chrome/browser/chromeos/drive/file_cache.h"
#include "chrome/browser/chromeos/drive/file_system_util.h"
#include "chrome/browser/chromeos/drive/job_scheduler.h"
#include "chrome/browser/chromeos/drive/resource_metadata.h"
#include "chrome/browser/chromeos/drive/test_util.h"
#include "chrome/browser/drive/fake_drive_service.h"
#include "chrome/browser/google_apis/test_util.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace drive {
namespace internal {

class TestChangeListLoaderObserver : public ChangeListLoaderObserver {
 public:
  explicit TestChangeListLoaderObserver(ChangeListLoader* loader)
      : loader_(loader),
        load_from_server_complete_count_(0),
        initial_load_complete_count_(0) {
    loader_->AddObserver(this);
  }

  virtual ~TestChangeListLoaderObserver() {
    loader_->RemoveObserver(this);
  }

  const std::set<base::FilePath>& changed_directories() const {
    return changed_directories_;
  }
  int load_from_server_complete_count() const {
    return load_from_server_complete_count_;
  }
  int initial_load_complete_count() const {
    return initial_load_complete_count_;
  }

  // ChageListObserver overrides:
  virtual void OnDirectoryChanged(
      const base::FilePath& directory_path) OVERRIDE {
    changed_directories_.insert(directory_path);
  }
  virtual void OnLoadFromServerComplete() OVERRIDE {
    ++load_from_server_complete_count_;
  }
  virtual void OnInitialLoadComplete() OVERRIDE {
    ++initial_load_complete_count_;
  }

 private:
  ChangeListLoader* loader_;
  std::set<base::FilePath> changed_directories_;
  int load_from_server_complete_count_;
  int initial_load_complete_count_;

  DISALLOW_COPY_AND_ASSIGN(TestChangeListLoaderObserver);
};

class ChangeListLoaderTest : public testing::Test {
 protected:
  virtual void SetUp() OVERRIDE {
    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
    pref_service_.reset(new TestingPrefServiceSimple);
    test_util::RegisterDrivePrefs(pref_service_->registry());

    drive_service_.reset(new FakeDriveService);
    ASSERT_TRUE(drive_service_->LoadResourceListForWapi(
        "gdata/root_feed.json"));
    ASSERT_TRUE(drive_service_->LoadAccountMetadataForWapi(
        "gdata/account_metadata.json"));

    scheduler_.reset(new JobScheduler(pref_service_.get(),
                                      drive_service_.get(),
                                      base::MessageLoopProxy::current().get()));
    metadata_storage_.reset(new ResourceMetadataStorage(
        temp_dir_.path(), base::MessageLoopProxy::current().get()));
    ASSERT_TRUE(metadata_storage_->Initialize());

    metadata_.reset(new ResourceMetadata(
        metadata_storage_.get(), base::MessageLoopProxy::current().get()));
    ASSERT_EQ(FILE_ERROR_OK, metadata_->Initialize());

    cache_.reset(new FileCache(metadata_storage_.get(),
                               temp_dir_.path(),
                               base::MessageLoopProxy::current().get(),
                               NULL /* free_disk_space_getter */));
    ASSERT_TRUE(cache_->Initialize());

    change_list_loader_.reset(
        new ChangeListLoader(base::MessageLoopProxy::current().get(),
                             metadata_.get(),
                             scheduler_.get()));
  }

  // Adds a new file to the root directory of the service.
  scoped_ptr<google_apis::ResourceEntry> AddNewFile(const std::string& title) {
    google_apis::GDataErrorCode error = google_apis::GDATA_FILE_ERROR;
    scoped_ptr<google_apis::ResourceEntry> entry;
    drive_service_->AddNewFile(
        "text/plain",
        "content text",
        drive_service_->GetRootResourceId(),
        title,
        false,  // shared_with_me
        google_apis::test_util::CreateCopyResultCallback(&error, &entry));
    base::RunLoop().RunUntilIdle();
    EXPECT_EQ(google_apis::HTTP_CREATED, error);
    return entry.Pass();
  }

  content::TestBrowserThreadBundle thread_bundle_;
  base::ScopedTempDir temp_dir_;
  scoped_ptr<TestingPrefServiceSimple> pref_service_;
  scoped_ptr<FakeDriveService> drive_service_;
  scoped_ptr<JobScheduler> scheduler_;
  scoped_ptr<ResourceMetadataStorage,
             test_util::DestroyHelperForTests> metadata_storage_;
  scoped_ptr<ResourceMetadata, test_util::DestroyHelperForTests> metadata_;
  scoped_ptr<FileCache, test_util::DestroyHelperForTests> cache_;
  scoped_ptr<ChangeListLoader> change_list_loader_;
};

TEST_F(ChangeListLoaderTest, LoadIfNeeded) {
  EXPECT_FALSE(change_list_loader_->IsRefreshing());

  // Start initial load.
  TestChangeListLoaderObserver observer(change_list_loader_.get());

  FileError error = FILE_ERROR_FAILED;
  change_list_loader_->LoadIfNeeded(
      DirectoryFetchInfo(),
      google_apis::test_util::CreateCopyResultCallback(&error));
  EXPECT_TRUE(change_list_loader_->IsRefreshing());
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(FILE_ERROR_OK, error);

  EXPECT_FALSE(change_list_loader_->IsRefreshing());
  EXPECT_LT(0, metadata_->GetLargestChangestamp());
  EXPECT_EQ(1, drive_service_->resource_list_load_count());
  EXPECT_EQ(1, observer.initial_load_complete_count());
  EXPECT_EQ(1, observer.load_from_server_complete_count());
  EXPECT_TRUE(observer.changed_directories().empty());

  base::FilePath file_path =
      util::GetDriveMyDriveRootPath().AppendASCII("File 1.txt");
  ResourceEntry entry;
  EXPECT_EQ(FILE_ERROR_OK,
            metadata_->GetResourceEntryByPath(file_path, &entry));

  // Reload. This should result in no-op.
  int64 previous_changestamp = metadata_->GetLargestChangestamp();
  int previous_resource_list_load_count =
      drive_service_->resource_list_load_count();
  change_list_loader_->LoadIfNeeded(
      DirectoryFetchInfo(),
      google_apis::test_util::CreateCopyResultCallback(&error));
  EXPECT_FALSE(change_list_loader_->IsRefreshing());
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(FILE_ERROR_OK, error);

  EXPECT_FALSE(change_list_loader_->IsRefreshing());
  EXPECT_EQ(previous_changestamp, metadata_->GetLargestChangestamp());
  EXPECT_EQ(previous_resource_list_load_count,
            drive_service_->resource_list_load_count());
}

TEST_F(ChangeListLoaderTest, LoadIfNeeded_LocalMetadataAvailable) {
  // Prepare metadata.
  FileError error = FILE_ERROR_FAILED;
  change_list_loader_->LoadIfNeeded(
      DirectoryFetchInfo(),
      google_apis::test_util::CreateCopyResultCallback(&error));
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(FILE_ERROR_OK, error);

  // Reset loader.
  change_list_loader_.reset(
      new ChangeListLoader(base::MessageLoopProxy::current().get(),
                           metadata_.get(),
                           scheduler_.get()));

  // Add a file to the service.
  scoped_ptr<google_apis::ResourceEntry> gdata_entry = AddNewFile("New File");
  ASSERT_TRUE(gdata_entry);

  // Start loading. Because local metadata is available, the load results in
  // returning FILE_ERROR_OK without fetching full list of resources.
  const int previous_resource_list_load_count =
      drive_service_->resource_list_load_count();
  TestChangeListLoaderObserver observer(change_list_loader_.get());

  change_list_loader_->LoadIfNeeded(
      DirectoryFetchInfo(),
      google_apis::test_util::CreateCopyResultCallback(&error));
  EXPECT_TRUE(change_list_loader_->IsRefreshing());
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(FILE_ERROR_OK, error);
  EXPECT_EQ(previous_resource_list_load_count,
            drive_service_->resource_list_load_count());
  EXPECT_EQ(1, observer.initial_load_complete_count());

  // Update should be checked by LoadIfNeeded().
  EXPECT_EQ(drive_service_->largest_changestamp(),
            metadata_->GetLargestChangestamp());
  EXPECT_EQ(1, drive_service_->change_list_load_count());
  EXPECT_EQ(1, observer.load_from_server_complete_count());
  EXPECT_EQ(1U, observer.changed_directories().count(
      util::GetDriveMyDriveRootPath()));

  base::FilePath file_path =
      util::GetDriveMyDriveRootPath().AppendASCII(gdata_entry->title());
  ResourceEntry entry;
  EXPECT_EQ(FILE_ERROR_OK,
            metadata_->GetResourceEntryByPath(file_path, &entry));
}

TEST_F(ChangeListLoaderTest, CheckForUpdates) {
  // CheckForUpdates() results in no-op before load.
  FileError check_for_updates_error = FILE_ERROR_FAILED;
  change_list_loader_->CheckForUpdates(
      google_apis::test_util::CreateCopyResultCallback(
          &check_for_updates_error));
  EXPECT_FALSE(change_list_loader_->IsRefreshing());
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(FILE_ERROR_FAILED,
            check_for_updates_error);  // Callback was not run.
  EXPECT_EQ(0, metadata_->GetLargestChangestamp());
  EXPECT_EQ(0, drive_service_->resource_list_load_count());

  // Start initial load.
  FileError load_error = FILE_ERROR_FAILED;
  change_list_loader_->LoadIfNeeded(
      DirectoryFetchInfo(),
      google_apis::test_util::CreateCopyResultCallback(&load_error));
  EXPECT_TRUE(change_list_loader_->IsRefreshing());

  // CheckForUpdates() while loading.
  change_list_loader_->CheckForUpdates(
      google_apis::test_util::CreateCopyResultCallback(
          &check_for_updates_error));

  base::RunLoop().RunUntilIdle();
  EXPECT_FALSE(change_list_loader_->IsRefreshing());
  EXPECT_EQ(FILE_ERROR_OK, load_error);
  EXPECT_EQ(FILE_ERROR_OK, check_for_updates_error);
  EXPECT_LT(0, metadata_->GetLargestChangestamp());
  EXPECT_EQ(1, drive_service_->resource_list_load_count());

  int64 previous_changestamp = metadata_->GetLargestChangestamp();
  // CheckForUpdates() results in no update.
  change_list_loader_->CheckForUpdates(
      google_apis::test_util::CreateCopyResultCallback(
          &check_for_updates_error));
  EXPECT_TRUE(change_list_loader_->IsRefreshing());
  base::RunLoop().RunUntilIdle();
  EXPECT_FALSE(change_list_loader_->IsRefreshing());
  EXPECT_EQ(previous_changestamp, metadata_->GetLargestChangestamp());

  // Add a file to the service.
  scoped_ptr<google_apis::ResourceEntry> gdata_entry = AddNewFile("New File");
  ASSERT_TRUE(gdata_entry);

  // CheckForUpdates() results in update.
  TestChangeListLoaderObserver observer(change_list_loader_.get());
  change_list_loader_->CheckForUpdates(
      google_apis::test_util::CreateCopyResultCallback(
          &check_for_updates_error));
  EXPECT_TRUE(change_list_loader_->IsRefreshing());
  base::RunLoop().RunUntilIdle();
  EXPECT_FALSE(change_list_loader_->IsRefreshing());
  EXPECT_LT(previous_changestamp, metadata_->GetLargestChangestamp());
  EXPECT_EQ(1, observer.load_from_server_complete_count());
  EXPECT_EQ(1U, observer.changed_directories().count(
      util::GetDriveMyDriveRootPath()));

  // The new file is found in the local metadata.
  base::FilePath new_file_path =
      util::GetDriveMyDriveRootPath().AppendASCII(gdata_entry->title());
  ResourceEntry entry;
  EXPECT_EQ(FILE_ERROR_OK,
            metadata_->GetResourceEntryByPath(new_file_path, &entry));
}

}  // namespace internal
}  // namespace drive
<commit_msg>drive: Add test for ChangeListLoader::LoadIfNeeded with non empty DirectoryFetchInfo<commit_after>// Copyright 2013 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/drive/change_list_loader.h"

#include "base/files/scoped_temp_dir.h"
#include "base/memory/scoped_ptr.h"
#include "base/prefs/testing_pref_service.h"
#include "base/run_loop.h"
#include "chrome/browser/chromeos/drive/change_list_loader_observer.h"
#include "chrome/browser/chromeos/drive/file_cache.h"
#include "chrome/browser/chromeos/drive/file_system_util.h"
#include "chrome/browser/chromeos/drive/job_scheduler.h"
#include "chrome/browser/chromeos/drive/resource_metadata.h"
#include "chrome/browser/chromeos/drive/test_util.h"
#include "chrome/browser/drive/fake_drive_service.h"
#include "chrome/browser/google_apis/test_util.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace drive {
namespace internal {

class TestChangeListLoaderObserver : public ChangeListLoaderObserver {
 public:
  explicit TestChangeListLoaderObserver(ChangeListLoader* loader)
      : loader_(loader),
        load_from_server_complete_count_(0),
        initial_load_complete_count_(0) {
    loader_->AddObserver(this);
  }

  virtual ~TestChangeListLoaderObserver() {
    loader_->RemoveObserver(this);
  }

  const std::set<base::FilePath>& changed_directories() const {
    return changed_directories_;
  }
  int load_from_server_complete_count() const {
    return load_from_server_complete_count_;
  }
  int initial_load_complete_count() const {
    return initial_load_complete_count_;
  }

  // ChageListObserver overrides:
  virtual void OnDirectoryChanged(
      const base::FilePath& directory_path) OVERRIDE {
    changed_directories_.insert(directory_path);
  }
  virtual void OnLoadFromServerComplete() OVERRIDE {
    ++load_from_server_complete_count_;
  }
  virtual void OnInitialLoadComplete() OVERRIDE {
    ++initial_load_complete_count_;
  }

 private:
  ChangeListLoader* loader_;
  std::set<base::FilePath> changed_directories_;
  int load_from_server_complete_count_;
  int initial_load_complete_count_;

  DISALLOW_COPY_AND_ASSIGN(TestChangeListLoaderObserver);
};

class TestDriveService : public FakeDriveService {
 public:
  TestDriveService() : never_return_all_resource_list_(false),
                       blocked_call_count_(0) {}

  void set_never_return_all_resource_list(bool value) {
    never_return_all_resource_list_ = value;
  }

  int blocked_call_count() const { return blocked_call_count_; }

  // FakeDriveService override.
  virtual google_apis::CancelCallback GetAllResourceList(
      const google_apis::GetResourceListCallback& callback) OVERRIDE {
    if (never_return_all_resource_list_) {
      ++blocked_call_count_;
      return google_apis::CancelCallback();
    }
    return FakeDriveService::GetAllResourceList(callback);
  }

 private:
  // GetAllResourceList never returns result when this is set to true.
  // Used to emulate the real server's slowness.
  bool never_return_all_resource_list_;

  int blocked_call_count_;  // Number of blocked method calls.
};

class ChangeListLoaderTest : public testing::Test {
 protected:
  virtual void SetUp() OVERRIDE {
    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
    pref_service_.reset(new TestingPrefServiceSimple);
    test_util::RegisterDrivePrefs(pref_service_->registry());

    drive_service_.reset(new TestDriveService);
    ASSERT_TRUE(drive_service_->LoadResourceListForWapi(
        "gdata/root_feed.json"));
    ASSERT_TRUE(drive_service_->LoadAccountMetadataForWapi(
        "gdata/account_metadata.json"));

    scheduler_.reset(new JobScheduler(pref_service_.get(),
                                      drive_service_.get(),
                                      base::MessageLoopProxy::current().get()));
    metadata_storage_.reset(new ResourceMetadataStorage(
        temp_dir_.path(), base::MessageLoopProxy::current().get()));
    ASSERT_TRUE(metadata_storage_->Initialize());

    metadata_.reset(new ResourceMetadata(
        metadata_storage_.get(), base::MessageLoopProxy::current().get()));
    ASSERT_EQ(FILE_ERROR_OK, metadata_->Initialize());

    cache_.reset(new FileCache(metadata_storage_.get(),
                               temp_dir_.path(),
                               base::MessageLoopProxy::current().get(),
                               NULL /* free_disk_space_getter */));
    ASSERT_TRUE(cache_->Initialize());

    change_list_loader_.reset(
        new ChangeListLoader(base::MessageLoopProxy::current().get(),
                             metadata_.get(),
                             scheduler_.get()));
  }

  // Adds a new file to the root directory of the service.
  scoped_ptr<google_apis::ResourceEntry> AddNewFile(const std::string& title) {
    google_apis::GDataErrorCode error = google_apis::GDATA_FILE_ERROR;
    scoped_ptr<google_apis::ResourceEntry> entry;
    drive_service_->AddNewFile(
        "text/plain",
        "content text",
        drive_service_->GetRootResourceId(),
        title,
        false,  // shared_with_me
        google_apis::test_util::CreateCopyResultCallback(&error, &entry));
    base::RunLoop().RunUntilIdle();
    EXPECT_EQ(google_apis::HTTP_CREATED, error);
    return entry.Pass();
  }

  content::TestBrowserThreadBundle thread_bundle_;
  base::ScopedTempDir temp_dir_;
  scoped_ptr<TestingPrefServiceSimple> pref_service_;
  scoped_ptr<TestDriveService> drive_service_;
  scoped_ptr<JobScheduler> scheduler_;
  scoped_ptr<ResourceMetadataStorage,
             test_util::DestroyHelperForTests> metadata_storage_;
  scoped_ptr<ResourceMetadata, test_util::DestroyHelperForTests> metadata_;
  scoped_ptr<FileCache, test_util::DestroyHelperForTests> cache_;
  scoped_ptr<ChangeListLoader> change_list_loader_;
};

TEST_F(ChangeListLoaderTest, LoadIfNeeded) {
  EXPECT_FALSE(change_list_loader_->IsRefreshing());

  // Start initial load.
  TestChangeListLoaderObserver observer(change_list_loader_.get());

  FileError error = FILE_ERROR_FAILED;
  change_list_loader_->LoadIfNeeded(
      DirectoryFetchInfo(),
      google_apis::test_util::CreateCopyResultCallback(&error));
  EXPECT_TRUE(change_list_loader_->IsRefreshing());
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(FILE_ERROR_OK, error);

  EXPECT_FALSE(change_list_loader_->IsRefreshing());
  EXPECT_LT(0, metadata_->GetLargestChangestamp());
  EXPECT_EQ(1, drive_service_->resource_list_load_count());
  EXPECT_EQ(1, observer.initial_load_complete_count());
  EXPECT_EQ(1, observer.load_from_server_complete_count());
  EXPECT_TRUE(observer.changed_directories().empty());

  base::FilePath file_path =
      util::GetDriveMyDriveRootPath().AppendASCII("File 1.txt");
  ResourceEntry entry;
  EXPECT_EQ(FILE_ERROR_OK,
            metadata_->GetResourceEntryByPath(file_path, &entry));

  // Reload. This should result in no-op.
  int64 previous_changestamp = metadata_->GetLargestChangestamp();
  int previous_resource_list_load_count =
      drive_service_->resource_list_load_count();
  change_list_loader_->LoadIfNeeded(
      DirectoryFetchInfo(),
      google_apis::test_util::CreateCopyResultCallback(&error));
  EXPECT_FALSE(change_list_loader_->IsRefreshing());
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(FILE_ERROR_OK, error);

  EXPECT_FALSE(change_list_loader_->IsRefreshing());
  EXPECT_EQ(previous_changestamp, metadata_->GetLargestChangestamp());
  EXPECT_EQ(previous_resource_list_load_count,
            drive_service_->resource_list_load_count());
}

TEST_F(ChangeListLoaderTest, LoadIfNeeded_LocalMetadataAvailable) {
  // Prepare metadata.
  FileError error = FILE_ERROR_FAILED;
  change_list_loader_->LoadIfNeeded(
      DirectoryFetchInfo(),
      google_apis::test_util::CreateCopyResultCallback(&error));
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(FILE_ERROR_OK, error);

  // Reset loader.
  change_list_loader_.reset(
      new ChangeListLoader(base::MessageLoopProxy::current().get(),
                           metadata_.get(),
                           scheduler_.get()));

  // Add a file to the service.
  scoped_ptr<google_apis::ResourceEntry> gdata_entry = AddNewFile("New File");
  ASSERT_TRUE(gdata_entry);

  // Start loading. Because local metadata is available, the load results in
  // returning FILE_ERROR_OK without fetching full list of resources.
  const int previous_resource_list_load_count =
      drive_service_->resource_list_load_count();
  TestChangeListLoaderObserver observer(change_list_loader_.get());

  change_list_loader_->LoadIfNeeded(
      DirectoryFetchInfo(),
      google_apis::test_util::CreateCopyResultCallback(&error));
  EXPECT_TRUE(change_list_loader_->IsRefreshing());
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(FILE_ERROR_OK, error);
  EXPECT_EQ(previous_resource_list_load_count,
            drive_service_->resource_list_load_count());
  EXPECT_EQ(1, observer.initial_load_complete_count());

  // Update should be checked by LoadIfNeeded().
  EXPECT_EQ(drive_service_->largest_changestamp(),
            metadata_->GetLargestChangestamp());
  EXPECT_EQ(1, drive_service_->change_list_load_count());
  EXPECT_EQ(1, observer.load_from_server_complete_count());
  EXPECT_EQ(1U, observer.changed_directories().count(
      util::GetDriveMyDriveRootPath()));

  base::FilePath file_path =
      util::GetDriveMyDriveRootPath().AppendASCII(gdata_entry->title());
  ResourceEntry entry;
  EXPECT_EQ(FILE_ERROR_OK,
            metadata_->GetResourceEntryByPath(file_path, &entry));
}

TEST_F(ChangeListLoaderTest, LoadIfNeeded_MyDrive) {
  // Emulate the slowness of GetAllResourceList().
  drive_service_->set_never_return_all_resource_list(true);

  // Load grand root.
  FileError error = FILE_ERROR_FAILED;
  change_list_loader_->LoadIfNeeded(
      DirectoryFetchInfo(util::kDriveGrandRootSpecialResourceId, 0),
      google_apis::test_util::CreateCopyResultCallback(&error));
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(FILE_ERROR_OK, error);

  // GetAllResourceList() was called.
  EXPECT_EQ(1, drive_service_->blocked_call_count());

  // My Drive is present in the local metadata, but its child is not.
  ResourceEntry entry;
  EXPECT_EQ(FILE_ERROR_OK,
            metadata_->GetResourceEntryByPath(util::GetDriveMyDriveRootPath(),
                                              &entry));
  const int64 mydrive_changestamp =
      entry.directory_specific_info().changestamp();

  base::FilePath file_path =
      util::GetDriveMyDriveRootPath().AppendASCII("File 1.txt");
  EXPECT_EQ(FILE_ERROR_NOT_FOUND,
            metadata_->GetResourceEntryByPath(file_path, &entry));

  // Load My Drive.
  change_list_loader_->LoadIfNeeded(
      DirectoryFetchInfo(drive_service_->GetRootResourceId(),
                         mydrive_changestamp),
      google_apis::test_util::CreateCopyResultCallback(&error));
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(FILE_ERROR_OK, error);

  // Now the file is present.
  EXPECT_EQ(FILE_ERROR_OK,
            metadata_->GetResourceEntryByPath(file_path, &entry));
}

TEST_F(ChangeListLoaderTest, LoadIfNeeded_NewDirectories) {
  // Make local metadata up to date.
  FileError error = FILE_ERROR_FAILED;
  change_list_loader_->LoadIfNeeded(
      DirectoryFetchInfo(),
      google_apis::test_util::CreateCopyResultCallback(&error));
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(FILE_ERROR_OK, error);

  // Add a new file.
  scoped_ptr<google_apis::ResourceEntry> file = AddNewFile("New File");
  ASSERT_TRUE(file);

  // Emulate the slowness of GetAllResourceList().
  drive_service_->set_never_return_all_resource_list(true);

  // Enter refreshing state.
  FileError check_for_updates_error = FILE_ERROR_FAILED;
  change_list_loader_->CheckForUpdates(
      google_apis::test_util::CreateCopyResultCallback(
          &check_for_updates_error));
  EXPECT_TRUE(change_list_loader_->IsRefreshing());

  // Load My Drive.
  change_list_loader_->LoadIfNeeded(
      DirectoryFetchInfo(drive_service_->GetRootResourceId(),
                         metadata_->GetLargestChangestamp()),
      google_apis::test_util::CreateCopyResultCallback(&error));
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(FILE_ERROR_OK, error);

  // The new file is present in the local metadata.
  base::FilePath file_path =
      util::GetDriveMyDriveRootPath().AppendASCII(file->title());
  ResourceEntry entry;
  EXPECT_EQ(FILE_ERROR_OK,
            metadata_->GetResourceEntryByPath(file_path, &entry));
}

TEST_F(ChangeListLoaderTest, CheckForUpdates) {
  // CheckForUpdates() results in no-op before load.
  FileError check_for_updates_error = FILE_ERROR_FAILED;
  change_list_loader_->CheckForUpdates(
      google_apis::test_util::CreateCopyResultCallback(
          &check_for_updates_error));
  EXPECT_FALSE(change_list_loader_->IsRefreshing());
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(FILE_ERROR_FAILED,
            check_for_updates_error);  // Callback was not run.
  EXPECT_EQ(0, metadata_->GetLargestChangestamp());
  EXPECT_EQ(0, drive_service_->resource_list_load_count());

  // Start initial load.
  FileError load_error = FILE_ERROR_FAILED;
  change_list_loader_->LoadIfNeeded(
      DirectoryFetchInfo(),
      google_apis::test_util::CreateCopyResultCallback(&load_error));
  EXPECT_TRUE(change_list_loader_->IsRefreshing());

  // CheckForUpdates() while loading.
  change_list_loader_->CheckForUpdates(
      google_apis::test_util::CreateCopyResultCallback(
          &check_for_updates_error));

  base::RunLoop().RunUntilIdle();
  EXPECT_FALSE(change_list_loader_->IsRefreshing());
  EXPECT_EQ(FILE_ERROR_OK, load_error);
  EXPECT_EQ(FILE_ERROR_OK, check_for_updates_error);
  EXPECT_LT(0, metadata_->GetLargestChangestamp());
  EXPECT_EQ(1, drive_service_->resource_list_load_count());

  int64 previous_changestamp = metadata_->GetLargestChangestamp();
  // CheckForUpdates() results in no update.
  change_list_loader_->CheckForUpdates(
      google_apis::test_util::CreateCopyResultCallback(
          &check_for_updates_error));
  EXPECT_TRUE(change_list_loader_->IsRefreshing());
  base::RunLoop().RunUntilIdle();
  EXPECT_FALSE(change_list_loader_->IsRefreshing());
  EXPECT_EQ(previous_changestamp, metadata_->GetLargestChangestamp());

  // Add a file to the service.
  scoped_ptr<google_apis::ResourceEntry> gdata_entry = AddNewFile("New File");
  ASSERT_TRUE(gdata_entry);

  // CheckForUpdates() results in update.
  TestChangeListLoaderObserver observer(change_list_loader_.get());
  change_list_loader_->CheckForUpdates(
      google_apis::test_util::CreateCopyResultCallback(
          &check_for_updates_error));
  EXPECT_TRUE(change_list_loader_->IsRefreshing());
  base::RunLoop().RunUntilIdle();
  EXPECT_FALSE(change_list_loader_->IsRefreshing());
  EXPECT_LT(previous_changestamp, metadata_->GetLargestChangestamp());
  EXPECT_EQ(1, observer.load_from_server_complete_count());
  EXPECT_EQ(1U, observer.changed_directories().count(
      util::GetDriveMyDriveRootPath()));

  // The new file is found in the local metadata.
  base::FilePath new_file_path =
      util::GetDriveMyDriveRootPath().AppendASCII(gdata_entry->title());
  ResourceEntry entry;
  EXPECT_EQ(FILE_ERROR_OK,
            metadata_->GetResourceEntryByPath(new_file_path, &entry));
}

}  // namespace internal
}  // namespace drive
<|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/app/chrome_command_ids.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_webnavigation_api.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/render_view_context_menu.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/browser/renderer_host/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/context_menu_params.h"
#include "net/base/mock_host_resolver.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebContextMenuData.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h"

using content::WebContents;

namespace {

class TestRenderViewContextMenu : public RenderViewContextMenu {
 public:
  TestRenderViewContextMenu(WebContents* web_contents,
                            const content::ContextMenuParams& params)
      : RenderViewContextMenu(web_contents, params) {
  }
  virtual ~TestRenderViewContextMenu() {}

 private:
  virtual void PlatformInit() {}
  virtual bool GetAcceleratorForCommandId(int, ui::Accelerator*) {
    return false;
  }

  DISALLOW_COPY_AND_ASSIGN(TestRenderViewContextMenu);
};

}  // namespace

IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WebNavigation) {
  FrameNavigationState::set_allow_extension_scheme(true);

  CommandLine::ForCurrentProcess()->AppendSwitch(
      switches::kAllowLegacyExtensionManifests);

  ASSERT_TRUE(
      RunExtensionSubtest("webnavigation", "test_api.html")) << message_;
}

IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WebNavigationGetFrame) {
  FrameNavigationState::set_allow_extension_scheme(true);

  CommandLine::ForCurrentProcess()->AppendSwitch(
      switches::kAllowLegacyExtensionManifests);

  ASSERT_TRUE(
      RunExtensionSubtest("webnavigation", "test_getFrame.html")) << message_;
}

IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WebNavigationClientRedirect) {
  FrameNavigationState::set_allow_extension_scheme(true);

  CommandLine::ForCurrentProcess()->AppendSwitch(
      switches::kAllowLegacyExtensionManifests);

  ASSERT_TRUE(
      RunExtensionSubtest("webnavigation", "test_clientRedirect.html"))
          << message_;
}

IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WebNavigationServerRedirect) {
  FrameNavigationState::set_allow_extension_scheme(true);
  host_resolver()->AddRule("*", "127.0.0.1");
  ASSERT_TRUE(StartTestServer());

  CommandLine::ForCurrentProcess()->AppendSwitch(
      switches::kAllowLegacyExtensionManifests);

  ASSERT_TRUE(
      RunExtensionSubtest("webnavigation", "test_serverRedirect.html"))
          << message_;
}

IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WebNavigationForwardBack) {
  FrameNavigationState::set_allow_extension_scheme(true);

  CommandLine::ForCurrentProcess()->AppendSwitch(
      switches::kAllowLegacyExtensionManifests);

  ASSERT_TRUE(
      RunExtensionSubtest("webnavigation", "test_forwardBack.html"))
          << message_;
}

IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WebNavigationIFrame) {
  FrameNavigationState::set_allow_extension_scheme(true);

  CommandLine::ForCurrentProcess()->AppendSwitch(
      switches::kAllowLegacyExtensionManifests);

  ASSERT_TRUE(
      RunExtensionSubtest("webnavigation", "test_iframe.html")) << message_;
}

IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WebNavigationOpenTab) {
  FrameNavigationState::set_allow_extension_scheme(true);

  CommandLine::ForCurrentProcess()->AppendSwitch(
      switches::kAllowLegacyExtensionManifests);

  ASSERT_TRUE(
      RunExtensionSubtest("webnavigation", "test_openTab.html")) << message_;
}

IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WebNavigationReferenceFragment) {
  FrameNavigationState::set_allow_extension_scheme(true);

  CommandLine::ForCurrentProcess()->AppendSwitch(
      switches::kAllowLegacyExtensionManifests);

  ASSERT_TRUE(
      RunExtensionSubtest("webnavigation", "test_referenceFragment.html"))
          << message_;
}

IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WebNavigationSimpleLoad) {
  FrameNavigationState::set_allow_extension_scheme(true);

  CommandLine::ForCurrentProcess()->AppendSwitch(
      switches::kAllowLegacyExtensionManifests);

  ASSERT_TRUE(
      RunExtensionSubtest("webnavigation", "test_simpleLoad.html")) << message_;
}

IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WebNavigationFailures) {
  FrameNavigationState::set_allow_extension_scheme(true);

  CommandLine::ForCurrentProcess()->AppendSwitch(
      switches::kAllowLegacyExtensionManifests);

  ASSERT_TRUE(
      RunExtensionSubtest("webnavigation", "test_failures.html")) << message_;
}

IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WebNavigationUserAction) {
  FrameNavigationState::set_allow_extension_scheme(true);

  CommandLine::ForCurrentProcess()->AppendSwitch(
      switches::kAllowLegacyExtensionManifests);

  // Wait for the extension to set itself up and return control to us.
  ASSERT_TRUE(
      RunExtensionSubtest("webnavigation", "test_userAction.html")) << message_;

  WebContents* tab = browser()->GetSelectedWebContents();
  ui_test_utils::WaitForLoadStop(tab);

  ResultCatcher catcher;

  ExtensionService* service = browser()->profile()->GetExtensionService();
  const Extension* extension =
      service->GetExtensionById(last_loaded_extension_id_, false);
  GURL url = extension->GetResourceURL("userAction/a.html");

  ui_test_utils::NavigateToURL(browser(), url);

  // This corresponds to "Open link in new tab".
  content::ContextMenuParams params;
  params.is_editable = false;
  params.media_type = WebKit::WebContextMenuData::MediaTypeNone;
  params.page_url = url;
  params.frame_id =
      ExtensionWebNavigationTabObserver::Get(tab)->
          frame_navigation_state().GetMainFrameID();
  params.link_url = extension->GetResourceURL("userAction/b.html");

  TestRenderViewContextMenu menu(tab, params);
  menu.Init();
  menu.ExecuteCommand(IDC_CONTENT_CONTEXT_OPENLINKNEWTAB);

  ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
}

IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WebNavigationRequestOpenTab) {
  FrameNavigationState::set_allow_extension_scheme(true);

  CommandLine::ForCurrentProcess()->AppendSwitch(
      switches::kAllowLegacyExtensionManifests);

  // Wait for the extension to set itself up and return control to us.
  ASSERT_TRUE(RunExtensionSubtest("webnavigation", "test_requestOpenTab.html"))
      << message_;

  WebContents* tab = browser()->GetSelectedWebContents();
  ui_test_utils::WaitForLoadStop(tab);

  ResultCatcher catcher;

  ExtensionService* service = browser()->profile()->GetExtensionService();
  const Extension* extension =
      service->GetExtensionById(last_loaded_extension_id_, false);
  GURL url = extension->GetResourceURL("requestOpenTab/a.html");

  ui_test_utils::NavigateToURL(browser(), url);

  // There's a link on a.html. Middle-click on it to open it in a new tab.
  WebKit::WebMouseEvent mouse_event;
  mouse_event.type = WebKit::WebInputEvent::MouseDown;
  mouse_event.button = WebKit::WebMouseEvent::ButtonMiddle;
  mouse_event.x = 7;
  mouse_event.y = 7;
  mouse_event.clickCount = 1;
  tab->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
  mouse_event.type = WebKit::WebInputEvent::MouseUp;
  tab->GetRenderViewHost()->ForwardMouseEvent(mouse_event);

  ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
}

IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WebNavigationTargetBlank) {
  FrameNavigationState::set_allow_extension_scheme(true);
  ASSERT_TRUE(StartTestServer());

  CommandLine::ForCurrentProcess()->AppendSwitch(
      switches::kAllowLegacyExtensionManifests);

  // Wait for the extension to set itself up and return control to us.
  ASSERT_TRUE(RunExtensionSubtest("webnavigation", "test_targetBlank.html"))
      << message_;

  WebContents* tab = browser()->GetSelectedWebContents();
  ui_test_utils::WaitForLoadStop(tab);

  ResultCatcher catcher;

  GURL url = test_server()->GetURL(
      "files/extensions/api_test/webnavigation/targetBlank/a.html");

  browser::NavigateParams params(browser(), url, content::PAGE_TRANSITION_LINK);
  ui_test_utils::NavigateToURL(&params);

  // There's a link with target=_blank on a.html. Click on it to open it in a
  // new tab.
  WebKit::WebMouseEvent mouse_event;
  mouse_event.type = WebKit::WebInputEvent::MouseDown;
  mouse_event.button = WebKit::WebMouseEvent::ButtonLeft;
  mouse_event.x = 7;
  mouse_event.y = 7;
  mouse_event.clickCount = 1;
  tab->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
  mouse_event.type = WebKit::WebInputEvent::MouseUp;
  tab->GetRenderViewHost()->ForwardMouseEvent(mouse_event);

  ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
}

IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WebNavigationTargetBlankIncognito) {
  FrameNavigationState::set_allow_extension_scheme(true);
  ASSERT_TRUE(StartTestServer());

  CommandLine::ForCurrentProcess()->AppendSwitch(
      switches::kAllowLegacyExtensionManifests);

  // Wait for the extension to set itself up and return control to us.
  ASSERT_TRUE(RunExtensionSubtestIncognito(
      "webnavigation", "test_targetBlank.html")) << message_;

  ResultCatcher catcher;

  GURL url = test_server()->GetURL(
      "files/extensions/api_test/webnavigation/targetBlank/a.html");

  ui_test_utils::OpenURLOffTheRecord(browser()->profile(), url);
  WebContents* tab = BrowserList::FindTabbedBrowser(
      browser()->profile()->GetOffTheRecordProfile(), false)->
          GetSelectedWebContents();

  // There's a link with target=_blank on a.html. Click on it to open it in a
  // new tab.
  WebKit::WebMouseEvent mouse_event;
  mouse_event.type = WebKit::WebInputEvent::MouseDown;
  mouse_event.button = WebKit::WebMouseEvent::ButtonLeft;
  mouse_event.x = 7;
  mouse_event.y = 7;
  mouse_event.clickCount = 1;
  tab->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
  mouse_event.type = WebKit::WebInputEvent::MouseUp;
  tab->GetRenderViewHost()->ForwardMouseEvent(mouse_event);

  ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
}
<commit_msg>Marks a test as flaky.<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/app/chrome_command_ids.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_webnavigation_api.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/render_view_context_menu.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/browser/renderer_host/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/context_menu_params.h"
#include "net/base/mock_host_resolver.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebContextMenuData.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h"

using content::WebContents;

namespace {

class TestRenderViewContextMenu : public RenderViewContextMenu {
 public:
  TestRenderViewContextMenu(WebContents* web_contents,
                            const content::ContextMenuParams& params)
      : RenderViewContextMenu(web_contents, params) {
  }
  virtual ~TestRenderViewContextMenu() {}

 private:
  virtual void PlatformInit() {}
  virtual bool GetAcceleratorForCommandId(int, ui::Accelerator*) {
    return false;
  }

  DISALLOW_COPY_AND_ASSIGN(TestRenderViewContextMenu);
};

}  // namespace

IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WebNavigation) {
  FrameNavigationState::set_allow_extension_scheme(true);

  CommandLine::ForCurrentProcess()->AppendSwitch(
      switches::kAllowLegacyExtensionManifests);

  ASSERT_TRUE(
      RunExtensionSubtest("webnavigation", "test_api.html")) << message_;
}

IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WebNavigationGetFrame) {
  FrameNavigationState::set_allow_extension_scheme(true);

  CommandLine::ForCurrentProcess()->AppendSwitch(
      switches::kAllowLegacyExtensionManifests);

  ASSERT_TRUE(
      RunExtensionSubtest("webnavigation", "test_getFrame.html")) << message_;
}

IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WebNavigationClientRedirect) {
  FrameNavigationState::set_allow_extension_scheme(true);

  CommandLine::ForCurrentProcess()->AppendSwitch(
      switches::kAllowLegacyExtensionManifests);

  ASSERT_TRUE(
      RunExtensionSubtest("webnavigation", "test_clientRedirect.html"))
          << message_;
}

IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WebNavigationServerRedirect) {
  FrameNavigationState::set_allow_extension_scheme(true);
  host_resolver()->AddRule("*", "127.0.0.1");
  ASSERT_TRUE(StartTestServer());

  CommandLine::ForCurrentProcess()->AppendSwitch(
      switches::kAllowLegacyExtensionManifests);

  ASSERT_TRUE(
      RunExtensionSubtest("webnavigation", "test_serverRedirect.html"))
          << message_;
}

IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WebNavigationForwardBack) {
  FrameNavigationState::set_allow_extension_scheme(true);

  CommandLine::ForCurrentProcess()->AppendSwitch(
      switches::kAllowLegacyExtensionManifests);

  ASSERT_TRUE(
      RunExtensionSubtest("webnavigation", "test_forwardBack.html"))
          << message_;
}

IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WebNavigationIFrame) {
  FrameNavigationState::set_allow_extension_scheme(true);

  CommandLine::ForCurrentProcess()->AppendSwitch(
      switches::kAllowLegacyExtensionManifests);

  ASSERT_TRUE(
      RunExtensionSubtest("webnavigation", "test_iframe.html")) << message_;
}

IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WebNavigationOpenTab) {
  FrameNavigationState::set_allow_extension_scheme(true);

  CommandLine::ForCurrentProcess()->AppendSwitch(
      switches::kAllowLegacyExtensionManifests);

  ASSERT_TRUE(
      RunExtensionSubtest("webnavigation", "test_openTab.html")) << message_;
}

// This test has been timing out: 114208.
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, FLAKY_WebNavigationReferenceFragment) {
  FrameNavigationState::set_allow_extension_scheme(true);

  CommandLine::ForCurrentProcess()->AppendSwitch(
      switches::kAllowLegacyExtensionManifests);

  ASSERT_TRUE(
      RunExtensionSubtest("webnavigation", "test_referenceFragment.html"))
          << message_;
}

IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WebNavigationSimpleLoad) {
  FrameNavigationState::set_allow_extension_scheme(true);

  CommandLine::ForCurrentProcess()->AppendSwitch(
      switches::kAllowLegacyExtensionManifests);

  ASSERT_TRUE(
      RunExtensionSubtest("webnavigation", "test_simpleLoad.html")) << message_;
}

IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WebNavigationFailures) {
  FrameNavigationState::set_allow_extension_scheme(true);

  CommandLine::ForCurrentProcess()->AppendSwitch(
      switches::kAllowLegacyExtensionManifests);

  ASSERT_TRUE(
      RunExtensionSubtest("webnavigation", "test_failures.html")) << message_;
}

IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WebNavigationUserAction) {
  FrameNavigationState::set_allow_extension_scheme(true);

  CommandLine::ForCurrentProcess()->AppendSwitch(
      switches::kAllowLegacyExtensionManifests);

  // Wait for the extension to set itself up and return control to us.
  ASSERT_TRUE(
      RunExtensionSubtest("webnavigation", "test_userAction.html")) << message_;

  WebContents* tab = browser()->GetSelectedWebContents();
  ui_test_utils::WaitForLoadStop(tab);

  ResultCatcher catcher;

  ExtensionService* service = browser()->profile()->GetExtensionService();
  const Extension* extension =
      service->GetExtensionById(last_loaded_extension_id_, false);
  GURL url = extension->GetResourceURL("userAction/a.html");

  ui_test_utils::NavigateToURL(browser(), url);

  // This corresponds to "Open link in new tab".
  content::ContextMenuParams params;
  params.is_editable = false;
  params.media_type = WebKit::WebContextMenuData::MediaTypeNone;
  params.page_url = url;
  params.frame_id =
      ExtensionWebNavigationTabObserver::Get(tab)->
          frame_navigation_state().GetMainFrameID();
  params.link_url = extension->GetResourceURL("userAction/b.html");

  TestRenderViewContextMenu menu(tab, params);
  menu.Init();
  menu.ExecuteCommand(IDC_CONTENT_CONTEXT_OPENLINKNEWTAB);

  ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
}

IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WebNavigationRequestOpenTab) {
  FrameNavigationState::set_allow_extension_scheme(true);

  CommandLine::ForCurrentProcess()->AppendSwitch(
      switches::kAllowLegacyExtensionManifests);

  // Wait for the extension to set itself up and return control to us.
  ASSERT_TRUE(RunExtensionSubtest("webnavigation", "test_requestOpenTab.html"))
      << message_;

  WebContents* tab = browser()->GetSelectedWebContents();
  ui_test_utils::WaitForLoadStop(tab);

  ResultCatcher catcher;

  ExtensionService* service = browser()->profile()->GetExtensionService();
  const Extension* extension =
      service->GetExtensionById(last_loaded_extension_id_, false);
  GURL url = extension->GetResourceURL("requestOpenTab/a.html");

  ui_test_utils::NavigateToURL(browser(), url);

  // There's a link on a.html. Middle-click on it to open it in a new tab.
  WebKit::WebMouseEvent mouse_event;
  mouse_event.type = WebKit::WebInputEvent::MouseDown;
  mouse_event.button = WebKit::WebMouseEvent::ButtonMiddle;
  mouse_event.x = 7;
  mouse_event.y = 7;
  mouse_event.clickCount = 1;
  tab->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
  mouse_event.type = WebKit::WebInputEvent::MouseUp;
  tab->GetRenderViewHost()->ForwardMouseEvent(mouse_event);

  ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
}

IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WebNavigationTargetBlank) {
  FrameNavigationState::set_allow_extension_scheme(true);
  ASSERT_TRUE(StartTestServer());

  CommandLine::ForCurrentProcess()->AppendSwitch(
      switches::kAllowLegacyExtensionManifests);

  // Wait for the extension to set itself up and return control to us.
  ASSERT_TRUE(RunExtensionSubtest("webnavigation", "test_targetBlank.html"))
      << message_;

  WebContents* tab = browser()->GetSelectedWebContents();
  ui_test_utils::WaitForLoadStop(tab);

  ResultCatcher catcher;

  GURL url = test_server()->GetURL(
      "files/extensions/api_test/webnavigation/targetBlank/a.html");

  browser::NavigateParams params(browser(), url, content::PAGE_TRANSITION_LINK);
  ui_test_utils::NavigateToURL(&params);

  // There's a link with target=_blank on a.html. Click on it to open it in a
  // new tab.
  WebKit::WebMouseEvent mouse_event;
  mouse_event.type = WebKit::WebInputEvent::MouseDown;
  mouse_event.button = WebKit::WebMouseEvent::ButtonLeft;
  mouse_event.x = 7;
  mouse_event.y = 7;
  mouse_event.clickCount = 1;
  tab->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
  mouse_event.type = WebKit::WebInputEvent::MouseUp;
  tab->GetRenderViewHost()->ForwardMouseEvent(mouse_event);

  ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
}

IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WebNavigationTargetBlankIncognito) {
  FrameNavigationState::set_allow_extension_scheme(true);
  ASSERT_TRUE(StartTestServer());

  CommandLine::ForCurrentProcess()->AppendSwitch(
      switches::kAllowLegacyExtensionManifests);

  // Wait for the extension to set itself up and return control to us.
  ASSERT_TRUE(RunExtensionSubtestIncognito(
      "webnavigation", "test_targetBlank.html")) << message_;

  ResultCatcher catcher;

  GURL url = test_server()->GetURL(
      "files/extensions/api_test/webnavigation/targetBlank/a.html");

  ui_test_utils::OpenURLOffTheRecord(browser()->profile(), url);
  WebContents* tab = BrowserList::FindTabbedBrowser(
      browser()->profile()->GetOffTheRecordProfile(), false)->
          GetSelectedWebContents();

  // There's a link with target=_blank on a.html. Click on it to open it in a
  // new tab.
  WebKit::WebMouseEvent mouse_event;
  mouse_event.type = WebKit::WebInputEvent::MouseDown;
  mouse_event.button = WebKit::WebMouseEvent::ButtonLeft;
  mouse_event.x = 7;
  mouse_event.y = 7;
  mouse_event.clickCount = 1;
  tab->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
  mouse_event.type = WebKit::WebInputEvent::MouseUp;
  tab->GetRenderViewHost()->ForwardMouseEvent(mouse_event);

  ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
}
<|endoftext|>


<commit_before>
#include "Globals.h"  // NOTE: MSVC stupidness requires this to be the same across all modules

#include "BeaconEntity.h"
#include "../BlockArea.h"
#include "../Entities/Player.h"
#include "../UI/BeaconWindow.h"
#include "../ClientHandle.h"

cBeaconEntity::cBeaconEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World):
	Super(a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, 1, 1, a_World),
	m_IsActive(false),
	m_BeaconLevel(0),
	m_PrimaryEffect(cEntityEffect::effNoEffect),
	m_SecondaryEffect(cEntityEffect::effNoEffect)
{
	ASSERT(a_BlockType == E_BLOCK_BEACON);
	if (m_World != nullptr)
	{
		UpdateBeacon();
	}
}

char cBeaconEntity::CalculatePyramidLevel(void)
{
	cBlockArea Area;
	int MinY = std::max(GetPosY() - 4, 0);
	int MaxY = std::max(GetPosY() - 1, 0);

	Area.Read(
		*m_World,
		GetPosX() - 4, GetPosX() + 4,
		MinY, MaxY,
		GetPosZ() - 4, GetPosZ() + 4,
		cBlockArea::baTypes
	);

	int Layer = 1;
	int MiddleXZ = 4;

	for (int Y = (Area.GetSizeY() - 1); Y >= 0; Y--)
	{
		for (int X = MiddleXZ - Layer; X <= (MiddleXZ + Layer); X++)
		{
			for (int Z = MiddleXZ - Layer; Z <= (MiddleXZ + Layer); Z++)
			{
				if (!IsMineralBlock(Area.GetRelBlockType(X, Y, Z)))
				{
					return static_cast<char>(Layer - 1);
				}
			}
		}
		Layer++;
	}

	return static_cast<char>(Layer - 1);
}

bool cBeaconEntity::IsValidEffect(cEntityEffect::eType a_Effect, char a_BeaconLevel)
{
	switch (a_Effect)
	{
		case cEntityEffect::effRegeneration: return (a_BeaconLevel >= 4);
		case cEntityEffect::effStrength:     return (a_BeaconLevel >= 3);
		case cEntityEffect::effResistance:   return (a_BeaconLevel >= 2);
		case cEntityEffect::effJumpBoost:    return (a_BeaconLevel >= 2);
		case cEntityEffect::effSpeed:        return (a_BeaconLevel >= 1);
		case cEntityEffect::effHaste:        return (a_BeaconLevel >= 1);
		case cEntityEffect::effNoEffect:     return true;

		default:
		{
			LOGD("%s: Invalid beacon effect: %d", __FUNCTION__, static_cast<int>(a_Effect));
			return false;
		}
	}
}

bool cBeaconEntity::SetPrimaryEffect(cEntityEffect::eType a_Effect)
{
	if (!IsValidEffect(a_Effect, m_BeaconLevel))
	{
		m_PrimaryEffect = cEntityEffect::effNoEffect;
		return false;
	}

	m_PrimaryEffect = a_Effect;

	// Send window update:
	if (GetWindow() != nullptr)
	{
		GetWindow()->SetProperty(1, m_PrimaryEffect);
	}
	return true;
}

bool cBeaconEntity::SetSecondaryEffect(cEntityEffect::eType a_Effect)
{
	if (!IsValidEffect(a_Effect, m_BeaconLevel))
	{
		m_SecondaryEffect = cEntityEffect::effNoEffect;
		return false;
	}

	m_SecondaryEffect = a_Effect;

	// Send window update:
	if (GetWindow() != nullptr)
	{
		GetWindow()->SetProperty(2, m_SecondaryEffect);
	}
	return true;
}

bool cBeaconEntity::IsBeaconBlocked(void)
{
	for (int Y = m_PosY; Y < cChunkDef::Height; ++Y)
	{
		BLOCKTYPE Block = m_World->GetBlock(m_PosX, Y, m_PosZ);
		if (!cBlockInfo::IsTransparent(Block))
		{
			return true;
		}
	}
	return false;
}

bool cBeaconEntity::IsMineralBlock(BLOCKTYPE a_BlockType)
{
	switch (a_BlockType)
	{
		case E_BLOCK_DIAMOND_BLOCK:
		case E_BLOCK_GOLD_BLOCK:
		case E_BLOCK_IRON_BLOCK:
		case E_BLOCK_EMERALD_BLOCK:
		{
			return true;
		}
	}
	return false;
}

void cBeaconEntity::UpdateBeacon(void)
{
	int OldBeaconLevel = m_BeaconLevel;

	if (IsBeaconBlocked())
	{
		m_IsActive = false;
		m_BeaconLevel = 0;
	}
	else
	{
		m_BeaconLevel = CalculatePyramidLevel();
		m_IsActive = (m_BeaconLevel > 0);
	}

	if (m_BeaconLevel != OldBeaconLevel)
	{
		// Send window update:
		if (GetWindow() != nullptr)
		{
			GetWindow()->SetProperty(0, m_BeaconLevel);
		}
	}

	// TODO: Add achievement
}

void cBeaconEntity::GiveEffects(void)
{
	if (!m_IsActive || (m_BeaconLevel < 0))
	{
		return;
	}

	int Radius = m_BeaconLevel * 10 + 10;
	short EffectLevel = 0;
	if ((m_BeaconLevel >= 4) && (m_PrimaryEffect == m_SecondaryEffect))
	{
		EffectLevel = 1;
	}

	cEntityEffect::eType SecondaryEffect = cEntityEffect::effNoEffect;
	if ((m_BeaconLevel >= 4) && (m_PrimaryEffect != m_SecondaryEffect) && (m_SecondaryEffect > 0))
	{
		SecondaryEffect = m_SecondaryEffect;
	}

	class cPlayerCallback : public cPlayerListCallback
	{
		int m_Radius;
		int m_PosX, m_PosY, m_PosZ;
		cEntityEffect::eType m_PrimaryEffect, m_SecondaryEffect;
		short m_EffectLevel;

		virtual bool Item(cPlayer * a_Player)
		{
			Vector3d PlayerPosition = Vector3d(a_Player->GetPosition());
			if (PlayerPosition.y > static_cast<double>(m_PosY))
			{
				PlayerPosition.y = static_cast<double>(m_PosY);
			}

			// TODO: Vanilla minecraft uses an AABB check instead of a radius one
			Vector3d BeaconPosition = Vector3d(m_PosX, m_PosY, m_PosZ);
			if ((PlayerPosition - BeaconPosition).Length() <= m_Radius)
			{
				a_Player->AddEntityEffect(m_PrimaryEffect, 180, m_EffectLevel);

				if (m_SecondaryEffect != cEntityEffect::effNoEffect)
				{
					a_Player->AddEntityEffect(m_SecondaryEffect, 180, 0);
				}
			}
			return false;
		}

	public:
		cPlayerCallback(int a_Radius, int a_PosX, int a_PosY, int a_PosZ, cEntityEffect::eType a_PrimaryEffect, cEntityEffect::eType a_SecondaryEffect, short a_EffectLevel):
			m_Radius(a_Radius),
			m_PosX(a_PosX),
			m_PosY(a_PosY),
			m_PosZ(a_PosZ),
			m_PrimaryEffect(a_PrimaryEffect),
			m_SecondaryEffect(a_SecondaryEffect),
			m_EffectLevel(a_EffectLevel)
		{
		}

	} PlayerCallback(Radius, m_PosX, m_PosY, m_PosZ, m_PrimaryEffect, SecondaryEffect, EffectLevel);
	GetWorld()->ForEachPlayer(PlayerCallback);
}

void cBeaconEntity::CopyFrom(const cBlockEntity & a_Src)
{
	Super::CopyFrom(a_Src);
	auto & src = reinterpret_cast<const cBeaconEntity &>(a_Src);
	m_BeaconLevel = src.m_BeaconLevel;
	m_Contents.CopyFrom(src.m_Contents);
	m_IsActive = src.m_IsActive;
	m_PrimaryEffect = src.m_PrimaryEffect;
	m_SecondaryEffect = src.m_SecondaryEffect;
}

void cBeaconEntity::SendTo(cClientHandle & a_Client)
{
	a_Client.SendUpdateBlockEntity(*this);
}

bool cBeaconEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
	// Update the beacon every 4 seconds
	if ((GetWorld()->GetWorldAge() % 80) == 0)
	{
		UpdateBeacon();
		GiveEffects();
	}
	return false;
}

bool cBeaconEntity::UsedBy(cPlayer * a_Player)
{
	cWindow * Window = GetWindow();
	if (Window == nullptr)
	{
		OpenWindow(new cBeaconWindow(m_PosX, m_PosY, m_PosZ, this));
		Window = GetWindow();
	}

	if (Window != nullptr)
	{
		// if (a_Player->GetWindow() != Window)
		// -> Because mojang doesn't send a 'close window' packet when you click the cancel button in the beacon inventory ...
		{
			a_Player->OpenWindow(*Window);
		}
	}
	return true;
}

<commit_msg>Award player an achievement when creating a beacon (#3930)<commit_after>
#include "Globals.h"  // NOTE: MSVC stupidness requires this to be the same across all modules

#include "BeaconEntity.h"
#include "../BlockArea.h"
#include "../Entities/Player.h"
#include "../UI/BeaconWindow.h"
#include "../ClientHandle.h"

cBeaconEntity::cBeaconEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World):
	Super(a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, 1, 1, a_World),
	m_IsActive(false),
	m_BeaconLevel(0),
	m_PrimaryEffect(cEntityEffect::effNoEffect),
	m_SecondaryEffect(cEntityEffect::effNoEffect)
{
	ASSERT(a_BlockType == E_BLOCK_BEACON);
	if (m_World != nullptr)
	{
		UpdateBeacon();
	}
}

char cBeaconEntity::CalculatePyramidLevel(void)
{
	cBlockArea Area;
	int MinY = std::max(GetPosY() - 4, 0);
	int MaxY = std::max(GetPosY() - 1, 0);

	Area.Read(
		*m_World,
		GetPosX() - 4, GetPosX() + 4,
		MinY, MaxY,
		GetPosZ() - 4, GetPosZ() + 4,
		cBlockArea::baTypes
	);

	int Layer = 1;
	int MiddleXZ = 4;

	for (int Y = (Area.GetSizeY() - 1); Y >= 0; Y--)
	{
		for (int X = MiddleXZ - Layer; X <= (MiddleXZ + Layer); X++)
		{
			for (int Z = MiddleXZ - Layer; Z <= (MiddleXZ + Layer); Z++)
			{
				if (!IsMineralBlock(Area.GetRelBlockType(X, Y, Z)))
				{
					return static_cast<char>(Layer - 1);
				}
			}
		}
		Layer++;
	}

	return static_cast<char>(Layer - 1);
}

bool cBeaconEntity::IsValidEffect(cEntityEffect::eType a_Effect, char a_BeaconLevel)
{
	switch (a_Effect)
	{
		case cEntityEffect::effRegeneration: return (a_BeaconLevel >= 4);
		case cEntityEffect::effStrength:     return (a_BeaconLevel >= 3);
		case cEntityEffect::effResistance:   return (a_BeaconLevel >= 2);
		case cEntityEffect::effJumpBoost:    return (a_BeaconLevel >= 2);
		case cEntityEffect::effSpeed:        return (a_BeaconLevel >= 1);
		case cEntityEffect::effHaste:        return (a_BeaconLevel >= 1);
		case cEntityEffect::effNoEffect:     return true;

		default:
		{
			LOGD("%s: Invalid beacon effect: %d", __FUNCTION__, static_cast<int>(a_Effect));
			return false;
		}
	}
}

bool cBeaconEntity::SetPrimaryEffect(cEntityEffect::eType a_Effect)
{
	if (!IsValidEffect(a_Effect, m_BeaconLevel))
	{
		m_PrimaryEffect = cEntityEffect::effNoEffect;
		return false;
	}

	m_PrimaryEffect = a_Effect;

	// Send window update:
	if (GetWindow() != nullptr)
	{
		GetWindow()->SetProperty(1, m_PrimaryEffect);
	}
	return true;
}

bool cBeaconEntity::SetSecondaryEffect(cEntityEffect::eType a_Effect)
{
	if (!IsValidEffect(a_Effect, m_BeaconLevel))
	{
		m_SecondaryEffect = cEntityEffect::effNoEffect;
		return false;
	}

	m_SecondaryEffect = a_Effect;

	// Send window update:
	if (GetWindow() != nullptr)
	{
		GetWindow()->SetProperty(2, m_SecondaryEffect);
	}
	return true;
}

bool cBeaconEntity::IsBeaconBlocked(void)
{
	for (int Y = m_PosY; Y < cChunkDef::Height; ++Y)
	{
		BLOCKTYPE Block = m_World->GetBlock(m_PosX, Y, m_PosZ);
		if (!cBlockInfo::IsTransparent(Block))
		{
			return true;
		}
	}
	return false;
}

bool cBeaconEntity::IsMineralBlock(BLOCKTYPE a_BlockType)
{
	switch (a_BlockType)
	{
		case E_BLOCK_DIAMOND_BLOCK:
		case E_BLOCK_GOLD_BLOCK:
		case E_BLOCK_IRON_BLOCK:
		case E_BLOCK_EMERALD_BLOCK:
		{
			return true;
		}
	}
	return false;
}

void cBeaconEntity::UpdateBeacon(void)
{
	int OldBeaconLevel = m_BeaconLevel;

	if (IsBeaconBlocked())
	{
		m_IsActive = false;
		m_BeaconLevel = 0;
	}
	else
	{
		m_BeaconLevel = CalculatePyramidLevel();
		m_IsActive = (m_BeaconLevel > 0);
	}

	if ((m_BeaconLevel != OldBeaconLevel) && (m_BeaconLevel == 4))
	{
		// Send window update:
		if (GetWindow() != nullptr)
		{
			GetWindow()->SetProperty(0, m_BeaconLevel);
		}

		class cPlayerCallback :
			public cPlayerListCallback
		{
		public:
			cPlayerCallback(Vector3d a_Position):
				m_Position(a_Position)
			{
			}

			virtual bool Item(cPlayer * a_Player)
			{
				Vector3d Distance = m_Position - a_Player->GetPosition();
				if (
					(std::abs(Distance.y) <= 14) &&
					(std::abs(Distance.x) <= 20) &&
					(std::abs(Distance.z) <= 20)
				)
				{
					a_Player->AwardAchievement(eStatistic::achFullBeacon);
				}
				return false;
			}

		private:
			Vector3d m_Position;
		} PlayerCallback(Vector3d(m_PosX, m_PosY, m_PosZ));
		GetWorld()->ForEachPlayer(PlayerCallback);
	}
}

void cBeaconEntity::GiveEffects(void)
{
	if (!m_IsActive || (m_BeaconLevel < 0))
	{
		return;
	}

	int Radius = m_BeaconLevel * 10 + 10;
	short EffectLevel = 0;
	if ((m_BeaconLevel >= 4) && (m_PrimaryEffect == m_SecondaryEffect))
	{
		EffectLevel = 1;
	}

	cEntityEffect::eType SecondaryEffect = cEntityEffect::effNoEffect;
	if ((m_BeaconLevel >= 4) && (m_PrimaryEffect != m_SecondaryEffect) && (m_SecondaryEffect > 0))
	{
		SecondaryEffect = m_SecondaryEffect;
	}

	class cPlayerCallback : public cPlayerListCallback
	{
		int m_Radius;
		Vector3d m_Position;
		cEntityEffect::eType m_PrimaryEffect, m_SecondaryEffect;
		short m_EffectLevel;

		virtual bool Item(cPlayer * a_Player)
		{
			Vector3d PlayerPosition = Vector3d(a_Player->GetPosition());
			if (PlayerPosition.y > m_Position.y)
			{
				PlayerPosition.y = m_Position.y;
			}

			// TODO: Vanilla minecraft uses an AABB check instead of a radius one
			if ((PlayerPosition - m_Position).Length() <= m_Radius)
			{
				a_Player->AddEntityEffect(m_PrimaryEffect, 180, m_EffectLevel);

				if (m_SecondaryEffect != cEntityEffect::effNoEffect)
				{
					a_Player->AddEntityEffect(m_SecondaryEffect, 180, 0);
				}
			}
			return false;
		}

	public:
		cPlayerCallback(int a_Radius, Vector3d a_Position, cEntityEffect::eType a_PrimaryEffect, cEntityEffect::eType a_SecondaryEffect, short a_EffectLevel):
			m_Radius(a_Radius),
			m_Position(a_Position),
			m_PrimaryEffect(a_PrimaryEffect),
			m_SecondaryEffect(a_SecondaryEffect),
			m_EffectLevel(a_EffectLevel)
		{
		}

	} PlayerCallback(Radius, Vector3d(m_PosX, m_PosY, m_PosZ), m_PrimaryEffect, SecondaryEffect, EffectLevel);
	GetWorld()->ForEachPlayer(PlayerCallback);
}

void cBeaconEntity::CopyFrom(const cBlockEntity & a_Src)
{
	Super::CopyFrom(a_Src);
	auto & src = reinterpret_cast<const cBeaconEntity &>(a_Src);
	m_BeaconLevel = src.m_BeaconLevel;
	m_Contents.CopyFrom(src.m_Contents);
	m_IsActive = src.m_IsActive;
	m_PrimaryEffect = src.m_PrimaryEffect;
	m_SecondaryEffect = src.m_SecondaryEffect;
}

void cBeaconEntity::SendTo(cClientHandle & a_Client)
{
	a_Client.SendUpdateBlockEntity(*this);
}

bool cBeaconEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
	// Update the beacon every 4 seconds
	if ((GetWorld()->GetWorldAge() % 80) == 0)
	{
		UpdateBeacon();
		GiveEffects();
	}
	return false;
}

bool cBeaconEntity::UsedBy(cPlayer * a_Player)
{
	cWindow * Window = GetWindow();
	if (Window == nullptr)
	{
		OpenWindow(new cBeaconWindow(m_PosX, m_PosY, m_PosZ, this));
		Window = GetWindow();
	}

	if (Window != nullptr)
	{
		// if (a_Player->GetWindow() != Window)
		// -> Because mojang doesn't send a 'close window' packet when you click the cancel button in the beacon inventory ...
		{
			a_Player->OpenWindow(*Window);
		}
	}
	return true;
}

<|endoftext|>


<commit_before>/**
 * The Seeks proxy and plugin framework are part of the SEEKS project.
 * Copyright (C) 2009 Emmanuel Benazera, juban@free.fr
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "plugin_manager.h"

#include "seeks_proxy.h"
#include "proxy_configuration.h"
#include "errlog.h"

#include "plugin.h"
#include "interceptor_plugin.h"
#include "action_plugin.h"
#include "filter_plugin.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>  // linux, TODO: windows.

#include <list>
#include <iostream>

#include <assert.h>

using sp::proxy_configuration;

namespace sp
{
   // variables.
   std::vector<plugin*> plugin_manager::_plugins = std::vector<plugin*>();
   std::vector<interceptor_plugin*> plugin_manager::_ref_interceptor_plugins
     = std::vector<interceptor_plugin*>();
   std::vector<action_plugin*> plugin_manager::_ref_action_plugins
     = std::vector<action_plugin*>();
   std::vector<filter_plugin*> plugin_manager::_ref_filter_plugins
     = std::vector<filter_plugin*>();

   hash_map<const char*,cgi_dispatcher*,hash<const char*>,eqstr> plugin_manager::_cgi_dispatchers
     = hash_map<const char*,cgi_dispatcher*,hash<const char*>,eqstr>();

   std::string plugin_manager::_plugin_repository = "";

   std::map<std::string,maker_ptr*,std::less<std::string> > plugin_manager::_factory
     = std::map<std::string,maker_ptr*,std::less<std::string> >();

   std::list<void*> plugin_manager::_dl_list = std::list<void*>();

   std::map<std::string,configuration_spec*,std::less<std::string> > plugin_manager::_configurations
     = std::map<std::string,configuration_spec*,std::less<std::string> >();

   std::string plugin_manager::_config_html_template = "templates/pm_config.html";

   int plugin_manager::load_all_plugins()
     {
	/**
	 * Defaults the plugin repository to the base directory, only if the repository has not been set
	 * through the command line, or in the configuration file, in that order.
	 */
	if (plugin_manager::_plugin_repository.empty() && seeks_proxy::_config->_plugindir)
	  {
	     plugin_manager::_plugin_repository = std::string(seeks_proxy::_config->_plugindir);
	  }
	else if (plugin_manager::_plugin_repository.empty())
	  {
	     // basedir.
	     assert(seeks_proxy::_basedir);
	     plugin_manager::_plugin_repository = std::string(seeks_proxy::_basedir)
#ifdef unix
	       + "/plugins/"
#endif
	       ;
#if defined(_WIN32)
	     + "\plugins\\";
#endif
	  }

	unsigned int BUF_SIZE = 1024;

	// TODO: win32...

	std::string command_str = "find " + plugin_manager::_plugin_repository
#if defined(ON_OPENBSD)
	  + " -name *.so*";
#elsif defined (ON_OSX)
	+ " -name *plugin.dylib";
#else
	+ " -name *.so";
#endif
	FILE *dl = popen(command_str.c_str(), "r"); // reading directory.
	if (!dl)
	  {
	     perror("popen");
	     exit(-1);
	  }

	void *dlib;
	char name[1024];
	char in_buf[BUF_SIZE]; // input buffer for lib names.
	while(fgets(in_buf, BUF_SIZE, dl))
	  {
	     char *ws = strpbrk(in_buf, " \t\n"); // remove spaces.
	     if (ws) *ws = '\0';

	     sprintf(name, "%s", in_buf); // append './' to lib name.
	     dlib = dlopen(name, RTLD_NOW);  // NOW imposes resolving all symbols
	                                     // required for auto-registration.
	     if (dlib == NULL)
	       {
		  errlog::log_error(LOG_LEVEL_FATAL, "%s", dlerror());
		  exit(-1);
	       }

	     plugin_manager::_dl_list.insert(plugin_manager::_dl_list.end(),dlib); // add lib handle to the list.

#if defined(ON_OPENBSD) || defined(ON_OSX)
	     maker_ptr *pl_fct = (maker_ptr*)dlsym(dlib,"maker");
	     if (!pl_fct)
	       continue;

	     plugin *pl = (*pl_fct)();
	     if (pl)
	       plugin_manager::_factory[pl->get_name()] = pl_fct;
#endif
	  }

	pclose(dl);

	//debug
	std::map<std::string,maker_ptr*,std::less<std::string> >::const_iterator mit
	  = plugin_manager::_factory.begin();
	while(mit!=plugin_manager::_factory.end())
	  {
	     errlog::log_error(LOG_LEVEL_INFO,"loaded plugin \t%s", (*mit).first.c_str());
	     mit++;
	  }
	//debug

	return 1;
     }

   int plugin_manager::close_all_plugins()
     {
	// destroy all plugins that have been created.
	std::vector<plugin*>::iterator vit = plugin_manager::_plugins.begin();
	while(vit!=plugin_manager::_plugins.end())
	  {
	     delete *vit;
	     ++vit;
	  }
	plugin_manager::_plugins.clear();

	// close all the opened dynamic libs.
	std::list<void*>::iterator lit = plugin_manager::_dl_list.begin();
	while(lit!=plugin_manager::_dl_list.end())
	  {
	     dlclose((*lit));
	     ++lit;
	  }

	return 1;
     }

   int plugin_manager::instanciate_plugins()
     {
	std::map<std::string,maker_ptr*,std::less<std::string> >::const_iterator mit
	  = plugin_manager::_factory.begin();
	while(mit!=plugin_manager::_factory.end())
	  {
	     plugin *p = (*mit).second(); // call to a maker function.

	     // register the plugin object and its functions, if activated.
	     if (seeks_proxy::_config->is_plugin_activated(p->get_name_cstr()))
		 {
		    plugin_manager::register_plugin(p);

		    // register the plugin elements.
		    if (p->_interceptor_plugin)
		      plugin_manager::_ref_interceptor_plugins.push_back(p->_interceptor_plugin);
		    if (p->_action_plugin)
		      plugin_manager::_ref_action_plugins.push_back(p->_action_plugin);
		    if (p->_filter_plugin)
		      plugin_manager::_ref_filter_plugins.push_back(p->_filter_plugin);

		    // run start() on plugin.
		    p->start();
		 }

	     ++mit;
	  }
	return 0;
     }

   //TODO: deinstanciate plugin = deregister + stop().

   void plugin_manager::register_plugin(plugin *p)
     {
	plugin_manager::_plugins.push_back(p);

	errlog::log_error(LOG_LEVEL_INFO,"Registering plugin %s, and %d CGI dispatchers",
			  p->get_name_cstr(), p->_cgi_dispatchers.size());

	std::vector<cgi_dispatcher*>::const_iterator vit = p->_cgi_dispatchers.begin();
	while(vit != p->_cgi_dispatchers.end())
	  {
	     cgi_dispatcher *cgid = (*vit);

	     hash_map<const char*,cgi_dispatcher*,hash<const char*>,eqstr>::iterator hit;
	     if ((hit = plugin_manager::_cgi_dispatchers.find(cgid->_name)) != plugin_manager::_cgi_dispatchers.end())
	       {
		  errlog::log_error(LOG_LEVEL_CGI, "CGI function %s of plugin %s, has already been registered by another plugin.",
				    cgid->_name, p->get_name_cstr());
	       }
	     else
	       {
		  errlog::log_error(LOG_LEVEL_INFO, "registering CGI dispatcher %s", cgid->_name);

		  plugin_manager::_cgi_dispatchers.insert(std::pair<const char*,cgi_dispatcher*>(cgid->_name,
												 cgid));
	       }

	     ++vit;
	  }
     }

   cgi_dispatcher* plugin_manager::find_plugin_cgi_dispatcher(const char *path)
     {
	hash_map<const char*,cgi_dispatcher*,hash<const char*>,eqstr>::const_iterator hit;
	if((hit = plugin_manager::_cgi_dispatchers.find(path)) != plugin_manager::_cgi_dispatchers.end())
	  return (*hit).second;
	else
	  {
	     errlog::log_error(LOG_LEVEL_ERROR, "Can't find any plugin dispatcher in %s", path);
	     return NULL;
	  }
     }

   void plugin_manager::get_url_plugins(client_state *csp, http_request *http)
     {
	std::vector<interceptor_plugin*>::const_iterator lit1
	  = plugin_manager::_ref_interceptor_plugins.begin();
	while(lit1!=plugin_manager::_ref_interceptor_plugins.end())
	  {
	     interceptor_plugin *ip = (*lit1);
#ifdef PLUGIN_DEBUG
	     ip->reload();
#endif
	     if (ip->match_url(http))
	       csp->add_interceptor_plugin(ip);
	     ++lit1;
	  }

	std::vector<action_plugin*>::const_iterator lit2
	  = plugin_manager::_ref_action_plugins.begin();
	while(lit2!=plugin_manager::_ref_action_plugins.end())
	  {
	     action_plugin *ip = (*lit2);
#ifdef PLUGIN_DEBUG
	     ip->reload();
#endif
	     if (ip->match_url(http))
	       csp->add_action_plugin(ip);
	     ++lit2;
	  }

	std::vector<filter_plugin*>::const_iterator lit3
	  = plugin_manager::_ref_filter_plugins.begin();
	while(lit3!=plugin_manager::_ref_filter_plugins.end())
	  {
	     filter_plugin *ip = (*lit3);
#ifdef PLUGIN_DEBUG
	     ip->reload();
#endif
	     if (ip->match_url(http))
	       csp->add_filter_plugin(ip);
	     ++lit3;
	  }

	// debug
	/* std::cout << "[Debug]:plugin_manager::get_url_plugin: interceptor plugins: "
	  << csp->_interceptor_plugins.size() << std::endl; */
	//debug
     }

   plugin* plugin_manager::get_plugin(const std::string &name)
     {
	std::vector<plugin*>::const_iterator vit = plugin_manager::_plugins.begin();
	while(vit!=plugin_manager::_plugins.end())
	  {
	     if ((*vit)->get_name() == name)
	       return (*vit);
	     ++vit;
	  }
	return NULL;
     }

} /* end of namespace. */
<commit_msg>plugin loading failure is no more a fatal error<commit_after>/**
 * The Seeks proxy and plugin framework are part of the SEEKS project.
 * Copyright (C) 2009 Emmanuel Benazera, juban@free.fr
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "plugin_manager.h"

#include "seeks_proxy.h"
#include "proxy_configuration.h"
#include "errlog.h"

#include "plugin.h"
#include "interceptor_plugin.h"
#include "action_plugin.h"
#include "filter_plugin.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>  // linux, TODO: windows.

#include <list>
#include <iostream>

#include <assert.h>

using sp::proxy_configuration;

namespace sp
{
   // variables.
   std::vector<plugin*> plugin_manager::_plugins = std::vector<plugin*>();
   std::vector<interceptor_plugin*> plugin_manager::_ref_interceptor_plugins
     = std::vector<interceptor_plugin*>();
   std::vector<action_plugin*> plugin_manager::_ref_action_plugins
     = std::vector<action_plugin*>();
   std::vector<filter_plugin*> plugin_manager::_ref_filter_plugins
     = std::vector<filter_plugin*>();

   hash_map<const char*,cgi_dispatcher*,hash<const char*>,eqstr> plugin_manager::_cgi_dispatchers
     = hash_map<const char*,cgi_dispatcher*,hash<const char*>,eqstr>();

   std::string plugin_manager::_plugin_repository = "";

   std::map<std::string,maker_ptr*,std::less<std::string> > plugin_manager::_factory
     = std::map<std::string,maker_ptr*,std::less<std::string> >();

   std::list<void*> plugin_manager::_dl_list = std::list<void*>();

   std::map<std::string,configuration_spec*,std::less<std::string> > plugin_manager::_configurations
     = std::map<std::string,configuration_spec*,std::less<std::string> >();

   std::string plugin_manager::_config_html_template = "templates/pm_config.html";

   int plugin_manager::load_all_plugins()
     {
	/**
	 * Defaults the plugin repository to the base directory, only if the repository has not been set
	 * through the command line, or in the configuration file, in that order.
	 */
	if (plugin_manager::_plugin_repository.empty() && seeks_proxy::_config->_plugindir)
	  {
	     plugin_manager::_plugin_repository = std::string(seeks_proxy::_config->_plugindir);
	  }
	else if (plugin_manager::_plugin_repository.empty())
	  {
	     // basedir.
	     assert(seeks_proxy::_basedir);
	     plugin_manager::_plugin_repository = std::string(seeks_proxy::_basedir)
#ifdef unix
	       + "/plugins/"
#endif
	       ;
#if defined(_WIN32)
	     + "\plugins\\";
#endif
	  }

	unsigned int BUF_SIZE = 1024;

	// TODO: win32...

	std::string command_str = "find " + plugin_manager::_plugin_repository
#if defined(ON_OPENBSD)
	  + " -name *.so*";
#elsif defined (ON_OSX)
	+ " -name *plugin.dylib";
#else
	+ " -name *.so";
#endif
	FILE *dl = popen(command_str.c_str(), "r"); // reading directory.
	if (!dl)
	  {
	     perror("popen");
	     exit(-1);
	  }

	void *dlib;
	char name[1024];
	char in_buf[BUF_SIZE]; // input buffer for lib names.
	while(fgets(in_buf, BUF_SIZE, dl))
	  {
	     char *ws = strpbrk(in_buf, " \t\n"); // remove spaces.
	     if (ws) *ws = '\0';

	     sprintf(name, "%s", in_buf); // append './' to lib name.
	     dlib = dlopen(name, RTLD_NOW);  // NOW imposes resolving all symbols
	                                     // required for auto-registration.
	     if (dlib == NULL)
	       {
		  errlog::log_error(LOG_LEVEL_ERROR, "%s", dlerror());
		  //exit(-1);
	       }

	     plugin_manager::_dl_list.insert(plugin_manager::_dl_list.end(),dlib); // add lib handle to the list.

#if defined(ON_OPENBSD) || defined(ON_OSX)
	     maker_ptr *pl_fct = (maker_ptr*)dlsym(dlib,"maker");
	     if (!pl_fct)
	       continue;

	     plugin *pl = (*pl_fct)();
	     if (pl)
	       plugin_manager::_factory[pl->get_name()] = pl_fct;
#endif
	  }

	pclose(dl);

	//debug
	std::map<std::string,maker_ptr*,std::less<std::string> >::const_iterator mit
	  = plugin_manager::_factory.begin();
	while(mit!=plugin_manager::_factory.end())
	  {
	     errlog::log_error(LOG_LEVEL_INFO,"loaded plugin \t%s", (*mit).first.c_str());
	     mit++;
	  }
	//debug

	return 1;
     }

   int plugin_manager::close_all_plugins()
     {
	// destroy all plugins that have been created.
	std::vector<plugin*>::iterator vit = plugin_manager::_plugins.begin();
	while(vit!=plugin_manager::_plugins.end())
	  {
	     delete *vit;
	     ++vit;
	  }
	plugin_manager::_plugins.clear();

	// close all the opened dynamic libs.
	std::list<void*>::iterator lit = plugin_manager::_dl_list.begin();
	while(lit!=plugin_manager::_dl_list.end())
	  {
	     dlclose((*lit));
	     ++lit;
	  }

	return 1;
     }

   int plugin_manager::instanciate_plugins()
     {
	std::map<std::string,maker_ptr*,std::less<std::string> >::const_iterator mit
	  = plugin_manager::_factory.begin();
	while(mit!=plugin_manager::_factory.end())
	  {
	     plugin *p = (*mit).second(); // call to a maker function.

	     // register the plugin object and its functions, if activated.
	     if (seeks_proxy::_config->is_plugin_activated(p->get_name_cstr()))
		 {
		    plugin_manager::register_plugin(p);

		    // register the plugin elements.
		    if (p->_interceptor_plugin)
		      plugin_manager::_ref_interceptor_plugins.push_back(p->_interceptor_plugin);
		    if (p->_action_plugin)
		      plugin_manager::_ref_action_plugins.push_back(p->_action_plugin);
		    if (p->_filter_plugin)
		      plugin_manager::_ref_filter_plugins.push_back(p->_filter_plugin);

		    // run start() on plugin.
		    p->start();
		 }

	     ++mit;
	  }
	return 0;
     }

   //TODO: deinstanciate plugin = deregister + stop().

   void plugin_manager::register_plugin(plugin *p)
     {
	plugin_manager::_plugins.push_back(p);

	errlog::log_error(LOG_LEVEL_INFO,"Registering plugin %s, and %d CGI dispatchers",
			  p->get_name_cstr(), p->_cgi_dispatchers.size());

	std::vector<cgi_dispatcher*>::const_iterator vit = p->_cgi_dispatchers.begin();
	while(vit != p->_cgi_dispatchers.end())
	  {
	     cgi_dispatcher *cgid = (*vit);

	     hash_map<const char*,cgi_dispatcher*,hash<const char*>,eqstr>::iterator hit;
	     if ((hit = plugin_manager::_cgi_dispatchers.find(cgid->_name)) != plugin_manager::_cgi_dispatchers.end())
	       {
		  errlog::log_error(LOG_LEVEL_CGI, "CGI function %s of plugin %s, has already been registered by another plugin.",
				    cgid->_name, p->get_name_cstr());
	       }
	     else
	       {
		  errlog::log_error(LOG_LEVEL_INFO, "registering CGI dispatcher %s", cgid->_name);

		  plugin_manager::_cgi_dispatchers.insert(std::pair<const char*,cgi_dispatcher*>(cgid->_name,
												 cgid));
	       }

	     ++vit;
	  }
     }

   cgi_dispatcher* plugin_manager::find_plugin_cgi_dispatcher(const char *path)
     {
	hash_map<const char*,cgi_dispatcher*,hash<const char*>,eqstr>::const_iterator hit;
	if((hit = plugin_manager::_cgi_dispatchers.find(path)) != plugin_manager::_cgi_dispatchers.end())
	  return (*hit).second;
	else
	  {
	     errlog::log_error(LOG_LEVEL_ERROR, "Can't find any plugin dispatcher in %s", path);
	     return NULL;
	  }
     }

   void plugin_manager::get_url_plugins(client_state *csp, http_request *http)
     {
	std::vector<interceptor_plugin*>::const_iterator lit1
	  = plugin_manager::_ref_interceptor_plugins.begin();
	while(lit1!=plugin_manager::_ref_interceptor_plugins.end())
	  {
	     interceptor_plugin *ip = (*lit1);
#ifdef PLUGIN_DEBUG
	     ip->reload();
#endif
	     if (ip->match_url(http))
	       csp->add_interceptor_plugin(ip);
	     ++lit1;
	  }

	std::vector<action_plugin*>::const_iterator lit2
	  = plugin_manager::_ref_action_plugins.begin();
	while(lit2!=plugin_manager::_ref_action_plugins.end())
	  {
	     action_plugin *ip = (*lit2);
#ifdef PLUGIN_DEBUG
	     ip->reload();
#endif
	     if (ip->match_url(http))
	       csp->add_action_plugin(ip);
	     ++lit2;
	  }

	std::vector<filter_plugin*>::const_iterator lit3
	  = plugin_manager::_ref_filter_plugins.begin();
	while(lit3!=plugin_manager::_ref_filter_plugins.end())
	  {
	     filter_plugin *ip = (*lit3);
#ifdef PLUGIN_DEBUG
	     ip->reload();
#endif
	     if (ip->match_url(http))
	       csp->add_filter_plugin(ip);
	     ++lit3;
	  }

	// debug
	/* std::cout << "[Debug]:plugin_manager::get_url_plugin: interceptor plugins: "
	  << csp->_interceptor_plugins.size() << std::endl; */
	//debug
     }

   plugin* plugin_manager::get_plugin(const std::string &name)
     {
	std::vector<plugin*>::const_iterator vit = plugin_manager::_plugins.begin();
	while(vit!=plugin_manager::_plugins.end())
	  {
	     if ((*vit)->get_name() == name)
	       return (*vit);
	     ++vit;
	  }
	return NULL;
     }

} /* end of namespace. */
<|endoftext|>