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
41namespace WebCore {
42
43bool 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)
107static 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
122static 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
133bool 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
208abort:
209    unloadWithoutShutdown();
210    return false;
211}
212
213uint16_t PluginPackage::NPVersion() const
214{
215    return NPVERS_HAS_PLUGIN_THREAD_ASYNC_CALL;
216}
217}
218