1/*
2 * Copyright (C) 2007 Apple Inc.  All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "WebKitDLL.h"
28#include "DefaultPolicyDelegate.h"
29
30#include <WebCore/COMPtr.h>
31#include <WebCore/PlatformString.h>
32
33using namespace WebCore;
34
35// FIXME: move this enum to a separate header file when other code begins to use it.
36typedef enum WebExtraNavigationType {
37    WebNavigationTypePlugInRequest = WebNavigationTypeOther + 1
38} WebExtraNavigationType;
39
40// DefaultPolicyDelegate ----------------------------------------------------------------
41
42DefaultPolicyDelegate::DefaultPolicyDelegate()
43    : m_refCount(0)
44{
45    gClassCount++;
46    gClassNameCount.add("DefaultPolicyDelegate");
47}
48
49DefaultPolicyDelegate::~DefaultPolicyDelegate()
50{
51    gClassCount--;
52    gClassNameCount.remove("DefaultPolicyDelegate");
53}
54
55DefaultPolicyDelegate* DefaultPolicyDelegate::sharedInstance()
56{
57    static COMPtr<DefaultPolicyDelegate> shared;
58    if (!shared)
59        shared.adoptRef(DefaultPolicyDelegate::createInstance());
60    return shared.get();
61}
62
63DefaultPolicyDelegate* DefaultPolicyDelegate::createInstance()
64{
65    DefaultPolicyDelegate* instance = new DefaultPolicyDelegate();
66    instance->AddRef();
67    return instance;
68}
69
70// IUnknown -------------------------------------------------------------------
71
72HRESULT STDMETHODCALLTYPE DefaultPolicyDelegate::QueryInterface(REFIID riid, void** ppvObject)
73{
74    *ppvObject = 0;
75    if (IsEqualGUID(riid, IID_IUnknown))
76        *ppvObject = static_cast<IUnknown*>(this);
77    else if (IsEqualGUID(riid, IID_IWebPolicyDelegate))
78        *ppvObject = static_cast<IWebPolicyDelegate*>(this);
79    else
80        return E_NOINTERFACE;
81
82    AddRef();
83    return S_OK;
84}
85
86ULONG STDMETHODCALLTYPE DefaultPolicyDelegate::AddRef()
87{
88    return ++m_refCount;
89}
90
91ULONG STDMETHODCALLTYPE DefaultPolicyDelegate::Release()
92{
93    ULONG newRef = --m_refCount;
94    if (!newRef)
95        delete(this);
96
97    return newRef;
98}
99
100HRESULT STDMETHODCALLTYPE DefaultPolicyDelegate::decidePolicyForNavigationAction(
101    /*[in]*/ IWebView* webView,
102    /*[in]*/ IPropertyBag* actionInformation,
103    /*[in]*/ IWebURLRequest* request,
104    /*[in]*/ IWebFrame* /*frame*/,
105    /*[in]*/ IWebPolicyDecisionListener* listener)
106{
107    int navType = 0;
108    VARIANT var;
109    if (SUCCEEDED(actionInformation->Read(WebActionNavigationTypeKey, &var, 0))) {
110        V_VT(&var) = VT_I4;
111        navType = V_I4(&var);
112    }
113    COMPtr<IWebViewPrivate> wvPrivate(Query, webView);
114    if (wvPrivate) {
115        BOOL canHandleRequest = FALSE;
116        if (SUCCEEDED(wvPrivate->canHandleRequest(request, &canHandleRequest)) && canHandleRequest)
117            listener->use();
118        else if (navType == WebNavigationTypePlugInRequest)
119            listener->use();
120        else {
121            BSTR url;
122            // A file URL shouldn't fall through to here, but if it did,
123            // it would be a security risk to open it.
124            if (SUCCEEDED(request->URL(&url)) && !String(url, SysStringLen(url)).startsWith("file:")) {
125                // FIXME: Open the URL not by means of a webframe, but by handing it over to the system and letting it determine how to open that particular URL scheme.  See documentation for [NSWorkspace openURL]
126                ;
127            }
128            listener->ignore();
129            SysFreeString(url);
130        }
131    }
132    return S_OK;
133}
134
135HRESULT STDMETHODCALLTYPE DefaultPolicyDelegate::decidePolicyForNewWindowAction(
136    /*[in]*/ IWebView* /*webView*/,
137    /*[in]*/ IPropertyBag* /*actionInformation*/,
138    /*[in]*/ IWebURLRequest* /*request*/,
139    /*[in]*/ BSTR /*frameName*/,
140    /*[in]*/ IWebPolicyDecisionListener* listener)
141{
142    listener->use();
143    return S_OK;
144}
145
146HRESULT STDMETHODCALLTYPE DefaultPolicyDelegate::decidePolicyForMIMEType(
147    /*[in]*/ IWebView* webView,
148    /*[in]*/ BSTR type,
149    /*[in]*/ IWebURLRequest* request,
150    /*[in]*/ IWebFrame* /*frame*/,
151    /*[in]*/ IWebPolicyDecisionListener* listener)
152{
153    BOOL canShowMIMEType;
154    if (FAILED(webView->canShowMIMEType(type, &canShowMIMEType)))
155        canShowMIMEType = FALSE;
156
157    BSTR url;
158    request->URL(&url);
159
160    if (String(url, SysStringLen(url)).startsWith("file:")) {
161        BOOL isDirectory = FALSE;
162        WIN32_FILE_ATTRIBUTE_DATA attrs;
163        if (GetFileAttributesEx(url, GetFileExInfoStandard, &attrs))
164            isDirectory = !!(attrs.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
165
166        if (isDirectory)
167            listener->ignore();
168        else if(canShowMIMEType)
169            listener->use();
170        else
171            listener->ignore();
172    } else if (canShowMIMEType)
173        listener->use();
174    else
175        listener->ignore();
176    SysFreeString(url);
177    return S_OK;
178}
179
180HRESULT STDMETHODCALLTYPE DefaultPolicyDelegate::unableToImplementPolicyWithError(
181    /*[in]*/ IWebView* /*webView*/,
182    /*[in]*/ IWebError* error,
183    /*[in]*/ IWebFrame* frame)
184{
185    BSTR errorStr;
186    error->localizedDescription(&errorStr);
187
188    BSTR frameName;
189    frame->name(&frameName);
190
191    LOG_ERROR("called unableToImplementPolicyWithError:%S inFrame:%S", errorStr ? errorStr : TEXT(""), frameName ? frameName : TEXT(""));
192    SysFreeString(errorStr);
193    SysFreeString(frameName);
194
195    return S_OK;
196}
197