1/*
2 * Copyright (C) 2012 Intel Corporation. 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 INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "DownloadManagerEfl.h"
28
29#include "EwkView.h"
30#include "WKContext.h"
31#include "WKDownload.h"
32#include "WKString.h"
33#include "ewk_context_private.h"
34#include "ewk_error_private.h"
35#include "ewk_view.h"
36
37using namespace EwkViewCallbacks;
38
39namespace WebKit {
40
41static inline DownloadManagerEfl* toDownloadManagerEfl(const void* clientInfo)
42{
43    return static_cast<DownloadManagerEfl*>(const_cast<void*>(clientInfo));
44}
45
46WKStringRef DownloadManagerEfl::decideDestinationWithSuggestedFilename(WKContextRef, WKDownloadRef wkDownload, WKStringRef filename, bool* /*allowOverwrite*/, const void* clientInfo)
47{
48    EwkDownloadJob* download = toDownloadManagerEfl(clientInfo)->ewkDownloadJob(wkDownload);
49    ASSERT(download);
50
51    download->setSuggestedFileName(toImpl(filename)->string().utf8().data());
52
53    // We send the new download signal on the Ewk_View only once we have received the response
54    // and the suggested file name.
55    download->view()->smartCallback<DownloadJobRequested>().call(download);
56
57    // DownloadSoup expects the destination to be a URL.
58    String destination = ASCIILiteral("file://") + String::fromUTF8(download->destination());
59
60    return WKStringCreateWithUTF8CString(destination.utf8().data());
61}
62
63void DownloadManagerEfl::didReceiveResponse(WKContextRef, WKDownloadRef wkDownload, WKURLResponseRef wkResponse, const void* clientInfo)
64{
65    EwkDownloadJob* download = toDownloadManagerEfl(clientInfo)->ewkDownloadJob(wkDownload);
66    ASSERT(download);
67    download->setResponse(EwkUrlResponse::create(wkResponse));
68}
69
70void DownloadManagerEfl::didCreateDestination(WKContextRef, WKDownloadRef wkDownload, WKStringRef /*path*/, const void* clientInfo)
71{
72    EwkDownloadJob* download = toDownloadManagerEfl(clientInfo)->ewkDownloadJob(wkDownload);
73    ASSERT(download);
74
75    download->setState(EWK_DOWNLOAD_JOB_STATE_DOWNLOADING);
76}
77
78void DownloadManagerEfl::didReceiveData(WKContextRef, WKDownloadRef wkDownload, uint64_t length, const void* clientInfo)
79{
80    EwkDownloadJob* download = toDownloadManagerEfl(clientInfo)->ewkDownloadJob(wkDownload);
81    ASSERT(download);
82    download->incrementReceivedData(length);
83}
84
85void DownloadManagerEfl::didFail(WKContextRef, WKDownloadRef wkDownload, WKErrorRef error, const void* clientInfo)
86{
87    DownloadManagerEfl* downloadManager = toDownloadManagerEfl(clientInfo);
88    EwkDownloadJob* download = downloadManager->ewkDownloadJob(wkDownload);
89    ASSERT(download);
90
91    auto ewkError = std::make_unique<EwkError>(error);
92    download->setState(EWK_DOWNLOAD_JOB_STATE_FAILED);
93    Ewk_Download_Job_Error downloadError = { download, ewkError.get() };
94    download->view()->smartCallback<DownloadJobFailed>().call(&downloadError);
95    downloadManager->unregisterDownloadJob(wkDownload);
96}
97
98void DownloadManagerEfl::didCancel(WKContextRef, WKDownloadRef wkDownload, const void* clientInfo)
99{
100    DownloadManagerEfl* downloadManager = toDownloadManagerEfl(clientInfo);
101    EwkDownloadJob* download = downloadManager->ewkDownloadJob(wkDownload);
102    ASSERT(download);
103
104    download->setState(EWK_DOWNLOAD_JOB_STATE_CANCELLED);
105    download->view()->smartCallback<DownloadJobCancelled>().call(download);
106    downloadManager->unregisterDownloadJob(wkDownload);
107}
108
109void DownloadManagerEfl::didFinish(WKContextRef, WKDownloadRef wkDownload, const void* clientInfo)
110{
111    DownloadManagerEfl* downloadManager = toDownloadManagerEfl(clientInfo);
112    EwkDownloadJob* download = downloadManager->ewkDownloadJob(wkDownload);
113    ASSERT(download);
114
115    download->setState(EWK_DOWNLOAD_JOB_STATE_FINISHED);
116    download->view()->smartCallback<DownloadJobFinished>().call(download);
117    downloadManager->unregisterDownloadJob(wkDownload);
118}
119
120DownloadManagerEfl::DownloadManagerEfl(WKContextRef context)
121    : m_context(context)
122{
123    WKContextDownloadClientV0 wkDownloadClient;
124    memset(&wkDownloadClient, 0, sizeof(WKContextDownloadClient));
125
126    wkDownloadClient.base.version = 0;
127    wkDownloadClient.base.clientInfo = this;
128    wkDownloadClient.didCancel = didCancel;
129    wkDownloadClient.decideDestinationWithSuggestedFilename = decideDestinationWithSuggestedFilename;
130    wkDownloadClient.didCreateDestination = didCreateDestination;
131    wkDownloadClient.didReceiveResponse = didReceiveResponse;
132    wkDownloadClient.didReceiveData = didReceiveData;
133    wkDownloadClient.didFail = didFail;
134    wkDownloadClient.didFinish = didFinish;
135
136    WKContextSetDownloadClient(m_context.get(), &wkDownloadClient.base);
137}
138
139DownloadManagerEfl::~DownloadManagerEfl()
140{
141    WKContextSetDownloadClient(m_context.get(), 0);
142}
143
144void DownloadManagerEfl::registerDownloadJob(WKDownloadRef download, EwkView* viewImpl)
145{
146    uint64_t downloadId = WKDownloadGetID(download);
147    if (m_downloadJobs.contains(downloadId))
148        return;
149
150    RefPtr<EwkDownloadJob> ewkDownload = EwkDownloadJob::create(download, viewImpl);
151    m_downloadJobs.add(downloadId, ewkDownload);
152}
153
154EwkDownloadJob* DownloadManagerEfl::ewkDownloadJob(WKDownloadRef wkDownload)
155{
156    return m_downloadJobs.get(WKDownloadGetID(wkDownload));
157}
158
159void DownloadManagerEfl::unregisterDownloadJob(WKDownloadRef wkDownload)
160{
161    m_downloadJobs.remove(WKDownloadGetID(wkDownload));
162}
163
164} // namespace WebKit
165