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#include "config.h"
26#include "WebKitDLL.h"
27#include "DefaultDownloadDelegate.h"
28
29#include "MarshallingHelpers.h"
30#include "WebKit.h"
31#include "WebKitLogging.h"
32#include "WebMutableURLRequest.h"
33#include <WebCore/COMPtr.h>
34#include <wtf/text/CString.h>
35
36#include <shlobj.h>
37#include <wchar.h>
38
39#include <WebCore/BString.h>
40
41using namespace WebCore;
42
43
44// DefaultDownloadDelegate ----------------------------------------------------------------
45
46DefaultDownloadDelegate::DefaultDownloadDelegate()
47    : m_refCount(0)
48{
49    gClassCount++;
50    gClassNameCount.add("DefaultDownloadDelegate");
51}
52
53DefaultDownloadDelegate::~DefaultDownloadDelegate()
54{
55    gClassCount--;
56    gClassNameCount.remove("DefaultDownloadDelegate");
57    HashSet<IWebDownload*>::iterator i = m_downloads.begin();
58    for (;i != m_downloads.end(); ++i)
59        (*i)->Release();
60}
61
62DefaultDownloadDelegate* DefaultDownloadDelegate::sharedInstance()
63{
64    static COMPtr<DefaultDownloadDelegate> shared;
65    if (!shared)
66        shared.adoptRef(DefaultDownloadDelegate::createInstance());
67    return shared.get();
68}
69
70DefaultDownloadDelegate* DefaultDownloadDelegate::createInstance()
71{
72    DefaultDownloadDelegate* instance = new DefaultDownloadDelegate();
73    instance->AddRef();
74    return instance;
75}
76
77// IUnknown -------------------------------------------------------------------
78
79HRESULT STDMETHODCALLTYPE DefaultDownloadDelegate::QueryInterface(REFIID riid, void** ppvObject)
80{
81    *ppvObject = 0;
82    if (IsEqualGUID(riid, IID_IUnknown))
83        *ppvObject = static_cast<IUnknown*>(this);
84    else if (IsEqualGUID(riid, IID_IWebDownloadDelegate))
85        *ppvObject = static_cast<IWebDownloadDelegate*>(this);
86    else
87        return E_NOINTERFACE;
88
89    AddRef();
90    return S_OK;
91}
92
93ULONG STDMETHODCALLTYPE DefaultDownloadDelegate::AddRef()
94{
95    return ++m_refCount;
96}
97
98ULONG STDMETHODCALLTYPE DefaultDownloadDelegate::Release()
99{
100    ULONG newRef = --m_refCount;
101    if (!newRef)
102        delete(this);
103
104    return newRef;
105}
106
107HRESULT STDMETHODCALLTYPE DefaultDownloadDelegate::decideDestinationWithSuggestedFilename(IWebDownload *download, BSTR filename)
108{
109    LOG(Download, "DefaultDownloadDelegate %p - decideDestinationWithSuggestedFilename %s", download, String(filename, SysStringLen(filename)).ascii().data());
110
111    WCHAR pathChars[MAX_PATH];
112    if (FAILED(SHGetFolderPath(0, CSIDL_DESKTOPDIRECTORY  | CSIDL_FLAG_CREATE, 0, 0, pathChars))) {
113        if (FAILED(download->setDestination(filename, true))) {
114            LOG_ERROR("Failed to set destination on file");
115            return E_FAIL;
116        }
117        return S_OK;
118    }
119
120    size_t fullLength = wcslen(pathChars) + SysStringLen(filename) + 2;
121    BSTR full = SysAllocStringLen(0, (UINT)fullLength);
122    if (!full)
123        return E_OUTOFMEMORY;
124
125    wcscpy_s(full, fullLength, pathChars);
126    wcscat_s(full, fullLength, L"\\");
127    wcscat_s(full, fullLength, filename);
128    BString fullPath;
129    fullPath.adoptBSTR(full);
130
131#ifndef NDEBUG
132    String debug((BSTR)fullPath, SysStringLen(BSTR(fullPath)));
133    LOG(Download, "Setting path to %s", debug.ascii().data());
134#endif
135
136    if (FAILED(download->setDestination(fullPath, true))) {
137        LOG_ERROR("Failed to set destination on file");
138        return E_FAIL;
139    }
140    return S_OK;
141}
142HRESULT STDMETHODCALLTYPE DefaultDownloadDelegate::didCancelAuthenticationChallenge(IWebDownload* download, IWebURLAuthenticationChallenge* challenge)
143{
144    LOG(Download, "DefaultDownloadDelegate %p - didCancelAuthenticationChallenge %p", download, challenge);
145    download = 0;
146    challenge = 0;
147    return S_OK;
148}
149HRESULT STDMETHODCALLTYPE DefaultDownloadDelegate::didCreateDestination(IWebDownload* download, BSTR destination)
150{
151    LOG(Download, "DefaultDownloadDelegate %p - didCreateDestination %s", download, String(destination, SysStringLen(destination)).ascii().data());
152    download = 0;
153    destination = 0;
154    return S_OK;
155}
156
157HRESULT STDMETHODCALLTYPE DefaultDownloadDelegate::didReceiveAuthenticationChallenge(IWebDownload* download, IWebURLAuthenticationChallenge* challenge)
158{
159    LOG(Download, "DefaultDownloadDelegate %p - didReceiveAuthenticationChallenge %p", download, challenge);
160    download = 0;
161    challenge = 0;
162    return S_OK;
163}
164
165HRESULT STDMETHODCALLTYPE DefaultDownloadDelegate::didReceiveDataOfLength(IWebDownload* download, unsigned length)
166{
167    LOG(Download, "DefaultDownloadDelegate %p - didReceiveDataOfLength %i", download, length);
168    download = 0;
169    length = 0;
170    return S_OK;
171}
172
173HRESULT STDMETHODCALLTYPE DefaultDownloadDelegate::didReceiveResponse(IWebDownload* download, IWebURLResponse* response)
174{
175    LOG(Download, "DefaultDownloadDelegate %p - didReceiveResponse %p", download, response);
176    download = 0;
177    response = 0;
178    return S_OK;
179}
180
181HRESULT STDMETHODCALLTYPE DefaultDownloadDelegate::shouldDecodeSourceDataOfMIMEType(IWebDownload* download, BSTR encodingType, BOOL* shouldDecode)
182{
183    LOG(Download, "DefaultDownloadDelegate %p - shouldDecodeSourceDataOfMIMEType %s", download, String(encodingType, SysStringLen(encodingType)).ascii().data());
184    download = 0;
185    encodingType = 0;
186    *shouldDecode = false;
187    return S_OK;
188}
189
190HRESULT STDMETHODCALLTYPE DefaultDownloadDelegate::willResumeWithResponse(IWebDownload* download, IWebURLResponse* response, long long fromByte)
191{
192    LOG(Download, "DefaultDownloadDelegate %p - willResumeWithResponse %p, %q", download, response, fromByte);
193    download = 0;
194    response = 0;
195    fromByte = 0;
196    return S_OK;
197}
198
199HRESULT STDMETHODCALLTYPE DefaultDownloadDelegate::willSendRequest(IWebDownload* download, IWebMutableURLRequest* request,
200                                                                 IWebURLResponse* redirectResponse, IWebMutableURLRequest** finalRequest)
201{
202    LOG(Download, "DefaultDownloadDelegate %p - willSendRequest %p %p", download, request, redirectResponse);
203    download = 0;
204    redirectResponse = 0;
205    *finalRequest = request;
206    (*finalRequest)->AddRef();
207    return S_OK;
208}
209
210HRESULT STDMETHODCALLTYPE DefaultDownloadDelegate::didBegin(IWebDownload* download)
211{
212    LOG(Download, "DefaultDownloadDelegate %p - didBegin", download);
213    registerDownload(download);
214    return S_OK;
215}
216
217HRESULT STDMETHODCALLTYPE DefaultDownloadDelegate::didFinish(IWebDownload* download)
218{
219    LOG(Download, "DefaultDownloadDelegate %p - didFinish", download);
220    unregisterDownload(download);
221    return S_OK;
222}
223
224HRESULT STDMETHODCALLTYPE DefaultDownloadDelegate::didFailWithError(IWebDownload* download, IWebError* error)
225{
226    LOG(Download, "DefaultDownloadDelegate %p - didFailWithError %p", download, error);
227    unregisterDownload(download);
228    error = 0;
229    return S_OK;
230}
231
232void DefaultDownloadDelegate::registerDownload(IWebDownload* download)
233{
234    if (m_downloads.contains(download))
235        return;
236    download->AddRef();
237    m_downloads.add(download);
238}
239
240void DefaultDownloadDelegate::unregisterDownload(IWebDownload* download)
241{
242    if (m_downloads.contains(download)) {
243        download->Release();
244        m_downloads.remove(download);
245    }
246}
247