1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 // XMergeFilter.cpp: implementation of the CXMergeFilter class.
23 //
24 //////////////////////////////////////////////////////////////////////
25 
26 
27 #include "stdafx.h"
28 
29 #include "XMergeFilter.h"
30 
31 #include <string>
32 
33 
34 #define ERR_NOJAVA       1
35 #define ERR_BADCLASSPATH 2
36 #define ERR_INITJAVA     3
37 
38 
39 const LPTSTR CXMergeFilter::m_pszPSWExportCLSID		= _T("{BDD611C3-7BAB-460F-8711-5B9AC9EF6020}");
40 const LPTSTR CXMergeFilter::m_pszPSWExportExt		= _T("sxw");
41 const LPTSTR CXMergeFilter::m_pszPSWExportDesc		= _T("OpenOffice.org XML Writer Document");
42 const LPTSTR CXMergeFilter::m_pszPSWExportShortDesc	= _T("OpenOffice.org XML Writer");
43 
44 const LPTSTR CXMergeFilter::m_pszPSWImportCLSID		= _T("{CB43F086-838D-4FA4-B5F6-3406B9A57439}");
45 const LPTSTR CXMergeFilter::m_pszPSWImportExt		= _T("psw");
46 const LPTSTR CXMergeFilter::m_pszPSWImportDesc		= _T("Pocket Word Document - Pocket PC");
47 const LPTSTR CXMergeFilter::m_pszPSWImportShortDesc	= _T("Pocket Word");
48 
49 const LPTSTR CXMergeFilter::m_pszPXLExportCLSID		= _T("{C6AB3E74-9F4F-4370-8120-A8A6FABB7A7C}");
50 const LPTSTR CXMergeFilter::m_pszPXLExportExt		= _T("sxc");
51 const LPTSTR CXMergeFilter::m_pszPXLExportDesc		= _T("OpenOffice.org XML Calc Document");
52 const LPTSTR CXMergeFilter::m_pszPXLExportShortDesc	= _T("OpenOffice.org XML Calc");
53 
54 const LPTSTR CXMergeFilter::m_pszPXLImportCLSID		= _T("{43887C67-4D5D-4127-BAAC-87A288494C7C}");
55 const LPTSTR CXMergeFilter::m_pszPXLImportExt		= _T("pxl");
56 const LPTSTR CXMergeFilter::m_pszPXLImportDesc		= _T("Pocket Excel Document - Pocket PC");
57 const LPTSTR CXMergeFilter::m_pszPXLImportShortDesc	= _T("Pocket Excel");
58 
59 
60 //////////////////////////////////////////////////////////////////////
61 // Construction/Destruction
62 //////////////////////////////////////////////////////////////////////
63 
CXMergeFilter()64 CXMergeFilter::CXMergeFilter() : m_cRef(1)
65 {
66 	m_bHaveExcel = FALSE;
67 	m_bHaveWord  = FALSE;
68 
69 	m_szClasspath   = NULL;
70 	m_szJavaBaseDir = NULL;
71 }
72 
~CXMergeFilter()73 CXMergeFilter::~CXMergeFilter()
74 {
75 	if (m_szClasspath != NULL)
76 	{
77 		delete m_szClasspath;
78 	}
79 
80 	if (m_szJavaBaseDir != NULL)
81 	{
82 		delete m_szJavaBaseDir;
83 	}
84 
85 }
86 
87 
88 //////////////////////////////////////////////////////////////////////
89 // IUnknown Methods
90 //////////////////////////////////////////////////////////////////////
91 
QueryInterface(REFIID riid,void ** ppvObject)92 STDMETHODIMP CXMergeFilter::QueryInterface(REFIID riid, void **ppvObject)
93 {
94 	if(ppvObject == NULL)
95 		return E_INVALIDARG;
96 
97     if (::IsEqualIID(riid, IID_IUnknown))
98 	{
99         *ppvObject = static_cast<IUnknown *>(this);
100 	}
101     else if (::IsEqualIID(riid, IID_ICeFileFilter))
102 	{
103         *ppvObject = static_cast<ICeFileFilter *>(this);
104 	}
105 	else
106 	{
107 		*ppvObject = NULL;
108 		return E_NOINTERFACE;
109 	}
110 
111 	reinterpret_cast<IUnknown *>(*ppvObject)->AddRef();
112 	return S_OK;
113 }
114 
115 
STDMETHODIMP_(ULONG)116 STDMETHODIMP_(ULONG) CXMergeFilter::AddRef()
117 {
118 	return ::InterlockedIncrement(&m_cRef);
119 }
120 
121 
STDMETHODIMP_(ULONG)122 STDMETHODIMP_(ULONG) CXMergeFilter::Release()
123 {
124 	if(::InterlockedDecrement(&m_cRef) == 0)
125 	{
126 		delete this;
127 		return 0;
128 	}
129 	return m_cRef;
130 }
131 
132 
133 //////////////////////////////////////////////////////////////////////
134 // ICeFileFilter
135 //////////////////////////////////////////////////////////////////////
136 
FilterOptions(HWND hwndParent)137 STDMETHODIMP CXMergeFilter::FilterOptions(HWND hwndParent)
138 {
139 	// We don't currently allow any options
140 	return HRESULT_FROM_WIN32(NOERROR);
141 }
142 
FormatMessage(DWORD dwFlags,DWORD dwMessageId,DWORD dwLanguageId,LPTSTR lpBuffer,DWORD nSize,va_list * Arguments,DWORD * pcb)143 STDMETHODIMP CXMergeFilter::FormatMessage(DWORD dwFlags, DWORD dwMessageId,
144 						DWORD dwLanguageId, LPTSTR lpBuffer, DWORD nSize,
145 						va_list *Arguments, DWORD *pcb)
146 {
147 	TCHAR errMsg[1024];
148 
149 	HKEY  hKey   = NULL;
150 	DWORD dwSize = 1024;
151 
152 
153 	long lRet = 0;
154 
155 	// Attempt to find the messages in the registry
156 	lRet = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Sun Microsystems\\StarOffice\\XMergeSync\\Messages\\Error"),
157 							0, KEY_READ, &hKey);
158 	if (lRet != ERROR_SUCCESS)
159 	{
160 		// Try the user's portion of the registry
161 		lRet = ::RegOpenKeyEx(HKEY_CURRENT_USER, _T("Software\\Sun Microsystems\\StarOffice\\XMergeSync\\Messages\\Error"),
162 							0, KEY_READ, &hKey);
163 		if (lRet != ERROR_SUCCESS)
164 		{
165 			hKey = NULL;
166 		}
167 	}
168 
169 
170 	switch(dwMessageId)
171 	{
172 	case ERR_NOJAVA:
173 		lRet = ::RegQueryValueEx(hKey, _T("Java"), 0, NULL, (LPBYTE)errMsg, &dwSize);
174 		if (lRet != ERROR_SUCCESS)
175 		{
176 			lstrcpy(errMsg, "Unable to locate Java 1.4/1.5 installation.");
177 		}
178 		break;
179 
180 	case ERR_BADCLASSPATH:
181 		lRet = ::RegQueryValueEx(hKey, _T("Classpath"), 0, NULL, (LPBYTE)errMsg, &dwSize);
182 		if (lRet != ERROR_SUCCESS)
183 		{
184 			lstrcpy(errMsg, "Unable to locate XMerge Jar files.");
185 		}
186 		break;
187 
188 	case ERR_INITJAVA:
189 		lRet = ::RegQueryValueEx(hKey, _T("JavaInit"), 0, NULL, (LPBYTE)errMsg, &dwSize);
190 		if (lRet != ERROR_SUCCESS)
191 		{
192 			lstrcpy(errMsg, "Error initialising the Java Runtime Environment.");
193 		}
194 		break;
195 	}
196 
197 	char* buf = (char*)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, (lstrlen(errMsg) + 1) * sizeof(TCHAR));
198 	lstrcpyn(buf, errMsg, lstrlen(errMsg));
199 
200 	*(char**)lpBuffer = buf;
201 	*pcb = strlen(errMsg);
202 
203 	return HRESULT_FROM_WIN32(NOERROR);
204 }
205 
206 
NextConvertFile(int nConversion,CFF_CONVERTINFO * pci,CFF_SOURCEFILE * psf,CFF_DESTINATIONFILE * pdf,volatile BOOL * pbCancel,CF_ERROR * perr)207 STDMETHODIMP CXMergeFilter::NextConvertFile(int nConversion, CFF_CONVERTINFO *pci,
208 							 CFF_SOURCEFILE *psf, CFF_DESTINATIONFILE *pdf,
209 							 volatile BOOL *pbCancel, CF_ERROR *perr)
210 {
211 	std::string appArgs;
212 	std::string appName;
213 
214 	STARTUPINFO si;
215     PROCESS_INFORMATION pi;
216 
217     ZeroMemory( &si, sizeof(si) );
218 	ZeroMemory( &pi, sizeof(pi) );
219 
220 	si.cb = sizeof(si);
221 
222 
223 	/*
224 	 * First step: Locate Java and establish the classpath.  If these can't
225 	 *             be done succesfully, then avoid all further processing.
226 	 */
227 
228 	// Locate Java Home if it hasn't already been done.
229 	if (m_szJavaBaseDir == NULL)
230 	{
231 		m_szJavaBaseDir = GetJavaBaseDir();
232 
233 		if (m_szJavaBaseDir == NULL)
234 		{
235 			*perr = ERR_NOJAVA;
236 			return HRESULT_FROM_WIN32(E_FAIL);
237 		}
238 	}
239 
240 	// Get the Apache OpenOffice class directory
241 	if (m_szClasspath == NULL)
242 	{
243 		m_szClasspath = GetXMergeClassPath();
244 
245 		if (m_szClasspath == NULL)
246 		{
247 			*perr = ERR_BADCLASSPATH;
248 			return HRESULT_FROM_WIN32(E_FAIL);
249 		}
250 	}
251 
252 
253 	/*
254 	 * Second step:  Check the files we're going to process.  If we don't have
255 	 *				 an XMerge plugin for the file then we can't convert.
256 	 */
257 	if ((!lstrcmp(psf->szExtension, "sxw")  || !lstrcmp(psf->szExtension, "psw"))
258 		    && !m_bHaveWord)
259 	{
260 		*perr = ERR_BADCLASSPATH;
261 		return HRESULT_FROM_WIN32(E_FAIL);
262 	}
263 	else if ((!lstrcmp(psf->szExtension, "sxc")  || !lstrcmp(psf->szExtension, "pxl"))
264 				 && !m_bHaveExcel)
265 	{
266 		*perr = ERR_BADCLASSPATH;
267 		return HRESULT_FROM_WIN32(E_FAIL);
268 	}
269 
270 
271 	/*
272 	 * Third step:  Locate the Java executable and build and execute the command
273 	 *				line to carry out the conversion.
274 	 */
275 
276 	// Find the Java executable and make sure it exists
277 	appName += m_szJavaBaseDir;
278 	appName += "\\bin\\javaw.exe";
279 
280 	if (GetFileAttributes(appName.c_str()) == INVALID_FILE_SIZE)
281 	{
282 		*perr = ERR_NOJAVA;
283 		return HRESULT_FROM_WIN32(E_FAIL);
284 	}
285 
286 	// Wrap the executable path in quotes in case of spaces
287 	appName.insert(0, "\"");
288 	appName.append("\"");
289 
290 
291 
292 	// Need to build the entire command line for calling out to Java
293 	appArgs =  appName + " -Djava.class.path=";
294 	appArgs += m_szClasspath;
295 	appArgs += " org.openoffice.xmerge.util.ActiveSyncDriver ";
296 
297 	if (!lstrcmp(psf->szExtension, "sxw"))
298 	{
299 		appArgs += "staroffice/sxw ";
300 		appArgs += "application/x-pocket-word ";
301 	}
302 	else if(!lstrcmp(psf->szExtension, "psw"))
303 	{
304 		appArgs += "application/x-pocket-word ";
305 		appArgs += "staroffice/sxw ";
306 	}
307 	else if(!lstrcmp(psf->szExtension, "sxc"))
308 	{
309 		appArgs += "staroffice/sxc ";
310 		appArgs += "application/x-pocket-excel ";
311 	}
312 	else if(!lstrcmp(psf->szExtension, "pxl"))
313 	{
314 		appArgs += "application/x-pocket-excel ";
315 		appArgs += "staroffice/sxc ";
316 	}
317 
318 
319 	// ActiveSync sometimes gives out long file names, especially when automatically syncing
320 	appArgs += "\"";
321 	appArgs += psf->szFullpath;
322 	appArgs += "\" \"";
323 	appArgs += pdf->szFullpath;
324 	appArgs += "\"";
325 
326 	if(!CreateProcess(NULL,
327 				  (char*)appArgs.c_str(),
328 				  NULL,				// No Process Attributes
329 				  NULL,				// No Thread Attributes
330 				  FALSE,			// Don't want this process getting handles
331 				  CREATE_NO_WINDOW,	// No console
332 				  NULL,				// No special environment
333 				  NULL,				// Current Working Directory is okay
334 				  &si,
335 				  &pi))
336 	{
337 		*perr = ERR_INITJAVA;
338 		return HRESULT_FROM_WIN32(E_FAIL);
339 	}
340 
341 	// Wait for the new process to work
342 	WaitForSingleObject(pi.hProcess, INFINITE);
343 
344 	CloseHandle(pi.hProcess);
345 	CloseHandle(pi.hThread);
346 
347 	return HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS);
348 }
349 
350 
351 typedef HRESULT (WINAPI *SHGETFOLDERPATH)( HWND, int, HANDLE, DWORD, LPTSTR );
352 
353 
GetJavaBaseDir()354 TCHAR* CXMergeFilter::GetJavaBaseDir()
355 {
356 	HRESULT lRet;
357 
358 	HKEY hKey = NULL;
359 	HKEY hDataKey = NULL;
360 
361 	TCHAR szClassName[_MAX_PATH] = "\0";
362 	TCHAR szKeyName[_MAX_PATH]   = "\0";
363     TCHAR szCurrentJava[_MAX_PATH] = "\0";
364 	DWORD dwClassName            = _MAX_PATH;
365 	DWORD dwKeyName              = _MAX_PATH;
366 
367 	/*
368 	 * Java leaves registry keys at HKLM\SOFTWARE\JavaSoft.
369 	 *
370 	 * Check for a JRE installation first
371 	 */
372 	lRet = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\JavaSoft\\Java Runtime Environment"), 0, KEY_READ, &hKey);
373 	if (lRet != ERROR_SUCCESS)
374 		return NULL;
375 
376 	// Locations shouldn't be greater than _MAX_PATH
377 	TCHAR*  szJavaHome = new TCHAR[_MAX_PATH + 1];
378 	DWORD dwSize = _MAX_PATH + 1;
379 
380     /* use current version */
381     lRet = ::RegQueryValueEx(hKey, _T("CurrentVersion"), 0, NULL, (LPBYTE)szCurrentJava, &dwSize);
382 
383     /*
384 	for (DWORD i = 0; lRet != ERROR_NO_MORE_ITEMS; i++)
385 	{
386 		lRet = ::RegEnumKeyEx(hKey, i, szKeyName, &dwKeyName, 0, szClassName, &dwClassName, NULL);
387 		if(!strncmp(szKeyName, "1.4", 3))
388 			break;
389 		dwKeyName = _MAX_PATH;
390 	}
391     // Found a Java 1.4 installation.  Can now read its home directory.
392     */
393 
394 
395 	lRet = ::RegOpenKeyEx(hKey, _T(szCurrentJava), 0, KEY_READ, &hDataKey);
396 	if (lRet != ERROR_SUCCESS)
397 	{
398 		RegCloseKey(hKey);
399 		delete [] szJavaHome;
400 		return NULL;
401 	}
402 
403 
404 	// Now read the JavaHome value
405     dwSize = _MAX_PATH + 1;
406 	lRet = ::RegQueryValueEx(hDataKey, _T("JavaHome"), 0, NULL, (LPBYTE)szJavaHome, &dwSize);
407 	if (lRet != ERROR_SUCCESS)
408 	{
409 		RegCloseKey(hDataKey);
410 		RegCloseKey(hKey);
411 		delete [] szJavaHome;
412 		return NULL;
413 	}
414 
415 	RegCloseKey(hDataKey);
416 	RegCloseKey(hKey);
417 
418 
419 	// Check that the directory exists before returning it
420 	DWORD dwAttrs = GetFileAttributes(szJavaHome);
421 
422 	if (((dwAttrs & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY) || dwAttrs == INVALID_FILE_SIZE)
423 	{
424 		delete [] szJavaHome;
425 		return NULL;
426 	}
427 
428 	return szJavaHome;
429 }
430 
431 
432 
GetXMergeClassPath()433 TCHAR* CXMergeFilter::GetXMergeClassPath()
434 {
435 	/*
436 	 * The DLL will be installed by setup in the program directory of
437 	 * the installation.  The XMerge Jar files, if present, will be
438 	 * located in the classes directory below program.
439 	 */
440 
441 	TCHAR szJarPath[MAX_PATH];
442 	TCHAR szTmpPath[MAX_PATH];
443 
444 	ZeroMemory(szJarPath, MAX_PATH);
445 	ZeroMemory(szTmpPath, MAX_PATH);
446 
447 	WIN32_FILE_ATTRIBUTE_DATA fInfo;
448 
449 	std::string clsPath;
450 
451 
452 	// Get the location of the module.
453 	GetModuleFileName(_Module.m_hInst, szTmpPath, MAX_PATH);
454 
455 	// Strip off the xmergesync.dll component
456 	_strlwr(szTmpPath);
457 	char* modName = strstr(szTmpPath, "xmergesync.dll");
458 	strncpy(szJarPath, szTmpPath, modName - szTmpPath);
459 
460 	// Append the classes directory
461 	strncat(szJarPath, "classes\\", 8);
462 
463 
464 	// The core xmerge.jar must be present
465 	ZeroMemory(szTmpPath, MAX_PATH);
466 	_snprintf(szTmpPath, MAX_PATH, "%s%s\0", szJarPath, "xmerge.jar");
467 
468 	if (!GetFileAttributesEx(szTmpPath, GetFileExInfoStandard, &fInfo))
469 	{
470 		return NULL;
471 	}
472 	else
473 	{
474 		clsPath += szTmpPath;
475 		clsPath += ";";
476 	}
477 
478 
479 	// Now check for Pocket Word
480 	ZeroMemory(szTmpPath, MAX_PATH);
481 	_snprintf(szTmpPath, MAX_PATH, "%s%s\0", szJarPath, "pocketword.jar");
482 
483 	if (!GetFileAttributesEx(szTmpPath, GetFileExInfoStandard, &fInfo))
484 	{
485 		m_bHaveWord = FALSE;
486 	}
487 	else
488 	{
489 		m_bHaveWord = TRUE;
490 		clsPath += szTmpPath;
491 		clsPath += ";";
492 	}
493 
494 	// Now check for Pocket Excel
495 	ZeroMemory(szTmpPath, MAX_PATH);
496 	_snprintf(szTmpPath, MAX_PATH, "%s%s\0", szJarPath, "pexcel.jar");
497 
498 	if (!GetFileAttributesEx(szTmpPath, GetFileExInfoStandard, &fInfo))
499 	{
500 		m_bHaveExcel = FALSE;
501 	}
502 	else
503 	{
504 		m_bHaveExcel = TRUE;
505 		clsPath += szTmpPath;
506 		clsPath += ";";
507 	}
508 
509 	// Quotes may be need around the ClassPath
510 	clsPath.insert(0, "\"");
511 	clsPath += "\"";
512 
513 
514 	// Return the data
515 	return _strdup(clsPath.c_str());
516 }
517