1 /* AbiSource Application Framework
2  * Copyright (C) 1998-2000 AbiSource, Inc.
3  * Copyright (C) 2004 Hubert Figuiere
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (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 Street, Fifth Floor, Boston, MA
18  * 02110-1301 USA.
19  */
20 
21 
22 #include <windows.h>
23 #include <winreg.h>
24 
25 #include "xap_Win32AppImpl.h"
26 #include "ut_string_class.h"
27 #include "ut_path.h"
28 #include "xap_Frame.h"
29 #include "xap_App.h"
30 #include "xap_Win32FrameImpl.h"
31 
32 #include "ut_Win32LocaleString.h"
33 
openURL(const char * szURL)34 bool XAP_Win32AppImpl::openURL(const char * szURL)
35 {
36 	// NOTE: could get finer control over browser window via DDE
37 	// NOTE: may need to fallback to WinExec for old NSCP versions
38 
39 	UT_String sURL = szURL;
40 
41 	// If this is a file:// URL, strip off file:// and make it backslashed
42 	if (sURL.substr(0, 7) == "file://")
43 	{
44 		sURL = sURL.substr(7, sURL.size() - 7);
45 
46 		// View as WebPage likes to throw in an extra /\ just for fun, strip it off
47 		if (sURL.substr(0, 2) == "/\\")
48 			sURL = sURL.substr(2, sURL.size() - 2);
49 
50 		if (sURL.substr(0, 1) == "/")
51 			sURL = sURL.substr(1, sURL.size() - 1);
52 
53 		// Convert all forwardslashes to backslashes
54 		for (unsigned int i=0; i<sURL.length();i++)
55 			if (sURL[i]=='/')
56                 sURL[i]='\\';
57 
58 		// Convert from longpath to 8.3 shortpath, in case of spaces in the path
59 		char* longpath = NULL;
60 		char* shortpath = NULL;
61 		longpath = new char[PATH_MAX];
62 		shortpath = new char[PATH_MAX];
63 		strcpy(longpath, sURL.c_str());
64 		DWORD retval = GetShortPathName(longpath, shortpath, PATH_MAX);
65 		if((retval == 0) || (retval > PATH_MAX))
66 		{
67 			UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
68 			DELETEP(longpath);
69 			DELETEP(shortpath);
70 			return false;
71 		}
72 		sURL = shortpath;
73 		DELETEP(longpath);
74 		DELETEP(shortpath);
75 	}
76 
77 	// Query the registry for the default browser so we can directly invoke it
78 	UT_String sBrowser;
79 	HKEY hKey;
80 	unsigned long lType;
81 	DWORD dwSize;
82 	LPWSTR szValue = NULL;
83 	UT_Win32LocaleString str,str2;
84 	UT_UTF8String utf8;
85 
86 	if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"http\\shell\\open\\command", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
87 	{
88 		if(RegQueryValueExW(hKey, NULL, NULL, &lType, NULL, &dwSize) == ERROR_SUCCESS)
89 		{
90 			szValue = new WCHAR[dwSize + 1];
91 			RegQueryValueExW(hKey, NULL, NULL, &lType, (LPBYTE) szValue, &dwSize);
92 			str.fromLocale(szValue);
93 			utf8=str.utf8_str();
94 			sBrowser = utf8.utf8_str();
95 			DELETEP(szValue);
96 		}
97 		RegCloseKey(hKey);
98 	}
99 
100 	/* Now that we have sBrowser from the registry, we need to parse it out.
101 	 * If the first character is a double-quote, everything up to and including
102 	 * the next double-quote is the sBrowser command. Everything after the
103 	 * double-quote is appended to the parameters.
104 	 * If the first character is NOT a double-quote, we assume
105 	 * everything up to the first whitespace is the command and anything after
106 	 * is appended to the parameters.
107 	 */
108 
109 	int iDelimiter;
110 	if (sBrowser.substr(0, 1) == "\"")
111 		iDelimiter = UT_String_findCh(sBrowser.substr(1, sBrowser.length()-1), '"')+2;
112 	else
113 		iDelimiter = UT_String_findCh(sBrowser.substr(0, sBrowser.length()), ' ');
114 
115 	// Store params into a separate UT_String before we butcher sBrowser
116 	UT_String sParams = sBrowser.substr(iDelimiter+1, sBrowser.length()-iDelimiter+1);
117 	// Cut params off of sBrowser so all we're left with is the broweser path & executable
118 	sBrowser = sBrowser.substr(0, iDelimiter);
119 
120 	// Check for a %1 passed in from the registry.  If we find it,
121 	// substitute our URL for %1.  Otherwise, just append sURL to params.
122 	const char *pdest = strstr(sParams.c_str(), "%1");
123 	if (pdest != NULL)
124 	{
125 		int i = pdest - sParams.c_str() + 1;
126 		sParams = sParams.substr(0, i-1) + sURL + sParams.substr(i+1, sParams.length()-i+1);
127 	}
128 	else
129 	{
130 		sParams = sParams + " " + sURL;
131 	}
132 
133 	XAP_Frame * pFrame = XAP_App::getApp()->getLastFocussedFrame();
134 	UT_return_val_if_fail(pFrame, false);
135 	XAP_Win32FrameImpl *pFImp =  (XAP_Win32FrameImpl *) pFrame->getFrameImpl();
136 	UT_return_val_if_fail(pFImp, false);
137 
138 	str.fromUTF8(sBrowser.c_str());
139 	str2.fromUTF8(sParams.c_str());
140 
141 	intptr_t res = (intptr_t) ShellExecuteW(pFImp->getTopLevelWindow() /*(HWND)*/,
142 								 L"open", str.c_str(), str2.c_str(), NULL, SW_SHOW );
143 
144 	// TODO: localized error messages
145 	// added more specific error messages as documented in http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/system_error_codes.asp
146 	if (res <= 32)
147 	{
148 		UT_String errMsg;
149 		switch (res)
150 		{
151 			case ERROR_FILE_NOT_FOUND:
152 				{
153 					errMsg = "Error (";
154 					errMsg += UT_String_sprintf("%d", res);
155 					errMsg += ") displaying URL: The system cannot find the file specified.\n";
156 					errMsg += " [ ";  errMsg += sURL;  errMsg += " ] ";
157 				}
158 				break;
159 
160 			case ERROR_PATH_NOT_FOUND:
161 				{
162 					errMsg = "Error (";
163 					errMsg += UT_String_sprintf("%d", res);
164 					errMsg += ") displaying URL: The system cannot find the path specified.\n";
165 					errMsg += " [ ";  errMsg += sURL;  errMsg += " ] ";
166 				}
167 				break;
168 
169 			case SE_ERR_ACCESSDENIED:
170 				{
171 					errMsg = "Error (";
172 					errMsg += UT_String_sprintf("%d", res);
173 					errMsg += ") displaying URL: Access is denied.\n";
174 					errMsg += " [ ";  errMsg += sURL;  errMsg += " ] ";
175 				}
176 				break;
177 
178 			default:
179 				{
180 					errMsg = "Error (";
181 					errMsg += UT_String_sprintf("%d", res);
182 					errMsg += ") displaying URL: \n";
183 					errMsg += " [ ";  errMsg += sURL;  errMsg += " ] ";
184 				}
185 				break;
186 		} /* switch (res) */
187 		if (errMsg[0]) {
188 			str.fromUTF8(errMsg.c_str());
189 			MessageBoxW(pFImp->getTopLevelWindow(),str.c_str(),
190 				L"Error displaying URL", MB_OK|MB_ICONEXCLAMATION);
191 		}
192 	} /* if (res <= 32) */
193 
194 	return (res>32);
195 }
196 
197