add missing File NetFtpFileStorage.cs, added HttpClient based Http implementation
This commit is contained in:
		@@ -51,6 +51,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FtpClientTest", "FtpClientT
 | 
				
			|||||||
EndProject
 | 
					EndProject
 | 
				
			||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Net.FtpClient.Android", "netftpandroid\System.Net.FtpClient\System.Net.FtpClient.Android.csproj", "{146FD497-BA03-4740-B6C5-5C84EA8FCDE2}"
 | 
					Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Net.FtpClient.Android", "netftpandroid\System.Net.FtpClient\System.Net.FtpClient.Android.csproj", "{146FD497-BA03-4740-B6C5-5C84EA8FCDE2}"
 | 
				
			||||||
EndProject
 | 
					EndProject
 | 
				
			||||||
 | 
					Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kp2aUnitTests2", "Kp2aUnitTests2\Kp2aUnitTests2.csproj", "{B6062CC3-C238-40F3-B4BE-DD647300F96C}"
 | 
				
			||||||
 | 
					EndProject
 | 
				
			||||||
 | 
					Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebDavAndroid", "WebDavAndroid\WebDavAndroid.csproj", "{B6B866AF-D69C-4317-9838-51CF743E24B3}"
 | 
				
			||||||
 | 
					EndProject
 | 
				
			||||||
Global
 | 
					Global
 | 
				
			||||||
	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 | 
						GlobalSection(SolutionConfigurationPlatforms) = preSolution
 | 
				
			||||||
		Debug|Any CPU = Debug|Any CPU
 | 
							Debug|Any CPU = Debug|Any CPU
 | 
				
			||||||
@@ -571,6 +575,48 @@ Global
 | 
				
			|||||||
		{146FD497-BA03-4740-B6C5-5C84EA8FCDE2}.ReleaseNoNet|Mixed Platforms.Build.0 = Release|Any CPU
 | 
							{146FD497-BA03-4740-B6C5-5C84EA8FCDE2}.ReleaseNoNet|Mixed Platforms.Build.0 = Release|Any CPU
 | 
				
			||||||
		{146FD497-BA03-4740-B6C5-5C84EA8FCDE2}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU
 | 
							{146FD497-BA03-4740-B6C5-5C84EA8FCDE2}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU
 | 
				
			||||||
		{146FD497-BA03-4740-B6C5-5C84EA8FCDE2}.ReleaseNoNet|x64.ActiveCfg = Release|Any CPU
 | 
							{146FD497-BA03-4740-B6C5-5C84EA8FCDE2}.ReleaseNoNet|x64.ActiveCfg = Release|Any CPU
 | 
				
			||||||
 | 
							{B6062CC3-C238-40F3-B4BE-DD647300F96C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 | 
				
			||||||
 | 
							{B6062CC3-C238-40F3-B4BE-DD647300F96C}.Debug|Any CPU.Build.0 = Debug|Any CPU
 | 
				
			||||||
 | 
							{B6062CC3-C238-40F3-B4BE-DD647300F96C}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
 | 
				
			||||||
 | 
							{B6062CC3-C238-40F3-B4BE-DD647300F96C}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
 | 
				
			||||||
 | 
							{B6062CC3-C238-40F3-B4BE-DD647300F96C}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
 | 
				
			||||||
 | 
							{B6062CC3-C238-40F3-B4BE-DD647300F96C}.Debug|Mixed Platforms.Deploy.0 = Debug|Any CPU
 | 
				
			||||||
 | 
							{B6062CC3-C238-40F3-B4BE-DD647300F96C}.Debug|Win32.ActiveCfg = Debug|Any CPU
 | 
				
			||||||
 | 
							{B6062CC3-C238-40F3-B4BE-DD647300F96C}.Debug|x64.ActiveCfg = Debug|Any CPU
 | 
				
			||||||
 | 
							{B6062CC3-C238-40F3-B4BE-DD647300F96C}.Release|Any CPU.ActiveCfg = Release|Any CPU
 | 
				
			||||||
 | 
							{B6062CC3-C238-40F3-B4BE-DD647300F96C}.Release|Any CPU.Build.0 = Release|Any CPU
 | 
				
			||||||
 | 
							{B6062CC3-C238-40F3-B4BE-DD647300F96C}.Release|Any CPU.Deploy.0 = Release|Any CPU
 | 
				
			||||||
 | 
							{B6062CC3-C238-40F3-B4BE-DD647300F96C}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
 | 
				
			||||||
 | 
							{B6062CC3-C238-40F3-B4BE-DD647300F96C}.Release|Mixed Platforms.Build.0 = Release|Any CPU
 | 
				
			||||||
 | 
							{B6062CC3-C238-40F3-B4BE-DD647300F96C}.Release|Mixed Platforms.Deploy.0 = Release|Any CPU
 | 
				
			||||||
 | 
							{B6062CC3-C238-40F3-B4BE-DD647300F96C}.Release|Win32.ActiveCfg = Release|Any CPU
 | 
				
			||||||
 | 
							{B6062CC3-C238-40F3-B4BE-DD647300F96C}.Release|x64.ActiveCfg = Release|Any CPU
 | 
				
			||||||
 | 
							{B6062CC3-C238-40F3-B4BE-DD647300F96C}.ReleaseNoNet|Any CPU.ActiveCfg = Release|Any CPU
 | 
				
			||||||
 | 
							{B6062CC3-C238-40F3-B4BE-DD647300F96C}.ReleaseNoNet|Any CPU.Build.0 = Release|Any CPU
 | 
				
			||||||
 | 
							{B6062CC3-C238-40F3-B4BE-DD647300F96C}.ReleaseNoNet|Any CPU.Deploy.0 = Release|Any CPU
 | 
				
			||||||
 | 
							{B6062CC3-C238-40F3-B4BE-DD647300F96C}.ReleaseNoNet|Mixed Platforms.ActiveCfg = Release|Any CPU
 | 
				
			||||||
 | 
							{B6062CC3-C238-40F3-B4BE-DD647300F96C}.ReleaseNoNet|Mixed Platforms.Build.0 = Release|Any CPU
 | 
				
			||||||
 | 
							{B6062CC3-C238-40F3-B4BE-DD647300F96C}.ReleaseNoNet|Mixed Platforms.Deploy.0 = Release|Any CPU
 | 
				
			||||||
 | 
							{B6062CC3-C238-40F3-B4BE-DD647300F96C}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU
 | 
				
			||||||
 | 
							{B6062CC3-C238-40F3-B4BE-DD647300F96C}.ReleaseNoNet|x64.ActiveCfg = Release|Any CPU
 | 
				
			||||||
 | 
							{B6B866AF-D69C-4317-9838-51CF743E24B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 | 
				
			||||||
 | 
							{B6B866AF-D69C-4317-9838-51CF743E24B3}.Debug|Any CPU.Build.0 = Debug|Any CPU
 | 
				
			||||||
 | 
							{B6B866AF-D69C-4317-9838-51CF743E24B3}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
 | 
				
			||||||
 | 
							{B6B866AF-D69C-4317-9838-51CF743E24B3}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
 | 
				
			||||||
 | 
							{B6B866AF-D69C-4317-9838-51CF743E24B3}.Debug|Win32.ActiveCfg = Debug|Any CPU
 | 
				
			||||||
 | 
							{B6B866AF-D69C-4317-9838-51CF743E24B3}.Debug|x64.ActiveCfg = Debug|Any CPU
 | 
				
			||||||
 | 
							{B6B866AF-D69C-4317-9838-51CF743E24B3}.Release|Any CPU.ActiveCfg = Release|Any CPU
 | 
				
			||||||
 | 
							{B6B866AF-D69C-4317-9838-51CF743E24B3}.Release|Any CPU.Build.0 = Release|Any CPU
 | 
				
			||||||
 | 
							{B6B866AF-D69C-4317-9838-51CF743E24B3}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
 | 
				
			||||||
 | 
							{B6B866AF-D69C-4317-9838-51CF743E24B3}.Release|Mixed Platforms.Build.0 = Release|Any CPU
 | 
				
			||||||
 | 
							{B6B866AF-D69C-4317-9838-51CF743E24B3}.Release|Win32.ActiveCfg = Release|Any CPU
 | 
				
			||||||
 | 
							{B6B866AF-D69C-4317-9838-51CF743E24B3}.Release|x64.ActiveCfg = Release|Any CPU
 | 
				
			||||||
 | 
							{B6B866AF-D69C-4317-9838-51CF743E24B3}.ReleaseNoNet|Any CPU.ActiveCfg = Release|Any CPU
 | 
				
			||||||
 | 
							{B6B866AF-D69C-4317-9838-51CF743E24B3}.ReleaseNoNet|Any CPU.Build.0 = Release|Any CPU
 | 
				
			||||||
 | 
							{B6B866AF-D69C-4317-9838-51CF743E24B3}.ReleaseNoNet|Mixed Platforms.ActiveCfg = Release|Any CPU
 | 
				
			||||||
 | 
							{B6B866AF-D69C-4317-9838-51CF743E24B3}.ReleaseNoNet|Mixed Platforms.Build.0 = Release|Any CPU
 | 
				
			||||||
 | 
							{B6B866AF-D69C-4317-9838-51CF743E24B3}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU
 | 
				
			||||||
 | 
							{B6B866AF-D69C-4317-9838-51CF743E24B3}.ReleaseNoNet|x64.ActiveCfg = Release|Any CPU
 | 
				
			||||||
	EndGlobalSection
 | 
						EndGlobalSection
 | 
				
			||||||
	GlobalSection(SolutionProperties) = preSolution
 | 
						GlobalSection(SolutionProperties) = preSolution
 | 
				
			||||||
		HideSolutionNode = FALSE
 | 
							HideSolutionNode = FALSE
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
 | 
				
			|||||||
using System.Globalization;
 | 
					using System.Globalization;
 | 
				
			||||||
using System.IO;
 | 
					using System.IO;
 | 
				
			||||||
using System.Net;
 | 
					using System.Net;
 | 
				
			||||||
 | 
					using System.Net.Http;
 | 
				
			||||||
using System.Security;
 | 
					using System.Security;
 | 
				
			||||||
using Android;
 | 
					using Android;
 | 
				
			||||||
using Android.App;
 | 
					using Android.App;
 | 
				
			||||||
@@ -12,6 +13,7 @@ using Android.OS;
 | 
				
			|||||||
using Java.IO;
 | 
					using Java.IO;
 | 
				
			||||||
using KeePassLib.Serialization;
 | 
					using KeePassLib.Serialization;
 | 
				
			||||||
using KeePassLib.Utility;
 | 
					using KeePassLib.Utility;
 | 
				
			||||||
 | 
					using ModernHttpClient;
 | 
				
			||||||
using File = System.IO.File;
 | 
					using File = System.IO.File;
 | 
				
			||||||
using FileNotFoundException = System.IO.FileNotFoundException;
 | 
					using FileNotFoundException = System.IO.FileNotFoundException;
 | 
				
			||||||
using IOException = System.IO.IOException;
 | 
					using IOException = System.IO.IOException;
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										287
									
								
								src/Kp2aBusinessLogic/Io/HttpFileStorage.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										287
									
								
								src/Kp2aBusinessLogic/Io/HttpFileStorage.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,287 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.IO;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using System.Net;
 | 
				
			||||||
 | 
					using System.Net.Http;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using Android.App;
 | 
				
			||||||
 | 
					using Android.Content;
 | 
				
			||||||
 | 
					using Android.OS;
 | 
				
			||||||
 | 
					using Android.Runtime;
 | 
				
			||||||
 | 
					using Android.Views;
 | 
				
			||||||
 | 
					using Android.Widget;
 | 
				
			||||||
 | 
					using KeePassLib;
 | 
				
			||||||
 | 
					using KeePassLib.Serialization;
 | 
				
			||||||
 | 
					using KeePassLib.Utility;
 | 
				
			||||||
 | 
					using ModernHttpClient;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace keepass2android.Io
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						public class HttpFileStorage: IFileStorage
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							public IEnumerable<string> SupportedProtocols
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								get
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									yield return "http";
 | 
				
			||||||
 | 
									yield return "https";
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							HttpClient GetHttpClient(IOConnectionInfo ioc)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								var handler = new NativeMessageHandler();
 | 
				
			||||||
 | 
								//var handler = new HttpClientHandler();
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								if ((ioc.UserName.Length > 0) || (ioc.Password.Length > 0))
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									int backslashPos = ioc.UserName.IndexOf("\\", StringComparison.Ordinal);
 | 
				
			||||||
 | 
									if (backslashPos > 0)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										string domain = ioc.UserName.Substring(0, backslashPos);
 | 
				
			||||||
 | 
										string user = ioc.UserName.Substring(backslashPos + 1);
 | 
				
			||||||
 | 
										handler.Credentials = new NetworkCredential(user, ioc.Password, domain);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									else
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										handler.PreAuthenticate = true;
 | 
				
			||||||
 | 
										handler.Credentials = new NetworkCredential(ioc.UserName, ioc.Password);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return new HttpClient(handler);
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public void Delete(IOConnectionInfo ioc)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								GetHttpClient(ioc).DeleteAsync(ioc.Path).Result.EnsureSuccessStatusCode();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public bool CheckForFileChangeFast(IOConnectionInfo ioc, string previousFileVersion)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public string GetCurrentFileVersionFast(IOConnectionInfo ioc)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return null;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public Stream OpenFileForRead(IOConnectionInfo ioc)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return GetHttpClient(ioc).GetStreamAsync(ioc.Path).Result;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							class UploadOnCloseMemoryStream : MemoryStream
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								IOConnectionInfo ioc;
 | 
				
			||||||
 | 
								private HttpClient client;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								public UploadOnCloseMemoryStream(IOConnectionInfo _ioc, HttpClient _client)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									this.ioc = _ioc;
 | 
				
			||||||
 | 
									this.client = _client;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								public override void Close()
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									base.Close();
 | 
				
			||||||
 | 
									var msg = new HttpRequestMessage(HttpMethod.Put, ioc.Path);
 | 
				
			||||||
 | 
									msg.Headers.Add("Translate", "f");
 | 
				
			||||||
 | 
									msg.Content = new StreamContent(new MemoryStream(this.ToArray()));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									client.SendAsync(msg).Result.EnsureSuccessStatusCode();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							public class UntransactedWrite : IWriteTransaction
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								private readonly IOConnectionInfo _ioc;
 | 
				
			||||||
 | 
								private readonly HttpClient _client;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								public UntransactedWrite(IOConnectionInfo ioc, HttpClient client)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									_ioc = ioc;
 | 
				
			||||||
 | 
									_client = client;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								public void Dispose()
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								public Stream OpenFile()
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									return new UploadOnCloseMemoryStream(_ioc, _client);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								public void CommitWrite()
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public class TransactedWrite : IWriteTransaction
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								private readonly IOConnectionInfo _ioc;
 | 
				
			||||||
 | 
								private readonly HttpFileStorage _fileStorage;
 | 
				
			||||||
 | 
								private readonly IOConnectionInfo _iocTemp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								public TransactedWrite(IOConnectionInfo ioc, HttpFileStorage fileStorage)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									_ioc = ioc;
 | 
				
			||||||
 | 
									_iocTemp = _ioc.CloneDeep();
 | 
				
			||||||
 | 
									_iocTemp.Path += "." + new PwUuid(true).ToHexString().Substring(0, 6) + ".tmp";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									_fileStorage = fileStorage;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								public void Dispose()
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								public Stream OpenFile()
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									return new UploadOnCloseMemoryStream(_ioc, _fileStorage.GetHttpClient(_ioc));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								public void CommitWrite()
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									var client = _fileStorage.GetHttpClient(_ioc);
 | 
				
			||||||
 | 
									client.DeleteAsync(_ioc.Path).Result.EnsureSuccessStatusCode();
 | 
				
			||||||
 | 
									var msg = new HttpRequestMessage(new HttpMethod("MOVE"), _iocTemp.Path);
 | 
				
			||||||
 | 
									msg.Headers.Add("Destination",  _ioc.Path);
 | 
				
			||||||
 | 
									client.SendAsync(msg).Result.EnsureSuccessStatusCode();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public IWriteTransaction OpenWriteTransaction(IOConnectionInfo ioc, bool useFileTransaction)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (useFileTransaction)
 | 
				
			||||||
 | 
									return new TransactedWrite(ioc, this);
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
									return new UntransactedWrite(ioc, GetHttpClient(ioc));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public string GetFilenameWithoutPathAndExt(IOConnectionInfo ioc)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return UrlUtil.StripExtension(
 | 
				
			||||||
 | 
									UrlUtil.GetFileName(ioc.Path));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public bool RequiresCredentials(IOConnectionInfo ioc)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return ioc.CredSaveMode != IOCredSaveMode.SaveCred;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public void CreateDirectory(IOConnectionInfo ioc, string newDirName)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								throw new NotImplementedException();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public IEnumerable<FileDescription> ListContents(IOConnectionInfo ioc)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								throw new NotImplementedException();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public FileDescription GetFileDescription(IOConnectionInfo ioc)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								throw new NotImplementedException();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public bool RequiresSetup(IOConnectionInfo ioConnection)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public string IocToPath(IOConnectionInfo ioc)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return ioc.Path;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public void StartSelectFile(IFileStorageSetupInitiatorActivity activity, bool isForSave, int requestCode, string protocolId)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								activity.PerformManualFileSelect(isForSave, requestCode, protocolId);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public void PrepareFileUsage(IFileStorageSetupInitiatorActivity activity, IOConnectionInfo ioc, int requestCode,
 | 
				
			||||||
 | 
								bool alwaysReturnSuccess)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								Intent intent = new Intent();
 | 
				
			||||||
 | 
								activity.IocToIntent(intent, ioc);
 | 
				
			||||||
 | 
								activity.OnImmediateResult(requestCode, (int)FileStorageResults.FileUsagePrepared, intent);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public void PrepareFileUsage(Context ctx, IOConnectionInfo ioc)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public void OnCreate(IFileStorageSetupActivity activity, Bundle savedInstanceState)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public void OnResume(IFileStorageSetupActivity activity)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public void OnStart(IFileStorageSetupActivity activity)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public void OnActivityResult(IFileStorageSetupActivity activity, int requestCode, int resultCode, Intent data)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public string GetDisplayName(IOConnectionInfo ioc)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return ioc.GetDisplayName();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public string CreateFilePath(string parent, string newFilename)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (!parent.EndsWith("/"))
 | 
				
			||||||
 | 
									parent += "/";
 | 
				
			||||||
 | 
								return parent + newFilename;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public IOConnectionInfo GetParentPath(IOConnectionInfo ioc)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return IoUtil.GetParentPath(ioc);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public IOConnectionInfo GetFilePath(IOConnectionInfo folderPath, string filename)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								IOConnectionInfo res = folderPath.CloneDeep();
 | 
				
			||||||
 | 
								if (!res.Path.EndsWith("/"))
 | 
				
			||||||
 | 
									res.Path += "/";
 | 
				
			||||||
 | 
								res.Path += filename;
 | 
				
			||||||
 | 
								return res;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public bool IsPermanentLocation(IOConnectionInfo ioc)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							public bool IsReadOnly(IOConnectionInfo ioc, OptionalOut<UiStringKey> reason = null)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public void ResolveAccount(IOConnectionInfo ioc)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										399
									
								
								src/Kp2aBusinessLogic/Io/NetFtpFileStorage.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										399
									
								
								src/Kp2aBusinessLogic/Io/NetFtpFileStorage.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,399 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.IO;
 | 
				
			||||||
 | 
					using System.Net;
 | 
				
			||||||
 | 
					using System.Net.FtpClient;
 | 
				
			||||||
 | 
					using Android.Content;
 | 
				
			||||||
 | 
					using Android.OS;
 | 
				
			||||||
 | 
					using Android.Preferences;
 | 
				
			||||||
 | 
					using KeePassLib;
 | 
				
			||||||
 | 
					using KeePassLib.Serialization;
 | 
				
			||||||
 | 
					using KeePassLib.Utility;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace keepass2android.Io
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						public class NetFtpFileStorage: IFileStorage
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							struct ConnectionSettings
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								public FtpEncryptionMode EncryptionMode {get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								public static ConnectionSettings FromIoc(IOConnectionInfo ioc)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (ioc.Path.StartsWith(Kp2AAccountPathPrefix))
 | 
				
			||||||
 | 
										throw new InvalidOperationException("cannot extract settings from account-path");
 | 
				
			||||||
 | 
									string path = ioc.Path;
 | 
				
			||||||
 | 
									int schemeLength = path.IndexOf("://", StringComparison.Ordinal);
 | 
				
			||||||
 | 
									path = path.Substring(schemeLength + 3);
 | 
				
			||||||
 | 
									string settings = path.Substring(0, path.IndexOf("/", StringComparison.Ordinal));
 | 
				
			||||||
 | 
									return new ConnectionSettings()
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										EncryptionMode = (FtpEncryptionMode) int.Parse(settings)
 | 
				
			||||||
 | 
									};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							private const string Kp2AAccountPathPrefix = "__kp2a_account__";
 | 
				
			||||||
 | 
							private readonly Context _context;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public NetFtpFileStorage(Context context)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								_context = context;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public IEnumerable<string> SupportedProtocols
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								get { yield return "ftp"; }
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public void Delete(IOConnectionInfo ioc)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								using (FtpClient client = GetClient(ioc))
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									client.DeleteFile(IocPathToUri(ioc.Path).PathAndQuery);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							internal FtpClient GetClient(IOConnectionInfo ioc, bool enableCloneClient = true)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								FtpClient client = new FtpClient();
 | 
				
			||||||
 | 
								if ((ioc.UserName.Length > 0) || (ioc.Password.Length > 0))
 | 
				
			||||||
 | 
									client.Credentials = new NetworkCredential(ioc.UserName, ioc.Password);
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
									client.Credentials = new NetworkCredential("anonymous", ""); //TODO TEST
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								Uri uri = IocPathToUri(ioc.Path);
 | 
				
			||||||
 | 
								client.Host = uri.Host;
 | 
				
			||||||
 | 
								if (!uri.IsDefaultPort) //TODO test
 | 
				
			||||||
 | 
									client.Port = uri.Port;
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//TODO Validate 
 | 
				
			||||||
 | 
								//client.ValidateCertificate += app...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// we don't need to be thread safe in a classic sense, but OpenRead and OpenWrite don't 
 | 
				
			||||||
 | 
								//perform the actual stream operation so we'd need to wrap the stream (or just enable this:)
 | 
				
			||||||
 | 
								client.EnableThreadSafeDataConnections = enableCloneClient;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								client.EncryptionMode = ConnectionSettings.FromIoc(ioc).EncryptionMode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								client.Connect();
 | 
				
			||||||
 | 
								return client;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							internal Uri IocPathToUri(string path)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								//remove addition stuff like TLS param
 | 
				
			||||||
 | 
								int schemeLength = path.IndexOf("://", StringComparison.Ordinal);
 | 
				
			||||||
 | 
								string scheme = path.Substring(0, schemeLength);
 | 
				
			||||||
 | 
								path = path.Substring(schemeLength + 3);
 | 
				
			||||||
 | 
								string settings = path.Substring(0, path.IndexOf("/", StringComparison.Ordinal));
 | 
				
			||||||
 | 
								path = path.Substring(settings.Length + 1);
 | 
				
			||||||
 | 
								return new Uri(scheme + "://" + path);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							private string IocPathFromUri(IOConnectionInfo baseIoc, Uri uri)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								string basePath = baseIoc.Path;
 | 
				
			||||||
 | 
								int schemeLength = basePath.IndexOf("://", StringComparison.Ordinal);
 | 
				
			||||||
 | 
								string scheme = basePath.Substring(0, schemeLength);
 | 
				
			||||||
 | 
								basePath = basePath.Substring(schemeLength + 3);
 | 
				
			||||||
 | 
								string baseSettings = basePath.Substring(0, basePath.IndexOf("/", StringComparison.Ordinal));
 | 
				
			||||||
 | 
								return scheme + "://" + baseSettings + "/" + uri.AbsolutePath; //TODO does this contain Query?
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public bool CheckForFileChangeFast(IOConnectionInfo ioc, string previousFileVersion)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public string GetCurrentFileVersionFast(IOConnectionInfo ioc)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return null;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public Stream OpenFileForRead(IOConnectionInfo ioc)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								using (var cl = GetClient(ioc))
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									return cl.OpenRead(IocPathToUri(ioc.Path).PathAndQuery, FtpDataType.Binary, 0);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public IWriteTransaction OpenWriteTransaction(IOConnectionInfo ioc, bool useFileTransaction)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (useFileTransaction)
 | 
				
			||||||
 | 
									return new UntransactedWrite(ioc, this);
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
									return new TransactedWrite(ioc, this);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public string GetFilenameWithoutPathAndExt(IOConnectionInfo ioc)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								//TODO does this work when flags are encoded in the iocPath?
 | 
				
			||||||
 | 
								return UrlUtil.StripExtension(
 | 
				
			||||||
 | 
									UrlUtil.GetFileName(ioc.Path));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public bool RequiresCredentials(IOConnectionInfo ioc)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return ioc.CredSaveMode != IOCredSaveMode.SaveCred;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public void CreateDirectory(IOConnectionInfo ioc, string newDirName)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								using (var client = GetClient(ioc))
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									client.CreateDirectory(IocPathToUri(ioc.Path).PathAndQuery);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public IEnumerable<FileDescription> ListContents(IOConnectionInfo ioc)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								using (var client = GetClient(ioc))
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									List<FileDescription> files = new List<FileDescription>();
 | 
				
			||||||
 | 
									foreach (FtpListItem item in client.GetListing(IocPathToUri(ioc.Path).PathAndQuery,
 | 
				
			||||||
 | 
										FtpListOption.Modify | FtpListOption.Size | FtpListOption.DerefLinks))
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										switch (item.Type)
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											case FtpFileSystemObjectType.Directory:
 | 
				
			||||||
 | 
												files.Add(new FileDescription()
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													CanRead =  true, 
 | 
				
			||||||
 | 
													CanWrite = true,
 | 
				
			||||||
 | 
													DisplayName = item.Name,
 | 
				
			||||||
 | 
													IsDirectory = true,
 | 
				
			||||||
 | 
													LastModified = item.Modified,
 | 
				
			||||||
 | 
													Path = IocPathFromUri(ioc, new Uri(item.FullName))
 | 
				
			||||||
 | 
												});
 | 
				
			||||||
 | 
												break;
 | 
				
			||||||
 | 
											case FtpFileSystemObjectType.File:
 | 
				
			||||||
 | 
												files.Add(new FileDescription()
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													CanRead =  true, 
 | 
				
			||||||
 | 
													CanWrite = true,
 | 
				
			||||||
 | 
													DisplayName = item.Name,
 | 
				
			||||||
 | 
													IsDirectory = false,
 | 
				
			||||||
 | 
													LastModified = item.Modified,
 | 
				
			||||||
 | 
													Path = IocPathFromUri(ioc, new Uri(item.FullName)),
 | 
				
			||||||
 | 
													SizeInBytes = item.Size
 | 
				
			||||||
 | 
												});
 | 
				
			||||||
 | 
												break;
 | 
				
			||||||
 | 
											
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									return files;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							public FileDescription GetFileDescription(IOConnectionInfo ioc)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								//TODO when is this called? 
 | 
				
			||||||
 | 
								//is it very inefficient to connect for each description?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								using (FtpClient client = GetClient(ioc))
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									var uri = IocPathToUri(ioc.Path);
 | 
				
			||||||
 | 
									string path = uri.PathAndQuery;
 | 
				
			||||||
 | 
									return new FileDescription()
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										CanRead = true,
 | 
				
			||||||
 | 
										CanWrite = true,
 | 
				
			||||||
 | 
										Path = ioc.Path,
 | 
				
			||||||
 | 
										LastModified = client.GetModifiedTime(path),
 | 
				
			||||||
 | 
										SizeInBytes = client.GetFileSize(path),
 | 
				
			||||||
 | 
										DisplayName = UrlUtil.GetFileName(path),
 | 
				
			||||||
 | 
										IsDirectory = false
 | 
				
			||||||
 | 
									};
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public bool RequiresSetup(IOConnectionInfo ioConnection)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public string IocToPath(IOConnectionInfo ioc)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return ioc.Path;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public void StartSelectFile(IFileStorageSetupInitiatorActivity activity, bool isForSave, int requestCode, string protocolId)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								throw new NotImplementedException();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public void PrepareFileUsage(IFileStorageSetupInitiatorActivity activity, IOConnectionInfo ioc, int requestCode,
 | 
				
			||||||
 | 
								bool alwaysReturnSuccess)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								Intent intent = new Intent();
 | 
				
			||||||
 | 
								activity.IocToIntent(intent, ioc);
 | 
				
			||||||
 | 
								activity.OnImmediateResult(requestCode, (int)FileStorageResults.FileUsagePrepared, intent);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public void PrepareFileUsage(Context ctx, IOConnectionInfo ioc)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public void OnCreate(IFileStorageSetupActivity activity, Bundle savedInstanceState)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public void OnResume(IFileStorageSetupActivity activity)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public void OnStart(IFileStorageSetupActivity activity)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public void OnActivityResult(IFileStorageSetupActivity activity, int requestCode, int resultCode, Intent data)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public string GetDisplayName(IOConnectionInfo ioc)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								var uri = IocPathToUri(ioc.Path);
 | 
				
			||||||
 | 
								return uri.ToString(); //TODO is this good?
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public string CreateFilePath(string parent, string newFilename)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (!parent.EndsWith("/"))
 | 
				
			||||||
 | 
									parent += "/";
 | 
				
			||||||
 | 
								return parent + newFilename;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public IOConnectionInfo GetParentPath(IOConnectionInfo ioc)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return IoUtil.GetParentPath(ioc);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public IOConnectionInfo GetFilePath(IOConnectionInfo folderPath, string filename)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								IOConnectionInfo res = folderPath.CloneDeep();
 | 
				
			||||||
 | 
								if (!res.Path.EndsWith("/"))
 | 
				
			||||||
 | 
									res.Path += "/";
 | 
				
			||||||
 | 
								res.Path += filename;
 | 
				
			||||||
 | 
								return res;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public bool IsPermanentLocation(IOConnectionInfo ioc)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public bool IsReadOnly(IOConnectionInfo ioc, OptionalOut<UiStringKey> reason = null)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public void ResolveAccount(IOConnectionInfo ioc)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								string path = ioc.Path;
 | 
				
			||||||
 | 
								int schemeLength = path.IndexOf("://", StringComparison.Ordinal);
 | 
				
			||||||
 | 
								string scheme = path.Substring(0, schemeLength);
 | 
				
			||||||
 | 
								path = path.Substring(schemeLength+3);
 | 
				
			||||||
 | 
								if (path.StartsWith(Kp2AAccountPathPrefix))
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									string accountId = path.Substring(0, path.IndexOf("/", StringComparison.Ordinal));
 | 
				
			||||||
 | 
									path = path.Substring(accountId.Length + 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									var prefs = PreferenceManager.GetDefaultSharedPreferences(_context);
 | 
				
			||||||
 | 
									string host = prefs.GetString(accountId + "_Host", null);
 | 
				
			||||||
 | 
									int port = prefs.GetInt(accountId + "_Port", 0 /* auto*/);
 | 
				
			||||||
 | 
									string initialPath = prefs.GetString(accountId + "_InitPath", "");
 | 
				
			||||||
 | 
									if (initialPath.StartsWith("/"))
 | 
				
			||||||
 | 
										initialPath = initialPath.Substring(1);
 | 
				
			||||||
 | 
									if ((!initialPath.EndsWith("/") && (initialPath != "")))
 | 
				
			||||||
 | 
										initialPath += "/";
 | 
				
			||||||
 | 
									int encMode = prefs.GetInt(accountId + "_EncMode", (int) FtpEncryptionMode.None);
 | 
				
			||||||
 | 
									string settings = encMode.ToString();
 | 
				
			||||||
 | 
									ioc.Path = scheme + "://" + settings + "/" + host + (port == 0 ? "" : (":" + port)) + "/" + initialPath + path;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public Stream OpenWrite(IOConnectionInfo ioc)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								using (var client = GetClient(ioc))
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									return client.OpenWrite(IocPathToUri(ioc.Path).PathAndQuery);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public class TransactedWrite : IWriteTransaction
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							private readonly IOConnectionInfo _ioc;
 | 
				
			||||||
 | 
							private readonly NetFtpFileStorage _fileStorage;
 | 
				
			||||||
 | 
							private readonly IOConnectionInfo _iocTemp;
 | 
				
			||||||
 | 
							private FtpClient _client;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public TransactedWrite(IOConnectionInfo ioc, NetFtpFileStorage fileStorage)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								_ioc = ioc;
 | 
				
			||||||
 | 
								_iocTemp = _ioc.CloneDeep();
 | 
				
			||||||
 | 
								_iocTemp.Path += "." + new PwUuid(true).ToHexString().Substring(0, 6) + ".tmp";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								_fileStorage = fileStorage;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public void Dispose()
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (_client != null)
 | 
				
			||||||
 | 
									_client.Dispose();
 | 
				
			||||||
 | 
								_client = null;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public Stream OpenFile()
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								_client = _fileStorage.GetClient(_ioc, false);
 | 
				
			||||||
 | 
								return _client.OpenWrite(_fileStorage.IocPathToUri(_iocTemp.Path).PathAndQuery);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public void CommitWrite()
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								_client.DeleteFile(_fileStorage.IocPathToUri(_ioc.Path).PathAndQuery);
 | 
				
			||||||
 | 
								_client.Rename(_fileStorage.IocPathToUri(_iocTemp.Path).PathAndQuery, _fileStorage.IocPathToUri(_ioc.Path).PathAndQuery);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public class UntransactedWrite : IWriteTransaction
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							private readonly IOConnectionInfo _ioc;
 | 
				
			||||||
 | 
							private readonly NetFtpFileStorage _fileStorage;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public UntransactedWrite(IOConnectionInfo ioc, NetFtpFileStorage fileStorage)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								_ioc = ioc;
 | 
				
			||||||
 | 
								_fileStorage = fileStorage;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public void Dispose()
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public Stream OpenFile()
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return _fileStorage.OpenWrite(_ioc);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public void CommitWrite()
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -47,11 +47,18 @@
 | 
				
			|||||||
    <WarningLevel>4</WarningLevel>
 | 
					    <WarningLevel>4</WarningLevel>
 | 
				
			||||||
  </PropertyGroup>
 | 
					  </PropertyGroup>
 | 
				
			||||||
  <ItemGroup>
 | 
					  <ItemGroup>
 | 
				
			||||||
 | 
					    <Reference Include="ModernHttpClient">
 | 
				
			||||||
 | 
					      <HintPath>..\Components\modernhttpclient-2.4.2\lib\android\ModernHttpClient.dll</HintPath>
 | 
				
			||||||
 | 
					    </Reference>
 | 
				
			||||||
    <Reference Include="Mono.Android" />
 | 
					    <Reference Include="Mono.Android" />
 | 
				
			||||||
    <Reference Include="Mono.Security" />
 | 
					    <Reference Include="Mono.Security" />
 | 
				
			||||||
    <Reference Include="mscorlib" />
 | 
					    <Reference Include="mscorlib" />
 | 
				
			||||||
 | 
					    <Reference Include="OkHttp">
 | 
				
			||||||
 | 
					      <HintPath>..\Components\modernhttpclient-2.4.2\lib\android\OkHttp.dll</HintPath>
 | 
				
			||||||
 | 
					    </Reference>
 | 
				
			||||||
    <Reference Include="System" />
 | 
					    <Reference Include="System" />
 | 
				
			||||||
    <Reference Include="System.Core" />
 | 
					    <Reference Include="System.Core" />
 | 
				
			||||||
 | 
					    <Reference Include="System.Net.Http" />
 | 
				
			||||||
    <Reference Include="System.Xml.Linq" />
 | 
					    <Reference Include="System.Xml.Linq" />
 | 
				
			||||||
    <Reference Include="System.Xml" />
 | 
					    <Reference Include="System.Xml" />
 | 
				
			||||||
    <Reference Include="Xamarin.Insights">
 | 
					    <Reference Include="Xamarin.Insights">
 | 
				
			||||||
@@ -83,6 +90,7 @@
 | 
				
			|||||||
    <Compile Include="Io\FileStorageSetupActivity.cs" />
 | 
					    <Compile Include="Io\FileStorageSetupActivity.cs" />
 | 
				
			||||||
    <Compile Include="Io\FileStorageSetupInitiatorActivity.cs" />
 | 
					    <Compile Include="Io\FileStorageSetupInitiatorActivity.cs" />
 | 
				
			||||||
    <Compile Include="Io\GDriveFileStorage.cs" />
 | 
					    <Compile Include="Io\GDriveFileStorage.cs" />
 | 
				
			||||||
 | 
					    <Compile Include="Io\HttpFileStorage.cs" />
 | 
				
			||||||
    <Compile Include="Io\IFileStorage.cs" />
 | 
					    <Compile Include="Io\IFileStorage.cs" />
 | 
				
			||||||
    <Compile Include="Io\IoUtil.cs" />
 | 
					    <Compile Include="Io\IoUtil.cs" />
 | 
				
			||||||
    <Compile Include="Io\JavaFileStorage.cs" />
 | 
					    <Compile Include="Io\JavaFileStorage.cs" />
 | 
				
			||||||
@@ -149,6 +157,12 @@
 | 
				
			|||||||
  <ItemGroup>
 | 
					  <ItemGroup>
 | 
				
			||||||
    <Folder Include="Resources\" />
 | 
					    <Folder Include="Resources\" />
 | 
				
			||||||
  </ItemGroup>
 | 
					  </ItemGroup>
 | 
				
			||||||
 | 
					  <ItemGroup>
 | 
				
			||||||
 | 
					    <XamarinComponentReference Include="modernhttpclient">
 | 
				
			||||||
 | 
					      <Visible>False</Visible>
 | 
				
			||||||
 | 
					      <Version>2.4.2</Version>
 | 
				
			||||||
 | 
					    </XamarinComponentReference>
 | 
				
			||||||
 | 
					  </ItemGroup>
 | 
				
			||||||
  <Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
 | 
					  <Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
 | 
				
			||||||
  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
 | 
					  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
 | 
				
			||||||
       Other similar extension points exist, see Microsoft.Common.targets.
 | 
					       Other similar extension points exist, see Microsoft.Common.targets.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -286,7 +286,7 @@ namespace keepass2android
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
			ioc.Obfuscate(false);
 | 
								ioc.Obfuscate(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			App.Kp2a.GetFileStorage(ioc).ResolveAccount(ioc);
 | 
								//TODO enable for 1.1 release App.Kp2a.GetFileStorage(ioc).ResolveAccount(ioc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			return ioc;
 | 
								return ioc;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -219,7 +219,7 @@ namespace keepass2android
 | 
				
			|||||||
					TextView textView = (TextView)view;
 | 
										TextView textView = (TextView)view;
 | 
				
			||||||
					IOConnectionInfo ioc = new IOConnectionInfo {Path = path};
 | 
										IOConnectionInfo ioc = new IOConnectionInfo {Path = path};
 | 
				
			||||||
					var fileStorage = _app.GetFileStorage(ioc);
 | 
										var fileStorage = _app.GetFileStorage(ioc);
 | 
				
			||||||
					fileStorage.ResolveAccount(ioc);
 | 
										//TODO enable for 1.1 release fileStorage.ResolveAccount(ioc);
 | 
				
			||||||
					textView.Text = fileStorage.GetDisplayName(ioc);
 | 
										textView.Text = fileStorage.GetDisplayName(ioc);
 | 
				
			||||||
					textView.Tag = ioc.Path;
 | 
										textView.Tag = ioc.Path;
 | 
				
			||||||
					return true;
 | 
										return true;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -84,6 +84,7 @@
 | 
				
			|||||||
  </PropertyGroup>
 | 
					  </PropertyGroup>
 | 
				
			||||||
  <ItemGroup>
 | 
					  <ItemGroup>
 | 
				
			||||||
    <Reference Include="System" />
 | 
					    <Reference Include="System" />
 | 
				
			||||||
 | 
					    <Reference Include="System.Net.Http" />
 | 
				
			||||||
    <Reference Include="System.Xml" />
 | 
					    <Reference Include="System.Xml" />
 | 
				
			||||||
    <Reference Include="System.Core" />
 | 
					    <Reference Include="System.Core" />
 | 
				
			||||||
    <Reference Include="Mono.Android" />
 | 
					    <Reference Include="Mono.Android" />
 | 
				
			||||||
@@ -1679,4 +1680,9 @@
 | 
				
			|||||||
    </PropertyGroup>
 | 
					    </PropertyGroup>
 | 
				
			||||||
    <Error Condition="!Exists('..\packages\Xamarin.Insights.1.11.3\build\MonoAndroid10\Xamarin.Insights.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Insights.1.11.3\build\MonoAndroid10\Xamarin.Insights.targets'))" />
 | 
					    <Error Condition="!Exists('..\packages\Xamarin.Insights.1.11.3\build\MonoAndroid10\Xamarin.Insights.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Insights.1.11.3\build\MonoAndroid10\Xamarin.Insights.targets'))" />
 | 
				
			||||||
  </Target>
 | 
					  </Target>
 | 
				
			||||||
 | 
					  <Import Project="..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets" Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" />
 | 
				
			||||||
 | 
					  <Target Name="EnsureBclBuildImported" BeforeTargets="BeforeBuild" Condition="'$(BclBuildImported)' == ''">
 | 
				
			||||||
 | 
					    <Error Condition="!Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" Text="This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=317567." HelpKeyword="BCLBUILD2001" />
 | 
				
			||||||
 | 
					    <Error Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" Text="The build restored NuGet packages. Build the project again to include these packages in the build. For more information, see http://go.microsoft.com/fwlink/?LinkID=317568." HelpKeyword="BCLBUILD2002" />
 | 
				
			||||||
 | 
					  </Target>
 | 
				
			||||||
</Project>
 | 
					</Project>
 | 
				
			||||||
@@ -1,5 +1,7 @@
 | 
				
			|||||||
<?xml version="1.0" encoding="utf-8"?>
 | 
					<?xml version="1.0" encoding="utf-8"?>
 | 
				
			||||||
<packages>
 | 
					<packages>
 | 
				
			||||||
 | 
					  <package id="Microsoft.Bcl" version="1.1.10" targetFramework="MonoAndroid60" />
 | 
				
			||||||
 | 
					  <package id="Microsoft.Bcl.Build" version="1.0.14" targetFramework="MonoAndroid60" />
 | 
				
			||||||
  <package id="Xamarin.Android.Support.Design" version="22.2.1.0" targetFramework="MonoAndroid50" />
 | 
					  <package id="Xamarin.Android.Support.Design" version="22.2.1.0" targetFramework="MonoAndroid50" />
 | 
				
			||||||
  <package id="Xamarin.Android.Support.v4" version="22.2.1.0" targetFramework="MonoAndroid50" />
 | 
					  <package id="Xamarin.Android.Support.v4" version="22.2.1.0" targetFramework="MonoAndroid50" />
 | 
				
			||||||
  <package id="Xamarin.Android.Support.v7.AppCompat" version="22.2.1.0" targetFramework="MonoAndroid50" />
 | 
					  <package id="Xamarin.Android.Support.v7.AppCompat" version="22.2.1.0" targetFramework="MonoAndroid50" />
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user