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.Diagnostics;
23 using System.Drawing;
24 using System.IO;
25 using System.Text;
26 
27 using KeePass.Resources;
28 
29 using KeePassLib;
30 using KeePassLib.Interfaces;
31 using KeePassLib.Utility;
32 
33 namespace KeePass.DataExchange.Formats
34 {
35 	// 3.5.5+
36 	internal sealed class MSecureCsv355 : FileFormatProvider
37 	{
38 		public override bool SupportsImport { get { return true; } }
39 		public override bool SupportsExport { get { return false; } }
40 
41 		public override string FormatName { get { return "mSecure CSV"; } }
42 		public override string DefaultExtension { get { return "csv"; } }
43 		public override string ApplicationGroup { get { return KPRes.PasswordManagers; } }
44 
45 		public override bool ImportAppendsToRootGroupOnly { get { return false; } }
46 
47 		public override Image SmallIcon
48 		{
49 			get { return KeePass.Properties.Resources.B16x16_Imp_MSecure; }
50 		}
51 
Import(PwDatabase pwStorage, Stream sInput, IStatusLogger slLogger)52 		public override void Import(PwDatabase pwStorage, Stream sInput,
53 			IStatusLogger slLogger)
54 		{
55 			StreamReader sr = new StreamReader(sInput, Encoding.Default, true);
56 			string str = sr.ReadToEnd();
57 			sr.Close();
58 
59 			CsvOptions opt = new CsvOptions();
60 
61 			// Backslashes are not escaped, even though "\\n" is used
62 			// to encode new-line characters
63 			opt.BackslashIsEscape = false;
64 			opt.FieldSeparator = ';';
65 
66 			CsvStreamReaderEx csr = new CsvStreamReaderEx(str, opt);
67 			Dictionary<string, PwGroup> dGroups = new Dictionary<string, PwGroup>();
68 
69 			while(true)
70 			{
71 				string[] vLine = csr.ReadLine();
72 				if(vLine == null) break;
73 
74 				AddEntry(vLine, pwStorage, dGroups);
75 			}
76 		}
77 
AddEntry(string[] vLine, PwDatabase pd, Dictionary<string, PwGroup> dGroups)78 		private static void AddEntry(string[] vLine, PwDatabase pd,
79 			Dictionary<string, PwGroup> dGroups)
80 		{
81 			if(vLine.Length < 2) return;
82 
83 			string strGroup = vLine[0];
84 			PwGroup pg;
85 			if(string.IsNullOrEmpty(strGroup))
86 				pg = pd.RootGroup;
87 			else
88 			{
89 				if(!dGroups.TryGetValue(strGroup, out pg))
90 				{
91 					pg = new PwGroup(true, true);
92 					pg.Name = strGroup;
93 
94 					pd.RootGroup.AddGroup(pg, true);
95 					dGroups[strGroup] = pg;
96 				}
97 			}
98 
99 			PwEntry pe = new PwEntry(true, true);
100 			pg.AddEntry(pe, true);
101 
102 			MsAppend(pe, PwDefs.TitleField, vLine, 2, pd);
103 			MsAppend(pe, PwDefs.NotesField, vLine, 3, pd);
104 
105 			string strType = vLine[1];
106 			int i = 3;
107 			DateTime dt;
108 
109 			switch(strType)
110 			{
111 				case "Bank Accounts":
112 					MsAppend(pe, PwDefs.UserNameField, vLine, ++i, pd);
113 					MsAppend(pe, PwDefs.PasswordField, vLine, ++i, pd);
114 					MsAppend(pe, "Name", vLine, ++i, pd);
115 					MsAppend(pe, "Branch", vLine, ++i, pd);
116 					MsAppend(pe, "Phone No.", vLine, ++i, pd);
117 
118 					pe.IconId = PwIcon.Money;
119 					break;
120 
121 				case "Birthdays":
122 					MsAppend(pe, PwDefs.UserNameField, vLine, ++i, pd);
123 
124 					pe.IconId = PwIcon.UserCommunication;
125 					break;
126 
127 				case "Calling Cards":
128 				case "Social Security":
129 				case "Voice Mail":
130 					MsAppend(pe, PwDefs.UserNameField, vLine, ++i, pd);
131 					MsAppend(pe, PwDefs.PasswordField, vLine, ++i, pd);
132 
133 					pe.IconId = PwIcon.UserKey;
134 					break;
135 
136 				case "Clothes Size":
137 					MsAppend(pe, "Shirt Size", vLine, ++i, pd);
138 					MsAppend(pe, "Pant Size", vLine, ++i, pd);
139 					MsAppend(pe, "Shoe Size", vLine, ++i, pd);
140 					MsAppend(pe, "Dress Size", vLine, ++i, pd);
141 					break;
142 
143 				case "Combinations":
144 					MsAppend(pe, PwDefs.PasswordField, vLine, ++i, pd);
145 					break;
146 
147 				case "Credit Cards":
148 					MsAppend(pe, PwDefs.UserNameField, vLine, ++i, pd);
149 
150 					++i;
151 					if((vLine.Length > i) && StrUtil.TryParseDateTime(
152 						vLine[i], out dt))
153 					{
154 						pe.Expires = true;
155 						pe.ExpiryTime = TimeUtil.ToUtc(dt, false);
156 					}
157 					else MsAppend(pe, "Expiration", vLine, i, pd);
158 
159 					MsAppend(pe, "Name", vLine, ++i, pd);
160 					MsAppend(pe, PwDefs.PasswordField, vLine, ++i, pd);
161 					MsAppend(pe, "Bank", vLine, ++i, pd);
162 					MsAppend(pe, "Security Code", vLine, ++i, pd);
163 
164 					pe.IconId = PwIcon.Money;
165 					break;
166 
167 				case "Email Accounts":
168 					MsAppend(pe, PwDefs.UserNameField, vLine, ++i, pd);
169 					MsAppend(pe, PwDefs.PasswordField, vLine, ++i, pd);
170 					MsAppend(pe, "POP3 Host", vLine, ++i, pd);
171 					MsAppend(pe, "SMTP Host", vLine, ++i, pd);
172 
173 					pe.IconId = PwIcon.EMail;
174 					break;
175 
176 				case "Frequent Flyer":
177 					MsAppend(pe, "Number", vLine, ++i, pd);
178 					MsAppend(pe, PwDefs.UrlField, vLine, ++i, pd);
179 					MsAppend(pe, PwDefs.UserNameField, vLine, ++i, pd);
180 					MsAppend(pe, PwDefs.PasswordField, vLine, ++i, pd);
181 					MsAppend(pe, "Mileage", vLine, ++i, pd);
182 					break;
183 
184 				case "Identity":
185 					++i;
186 					MsAppend(pe, PwDefs.UserNameField, vLine, i + 1, pd); // Last name
187 					MsAppend(pe, PwDefs.UserNameField, vLine, i, pd); // First name
188 					++i;
189 
190 					MsAppend(pe, "Nick Name", vLine, ++i, pd);
191 					MsAppend(pe, "Company", vLine, ++i, pd);
192 					MsAppend(pe, PwDefs.UserNameField, vLine, ++i, pd);
193 					MsAppend(pe, "Address", vLine, ++i, pd);
194 					MsAppend(pe, "Address 2", vLine, ++i, pd);
195 					MsAppend(pe, "City", vLine, ++i, pd);
196 					MsAppend(pe, "State", vLine, ++i, pd);
197 					MsAppend(pe, "Country", vLine, ++i, pd);
198 					MsAppend(pe, "Zip", vLine, ++i, pd);
199 					MsAppend(pe, "Home Phone", vLine, ++i, pd);
200 					MsAppend(pe, "Office Phone", vLine, ++i, pd);
201 					MsAppend(pe, "Mobile Phone", vLine, ++i, pd);
202 					MsAppend(pe, "E-Mail", vLine, ++i, pd);
203 					MsAppend(pe, "E-Mail 2", vLine, ++i, pd);
204 					MsAppend(pe, "Skype", vLine, ++i, pd);
205 					MsAppend(pe, PwDefs.UrlField, vLine, ++i, pd);
206 
207 					pe.IconId = PwIcon.UserCommunication;
208 					break;
209 
210 				case "Insurance":
211 					MsAppend(pe, PwDefs.UserNameField, vLine, ++i, pd);
212 					MsAppend(pe, "Group No.", vLine, ++i, pd);
213 					MsAppend(pe, "Insured", vLine, ++i, pd);
214 					MsAppend(pe, "Date", vLine, ++i, pd);
215 					MsAppend(pe, "Phone No.", vLine, ++i, pd);
216 
217 					pe.IconId = PwIcon.Certificate;
218 					break;
219 
220 				case "Memberships":
221 					MsAppend(pe, PwDefs.PasswordField, vLine, ++i, pd);
222 					MsAppend(pe, PwDefs.UserNameField, vLine, ++i, pd);
223 					MsAppend(pe, "Date", vLine, ++i, pd);
224 
225 					pe.IconId = PwIcon.UserKey;
226 					break;
227 
228 				case "Note":
229 					pe.IconId = PwIcon.Notepad;
230 					break;
231 
232 				case "Passport":
233 					MsAppend(pe, PwDefs.UserNameField, vLine, ++i, pd);
234 					MsAppend(pe, PwDefs.PasswordField, vLine, ++i, pd);
235 					MsAppend(pe, "Type", vLine, ++i, pd);
236 					MsAppend(pe, "Issuing Country", vLine, ++i, pd);
237 					MsAppend(pe, "Issuing Authority", vLine, ++i, pd);
238 					MsAppend(pe, "Nationality", vLine, ++i, pd);
239 
240 					++i;
241 					if((vLine.Length > i) && StrUtil.TryParseDateTime(
242 						vLine[i], out dt))
243 					{
244 						pe.Expires = true;
245 						pe.ExpiryTime = TimeUtil.ToUtc(dt, false);
246 					}
247 					else MsAppend(pe, "Expiration", vLine, i, pd);
248 
249 					MsAppend(pe, "Place of Birth", vLine, ++i, pd);
250 
251 					pe.IconId = PwIcon.Certificate;
252 					break;
253 
254 				case "Prescriptions":
255 					MsAppend(pe, "RX Number", vLine, ++i, pd);
256 					MsAppend(pe, PwDefs.UserNameField, vLine, ++i, pd);
257 					MsAppend(pe, "Doctor", vLine, ++i, pd);
258 					MsAppend(pe, "Pharmacy", vLine, ++i, pd);
259 					MsAppend(pe, "Phone No.", vLine, ++i, pd);
260 					break;
261 
262 				case "Registration Codes":
263 					MsAppend(pe, PwDefs.UserNameField, vLine, ++i, pd);
264 					MsAppend(pe, "Date", vLine, ++i, pd);
265 
266 					pe.IconId = PwIcon.UserKey;
267 					break;
268 
269 				case "Unassigned":
270 					MsAppend(pe, "Field 1", vLine, ++i, pd);
271 					MsAppend(pe, "Field 2", vLine, ++i, pd);
272 					MsAppend(pe, "Field 3", vLine, ++i, pd);
273 					MsAppend(pe, "Field 4", vLine, ++i, pd);
274 					MsAppend(pe, "Field 5", vLine, ++i, pd);
275 					MsAppend(pe, "Field 6", vLine, ++i, pd);
276 					break;
277 
278 				case "Vehicle Info":
279 					MsAppend(pe, PwDefs.UserNameField, vLine, ++i, pd);
280 					MsAppend(pe, PwDefs.PasswordField, vLine, ++i, pd);
281 					MsAppend(pe, "Date Purchased", vLine, ++i, pd);
282 					MsAppend(pe, "Tire Size", vLine, ++i, pd);
283 					break;
284 
285 				case "Web Logins":
286 					MsAppend(pe, PwDefs.UrlField, vLine, ++i, pd);
287 					MsAppend(pe, PwDefs.UserNameField, vLine, ++i, pd);
288 					MsAppend(pe, PwDefs.PasswordField, vLine, ++i, pd);
289 					break;
290 
291 				default:
292 					Debug.Assert(false);
293 					break;
294 			}
295 			Debug.Assert((i + 1) == vLine.Length);
296 		}
297 
MsAppend(PwEntry pe, string strFieldName, string[] vLine, int iIndex, PwDatabase pdContext)298 		private static void MsAppend(PwEntry pe, string strFieldName,
299 			string[] vLine, int iIndex, PwDatabase pdContext)
300 		{
301 			if(iIndex >= vLine.Length) { Debug.Assert(false); return; }
302 
303 			string strValue = vLine[iIndex];
304 			if(string.IsNullOrEmpty(strValue)) return;
305 
306 			strValue = strValue.Replace("\\r\\n", "\\n");
307 			strValue = strValue.Replace("\\r", "\\n");
308 
309 			if(PwDefs.IsStandardField(strFieldName) &&
310 				(strFieldName != PwDefs.NotesField))
311 			{
312 				while(strValue.EndsWith("\\n"))
313 				{
314 					strValue = strValue.Substring(0, strValue.Length - 2);
315 				}
316 
317 				strValue = strValue.Replace("\\n", ", ");
318 			}
319 			else strValue = strValue.Replace("\\n", MessageService.NewLine);
320 
321 			ImportUtil.AppendToField(pe, strFieldName, strValue, pdContext);
322 		}
323 	}
324 }
325