summaryrefslogtreecommitdiff
path: root/NSCmpts/EncryptActions.cpp
blob: aac7fb5efeb1eaf06af95259f332dd75a038bf6f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
// EncryptActions.cpp: implementation of the CEncryptActions class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "EncryptActions.h"

#include "resource.h"
#include <appmisc.h>


//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

bool CEncryptActions::EncryptPrepare::Do(CActionEngine* pEngine, 
	  								     HWND hwndUpdates)
{
	ASSERT(pEngine != NULL);

	Update(hwndUpdates, _T("Listing files to encrypt..."), NULL);

	// Iterate through source folders
	string_array::const_iterator iterSrc;
	for(iterSrc = m_aFiles.begin(); iterSrc != m_aFiles.end(); iterSrc++)
	{
		Update(hwndUpdates, NULL, (LPCTSTR)*iterSrc);

		file_iterator fileIter((file_path)*iterSrc, file_iterator::sub_folders | file_iterator::full_paths), end;
		for( ; fileIter != end; fileIter++)
		{
			file_path srcFile(fileIter->cFileName);
			if(!(srcFile.attributes() & FILE_ATTRIBUTE_DIRECTORY))
			{
				if(m_asIgnore.find(srcFile.ext().make_lower()) == m_asIgnore.end())
				{
					// Construct File
					Encrypt* pEncrypt = new Encrypt(srcFile);
					pEngine->Add(pEncrypt);
				}
			}
		}
		
		// Error from file_iterator (listing folders)
		if(fileIter.state() != ERROR_SUCCESS)
			throw CActionError(HRESULT_FROM_WIN32(fileIter.state()), IDS_ENCRYPT_ERR_LIST, (file_path)*iterSrc);
	}

	return false;
}

HRESULT CEncryptActions::EncryptPrepare::Initialize(const CPropertyBag& data)
{
	if(!data.GetStringSet(NS_ENCRYPT_REG_FILES, m_aFiles))
		return S_FALSE;

	CEncryptActions::Encrypt::m_bEncryptReadOnly = data.GetInt(NS_ENCRYPT_REG_READONLY, false) ? true : false;

	string_array asTemp;
	data.GetStringSet(NS_IGNORE_REG_EXT, asTemp);

	// Make them all lower
	for_each(asTemp.begin(), asTemp.end(), Lower);

	// And copy them to the set (removes doubles)
	copy(asTemp.begin(), asTemp.end(), inserter(m_asIgnore, m_asIgnore.begin()));

	// Remove any blanks from ignore
	m_asIgnore.erase(_T(""));

	return S_OK;
}


IXpyExPtr CEncryptActions::Encrypt::m_pXpy;
bool CEncryptActions::Encrypt::m_bEncryptReadOnly = false;
UINT CEncryptActions::Encrypt::m_nXpyRefs = 0;

bool CEncryptActions::Encrypt::Do(CActionEngine* pEngine, 
	  								 HWND hwndUpdates)
{
	// Update any monitors
	Update(hwndUpdates, _T("Encrypting..."), m_file);

	// Initialize XPY
	HRESULT hr;
	if(FAILED(hr = InitXpy()))
	{
		// If it doesn't work then trash all the encryption actions 
		// in the engine
		if(pEngine)
			pEngine->RemoveAll(this);

		// And spit out an error
		throw CActionError(hr, IDS_ENCRYPT_ERR_XPYINIT);
	}


	// Use this in case we need to reset the attributes
	// in order to encrypt the file. XPY won't encrypt
	// read-only files. There's an option here 
	// to let you. So basically what we have to do is 
	// reset the file to normal attributes and then set 
	// it back

	// If it's 0 that means we haven't messed with the 
	// attributes yet. If it has a value that means we 
	// need to set the value back before returning
	DWORD dwAttributes = 0;

encrypt:

	try
	{
		// Here's the actual close code
		// rest is basically error checking
		m_pXpy->Close((LPCTSTR)m_file);

	}
	catch(_com_error& e)
	{
		// Here we check for the read-only error that Xpy 
		// will spit up. If the flag is set then go ahead
		// and reset the attributes

		if(e.Error() == XPY_E_FILE_ATTRIBUTES && // Read Only Error
		   m_bEncryptReadOnly)					 // flag to encrypt read-only
		{

			// If we haven't messed with the attributes 
			// yet then go ahead and reset them
			if(!dwAttributes)
			{
				// Get Attributes
				dwAttributes = GetFileAttributes(m_file);

				// Let System files blow! (with an error)
				if(!(dwAttributes & FILE_ATTRIBUTE_SYSTEM))
				{
					SetFileAttributes(m_file, FILE_ATTRIBUTE_NORMAL);
				
					// Reencrypt
					goto encrypt;
				}

			}

			// Otherwise we won't try again
		}

		// Set the Attributes back
		if(dwAttributes)
			SetFileAttributes(m_file, dwAttributes);

		// Get the proper error message
		_bstr_t bsError = e.Description();

		if(bsError.length())
			throw CActionError((LPCTSTR)bsError, e.Error(), IDS_ENCRYPT_ERR, m_file);
		else
			throw CActionError(e.Error(), IDS_ENCRYPT_ERR, m_file);
	}

	// Set the Attributes back
	if(dwAttributes)
		SetFileAttributes(m_file, dwAttributes);

	return false;
}

bool CEncryptActions::Encrypt::IsFixable(HRESULT hr) const
{
	switch(hr)
	{
	case XPY_E_FILE_ATTRIBUTES:
	case HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION):
	case HRESULT_FROM_WIN32(ERROR_LOCK_VIOLATION):
		return true;
	default:
		return false;
	}
}

void CEncryptActions::Encrypt::Fix(HRESULT hr)
{
	if(hr == XPY_E_FILE_ATTRIBUTES)
	{
		if(SetFileAttributes(m_file, FILE_ATTRIBUTE_NORMAL))
			Do(NULL, NULL);
		else
			throw CActionError(HRESULT_FROM_WIN32(::GetLastError()), IDS_ENCRYPT_ERR, m_file);
	}
	else if(hr == HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION) || 
		    hr == HRESULT_FROM_WIN32(ERROR_LOCK_VIOLATION))
	{
		bool bFirst = true;
start:
		try
		{
			// Try again
			Do(NULL, NULL);
			return;
		}
		catch(CActionError& err)
		{
			// If it's the first around and the error is the same...
			if(bFirst && IsFixable(err.m_hRes))
			{
				HCURSOR hCurs = ::GetCursor();

				// ... Prompt user to close programs
				MessageBox(NULL, _T("Files cannot be encrypted while they are opened in a program. Close all other programs and then click the OK button."), _T("Encrypt Files"), MB_OK | MB_ICONINFORMATION);

				if(hCurs)
					::SetCursor(hCurs);

				bFirst = false;
			}
			// Otherwise out with the error
			else
				throw;
		}

		goto start;
	}
}

HRESULT CEncryptActions::Encrypt::InitXpy()
{
	if(m_pXpy)
		return S_OK;
	else 
		return m_pXpy.CreateInstance(__uuidof(XpyEx));
}