242 lines
6.8 KiB
C#
242 lines
6.8 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
|
|
using Android.App;
|
|
using Android.Content;
|
|
using Android.OS;
|
|
using Android.Runtime;
|
|
using Android.Views;
|
|
using Android.Widget;
|
|
using Java.IO;
|
|
using keepass2android.Io;
|
|
using KeePassLib.Serialization;
|
|
using KeePassLib.Utility;
|
|
|
|
namespace keepass2android
|
|
{
|
|
public class FileSelectHelper
|
|
{
|
|
private readonly Activity _activity;
|
|
private readonly bool _isForSave;
|
|
private readonly int _requestCode;
|
|
|
|
public string DefaultExtension { get; set; }
|
|
|
|
public FileSelectHelper(Activity activity, bool isForSave, int requestCode)
|
|
{
|
|
_activity = activity;
|
|
_isForSave = isForSave;
|
|
_requestCode = requestCode;
|
|
}
|
|
|
|
private void ShowSftpDialog(Activity activity, Util.FileSelectedHandler onStartBrowse, Action onCancel)
|
|
{
|
|
#if !EXCLUDE_JAVAFILESTORAGE && !NoNet
|
|
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
|
View dlgContents = activity.LayoutInflater.Inflate(Resource.Layout.sftpcredentials, null);
|
|
builder.SetView(dlgContents);
|
|
builder.SetPositiveButton(Android.Resource.String.Ok,
|
|
(sender, args) =>
|
|
{
|
|
string host = dlgContents.FindViewById<EditText>(Resource.Id.sftp_host).Text;
|
|
string portText = dlgContents.FindViewById<EditText>(Resource.Id.sftp_port).Text;
|
|
int port = Keepass2android.Javafilestorage.SftpStorage.DefaultSftpPort;
|
|
if (!string.IsNullOrEmpty(portText))
|
|
int.TryParse(portText, out port);
|
|
string user = dlgContents.FindViewById<EditText>(Resource.Id.sftp_user).Text;
|
|
string password = dlgContents.FindViewById<EditText>(Resource.Id.sftp_password).Text;
|
|
string initialPath = dlgContents.FindViewById<EditText>(Resource.Id.sftp_initial_dir).Text;
|
|
string sftpPath = new Keepass2android.Javafilestorage.SftpStorage().BuildFullPath(host, port, initialPath, user,
|
|
password);
|
|
onStartBrowse(sftpPath);
|
|
});
|
|
EventHandler<DialogClickEventArgs> evtH = new EventHandler<DialogClickEventArgs>((sender, e) => onCancel());
|
|
|
|
builder.SetNegativeButton(Android.Resource.String.Cancel, evtH);
|
|
builder.SetTitle(activity.GetString(Resource.String.enter_sftp_login_title));
|
|
Dialog dialog = builder.Create();
|
|
|
|
dialog.Show();
|
|
#endif
|
|
}
|
|
|
|
public void PerformManualFileSelect(string defaultPath)
|
|
{
|
|
if (defaultPath.StartsWith("sftp://"))
|
|
ShowSftpDialog(_activity, StartFileChooser, ReturnCancel);
|
|
else
|
|
{
|
|
Func<string, Dialog, bool> onOpen = (filename, dialog) => OnOpenButton(filename, dialog);
|
|
Util.ShowFilenameDialog(_activity,
|
|
!_isForSave ? onOpen : null,
|
|
_isForSave ? onOpen : null,
|
|
ReturnCancel,
|
|
false,
|
|
defaultPath,
|
|
_activity.GetString(Resource.String.enter_filename_details_url),
|
|
_requestCode)
|
|
;
|
|
}
|
|
}
|
|
|
|
private void ReturnCancel()
|
|
{
|
|
if (OnCancel != null)
|
|
OnCancel(this, null);
|
|
}
|
|
|
|
|
|
protected void ShowFilenameWarning(string fileName, Action onUserWantsToContinue, Action onUserWantsToCorrect)
|
|
{
|
|
new AlertDialog.Builder(_activity)
|
|
.SetPositiveButton(keepass2android.Resource.String.Continue, delegate { onUserWantsToContinue(); })
|
|
.SetMessage(Resource.String.NoFilenameWarning)
|
|
.SetCancelable(false)
|
|
.SetNegativeButton(Android.Resource.String.Cancel, delegate { onUserWantsToCorrect(); })
|
|
.Create()
|
|
.Show();
|
|
|
|
}
|
|
private bool OnOpenButton(string filename, Dialog dialog)
|
|
{
|
|
|
|
IOConnectionInfo ioc = new IOConnectionInfo
|
|
{
|
|
Path = filename
|
|
};
|
|
|
|
// Make sure file name exists
|
|
if (filename.Length == 0)
|
|
{
|
|
Toast.MakeText(_activity,
|
|
Resource.String.error_filename_required,
|
|
ToastLength.Long).Show();
|
|
return false;
|
|
}
|
|
|
|
|
|
int lastSlashPos = filename.LastIndexOf('/');
|
|
int lastDotPos = filename.LastIndexOf('.');
|
|
if (lastSlashPos >= lastDotPos) //no dot after last slash or == in case neither / nor .
|
|
{
|
|
ShowFilenameWarning(filename, () => { IocSelected(ioc); dialog.Dismiss(); }, () => { /* don't do anything, leave dialog open, let user try again*/ });
|
|
//signal that the dialog should be kept open
|
|
return false;
|
|
}
|
|
|
|
IFileStorage fileStorage;
|
|
try
|
|
{
|
|
fileStorage = App.Kp2a.GetFileStorage(ioc);
|
|
}
|
|
catch (NoFileStorageFoundException)
|
|
{
|
|
Toast.MakeText(_activity,
|
|
"Unexpected scheme in "+filename,
|
|
ToastLength.Long).Show();
|
|
return false;
|
|
}
|
|
|
|
if (_isForSave && ioc.IsLocalFile())
|
|
{
|
|
// Try to create the file
|
|
File file = new File(filename);
|
|
try
|
|
{
|
|
File parent = file.ParentFile;
|
|
|
|
if (parent == null || (parent.Exists() && !parent.IsDirectory))
|
|
{
|
|
Toast.MakeText(_activity,
|
|
Resource.String.error_invalid_path,
|
|
ToastLength.Long).Show();
|
|
return false;
|
|
}
|
|
|
|
if (!parent.Exists())
|
|
{
|
|
// Create parent dircetory
|
|
if (!parent.Mkdirs())
|
|
{
|
|
Toast.MakeText(_activity,
|
|
Resource.String.error_could_not_create_parent,
|
|
ToastLength.Long).Show();
|
|
return false;
|
|
|
|
}
|
|
}
|
|
System.IO.File.Create(filename);
|
|
|
|
}
|
|
catch (IOException ex)
|
|
{
|
|
Toast.MakeText(
|
|
_activity,
|
|
_activity.GetText(Resource.String.error_file_not_create) + " "
|
|
+ ex.LocalizedMessage,
|
|
ToastLength.Long).Show();
|
|
return false;
|
|
}
|
|
|
|
}
|
|
if (fileStorage.RequiresCredentials(ioc))
|
|
{
|
|
Util.QueryCredentials(ioc, IocSelected, _activity);
|
|
}
|
|
else
|
|
{
|
|
IocSelected(ioc);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private void IocSelected(IOConnectionInfo ioc)
|
|
{
|
|
if (OnOpen != null)
|
|
OnOpen(this, ioc);
|
|
}
|
|
|
|
public bool StartFileChooser(string defaultPath)
|
|
{
|
|
#if !EXCLUDE_FILECHOOSER
|
|
Kp2aLog.Log("FSA: defaultPath=" + defaultPath);
|
|
string fileProviderAuthority = FileChooserFileProvider.TheAuthority;
|
|
if (defaultPath.StartsWith("file://"))
|
|
{
|
|
fileProviderAuthority = _activity.PackageName + ".android-filechooser.localfile";
|
|
}
|
|
Intent i = Keepass2android.Kp2afilechooser.Kp2aFileChooserBridge.GetLaunchFileChooserIntent(_activity, fileProviderAuthority,
|
|
defaultPath);
|
|
|
|
|
|
if (_isForSave)
|
|
{
|
|
i.PutExtra("group.pals.android.lib.ui.filechooser.FileChooserActivity.save_dialog", true);
|
|
string ext;
|
|
if (!string.IsNullOrEmpty(DefaultExtension))
|
|
{
|
|
ext = DefaultExtension;
|
|
}
|
|
else
|
|
{
|
|
ext = UrlUtil.GetExtension(defaultPath);
|
|
}
|
|
if ((ext != String.Empty) && (ext.Contains("?") == false))
|
|
i.PutExtra("group.pals.android.lib.ui.filechooser.FileChooserActivity.default_file_ext", ext);
|
|
}
|
|
_activity.StartActivityForResult(i, _requestCode);
|
|
|
|
#else
|
|
Toast.MakeText(this, "File chooser is excluded!", ToastLength.Long).Show();
|
|
#endif
|
|
return true;
|
|
}
|
|
|
|
public event EventHandler OnCancel;
|
|
|
|
public event EventHandler<IOConnectionInfo> OnOpen;
|
|
}
|
|
} |