using System; using System.Collections.Generic; using System.IO; using Android.Content; using Android.OS; using KeePassLib.Serialization; namespace keepass2android.Io { public enum FileStorageResults { FullFilenameSelected = 874345 + 1, FileChooserPrepared = FullFilenameSelected + 1, FileUsagePrepared = FileChooserPrepared + 1 } public static class FileStorageSetupDefs { public static String ProcessNameSelectfile = "SELECT_FILE"; public static String ProcessNameFileUsageSetup = "FILE_USAGE_SETUP"; public static String ExtraProcessName = "EXTRA_PROCESS_NAME"; public static String ExtraAlwaysReturnSuccess = "EXTRA_ALWAYS_RETURN_SUCCESS"; public static String ExtraPath = "PATH"; public static String ExtraIsForSave = "IS_FOR_SAVE"; public static String ExtraErrorMessage = "EXTRA_ERROR_MESSAGE"; } /// /// Interface to encapsulate all access to disk or cloud. /// /// Note that it was decided to use the IOConnectionInfo also for cloud storage. /// The advantage is that the database for saving recent files etc. will then work without /// much work to do. Furthermore, the IOConnectionInfo seems generic info to capture all required data, even though it might be nicer to /// have an IIoStorageId interface in few cases.*/ public interface IFileStorage { /// /// returns the protocol ids supported by this FileStorage. Can return pseudo-protocols like "dropbox" or real protocols like "ftp" /// IEnumerable SupportedProtocols { get; } /// /// Deletes the given file or directory. /// void Delete(IOConnectionInfo ioc); /// /// Tests whether the file was changed. /// /// Note: This function may return false even if the file might have changed. The function /// should focus on being fast and cheap instead of doing things like hashing or downloading a full file. /// previousFileVersion may be null to indicate no previous version is known. /// Returns true if a change was detected, false otherwise. bool CheckForFileChangeFast(IOConnectionInfo ioc , string previousFileVersion); /// /// Returns a string describing the "version" of the file specified by ioc. /// /// This string may have a deliberate value (except null) and should not be used by callers except for passing it to /// CheckForFileChangeFast(). /// A string describing the version. Null means, there is no way to get a file version (or it's not implemented). string GetCurrentFileVersionFast(IOConnectionInfo ioc); /// /// Opens the given file for reading /// Stream OpenFileForRead(IOConnectionInfo ioc); /// /// Opens a write transaction for writing to the given ioc. /// /// ioc to write to /// if true, force to use file system level transaction. This might be ignored if the file storage has built in transaction support IWriteTransaction OpenWriteTransaction(IOConnectionInfo ioc, bool useFileTransaction); string GetFilenameWithoutPathAndExt(IOConnectionInfo ioc); /// /// Returns true if the the given ioc must be filled with username/password /// bool RequiresCredentials(IOConnectionInfo ioc); /// /// Creates the directory described by ioc /// void CreateDirectory(IOConnectionInfo ioc, string newDirName); /// /// Lists the contents of the given path /// IEnumerable ListContents(IOConnectionInfo ioc); /// /// returns the description of the given file /// FileDescription GetFileDescription(IOConnectionInfo ioc); /// /// returns true if everything is ok with connecting to the given file. /// Returns False if PrepareFileUsage must be called first. /// bool RequiresSetup(IOConnectionInfo ioConnection); /// /// converts the ioc to a path which may contain the credentials /// string IocToPath(IOConnectionInfo ioc); /// /// Initiates the process for choosing a file in the given file storage. /// The file storage should either call OnImmediateResult or StartSelectFileProcess /// void StartSelectFile(IFileStorageSetupInitiatorActivity activity, bool isForSave, int requestCode, string protocolId); /// /// Initiates the process for using a file in the given file storage. /// The file storage should either call OnImmediateResult or StartFileUsageProcess /// If alwaysReturnSuccess is true, the activity should be finished with ResultCode Ok. /// This can make sense if a higher-level file storage has the file cached but still wants to /// give the cached storage the chance to initialize file access. /// void PrepareFileUsage(IFileStorageSetupInitiatorActivity activity, IOConnectionInfo ioc, int requestCode, bool alwaysReturnSuccess); /// /// Initiates the process for using a file in the given file storage. /// This method either silently prepares using the file (if any preparation is required) or throws /// UserInteractionRequiredException (or any other exception in case of an error). /// Can be used from a service, i.e. when no Activity is open. /// void PrepareFileUsage(Context ctx, IOConnectionInfo ioc); //Setup methods: these are called from the setup activity so the file storage can handle UI events for authorization etc. void OnCreate(IFileStorageSetupActivity activity, Bundle savedInstanceState); void OnResume(IFileStorageSetupActivity activity); void OnStart(IFileStorageSetupActivity activity); void OnActivityResult(IFileStorageSetupActivity activity, int requestCode, int resultCode, Intent data); /// /// Converts the given path to a displayable string /// string GetDisplayName(IOConnectionInfo ioc); //returns the path of a file "newFilename" in the folder "parent" //this may create the file if this is required to get a path (if a UUID is part of the file path) string CreateFilePath(string parent, string newFilename); /// /// returns the parent folder of ioc /// IOConnectionInfo GetParentPath(IOConnectionInfo ioc); /// /// returns the file path of the file "filename" in the folderPath. /// /// The method may throw FileNotFoundException or not in case the file doesn't exist. IOConnectionInfo GetFilePath(IOConnectionInfo folderPath, string filename); /// /// returns true if it can be expected that this location will be available permanently (in contrast to a cache copy or temporary URI permissions in Android) /// /// Does not require to exist forever! bool IsPermanentLocation(IOConnectionInfo ioc); /// /// Should return true if the file cannot be written. /// bool IsReadOnly(IOConnectionInfo ioc); } public interface IWriteTransaction: IDisposable { Stream OpenFile(); void CommitWrite(); } public class FileStorageSelectionInfo { public enum FileStorageSelectionMessageType { Info, //show only ok button CancellableInfo, //show Ok/Cancel Error //show cancel only } public UiStringKey SelectionMessage { get; set; } public FileStorageSelectionMessageType MessageType { get; set; } } /// /// Can be implemented by IFileStorage implementers to add additional information for the /// process of selecting the file storage /// public interface IFileStorageSelectionInfoProvider { FileStorageSelectionInfo TryGetSelectionInfo(string protocolId); } }