xref: /AOO41X/main/xmerge/source/activesync/XMergeFilter.cpp (revision 626e624c128f1faec44d18081e6f415e4f6877c8)
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;
294         if (*m_szClasspath) {
295             appArgs += " -Djava.class.path=";
296             appArgs += m_szClasspath;
297         } // else avoid empty class path
298     appArgs += " org.openoffice.xmerge.util.ActiveSyncDriver ";
299 
300     if (!lstrcmp(psf->szExtension, "sxw"))
301     {
302         appArgs += "staroffice/sxw ";
303         appArgs += "application/x-pocket-word ";
304     }
305     else if(!lstrcmp(psf->szExtension, "psw"))
306     {
307         appArgs += "application/x-pocket-word ";
308         appArgs += "staroffice/sxw ";
309     }
310     else if(!lstrcmp(psf->szExtension, "sxc"))
311     {
312         appArgs += "staroffice/sxc ";
313         appArgs += "application/x-pocket-excel ";
314     }
315     else if(!lstrcmp(psf->szExtension, "pxl"))
316     {
317         appArgs += "application/x-pocket-excel ";
318         appArgs += "staroffice/sxc ";
319     }
320 
321 
322     // ActiveSync sometimes gives out long file names, especially when automatically syncing
323     appArgs += "\"";
324     appArgs += psf->szFullpath;
325     appArgs += "\" \"";
326     appArgs += pdf->szFullpath;
327     appArgs += "\"";
328 
329     if(!CreateProcess(NULL,
330                   (char*)appArgs.c_str(),
331                   NULL,             // No Process Attributes
332                   NULL,             // No Thread Attributes
333                   FALSE,            // Don't want this process getting handles
334                   CREATE_NO_WINDOW, // No console
335                   NULL,             // No special environment
336                   NULL,             // Current Working Directory is okay
337                   &si,
338                   &pi))
339     {
340         *perr = ERR_INITJAVA;
341         return HRESULT_FROM_WIN32(E_FAIL);
342     }
343 
344     // Wait for the new process to work
345     WaitForSingleObject(pi.hProcess, INFINITE);
346 
347     CloseHandle(pi.hProcess);
348     CloseHandle(pi.hThread);
349 
350     return HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS);
351 }
352 
353 
354 typedef HRESULT (WINAPI *SHGETFOLDERPATH)( HWND, int, HANDLE, DWORD, LPTSTR );
355 
356 
GetJavaBaseDir()357 TCHAR* CXMergeFilter::GetJavaBaseDir()
358 {
359     HRESULT lRet;
360 
361     HKEY hKey = NULL;
362     HKEY hDataKey = NULL;
363 
364     TCHAR szClassName[_MAX_PATH] = "\0";
365     TCHAR szKeyName[_MAX_PATH]   = "\0";
366     TCHAR szCurrentJava[_MAX_PATH] = "\0";
367     DWORD dwClassName            = _MAX_PATH;
368     DWORD dwKeyName              = _MAX_PATH;
369 
370     /*
371      * Java leaves registry keys at HKLM\SOFTWARE\JavaSoft.
372      *
373      * Check for a JRE installation first
374      */
375     lRet = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\JavaSoft\\Java Runtime Environment"), 0, KEY_READ, &hKey);
376     if (lRet != ERROR_SUCCESS)
377         return NULL;
378 
379     // Locations shouldn't be greater than _MAX_PATH
380     TCHAR*  szJavaHome = new TCHAR[_MAX_PATH + 1];
381     DWORD dwSize = _MAX_PATH + 1;
382 
383     /* use current version */
384     lRet = ::RegQueryValueEx(hKey, _T("CurrentVersion"), 0, NULL, (LPBYTE)szCurrentJava, &dwSize);
385 
386     /*
387     for (DWORD i = 0; lRet != ERROR_NO_MORE_ITEMS; i++)
388     {
389         lRet = ::RegEnumKeyEx(hKey, i, szKeyName, &dwKeyName, 0, szClassName, &dwClassName, NULL);
390         if(!strncmp(szKeyName, "1.4", 3))
391             break;
392         dwKeyName = _MAX_PATH;
393     }
394     // Found a Java 1.4 installation.  Can now read its home directory.
395     */
396 
397 
398     lRet = ::RegOpenKeyEx(hKey, _T(szCurrentJava), 0, KEY_READ, &hDataKey);
399     if (lRet != ERROR_SUCCESS)
400     {
401         RegCloseKey(hKey);
402         delete [] szJavaHome;
403         return NULL;
404     }
405 
406 
407     // Now read the JavaHome value
408     dwSize = _MAX_PATH + 1;
409     lRet = ::RegQueryValueEx(hDataKey, _T("JavaHome"), 0, NULL, (LPBYTE)szJavaHome, &dwSize);
410     if (lRet != ERROR_SUCCESS)
411     {
412         RegCloseKey(hDataKey);
413         RegCloseKey(hKey);
414         delete [] szJavaHome;
415         return NULL;
416     }
417 
418     RegCloseKey(hDataKey);
419     RegCloseKey(hKey);
420 
421 
422     // Check that the directory exists before returning it
423     DWORD dwAttrs = GetFileAttributes(szJavaHome);
424 
425     if (((dwAttrs & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY) || dwAttrs == INVALID_FILE_SIZE)
426     {
427         delete [] szJavaHome;
428         return NULL;
429     }
430 
431     return szJavaHome;
432 }
433 
434 
435 
GetXMergeClassPath()436 TCHAR* CXMergeFilter::GetXMergeClassPath()
437 {
438     /*
439      * The DLL will be installed by setup in the program directory of
440      * the installation.  The XMerge Jar files, if present, will be
441      * located in the classes directory below program.
442      */
443 
444     TCHAR szJarPath[MAX_PATH];
445     TCHAR szTmpPath[MAX_PATH];
446 
447     ZeroMemory(szJarPath, MAX_PATH);
448     ZeroMemory(szTmpPath, MAX_PATH);
449 
450     WIN32_FILE_ATTRIBUTE_DATA fInfo;
451 
452     std::string clsPath;
453 
454 
455     // Get the location of the module.
456     GetModuleFileName(_Module.m_hInst, szTmpPath, MAX_PATH);
457 
458     // Strip off the xmergesync.dll component
459     _strlwr(szTmpPath);
460     char* modName = strstr(szTmpPath, "xmergesync.dll");
461     strncpy(szJarPath, szTmpPath, modName - szTmpPath);
462 
463     // Append the classes directory
464     strncat(szJarPath, "classes\\", 8);
465 
466 
467     // The core xmerge.jar must be present
468     ZeroMemory(szTmpPath, MAX_PATH);
469     _snprintf(szTmpPath, MAX_PATH, "%s%s\0", szJarPath, "xmerge.jar");
470 
471     if (!GetFileAttributesEx(szTmpPath, GetFileExInfoStandard, &fInfo))
472     {
473         return NULL;
474     }
475     else
476     {
477         clsPath += szTmpPath;
478         clsPath += ";";
479     }
480 
481 
482     // Now check for Pocket Word
483     ZeroMemory(szTmpPath, MAX_PATH);
484     _snprintf(szTmpPath, MAX_PATH, "%s%s\0", szJarPath, "pocketword.jar");
485 
486     if (!GetFileAttributesEx(szTmpPath, GetFileExInfoStandard, &fInfo))
487     {
488         m_bHaveWord = FALSE;
489     }
490     else
491     {
492         m_bHaveWord = TRUE;
493         clsPath += szTmpPath;
494         clsPath += ";";
495     }
496 
497     // Now check for Pocket Excel
498     ZeroMemory(szTmpPath, MAX_PATH);
499     _snprintf(szTmpPath, MAX_PATH, "%s%s\0", szJarPath, "pexcel.jar");
500 
501     if (!GetFileAttributesEx(szTmpPath, GetFileExInfoStandard, &fInfo))
502     {
503         m_bHaveExcel = FALSE;
504     }
505     else
506     {
507         m_bHaveExcel = TRUE;
508         clsPath += szTmpPath;
509         clsPath += ";";
510     }
511 
512     // Quotes may be need around the ClassPath
513     clsPath.insert(0, "\"");
514     clsPath += "\"";
515 
516 
517     // Return the data
518     return _strdup(clsPath.c_str());
519 }
520