15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/api/sync_file_system/sync_file_system_api.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string> 82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <utility> 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h" 132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/api/sync_file_system/extension_sync_event_observer.h" 142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/api/sync_file_system/extension_sync_event_observer_factory.h" 15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/extensions/api/sync_file_system/sync_file_system_api_helpers.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h" 177dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/sync_file_system/drive_backend/drive_file_sync_service.h" 182385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch#include "chrome/browser/sync_file_system/sync_file_status.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/sync_file_system/sync_file_system_service.h" 202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/sync_file_system/sync_file_system_service_factory.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/extensions/api/sync_file_system.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_context.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/render_view_host.h" 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/storage_partition.h" 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/common/content_client.h" 2690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "webkit/browser/fileapi/file_system_context.h" 2790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "webkit/browser/fileapi/file_system_url.h" 28868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "webkit/browser/quota/quota_manager.h" 2990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "webkit/common/fileapi/file_system_types.h" 3090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "webkit/common/fileapi/file_system_util.h" 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserContext; 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserThread; 342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using sync_file_system::ConflictResolutionPolicy; 352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using sync_file_system::SyncFileStatus; 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using sync_file_system::SyncFileSystemServiceFactory; 372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using sync_file_system::SyncStatusCode; 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace extensions { 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Error messages. 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kFileError[] = "File error %d."; 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kQuotaError[] = "Quota error %d."; 462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kUnsupportedConflictResolutionPolicy[] = 472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "Policy %s is not supported."; 482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)sync_file_system::SyncFileSystemService* GetSyncFileSystemService( 502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Profile* profile) { 512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) sync_file_system::SyncFileSystemService* service = 522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SyncFileSystemServiceFactory::GetForProfile(profile); 532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(service); 542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ExtensionSyncEventObserver* observer = 552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ExtensionSyncEventObserverFactory::GetForProfile(profile); 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(observer); 57868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) observer->InitializeForService(service); 582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return service; 592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SyncFileSystemDeleteFileSystemFunction::RunImpl() { 642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string url; 652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &url)); 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<fileapi::FileSystemContext> file_system_context = 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserContext::GetStoragePartition( 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile(), 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) render_view_host()->GetSiteInstance())->GetFileSystemContext(); 712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) fileapi::FileSystemURL file_system_url( 722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) file_system_context->CrackURL(GURL(url))); 732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserThread::PostTask( 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserThread::IO, 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FROM_HERE, 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Bind(&fileapi::FileSystemContext::DeleteFileSystem, 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file_system_context, 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) source_url().GetOrigin(), 802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) file_system_url.type(), 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Bind(&SyncFileSystemDeleteFileSystemFunction::DidDeleteFileSystem, 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this))); 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SyncFileSystemDeleteFileSystemFunction::DidDeleteFileSystem( 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::PlatformFileError error) { 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Repost to switch from IO thread to UI thread for SendResponse(). 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserThread::PostTask( 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserThread::UI, 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FROM_HERE, 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Bind(&SyncFileSystemDeleteFileSystemFunction::DidDeleteFileSystem, this, 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) error)); 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (error != base::PLATFORM_FILE_OK) { 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) error_ = base::StringPrintf(kFileError, static_cast<int>(error)); 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetResult(base::Value::CreateBooleanValue(false)); 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SendResponse(false); 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetResult(base::Value::CreateBooleanValue(true)); 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SendResponse(true); 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SyncFileSystemRequestFileSystemFunction::RunImpl() { 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Initializes sync context for this extension and continue to open 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // a new file system. 1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) GetSyncFileSystemService(profile())-> 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) InitializeForApp( 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetFileSystemContext(), 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) source_url().GetOrigin(), 118868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) base::Bind(&self::DidInitializeFileSystemContext, this)); 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)fileapi::FileSystemContext* 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SyncFileSystemRequestFileSystemFunction::GetFileSystemContext() { 124c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK(render_view_host()); 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return BrowserContext::GetStoragePartition( 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile(), 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) render_view_host()->GetSiteInstance())->GetFileSystemContext(); 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SyncFileSystemRequestFileSystemFunction::DidInitializeFileSystemContext( 1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SyncStatusCode status) { 1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (status != sync_file_system::SYNC_STATUS_OK) { 1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) error_ = sync_file_system::SyncStatusCodeToString(status); 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SendResponse(false); 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 138c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!render_view_host()) { 139c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // The app seems to have been closed. 140c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return; 141c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 142c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) BrowserThread::PostTask( 1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) BrowserThread::IO, FROM_HERE, 145eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch Bind(&fileapi::FileSystemContext::OpenFileSystem, 1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) GetFileSystemContext(), 1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) source_url().GetOrigin(), 1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) fileapi::kFileSystemTypeSyncable, 14990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) fileapi::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT, 1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&self::DidOpenFileSystem, this))); 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SyncFileSystemRequestFileSystemFunction::DidOpenFileSystem( 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::PlatformFileError error, 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& file_system_name, 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const GURL& root_url) { 1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Repost to switch from IO thread to UI thread for SendResponse(). 1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { 1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) BrowserThread::PostTask( 1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) BrowserThread::UI, FROM_HERE, 1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Bind(&SyncFileSystemRequestFileSystemFunction::DidOpenFileSystem, 1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) this, error, file_system_name, root_url)); 1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (error != base::PLATFORM_FILE_OK) { 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) error_ = base::StringPrintf(kFileError, static_cast<int>(error)); 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SendResponse(false); 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 174eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::DictionaryValue* dict = new base::DictionaryValue(); 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetResult(dict); 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dict->SetString("name", file_system_name); 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dict->SetString("root", root_url.spec()); 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SendResponse(true); 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SyncFileSystemGetFileStatusFunction::RunImpl() { 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string url; 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &url)); 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_refptr<fileapi::FileSystemContext> file_system_context = 1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) BrowserContext::GetStoragePartition( 1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) profile(), 1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) render_view_host()->GetSiteInstance())->GetFileSystemContext(); 1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) fileapi::FileSystemURL file_system_url( 1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) file_system_context->CrackURL(GURL(url))); 1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SyncFileSystemServiceFactory::GetForProfile(profile())->GetFileSyncStatus( 1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) file_system_url, 1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Bind(&SyncFileSystemGetFileStatusFunction::DidGetFileStatus, 1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) this)); 1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SyncFileSystemGetFileStatusFunction::DidGetFileStatus( 2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const SyncStatusCode sync_status_code, 2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const SyncFileStatus sync_file_status) { 2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (sync_status_code != sync_file_system::SYNC_STATUS_OK) { 2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) error_ = sync_file_system::SyncStatusCodeToString(sync_status_code); 2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SendResponse(false); 2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Convert from C++ to JavaScript enum. 2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) results_ = api::sync_file_system::GetFileStatus::Results::Create( 211c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) SyncFileStatusToExtensionEnum(sync_file_status)); 2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SendResponse(true); 2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)SyncFileSystemGetFileStatusesFunction::SyncFileSystemGetFileStatusesFunction() { 2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)SyncFileSystemGetFileStatusesFunction::~SyncFileSystemGetFileStatusesFunction( 2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ) {} 2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SyncFileSystemGetFileStatusesFunction::RunImpl() { 2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // All FileEntries converted into array of URL Strings in JS custom bindings. 223eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::ListValue* file_entry_urls = NULL; 2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) EXTENSION_FUNCTION_VALIDATE(args_->GetList(0, &file_entry_urls)); 2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_refptr<fileapi::FileSystemContext> file_system_context = 2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) BrowserContext::GetStoragePartition( 2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) profile(), 2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) render_view_host()->GetSiteInstance())->GetFileSystemContext(); 2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Map each file path->SyncFileStatus in the callback map. 2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(calvinlo): Overload GetFileSyncStatus to take in URL array. 2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) num_expected_results_ = file_entry_urls->GetSize(); 2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) num_results_received_ = 0; 2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) file_sync_statuses_.clear(); 2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) sync_file_system::SyncFileSystemService* sync_file_system_service = 2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SyncFileSystemServiceFactory::GetForProfile(profile()); 2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (unsigned int i = 0; i < num_expected_results_; i++) { 2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string url; 2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) file_entry_urls->GetString(i, &url); 2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) fileapi::FileSystemURL file_system_url( 2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) file_system_context->CrackURL(GURL(url))); 2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) sync_file_system_service->GetFileSyncStatus( 2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) file_system_url, 2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Bind(&SyncFileSystemGetFileStatusesFunction::DidGetFileStatus, 2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) this, file_system_url)); 2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SyncFileSystemGetFileStatusesFunction::DidGetFileStatus( 2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const fileapi::FileSystemURL& file_system_url, 2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SyncStatusCode sync_status_code, 2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SyncFileStatus sync_file_status) { 2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) num_results_received_++; 2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK_LE(num_results_received_, num_expected_results_); 2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) file_sync_statuses_[file_system_url] = 2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::make_pair(sync_status_code, sync_file_status); 2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Keep mapping file statuses until all of them have been received. 2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(calvinlo): Get rid of this check when batch version of 2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // GetFileSyncStatus(GURL urls[]); is added. 2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (num_results_received_ < num_expected_results_) 2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // All results received. Dump array of statuses into extension enum values. 2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Note that the enum types need to be set as strings manually as the 2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // autogenerated Results::Create function thinks the enum values should be 2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // returned as int values. 2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::ListValue* status_array = new base::ListValue(); 2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (URLToStatusMap::iterator it = file_sync_statuses_.begin(); 2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) it != file_sync_statuses_.end(); ++it) { 277eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::DictionaryValue* dict = new base::DictionaryValue(); 2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) status_array->Append(dict); 2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) fileapi::FileSystemURL url = it->first; 2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SyncStatusCode file_error = it->second.first; 2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) api::sync_file_system::FileStatus file_status = 283c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) SyncFileStatusToExtensionEnum(it->second.second); 284c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 285c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) dict->Set("entry", CreateDictionaryValueForFileSystemEntry( 286c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) url, sync_file_system::SYNC_FILE_TYPE_FILE)); 2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) dict->SetString("status", ToString(file_status)); 2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (file_error == sync_file_system::SYNC_STATUS_OK) 2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) continue; 2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) dict->SetString("error", 2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) sync_file_system::SyncStatusCodeToString(file_error)); 2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SetResult(status_array); 2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SendResponse(true); 2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SyncFileSystemGetUsageAndQuotaFunction::RunImpl() { 3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string url; 3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &url)); 3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_refptr<fileapi::FileSystemContext> file_system_context = 3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) BrowserContext::GetStoragePartition( 3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) profile(), 3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) render_view_host()->GetSiteInstance())->GetFileSystemContext(); 3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) fileapi::FileSystemURL file_system_url( 3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) file_system_context->CrackURL(GURL(url))); 3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<quota::QuotaManager> quota_manager = 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserContext::GetStoragePartition( 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile(), 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) render_view_host()->GetSiteInstance())->GetQuotaManager(); 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserThread::PostTask( 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserThread::IO, 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FROM_HERE, 318c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) Bind("a::QuotaManager::GetUsageAndQuotaForWebApps, 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) quota_manager, 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) source_url().GetOrigin(), 3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) fileapi::FileSystemTypeToQuotaStorageType(file_system_url.type()), 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Bind(&SyncFileSystemGetUsageAndQuotaFunction::DidGetUsageAndQuota, 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this))); 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SyncFileSystemGetUsageAndQuotaFunction::DidGetUsageAndQuota( 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) quota::QuotaStatusCode status, int64 usage, int64 quota) { 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Repost to switch from IO thread to UI thread for SendResponse(). 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserThread::PostTask( 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserThread::UI, 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FROM_HERE, 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Bind(&SyncFileSystemGetUsageAndQuotaFunction::DidGetUsageAndQuota, this, 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) status, usage, quota)); 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (status != quota::kQuotaStatusOk) { 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) error_ = QuotaStatusCodeToString(status); 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SendResponse(false); 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) api::sync_file_system::StorageInfo info; 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) info.usage_bytes = usage; 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) info.quota_bytes = quota; 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) results_ = api::sync_file_system::GetUsageAndQuota::Results::Create(info); 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SendResponse(true); 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SyncFileSystemSetConflictResolutionPolicyFunction::RunImpl() { 3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string policy_string; 3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &policy_string)); 358c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ConflictResolutionPolicy policy = ExtensionEnumToConflictResolutionPolicy( 359c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) api::sync_file_system::ParseConflictResolutionPolicy(policy_string)); 360eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (policy == sync_file_system::CONFLICT_RESOLUTION_POLICY_UNKNOWN) { 3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SetError(base::StringPrintf(kUnsupportedConflictResolutionPolicy, 3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) policy_string.c_str())); 3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) sync_file_system::SyncFileSystemService* service = GetSyncFileSystemService( 3662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) profile()); 3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(service); 3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SyncStatusCode status = service->SetConflictResolutionPolicy(policy); 3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (status != sync_file_system::SYNC_STATUS_OK) { 3702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SetError(sync_file_system::SyncStatusCodeToString(status)); 3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 3742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SyncFileSystemGetConflictResolutionPolicyFunction::RunImpl() { 3772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) sync_file_system::SyncFileSystemService* service = GetSyncFileSystemService( 3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) profile()); 3792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(service); 3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) api::sync_file_system::ConflictResolutionPolicy policy = 3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ConflictResolutionPolicyToExtensionEnum( 3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) service->GetConflictResolutionPolicy()); 3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SetResult(Value::CreateStringValue( 3842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) api::sync_file_system::ToString(policy))); 3852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 3862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace extensions 389