1 /*
2 * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Collabora Ltd. All rights reserved.
4 * Copyright (C) 2008 Nuanti Ltd.
5 * Copyright (C) 2008 Novell Inc. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
24 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include "config.h"
30 #include "PluginPackage.h"
31
32 #include "GOwnPtrGtk.h"
33 #include "GRefPtrGtk.h"
34 #include "MIMETypeRegistry.h"
35 #include "NotImplemented.h"
36 #include "npruntime_impl.h"
37 #include "PluginDebug.h"
38 #include <gio/gio.h>
39 #include <wtf/text/CString.h>
40
41 namespace WebCore {
42
fetchInfo()43 bool PluginPackage::fetchInfo()
44 {
45 #if defined(XP_UNIX)
46 if (!load())
47 return false;
48
49 NP_GetMIMEDescriptionFuncPtr NP_GetMIMEDescription = 0;
50 NPP_GetValueProcPtr NPP_GetValue = 0;
51
52 g_module_symbol(m_module, "NP_GetMIMEDescription", (void**)&NP_GetMIMEDescription);
53 g_module_symbol(m_module, "NP_GetValue", (void**)&NPP_GetValue);
54
55 if (!NP_GetMIMEDescription || !NPP_GetValue)
56 return false;
57
58 char* buffer = 0;
59 NPError err = NPP_GetValue(0, NPPVpluginNameString, &buffer);
60 if (err == NPERR_NO_ERROR)
61 m_name = buffer;
62
63 buffer = 0;
64 err = NPP_GetValue(0, NPPVpluginDescriptionString, &buffer);
65 if (err == NPERR_NO_ERROR) {
66 m_description = buffer;
67 determineModuleVersionFromDescription();
68 }
69
70 const gchar* types = NP_GetMIMEDescription();
71 if (!types)
72 return true;
73
74 gchar** mimeDescs = g_strsplit(types, ";", -1);
75 for (int i = 0; mimeDescs[i] && mimeDescs[i][0]; i++) {
76 GOwnPtr<char> mime(g_utf8_strdown(mimeDescs[i], -1));
77 gchar** mimeData = g_strsplit(mime.get(), ":", 3);
78 if (g_strv_length(mimeData) < 3) {
79 g_strfreev(mimeData);
80 continue;
81 }
82
83 String description = String::fromUTF8(mimeData[2]);
84 gchar** extensions = g_strsplit(mimeData[1], ",", -1);
85
86 Vector<String> extVector;
87 for (int j = 0; extensions[j]; j++)
88 extVector.append(String::fromUTF8(extensions[j]));
89
90 determineQuirks(mimeData[0]);
91 m_mimeToExtensions.add(mimeData[0], extVector);
92 m_mimeToDescriptions.add(mimeData[0], description);
93
94 g_strfreev(extensions);
95 g_strfreev(mimeData);
96 }
97 g_strfreev(mimeDescs);
98
99 return true;
100 #else
101 notImplemented();
102 return false;
103 #endif
104 }
105
106 #if defined(XP_UNIX)
webkitgtkXError(Display * xdisplay,XErrorEvent * error)107 static int webkitgtkXError(Display* xdisplay, XErrorEvent* error)
108 {
109 gchar errorMessage[64];
110 XGetErrorText(xdisplay, error->error_code, errorMessage, 63);
111 g_warning("The program '%s' received an X Window System error.\n"
112 "This probably reflects a bug in the Adobe Flash plugin.\n"
113 "The error was '%s'.\n"
114 " (Details: serial %ld error_code %d request_code %d minor_code %d)\n",
115 g_get_prgname(), errorMessage,
116 error->serial, error->error_code,
117 error->request_code, error->minor_code);
118 return 0;
119 }
120 #endif
121
moduleMixesGtkSymbols(GModule * module)122 static bool moduleMixesGtkSymbols(GModule* module)
123 {
124 gpointer symbol;
125 #ifdef GTK_API_VERSION_2
126 return g_module_symbol(module, "gtk_application_get_type", &symbol);
127 #else
128 return g_module_symbol(module, "gtk_object_get_type", &symbol);
129 #endif
130 }
131
132
load()133 bool PluginPackage::load()
134 {
135 if (m_isLoaded) {
136 m_loadCount++;
137 return true;
138 }
139
140 GOwnPtr<gchar> finalPath(g_strdup(m_path.utf8().data()));
141 while (g_file_test(finalPath.get(), G_FILE_TEST_IS_SYMLINK)) {
142 GRefPtr<GFile> file = adoptGRef(g_file_new_for_path(finalPath.get()));
143 GRefPtr<GFile> dir = adoptGRef(g_file_get_parent(file.get()));
144 GOwnPtr<gchar> linkPath(g_file_read_link(finalPath.get(), 0));
145 GRefPtr<GFile> resolvedFile = adoptGRef(g_file_resolve_relative_path(dir.get(), linkPath.get()));
146 finalPath.set(g_file_get_path(resolvedFile.get()));
147 }
148
149 // No joke. If there is a netscape component in the path, go back
150 // to the symlink, as flash breaks otherwise.
151 // See http://src.chromium.org/viewvc/chrome/trunk/src/webkit/glue/plugins/plugin_list_posix.cc
152 GOwnPtr<gchar> baseName(g_path_get_basename(finalPath.get()));
153 if (!g_strcmp0(baseName.get(), "libflashplayer.so")
154 && g_strstr_len(finalPath.get(), -1, "/netscape/"))
155 finalPath.set(g_strdup(m_path.utf8().data()));
156
157 m_module = g_module_open(finalPath.get(), G_MODULE_BIND_LOCAL);
158
159 if (!m_module) {
160 LOG(Plugins,"Module Load Failed :%s, Error:%s\n", (m_path.utf8()).data(), g_module_error());
161 return false;
162 }
163
164 if (moduleMixesGtkSymbols(m_module)) {
165 LOG(Plugins, "Module '%s' mixes GTK+ 2 and GTK+ 3 symbols, ignoring plugin.\n", m_path.utf8().data());
166 g_module_close(m_module);
167 return false;
168 }
169
170 m_isLoaded = true;
171
172 #if defined(XP_UNIX)
173 if (!g_strcmp0(baseName.get(), "libflashplayer.so")) {
174 // Flash plugin can produce X errors that are handled by the GDK X error handler, which
175 // exits the process. Since we don't want to crash due to flash bugs, we install a
176 // custom error handler to show a warning when a X error happens without aborting.
177 XSetErrorHandler(webkitgtkXError);
178 }
179 #endif
180
181 NP_InitializeFuncPtr NP_Initialize = 0;
182 m_NPP_Shutdown = 0;
183
184 NPError npErr;
185
186 g_module_symbol(m_module, "NP_Initialize", (void**)&NP_Initialize);
187 g_module_symbol(m_module, "NP_Shutdown", (void**)&m_NPP_Shutdown);
188
189 if (!NP_Initialize || !m_NPP_Shutdown)
190 goto abort;
191
192 memset(&m_pluginFuncs, 0, sizeof(m_pluginFuncs));
193 m_pluginFuncs.size = sizeof(m_pluginFuncs);
194
195 initializeBrowserFuncs();
196
197 #if defined(XP_UNIX)
198 npErr = NP_Initialize(&m_browserFuncs, &m_pluginFuncs);
199 #else
200 npErr = NP_Initialize(&m_browserFuncs);
201 #endif
202 if (npErr != NPERR_NO_ERROR)
203 goto abort;
204
205 m_loadCount++;
206 return true;
207
208 abort:
209 unloadWithoutShutdown();
210 return false;
211 }
212
NPVersion() const213 uint16_t PluginPackage::NPVersion() const
214 {
215 return NPVERS_HAS_PLUGIN_THREAD_ASYNC_CALL;
216 }
217 }
218