Ejemplo n.º 1
0
BOOL CPwCompatImpl::OpenDatabaseV1(CPwManager* pMgr, const TCHAR *pszFile)
{
	FILE *fp;
	char *pVirtualFile;
	unsigned long uFileSize, uAllocated, uEncryptedPartSize;
	size_t i, j, pos;
	PW_DBHEADER_V1 hdr;
	sha256_ctx sha32;
	UINT8 uFinalKey[32];
	DWORD dw, dw2;
	char *ptrTemp;
	char *ptrTitle;
	char *ptrUserName;
	char *ptrURL;
	char *ptrPassword;
	char *ptrAdditional;
	PW_TIME tNow;
	PW_GROUP pwTG;
	PW_ENTRY pwTE;

	_GetCurrentPwTime(&tNow);
	memset(&pwTG, 0, sizeof(PW_GROUP));
	memset(&pwTE, 0, sizeof(PW_ENTRY));
	pwTG.tCreation = tNow; pwTG.tExpire = g_pwTimeNever;
	pwTG.tLastAccess = tNow; pwTG.tLastMod = tNow;
	pwTE.tCreation = tNow; pwTE.tExpire = g_pwTimeNever;
	pwTE.tLastAccess = tNow; pwTE.tLastMod = tNow;

	ASSERT(sizeof(char) == 1);

	ASSERT(pszFile != NULL);
	if(pszFile == NULL) return FALSE;
	ASSERT(_tcslen(pszFile) != 0);
	if(_tcslen(pszFile) == 0) return FALSE;

	fp = NULL;
	_tfopen_s(&fp, pszFile, _T("rb"));
	if(fp == NULL) return FALSE;

	// Get file size
	fseek(fp, 0, SEEK_END);
	uFileSize = ftell(fp);
	fseek(fp, 0, SEEK_SET);

	if(uFileSize < sizeof(PW_DBHEADER_V1))
		{ fclose(fp); return FALSE; }

	// Allocate enough memory to hold the complete file
	uAllocated = uFileSize + 17;
	pVirtualFile = new char[uAllocated];
	if(pVirtualFile == NULL)
		{ fclose(fp); return FALSE; }
	pVirtualFile[uFileSize + 17 - 1] = 0;
	fread(pVirtualFile, 1, uFileSize, fp);
	fclose(fp);

	// Extract header structure from memory file
	memcpy(&hdr, pVirtualFile, sizeof(PW_DBHEADER_V1));

	// Check if we can open this
	if((hdr.dwSignature1 != PWM_DBSIG_1) || (hdr.dwSignature2 != PWM_DBSIG_2))
		{ _OPENDB_FAIL; }

	if((hdr.dwFlags & PWM_FLAG_RIJNDAEL) != 0) pMgr->SetAlgorithm(ALGO_AES);
	else if((hdr.dwFlags & PWM_FLAG_TWOFISH) != 0) pMgr->SetAlgorithm(ALGO_TWOFISH);
	else { ASSERT(FALSE); _OPENDB_FAIL; }

	BYTE aMasterKeyU[32];
	pMgr->GetRawMasterKey(aMasterKeyU);

	// Hash the master password with the salt in the file
	sha256_begin(&sha32);
	sha256_hash(hdr.aMasterSeed, 16, &sha32);
	sha256_hash(aMasterKeyU, 32, &sha32);
	sha256_end((unsigned char *)uFinalKey, &sha32);

	mem_erase(aMasterKeyU, 32);

	if(pMgr->GetAlgorithm() == ALGO_AES)
	{
		CRijndael aes;

		// Initialize Rijndael algorithm
		if(aes.Init(CRijndael::CBC, CRijndael::DecryptDir, uFinalKey,
			CRijndael::Key32Bytes, hdr.aEncryptionIV) != RIJNDAEL_SUCCESS)
			{ _OPENDB_FAIL; }

		// Decrypt! The first 48 bytes aren't encrypted (that's the header)
		uEncryptedPartSize = (unsigned long)aes.PadDecrypt((UINT8 *)pVirtualFile + 48,
			uFileSize - 48, (UINT8 *)pVirtualFile + 48);
	}
	else if(pMgr->GetAlgorithm() == ALGO_TWOFISH)
	{
		CTwofish twofish;

		if(twofish.Init(uFinalKey, 32, hdr.aEncryptionIV) != true)
			{ _OPENDB_FAIL };

		uEncryptedPartSize = (unsigned long)twofish.PadDecrypt(
			(UINT8 *)pVirtualFile + 48,
			uFileSize - 48, (UINT8 *)pVirtualFile + 48);
	}
Ejemplo n.º 2
0
void CPwImport::_AddStringStreamToDb(const char *pStream, unsigned long uStreamSize, BOOL bUTF8)
{
	DWORD s;
	char *pTitle = NULL, *pUserName = NULL, *pPassword = NULL, *pURL = NULL, *pNotes = NULL;
	char *p = (char *)pStream;
	char *pEnd = (char *)pStream + uStreamSize;
	TCHAR *tszTitle = NULL, *tszUserName = NULL, *tszPassword = NULL, *tszURL = NULL, *tszNotes = NULL;

	ASSERT(pStream != NULL);

	while(true)
	{
		if(p >= pEnd) break;
		pTitle = p;
		s = szlen(p);
		p += s + 1;

		if(p >= pEnd) break;
		pUserName = p;
		s = szlen(p);
		p += s + 1;

		if(p >= pEnd) break;
		pPassword = p;
		s = szlen(p);
		p += s + 1;

		if(p >= pEnd) break;
		pURL = p;
		s = szlen(p);
		p += s + 1;

		if(p >= pEnd) break;
		pNotes = p;
		s = szlen(p);
		p += s + 1;

		if((strcmp(pTitle, "Account") != 0) && (strcmp(pPassword, "Password") != 0))
		{
			PW_ENTRY pwTemplate;
			PW_TIME tNow;

			if(bUTF8 == TRUE)
			{
				tszTitle = _UTF8ToString((UTF8_BYTE *)pTitle);
				tszUserName = _UTF8ToString((UTF8_BYTE *)pUserName);
				tszPassword = _UTF8ToString((UTF8_BYTE *)pPassword);
				tszURL = _UTF8ToString((UTF8_BYTE *)pURL);
				tszNotes = _UTF8ToString((UTF8_BYTE *)pNotes);
			}
			else
			{
				tszTitle = (TCHAR *)pTitle;
				tszUserName = (TCHAR *)pUserName;
				tszPassword = (TCHAR *)pPassword;
				tszURL = (TCHAR *)pURL;
				tszNotes = (TCHAR *)pNotes;
			}

			memset(&pwTemplate, 0, sizeof(PW_ENTRY));
			_GetCurrentPwTime(&tNow);
			pwTemplate.pszAdditional = tszNotes;
			pwTemplate.pszPassword = tszPassword;
			pwTemplate.pszTitle = tszTitle;
			pwTemplate.pszURL = tszURL;
			pwTemplate.pszUserName = tszUserName;
			pwTemplate.tCreation = tNow; CPwManager::GetNeverExpireTime(&pwTemplate.tExpire);
			pwTemplate.tLastAccess = tNow; pwTemplate.tLastMod = tNow;
			pwTemplate.uGroupId = m_dwLastGroupId;
			pwTemplate.uImageId = _GetPreferredIcon(tszTitle);
			pwTemplate.uPasswordLen = static_cast<DWORD>(_tcslen(tszPassword));
			// UUID is zero -> create new UUID

			m_pLastMgr->AddEntry(&pwTemplate);

			if(bUTF8 == TRUE)
			{
				SAFE_DELETE_ARRAY(tszTitle);
				SAFE_DELETE_ARRAY(tszUserName);
				SAFE_DELETE_ARRAY(tszPassword);
				SAFE_DELETE_ARRAY(tszURL);
				SAFE_DELETE_ARRAY(tszNotes);
			}
		}
	}
}
Ejemplo n.º 3
0
BOOL CPwImport::ImportPVaultToDb(const TCHAR *pszFile, CPwManager *pMgr)
{
	char *pData;
	CString strTitle, strURL, strUserName, strPassword, strNotes;
	DWORD uFileSize, i, b;
	CString str;
	CString strLastCategory = _T("General");
	DWORD dwLastGroupId = 0;
	BOOL bInNotes = FALSE;

	ASSERT(pMgr != NULL);

	pData = CPwImport::FileToMemory(pszFile, &uFileSize);
	if(pData == NULL) return FALSE;

	strTitle.Empty(); strURL.Empty(); strUserName.Empty();
	strPassword.Empty(); strNotes.Empty();

	i = DWORD_MAX;

	if(uFileSize > 3)
		if((static_cast<unsigned char>(pData[0]) == 0xEF) &&
			(static_cast<unsigned char>(pData[1]) == 0xBB) &&
			(static_cast<unsigned char>(pData[2]) == 0xBF))
			i += 3; // Skip UTF-8 initialization characters

	while(true) // Processing the file
	{
		str.Empty();

		while(true) // Loading one line to CString
		{
			++i;
			if(i >= uFileSize) break;

			if(pData[i] == '\n') break;
			if(pData[i] != '\r') str += pData[i];
		}

		// Add the entry
		if((str == DEF_PV_SEPENTRY) || (i >= uFileSize) || (str.Left(12) == DEF_PV_CATEGORY))
		{
			if((strTitle.IsEmpty() == FALSE) || (strUserName.IsEmpty() == FALSE) ||
				(strURL.IsEmpty() == FALSE) || (strPassword.IsEmpty() == FALSE))
			{
				strTitle = strTitle.Trim();
				strURL = strURL.Trim();
				strUserName = strUserName.Trim();
				strPassword = strPassword.Trim();
				strNotes = strNotes.Trim();

				PW_ENTRY pwTemplate;
				PW_TIME tNow;

				_GetCurrentPwTime(&tNow);
				memset(&pwTemplate, 0, sizeof(PW_ENTRY));
				pwTemplate.pszAdditional = const_cast<LPTSTR>((LPCTSTR)strNotes);
				pwTemplate.pszPassword = const_cast<LPTSTR>((LPCTSTR)strPassword);
				pwTemplate.pszTitle = const_cast<LPTSTR>((LPCTSTR)strTitle);
				pwTemplate.pszURL = const_cast<LPTSTR>((LPCTSTR)strURL);
				pwTemplate.pszUserName = const_cast<LPTSTR>((LPCTSTR)strUserName);
				pwTemplate.tCreation = tNow; CPwManager::GetNeverExpireTime(&pwTemplate.tExpire);
				pwTemplate.tLastAccess = tNow; pwTemplate.tLastMod = tNow;
				pwTemplate.uGroupId = dwLastGroupId;
				pwTemplate.uImageId = _GetPreferredIcon(strTitle);
				pwTemplate.uPasswordLen = strPassword.GetLength();

				pMgr->AddEntry(&pwTemplate);
			}

			strTitle.Empty(); strURL.Empty(); strUserName.Empty();
			strPassword.Empty(); strNotes.Empty();
			bInNotes = FALSE;
		}

		if(i >= uFileSize) break;

		if(bInNotes == TRUE)
		{
			if(strNotes.GetLength() != 0) strNotes += _T("\r\n");
			strNotes += str.Right(str.GetLength() - 14);
		}

		if((str.Left(12) == DEF_PV_CATEGORY) && (str.Right(12) == DEF_PV_CATEGORY))
		{
			strLastCategory = str.Right(str.GetLength() - 12);
			strLastCategory = strLastCategory.Left(strLastCategory.GetLength() - 12);
			strLastCategory = strLastCategory.Trim();

			if(strLastCategory.GetLength() == 0)
				strLastCategory = TRL("General");
			dwLastGroupId = pMgr->GetGroupId((LPCTSTR)strLastCategory);
			if(dwLastGroupId == DWORD_MAX)
			{
				PW_GROUP pwT;
				PW_TIME tNow;
				_GetCurrentPwTime(&tNow);
				memset(&pwT, 0, sizeof(PW_GROUP));
				pwT.pszGroupName = (TCHAR *)(LPCTSTR)strLastCategory;
				pwT.tCreation = tNow; CPwManager::GetNeverExpireTime(&pwT.tExpire);
				pwT.tLastAccess = tNow; pwT.tLastMod = tNow;
				pwT.uGroupId = 0; // 0 = create new group ID
				pwT.uImageId = _GetPreferredIcon((LPCTSTR)strLastCategory);
				pMgr->AddGroup(&pwT);
				dwLastGroupId = pMgr->GetGroupId((LPCTSTR)strLastCategory);
			}
			ASSERT(dwLastGroupId != DWORD_MAX);
		}

		if((str.Left(9) == _T("Comments:")) && (bInNotes == FALSE))
		{
			bInNotes = TRUE;
			str = str.Right(str.GetLength() - 9);
			if(str.GetLength() != 0) strNotes = str;
			continue;
		}

		if(str.Left(9) == _T("Account: ")) {strTitle = str.Right(str.GetLength() - 9); b=1;}

		b=0;
		if(str.Left(11) == _T("User Name: ")) {strUserName = str.Right(str.GetLength() - 11); b=1;}

		if(str.Left(11) == _T("Hyperlink: ")) {strURL = str.Right(str.GetLength() - 11); b=1;}

		if(str.Left(10) == _T("Password: "******"\r\n");
			strNotes += str;
		}
	}

	SAFE_DELETE_ARRAY(pData);

	return TRUE;
}
Ejemplo n.º 4
0
BOOL CPwImport::ImportPwSafeToDb(const TCHAR *pszFile, CPwManager *pMgr)
{
	char *pData;
	unsigned long uFileSize, i;
	int nField, j;
	CString strGroup, strTitle, strUserName, strPassword, strNotes;
	DWORD dwGroupId;
	BOOL bInNotes = FALSE;
	CString str3, str4, str5, str6;

	ASSERT(pszFile != NULL); if(pszFile == NULL) return FALSE;
	ASSERT(pMgr != NULL); if(pMgr == NULL) return FALSE;

	pData = CPwImport::FileToMemory(pszFile, &uFileSize);
	if(pData == NULL) return FALSE;

	nField = 0;
	i = 0; j = 0;
	strGroup.Empty(); strTitle.Empty(); strUserName.Empty(); strPassword.Empty(); strNotes.Empty();

	if(uFileSize > 3)
		if((static_cast<unsigned char>(pData[0]) == 0xEF) &&
			(static_cast<unsigned char>(pData[1]) == 0xBB) &&
			(static_cast<unsigned char>(pData[2]) == 0xBF))
			i += 3; // Skip UTF-8 initialization characters

	while(true)
	{
		if((pData[i] == '\t') && (bInNotes == FALSE))
		{
			nField++;

			if(nField == 1)
			{
				j = strGroup.ReverseFind(_T('.'));

				// Thanks to Andrew D. Bond for the following improvement
				// Slightly enhanced by D. Reichl to detect some more URLs

				// -- Andrew D. Bond
				// Introduction: The Password Safe export format is rather flawed,
				// since it uses the '.' character as the group / title separator.
				// However, '.' is not likely to appear in the context of titles
				// that include 'com', 'org', 'edu', etc, (domain names) or even
				// 'zip' (password protected zip files)

				// Slightly-smarter import: if the '.' we just found is followed
				// by 'com', 'org', 'edu', etc, (domain names) or even
				// 'zip' (password protected zip files) then figure this is part
				// of the title and try the group / title splitting again.
				// Example:
				//  strGroup = "websites.someSite.com" // j == 17 // <- INCORRECT
				//
				// Overall, these fixes do make things much better.
				// However, they will still not be able to handle entries where
				// the title has _other_ "."'s in it.
				// For example, when the title is:
				//  subdomain.domain.com
				//  mySoftware version 8.5
				//	domain.tv (replace .tv with any domain suffix not included below)

				if((strGroup.GetLength() >= 4) && (j != -1))
					str3 = strGroup.Right(3);
				else
					str3 = _T("   ");
				if((strGroup.GetLength() >= 5) && (j != -1))
					str4 = strGroup.Right(4);
				else
					str4 = _T("    ");
				if((strGroup.GetLength() >= 6) && (j != -1))
					str5 = strGroup.Right(5);
				else
					str5 = _T("     ");
				if((strGroup.GetLength() >= 7) && (j != -1))
					str6 = strGroup.Right(6);
				else
					str6 = _T("      ");

				str3 = str3.MakeLower();
				str4 = str4.MakeLower();
				str5 = str5.MakeLower();
				str6 = str6.MakeLower();

				if((str4 == _T(".com")) || (str4 == _T(".org")) || (str4 == _T(".edu"))
					|| (str4 == _T(".net")) || (str4 == _T(".zip"))
					|| (str3 == _T(".uk")) || (str3 == _T(".de")) || (str3 == _T(".ch"))
					|| (str3 == _T(".at")) || (str3 == _T(".it")))
				{
					// Fix for double-point URLs like .co.uk
					if(str6 == _T(".co.uk")) j -= 3;

					strTitle = strGroup.Right(strGroup.GetLength() - j);
					strGroup = strGroup.Left(j);
					j = strGroup.ReverseFind(_T('.'));
				}

				if(j != -1)
				{
					strTitle = strGroup.Right(strGroup.GetLength() - j - 1) + strTitle;
					strGroup = strGroup.Left(j);
				}
				else
				{
					// No '.' was found, or it is part of a ".com" in the title.
					// Since Password Safe
					// **requires** a title but not a group name, this means
					// that a group name was not specified (a common
					// occurrence). We should assign a logical group name
					// and store the title we just identified. 
					strTitle = strGroup + strTitle;
					strGroup = TRL("Imported from Password Safe");
				}
			}
		}
		else if((pData[i] == '\"') && (bInNotes == FALSE) && (nField == 3))
		{
			bInNotes = TRUE;
		}
		else if((pData[i] == '\"') && (bInNotes == TRUE) && (nField == 3))
		{
			bInNotes = FALSE;

			if(strNotes.GetLength() != 0)
			{
				if(strNotes.GetAt(0) == _T('\"')) strNotes = strNotes.Right(strNotes.GetLength() - 1);
				if(strNotes.Right(1) == _T("\"")) strNotes = strNotes.Left(strNotes.GetLength() - 1);
			}
		}
		else if((pData[i] == '\r') && (bInNotes == FALSE))
		{
			// Ignore all \r
		}
		else if((pData[i] == '\n') && (bInNotes == FALSE))
		{
			dwGroupId = pMgr->GetGroupId((LPCTSTR)strGroup);
			if(dwGroupId == DWORD_MAX)
			{
				PW_GROUP pwT;
				PW_TIME tNow;
				_GetCurrentPwTime(&tNow);
				memset(&pwT, 0, sizeof(PW_GROUP));
				pwT.pszGroupName = (TCHAR *)(LPCTSTR)strGroup;
				pwT.tCreation = tNow; CPwManager::GetNeverExpireTime(&pwT.tExpire);
				pwT.tLastAccess = tNow; pwT.tLastMod = tNow;
				pwT.uGroupId = 0; // 0 = create new group ID
				pwT.uImageId = _GetPreferredIcon((LPCTSTR)strGroup);
				pMgr->AddGroup(&pwT);
				dwGroupId = pMgr->GetGroupId((LPCTSTR)strGroup);
			}
			ASSERT(dwGroupId != DWORD_MAX);

			PW_ENTRY pwTemplate;
			PW_TIME tNow;

			memset(&pwTemplate, 0, sizeof(PW_ENTRY));
			_GetCurrentPwTime(&tNow);
			pwTemplate.pszAdditional = const_cast<LPTSTR>((LPCTSTR)strNotes);
			pwTemplate.pszPassword = const_cast<LPTSTR>((LPCTSTR)strPassword);
			pwTemplate.pszTitle = const_cast<LPTSTR>((LPCTSTR)strTitle);
			pwTemplate.pszURL = g_pNullString;
			pwTemplate.pszUserName = const_cast<LPTSTR>((LPCTSTR)strUserName);
			pwTemplate.tCreation = tNow; CPwManager::GetNeverExpireTime(&pwTemplate.tExpire);
			pwTemplate.tLastAccess = tNow; pwTemplate.tLastMod = tNow;
			pwTemplate.uImageId = _GetPreferredIcon((LPCTSTR)strTitle);
			pwTemplate.uPasswordLen = strPassword.GetLength();
			pwTemplate.uGroupId = dwGroupId;
			// UUID is zero -> create new UUID

			pMgr->AddEntry(&pwTemplate);

			strGroup.Empty(); strTitle.Empty(); strUserName.Empty();
			strPassword.Empty(); strNotes.Empty();
			nField = 0;
		}
		else
		{
			if(nField == 0) strGroup += pData[i];
			else if(nField == 1) strUserName += pData[i];
			else if(nField == 2) strPassword += pData[i];
			else if(nField == 3) strNotes += pData[i];
		}

		i++;
		if(i >= uFileSize) break;
	}

	EraseCString(&strGroup); EraseCString(&strTitle); EraseCString(&strUserName);
	EraseCString(&strPassword); EraseCString(&strNotes);

	SAFE_DELETE_ARRAY(pData);
	return TRUE;
}
Ejemplo n.º 5
0
BOOL CPwImport::ImportCWalletToDb(const TCHAR *pszFile, CPwManager *pMgr)
{
	char *pData;
	CString strTitle, strURL, strUserName, strPassword, strNotes;
	DWORD uFileSize, i = DWORD_MAX, b;
	CString str;
	CString strLastCategory = _T("General");
	DWORD dwLastGroupId = 0;
	BOOL bInNotes = FALSE;

	ASSERT(pMgr != NULL);

	pData = CPwImport::FileToMemory(pszFile, &uFileSize);
	if(pData == NULL) return FALSE;

	strTitle.Empty(); strURL.Empty(); strUserName.Empty();
	strPassword.Empty(); strNotes.Empty();

	if((uFileSize > 3) && (static_cast<unsigned char>(pData[0]) == 0xEF) &&
		(static_cast<unsigned char>(pData[1]) == 0xBB) &&
		(static_cast<unsigned char>(pData[2]) == 0xBF))
		i += 3; // Skip UTF-8 initialization characters

	bool bUnicodeMode = false;
	if((uFileSize > 2) && (static_cast<unsigned char>(pData[0]) == 0xFF) &&
		(static_cast<unsigned char>(pData[1]) == 0xFE))
	{
		i += 2; // Skip Unicode initialization characters
		bUnicodeMode = true;
	}

	while(true) // Processing the file
	{
		str.Empty();

		while(true) // Loading one line to CString
		{
			++i;
			if(i >= uFileSize) break;

			const char chReadCx = pData[i];

			if(bUnicodeMode) ++i;

			if(chReadCx == '\n') break;
			if(chReadCx != '\r') str += chReadCx;
		}

		// Add the entry
		if(((str.Left(1) == _T("[")) && (str.Right(1) == _T("]"))) ||
			(str == DEF_CW_CATEGORY) || (str == DEF_CW_CATEGORY_NEW) || (i >= uFileSize))
		{
			CString strTrimmedNotes = strNotes;
			strTrimmedNotes = strTrimmedNotes.Trim();

			if((strTitle.IsEmpty() == FALSE) || (strUserName.IsEmpty() == FALSE) ||
				(strURL.IsEmpty() == FALSE) || (strPassword.IsEmpty() == FALSE) ||
				(strTrimmedNotes.IsEmpty() == FALSE))
			{
				strTitle = strTitle.Trim();
				strURL = strURL.Trim();
				strUserName = strUserName.Trim();
				strPassword = strPassword.Trim();
				strNotes = strNotes.Trim();

				PW_TIME tNow;
				_GetCurrentPwTime(&tNow);

				PW_ENTRY pwTemplate;
				memset(&pwTemplate, 0, sizeof(PW_ENTRY));
				pwTemplate.pszAdditional = const_cast<LPTSTR>((LPCTSTR)strNotes);
				pwTemplate.pszPassword = const_cast<LPTSTR>((LPCTSTR)strPassword);
				pwTemplate.pszTitle = const_cast<LPTSTR>((LPCTSTR)strTitle);
				pwTemplate.pszURL = const_cast<LPTSTR>((LPCTSTR)strURL);
				pwTemplate.pszUserName = const_cast<LPTSTR>((LPCTSTR)strUserName);
				pwTemplate.tCreation = tNow; CPwManager::GetNeverExpireTime(&pwTemplate.tExpire);
				pwTemplate.tLastAccess = tNow; pwTemplate.tLastMod = tNow;
				pwTemplate.uGroupId = dwLastGroupId;
				pwTemplate.uImageId = _GetPreferredIcon(strTitle);
				pwTemplate.uPasswordLen = strPassword.GetLength();

				if(pwTemplate.uGroupId != 0) pMgr->AddEntry(&pwTemplate);
			}

			strTitle.Empty(); strURL.Empty(); strUserName.Empty();
			strPassword.Empty(); strNotes.Empty();
			bInNotes = FALSE;
		}

		if(i >= uFileSize) break;

		if((str.Left(1) == _T("[")) && (str.Right(1) == _T("]")))
		{
			strTitle = str;
			strTitle = strTitle.Left(strTitle.GetLength() - 1);
			strTitle = strTitle.Right(strTitle.GetLength() - 1);
			continue;
		}

		if(bInNotes == TRUE)
		{
			if(strNotes.GetLength() != 0) strNotes += _T("\r\n");

			if((str != DEF_CW_CATEGORY) && (str != DEF_CW_CATEGORY_NEW))
				strNotes += str;
		}

		const std::basic_string<TCHAR> strFxCategory = _T("Category: ");
		const std::basic_string<TCHAR> strFxFolder = _T("Folder: ");
		const bool bStartsCat = (str.Left(static_cast<int>(strFxCategory.size())) ==
			strFxCategory.c_str());
		const bool bStartsFld = (str.Left(static_cast<int>(strFxFolder.size())) ==
			strFxFolder.c_str());

		if(bStartsCat || bStartsFld)
		{
			strLastCategory = str.Right(str.GetLength() - static_cast<int>(bStartsCat ?
				strFxCategory.size() : strFxFolder.size()));
			strLastCategory = strLastCategory.Trim();

			while(true)
			{
				strLastCategory = strLastCategory.Left(strLastCategory.GetLength() - 1);
				if(strLastCategory.GetLength() == 0) break;
				if(strLastCategory.Right(1) == _T("("))
				{
					strLastCategory = strLastCategory.Left(strLastCategory.GetLength() - 2);
					break;
				}
				if(strLastCategory.GetLength() == 0) break;
			}

			if(strLastCategory.GetLength() == 0)
				strLastCategory = TRL("General");
			dwLastGroupId = pMgr->GetGroupId((LPCTSTR)strLastCategory);
			if(dwLastGroupId == DWORD_MAX)
			{
				PW_GROUP pwT;
				PW_TIME tNow;
				_GetCurrentPwTime(&tNow);
				memset(&pwT, 0, sizeof(PW_GROUP));
				pwT.pszGroupName = (TCHAR *)(LPCTSTR)strLastCategory;
				pwT.tCreation = tNow; CPwManager::GetNeverExpireTime(&pwT.tExpire);
				pwT.tLastAccess = tNow; pwT.tLastMod = tNow;
				pwT.uGroupId = 0; // 0 = create new group ID
				pwT.uImageId = _GetPreferredIcon((LPCTSTR)strLastCategory);
				pMgr->AddGroup(&pwT);
				dwLastGroupId = pMgr->GetGroupId((LPCTSTR)strLastCategory);
			}
			ASSERT(dwLastGroupId != DWORD_MAX);
		}

		if((str.Left(6) == _T("Notes:")) && (bInNotes == FALSE))
		{
			bInNotes = TRUE;
			str = str.Right(str.GetLength() - 6);
			if(str.GetLength() != 0) strNotes = str;
			continue;
		}

		b=0;
		if(str.Left(9) == _T("User ID: ")) {strUserName = str.Right(str.GetLength() - 9); b=1;}
		if(str.Left(7) == _T("Login: "******"Access #: ")) {strUserName = str.Right(str.GetLength() - 10); b=1;}
		if(str.Left(8) == _T("System: ")) {strUserName = str.Right(str.GetLength() - 8); b=1;}
		if(str.Left(9) == _T("Content: ")) {strUserName = str.Right(str.GetLength() - 9); b=1;}
		if(strUserName.GetLength() == 0)
		{
			if(str.Left(6) == _T("Date: ")) {strUserName = str.Right(str.GetLength() - 6); b=1;}
			if(str.Left(8) == _T("Issuer: ")) {strUserName = str.Right(str.GetLength() - 8); b=1;}
			if(str.Left(8) == _T("Number: ")) {strUserName = str.Right(str.GetLength() - 8); b=1;}
			if(str.Left(9) == _T("Network: ")) {strUserName = str.Right(str.GetLength() - 9); b=1;}
			if(str.Left(11) == _T("Ftp login: "******"URL: ")) {strURL = str.Right(str.GetLength() - 5); b=1;}
		if(str.Left(10) == _T("Web site: ")) {strURL = str.Right(str.GetLength() - 10); b=1;}
		if(strURL.GetLength() == 0)
		{
			if(str.Left(19) == _T("Registered e-mail: ")) {strURL = str.Right(str.GetLength() - 19); b=1;}
		}

		if(str.Left(10) == _T("Password: "******"PIN: ")) {strPassword = str.Right(str.GetLength() - 5); b=1;}
		}

		if((b == 0) && (bInNotes == FALSE))
		{
			if(strNotes.GetLength() != 0) strNotes += _T("\r\n");

			if((str != DEF_CW_CATEGORY) && (str != DEF_CW_CATEGORY_NEW))
				strNotes += str;
		}
	}

	SAFE_DELETE_ARRAY(pData);
	return TRUE;
}