1 /* 2 KeePass Password Safe - The Open-Source Password Manager 3 Copyright (C) 2003-2021 Dominik Reichl <dominik.reichl@t-online.de> 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 2 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program; if not, write to the Free Software 17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 */ 19 20 using System; 21 using System.Collections.Generic; 22 using System.ComponentModel; 23 using System.Diagnostics; 24 using System.Drawing; 25 using System.IO; 26 using System.Text; 27 using System.Windows.Forms; 28 29 using KeePass.App; 30 using KeePass.DataExchange; 31 using KeePass.Resources; 32 using KeePass.UI; 33 34 using KeePassLib; 35 using KeePassLib.Serialization; 36 using KeePassLib.Utility; 37 38 namespace KeePass.Forms 39 { 40 public partial class ExchangeDataForm : Form 41 { 42 private bool m_bExport = false; 43 private PwDatabase m_pd = null; 44 private PwGroup m_pg = null; 45 46 private ImageList m_ilFormats = null; 47 48 private FileFormatProvider m_fmtCur = null; // Current selection 49 50 private FileFormatProvider m_fmtFinal = null; // Returned as result 51 private string[] m_vFiles = null; 52 53 private sealed class FormatGroupEx 54 { 55 private ListViewGroup m_lvg; 56 public ListViewGroup Group { get { return m_lvg; } } 57 58 private List<ListViewItem> m_lItems = new List<ListViewItem>(); 59 public List<ListViewItem> Items { get { return m_lItems; } } 60 FormatGroupEx(string strGroupName)61 public FormatGroupEx(string strGroupName) 62 { 63 m_lvg = new ListViewGroup(strGroupName); 64 } 65 } 66 67 public FileFormatProvider ResultFormat 68 { 69 get { return m_fmtFinal; } 70 } 71 72 public string[] ResultFiles 73 { 74 get { return m_vFiles; } 75 } 76 77 private PwExportInfo m_piExport = null; 78 internal PwExportInfo ExportInfo 79 { 80 get { return m_piExport; } 81 set { m_piExport = value; } 82 } 83 InitEx(bool bExport, PwDatabase pd, PwGroup pg)84 public void InitEx(bool bExport, PwDatabase pd, PwGroup pg) 85 { 86 m_bExport = bExport; 87 m_pd = pd; 88 m_pg = pg; 89 } 90 ExchangeDataForm()91 public ExchangeDataForm() 92 { 93 InitializeComponent(); 94 GlobalWindowManager.InitializeForm(this); 95 } 96 OnFormLoad(object sender, EventArgs e)97 private void OnFormLoad(object sender, EventArgs e) 98 { 99 if((m_pd == null) && (m_pg == null)) 100 { 101 Debug.Assert(false); 102 throw new InvalidOperationException(); 103 } 104 105 GlobalWindowManager.AddWindow(this); 106 107 string strTitle = (m_bExport ? KPRes.ExportFileTitle : KPRes.ImportFileTitle); 108 string strDesc = (m_bExport ? KPRes.ExportFileDesc : KPRes.ImportFileDesc); 109 Image img = (m_bExport ? Properties.Resources.B48x48_Folder_Txt : 110 Properties.Resources.B48x48_Folder_Download); 111 BannerFactory.CreateBannerEx(this, m_bannerImage, img, strTitle, strDesc); 112 113 this.Icon = AppIcons.Default; 114 this.Text = strTitle; 115 116 UIUtil.ConfigureToolTip(m_ttRect); 117 UIUtil.SetToolTip(m_ttRect, m_btnSelFile, StrUtil.TrimDots( 118 KPRes.SelectFile, true), true); 119 120 m_lvFormats.ShowGroups = true; 121 122 int w = m_lvFormats.ClientSize.Width - UIUtil.GetVScrollBarWidth(); 123 m_lvFormats.Columns.Add(string.Empty, w - 1); 124 125 List<Image> lImages = new List<Image>(); 126 Dictionary<string, FormatGroupEx> dictGroups = 127 new Dictionary<string, FormatGroupEx>(); 128 129 foreach(FileFormatProvider f in Program.FileFormatPool) 130 { 131 if(m_bExport && !f.SupportsExport) continue; 132 if(!m_bExport && !f.SupportsImport) continue; 133 134 string strDisplayName = f.DisplayName; 135 if(string.IsNullOrEmpty(strDisplayName)) { Debug.Assert(false); continue; } 136 137 string strAppGroup = f.ApplicationGroup; 138 if(string.IsNullOrEmpty(strAppGroup)) strAppGroup = KPRes.General; 139 140 FormatGroupEx grp; 141 if(!dictGroups.TryGetValue(strAppGroup, out grp)) 142 { 143 grp = new FormatGroupEx(strAppGroup); 144 dictGroups[strAppGroup] = grp; 145 } 146 147 ListViewItem lvi = new ListViewItem(strDisplayName); 148 lvi.Group = grp.Group; 149 lvi.Tag = f; 150 151 Image imgSmallIcon = f.SmallIcon; 152 if(imgSmallIcon == null) 153 imgSmallIcon = Properties.Resources.B16x16_Folder_Inbox; 154 155 lvi.ImageIndex = lImages.Count; 156 lImages.Add(imgSmallIcon); 157 158 grp.Items.Add(lvi); 159 } 160 161 foreach(FormatGroupEx formatGroup in dictGroups.Values) 162 { 163 m_lvFormats.Groups.Add(formatGroup.Group); 164 foreach(ListViewItem lvi in formatGroup.Items) 165 m_lvFormats.Items.Add(lvi); 166 } 167 168 m_ilFormats = UIUtil.BuildImageListUnscaled(lImages, 169 DpiUtil.ScaleIntX(16), DpiUtil.ScaleIntY(16)); 170 m_lvFormats.SmallImageList = m_ilFormats; 171 172 if(m_bExport) 173 { 174 m_grpFiles.Text = KPRes.Destination; 175 UIUtil.SetText(m_lblFiles, KPRes.File + ":"); 176 UIUtil.SetButtonImage(m_btnSelFile, 177 Properties.Resources.B16x16_FileSaveAs, false); 178 179 m_lnkFileFormats.Enabled = false; 180 m_lnkFileFormats.Visible = false; 181 } 182 else // Import 183 { 184 m_grpFiles.Text = KPRes.Source; 185 UIUtil.SetButtonImage(m_btnSelFile, 186 Properties.Resources.B16x16_Folder_Yellow_Open, false); 187 188 m_grpExport.Enabled = false; 189 m_grpExportPost.Enabled = false; 190 } 191 192 m_cbExportMasterKeySpec.Checked = Program.Config.Defaults.ExportMasterKeySpec; 193 m_cbExportParentGroups.Checked = Program.Config.Defaults.ExportParentGroups; 194 m_cbExportPostOpen.Checked = Program.Config.Defaults.ExportPostOpen; 195 m_cbExportPostShow.Checked = Program.Config.Defaults.ExportPostShow; 196 197 UpdateUIState(); 198 } 199 CleanUpEx()200 private void CleanUpEx() 201 { 202 Program.Config.Defaults.ExportMasterKeySpec = m_cbExportMasterKeySpec.Checked; 203 Program.Config.Defaults.ExportParentGroups = m_cbExportParentGroups.Checked; 204 Program.Config.Defaults.ExportPostOpen = m_cbExportPostOpen.Checked; 205 Program.Config.Defaults.ExportPostShow = m_cbExportPostShow.Checked; 206 207 if(m_ilFormats != null) 208 { 209 m_lvFormats.SmallImageList = null; // Detach event handlers 210 m_ilFormats.Dispose(); 211 m_ilFormats = null; 212 } 213 } 214 OnLinkFileFormats(object sender, LinkLabelLinkClickedEventArgs e)215 private void OnLinkFileFormats(object sender, LinkLabelLinkClickedEventArgs e) 216 { 217 AppHelp.ShowHelp(AppDefs.HelpTopics.ImportExport, null); 218 } 219 CheckFilePath(string strPath)220 private static bool CheckFilePath(string strPath) 221 { 222 if(string.IsNullOrEmpty(strPath)) { Debug.Assert(false); return false; } 223 224 if(strPath.IndexOf(';') >= 0) 225 { 226 MessageService.ShowWarning(strPath, KPRes.FileNameContainsSemicolonError); 227 return false; 228 } 229 230 return true; 231 } 232 OnBtnSelFile(object sender, EventArgs e)233 private void OnBtnSelFile(object sender, EventArgs e) 234 { 235 UpdateUIState(); 236 if(m_fmtCur == null) { Debug.Assert(false); return; } 237 if(!m_fmtCur.RequiresFile) return; // Break on double-click 238 239 string strFormat = m_fmtCur.FormatName; 240 if(string.IsNullOrEmpty(strFormat)) strFormat = KPRes.Data; 241 242 string strExts = m_fmtCur.DefaultExtension; 243 if(string.IsNullOrEmpty(strExts)) strExts = "export"; 244 string strPriExt = UIUtil.GetPrimaryFileTypeExt(strExts); 245 if(strPriExt.Length == 0) strPriExt = "export"; // In case of "|" 246 247 string strFilter = UIUtil.CreateFileTypeFilter(strExts, strFormat, true); 248 249 if(!m_bExport) // Import 250 { 251 OpenFileDialogEx ofd = UIUtil.CreateOpenFileDialog(KPRes.Import + 252 ": " + strFormat, strFilter, 1, strPriExt, true, 253 AppDefs.FileDialogContext.Import); 254 255 if(ofd.ShowDialog() != DialogResult.OK) return; 256 257 StringBuilder sb = new StringBuilder(); 258 foreach(string str in ofd.FileNames) 259 { 260 if(!CheckFilePath(str)) continue; 261 262 if(sb.Length != 0) sb.Append(';'); 263 sb.Append(str); 264 } 265 266 string strFiles = sb.ToString(); 267 if(strFiles.Length >= m_tbFile.MaxLength) 268 { 269 MessageService.ShowWarning(KPRes.TooManyFilesError); 270 return; 271 } 272 273 m_tbFile.Text = strFiles; 274 } 275 else // Export 276 { 277 SaveFileDialogEx sfd = UIUtil.CreateSaveFileDialog(KPRes.Export + 278 ": " + strFormat, null, strFilter, 1, strPriExt, 279 AppDefs.FileDialogContext.Export); 280 281 string strSuggestion = KPRes.Database; 282 if((m_pd != null) && (m_pd.IOConnectionInfo.Path.Length > 0)) 283 strSuggestion = UrlUtil.StripExtension(UrlUtil.GetFileName( 284 m_pd.IOConnectionInfo.Path)); 285 sfd.FileName = strSuggestion + "." + strPriExt; 286 287 if(sfd.ShowDialog() != DialogResult.OK) return; 288 289 string strFile = sfd.FileName; 290 if(!CheckFilePath(strFile)) return; 291 m_tbFile.Text = strFile; 292 } 293 294 UpdateUIState(); 295 } 296 UpdateUIState()297 private void UpdateUIState() 298 { 299 ListView.SelectedListViewItemCollection lvsc = m_lvFormats.SelectedItems; 300 m_fmtCur = (((lvsc != null) && (lvsc.Count == 1)) ? 301 (lvsc[0].Tag as FileFormatProvider) : null); 302 bool bFormat = (m_fmtCur != null); 303 304 bool bFileReq = (bFormat && m_fmtCur.RequiresFile); 305 UIUtil.SetEnabledFast(bFileReq, m_lblFiles, m_tbFile, m_btnSelFile); 306 307 bool bExportExt = (m_bExport && (m_piExport != null)); 308 UIUtil.SetEnabledFast((bExportExt && bFormat && m_fmtCur.RequiresKey), 309 m_cbExportMasterKeySpec, m_lblExportMasterKeySpec); 310 311 UIUtil.SetEnabledFast((bExportExt && bFormat && (m_pd != null) && 312 (m_pg != m_pd.RootGroup)), 313 m_cbExportParentGroups, m_lnkExportParentGroups); 314 315 UIUtil.SetEnabledFast((bExportExt && bFileReq), m_cbExportPostOpen, 316 m_cbExportPostShow); 317 318 m_btnOK.Enabled = (bFormat && ((m_tbFile.Text.Length != 0) || 319 !m_fmtCur.RequiresFile)); 320 } 321 PrepareExchangeEx()322 private bool PrepareExchangeEx() 323 { 324 UpdateUIState(); 325 if(m_fmtCur == null) return false; 326 327 string strFiles = m_tbFile.Text; 328 string[] vFiles = strFiles.Split(new char[] { ';' }, 329 StringSplitOptions.RemoveEmptyEntries); 330 331 if(m_fmtCur.RequiresFile) 332 { 333 if(vFiles.Length == 0) return false; 334 335 foreach(string strFile in vFiles) 336 { 337 IOConnectionInfo ioc = IOConnectionInfo.FromPath(strFile); 338 if(ioc.IsLocalFile() && !UrlUtil.IsAbsolutePath(strFile)) 339 { 340 MessageService.ShowWarning(strFile, KPRes.FilePathFullReq); 341 return false; 342 } 343 } 344 345 // Allow only one file when exporting 346 if(m_bExport && !CheckFilePath(strFiles)) return false; 347 } 348 else vFiles = new string[0]; 349 350 if(m_piExport != null) 351 { 352 m_piExport.ExportMasterKeySpec = m_cbExportMasterKeySpec.Checked; 353 m_piExport.ExportParentGroups = m_cbExportParentGroups.Checked; 354 m_piExport.ExportPostOpen = m_cbExportPostOpen.Checked; 355 m_piExport.ExportPostShow = m_cbExportPostShow.Checked; 356 } 357 358 m_fmtFinal = m_fmtCur; 359 m_vFiles = vFiles; 360 return true; 361 } 362 OnBtnOK(object sender, EventArgs e)363 private void OnBtnOK(object sender, EventArgs e) 364 { 365 if(!PrepareExchangeEx()) this.DialogResult = DialogResult.None; 366 } 367 OnBtnCancel(object sender, EventArgs e)368 private void OnBtnCancel(object sender, EventArgs e) 369 { 370 } 371 OnFormatsSelectedIndexChanged(object sender, EventArgs e)372 private void OnFormatsSelectedIndexChanged(object sender, EventArgs e) 373 { 374 UpdateUIState(); 375 } 376 OnFormClosed(object sender, FormClosedEventArgs e)377 private void OnFormClosed(object sender, FormClosedEventArgs e) 378 { 379 CleanUpEx(); 380 GlobalWindowManager.RemoveWindow(this); 381 } 382 OnImportFileTextChanged(object sender, EventArgs e)383 private void OnImportFileTextChanged(object sender, EventArgs e) 384 { 385 UpdateUIState(); 386 } 387 OnFormatsItemActivate(object sender, EventArgs e)388 private void OnFormatsItemActivate(object sender, EventArgs e) 389 { 390 OnBtnSelFile(sender, e); 391 } 392 OnLinkExportParentGroups(object sender, LinkLabelLinkClickedEventArgs e)393 private void OnLinkExportParentGroups(object sender, LinkLabelLinkClickedEventArgs e) 394 { 395 AppHelp.ShowHelp(AppDefs.HelpTopics.ImportExport, 396 AppDefs.HelpTopics.ImportExportParents); 397 } 398 } 399 } 400