1 | /* ============================================================ |
2 | * |
3 | * This file is a part of the rekonq project |
4 | * |
5 | * Copyright (C) 2008-2012 by Andrea Diamantini <adjam7 at gmail dot com> |
6 | * Copyright (C) 2011 by Pierre Rossi <pierre dot rossi at gmail dot com> |
7 | * |
8 | * |
9 | * This program is free software; you can redistribute it and/or |
10 | * modify it under the terms of the GNU General Public License as |
11 | * published by the Free Software Foundation; either version 2 of |
12 | * the License or (at your option) version 3 or any later version |
13 | * accepted by the membership of KDE e.V. (or its successor approved |
14 | * by the membership of KDE e.V.), which shall act as a proxy |
15 | * defined in Section 14 of version 3 of the license. |
16 | * |
17 | * This program is distributed in the hope that it will be useful, |
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
20 | * GNU General Public License for more details. |
21 | * |
22 | * You should have received a copy of the GNU General Public License |
23 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
24 | * |
25 | * ============================================================ */ |
26 | |
27 | |
28 | // Self Includes |
29 | #include "downloadmanager.h" |
30 | #include "downloadmanager.moc" |
31 | |
32 | // Auto Includes |
33 | #include "rekonq.h" |
34 | |
35 | // KDE Includes |
36 | #include <KStandardDirs> |
37 | #include <KToolInvocation> |
38 | #include <KFileDialog> |
39 | #include <krecentdirs.h> |
40 | |
41 | |
42 | #include <kio/scheduler.h> |
43 | |
44 | #include <KIO/Job> |
45 | #include <KIO/CopyJob> |
46 | #include <KIO/JobUiDelegate> |
47 | |
48 | // Qt Includes |
49 | #include <QApplication> |
50 | #include <QDataStream> |
51 | #include <QDateTime> |
52 | #include <QFile> |
53 | #include <QFileInfo> |
54 | #include <QString> |
55 | #include <QWebSettings> |
56 | #include <QNetworkReply> |
57 | |
58 | #include <QDBusConnection> |
59 | #include <QDBusConnectionInterface> |
60 | #include <QDBusInterface> |
61 | |
62 | |
63 | QWeakPointer<DownloadManager> DownloadManager::s_downloadManager; |
64 | |
65 | |
66 | DownloadManager *DownloadManager::self() |
67 | { |
68 | if (s_downloadManager.isNull()) |
69 | { |
70 | s_downloadManager = new DownloadManager(qApp); |
71 | } |
72 | return s_downloadManager.data(); |
73 | } |
74 | |
75 | |
76 | // ---------------------------------------------------------------------------------------------- |
77 | |
78 | |
79 | DownloadManager::DownloadManager(QObject *parent) |
80 | : QObject(parent) |
81 | , m_needToSave(false) |
82 | { |
83 | init(); |
84 | } |
85 | |
86 | |
87 | DownloadManager::~DownloadManager() |
88 | { |
89 | if (!m_needToSave) |
90 | return; |
91 | |
92 | QString downloadFilePath = KStandardDirs::locateLocal("appdata" , "downloads" ); |
93 | QFile downloadFile(downloadFilePath); |
94 | |
95 | if (!downloadFile.open(QFile::WriteOnly)) |
96 | { |
97 | kDebug() << "Unable to open download file (WRITE mode).." ; |
98 | return; |
99 | } |
100 | |
101 | QDataStream out(&downloadFile); |
102 | Q_FOREACH(DownloadItem * item, m_downloadList) |
103 | { |
104 | out << item->originUrl(); |
105 | out << item->destinationUrlString(); |
106 | out << item->dateTime(); |
107 | } |
108 | |
109 | downloadFile.close(); |
110 | } |
111 | |
112 | |
113 | void DownloadManager::init() |
114 | { |
115 | QString downloadFilePath = KStandardDirs::locateLocal("appdata" , "downloads" ); |
116 | QFile downloadFile(downloadFilePath); |
117 | if (!downloadFile.open(QFile::ReadOnly)) |
118 | { |
119 | kDebug() << "Unable to open download file (READ mode).." ; |
120 | return; |
121 | } |
122 | |
123 | QDataStream in(&downloadFile); |
124 | while (!in.atEnd()) |
125 | { |
126 | QString srcUrl; |
127 | in >> srcUrl; |
128 | QString destUrl; |
129 | in >> destUrl; |
130 | QDateTime dt; |
131 | in >> dt; |
132 | DownloadItem *item = new DownloadItem(srcUrl, destUrl, dt, this); |
133 | m_downloadList.append(item); |
134 | } |
135 | } |
136 | |
137 | |
138 | DownloadItem* DownloadManager::addDownload(KIO::CopyJob *job) |
139 | { |
140 | KIO::CopyJob *cJob = qobject_cast<KIO::CopyJob *>(job); |
141 | |
142 | QString downloadFilePath = KStandardDirs::locateLocal("appdata" , "downloads" ); |
143 | QFile downloadFile(downloadFilePath); |
144 | if (!downloadFile.open(QFile::WriteOnly | QFile::Append)) |
145 | { |
146 | kDebug() << "Unable to open download file (WRITE mode).." ; |
147 | return 0; |
148 | } |
149 | QDataStream out(&downloadFile); |
150 | out << cJob->srcUrls().at(0).url(); |
151 | out << cJob->destUrl().url(); |
152 | out << QDateTime::currentDateTime(); |
153 | downloadFile.close(); |
154 | DownloadItem *item = new DownloadItem(job, QDateTime::currentDateTime(), this); |
155 | m_downloadList.append(item); |
156 | emit newDownloadAdded(item); |
157 | return item; |
158 | } |
159 | |
160 | |
161 | bool DownloadManager::clearDownloadsHistory() |
162 | { |
163 | m_downloadList.clear(); |
164 | QString downloadFilePath = KStandardDirs::locateLocal("appdata" , "downloads" ); |
165 | QFile downloadFile(downloadFilePath); |
166 | return downloadFile.remove(); |
167 | } |
168 | |
169 | |
170 | void DownloadManager::downloadLinksWithKGet(const QVariant &contentList) |
171 | { |
172 | if (!QDBusConnection::sessionBus().interface()->isServiceRegistered("org.kde.kget" )) |
173 | { |
174 | KToolInvocation::kdeinitExecWait("kget" ); |
175 | } |
176 | QDBusInterface kget("org.kde.kget" , "/KGet" , "org.kde.kget.main" ); |
177 | if (kget.isValid()) |
178 | { |
179 | kget.call("importLinks" , contentList); |
180 | } |
181 | } |
182 | |
183 | |
184 | void DownloadManager::removeDownloadItem(int index) |
185 | { |
186 | DownloadItem *item = m_downloadList.takeAt(index); |
187 | delete item; |
188 | |
189 | m_needToSave = true; |
190 | } |
191 | |
192 | |
193 | // NOTE |
194 | // These 2 functions have been copied from the KWebPage class to implement a local version of the downloadResponse method. |
195 | // In this way, we can easily provide the extra functionality we need: |
196 | // 1. KGet Integration |
197 | // 2. Save downloads history |
198 | bool DownloadManager::downloadResource(const KUrl &srcUrl, const KIO::MetaData &metaData, |
199 | QWidget *parent, bool forceDirRequest, const QString &suggestedName, bool registerDownload) |
200 | { |
201 | // manage downloads with KGet if found |
202 | if (ReKonfig::kgetDownload() && !KStandardDirs::findExe("kget" ).isNull()) |
203 | { |
204 | //KGet integration: |
205 | if (!QDBusConnection::sessionBus().interface()->isServiceRegistered("org.kde.kget" )) |
206 | { |
207 | KToolInvocation::kdeinitExecWait("kget" ); |
208 | } |
209 | QDBusInterface kget("org.kde.kget" , "/KGet" , "org.kde.kget.main" ); |
210 | if (!kget.isValid()) |
211 | return false; |
212 | |
213 | QDBusMessage transfer = kget.call(QL1S("addTransfer" ), srcUrl.prettyUrl(), QString(), true); |
214 | |
215 | return true; |
216 | } |
217 | |
218 | KUrl destUrl; |
219 | |
220 | const QString fileName((suggestedName.isEmpty() ? srcUrl.fileName() : suggestedName)); |
221 | |
222 | if (forceDirRequest || ReKonfig::askDownloadPath()) |
223 | { |
224 | // follow bug:184202 fixes |
225 | |
226 | // Downloads should default to the default download directory. At the |
227 | // same time when the user has been using a different directory |
228 | // previously, it should be used instead. |
229 | // To enable this behavior we inject the default download path into |
230 | // KRecentDirs (which is internally used by KFileDialog to get the |
231 | // most recently used directory of a fileclass). |
232 | // If a user then uses a different directory it will replace the |
233 | // downloads directory in KRecentDirs and become the new default when |
234 | // trying to save a file. Also see KFileDialog, KFileWidget and |
235 | // KRecentDirs documentation. |
236 | |
237 | // If this is the first invocation insert the defaults downloads directory. |
238 | static const QString fileClass = QL1S(":download" ); |
239 | if (KRecentDirs::list(fileClass).count() <= 1) // Always has one entry by default. |
240 | KRecentDirs::add(fileClass, KGlobalSettings::downloadPath()); |
241 | |
242 | const KUrl startDir(QString("kfiledialog:///download/%1" ).arg(fileName)); |
243 | |
244 | // NOTE: We used to use getSaveFileName here but it proved unable to |
245 | // handle remote URLs, which we need to handle here, making the use of |
246 | // getSaveUrl deliberate. |
247 | destUrl = KFileDialog::getSaveUrl(startDir, QString(), parent); |
248 | } |
249 | else |
250 | { |
251 | destUrl = KUrl(ReKonfig::downloadPath().path() + QL1C('/') + fileName); |
252 | } |
253 | |
254 | kDebug() << "DEST URL: " << destUrl; |
255 | |
256 | if (!destUrl.isValid()) |
257 | return false; |
258 | |
259 | KIO::CopyJob *job = KIO::copy(srcUrl, destUrl); |
260 | |
261 | if (!metaData.isEmpty()) |
262 | job->setMetaData(metaData); |
263 | |
264 | job->addMetaData(QL1S("MaxCacheSize" ), QL1S("0" )); // Don't store in http cache. |
265 | job->addMetaData(QL1S("cache" ), QL1S("cache" )); // Use entry from cache if available. |
266 | job->ui()->setWindow((parent ? parent->window() : 0)); |
267 | job->ui()->setAutoErrorHandlingEnabled(true); |
268 | |
269 | if (registerDownload) |
270 | addDownload(job); |
271 | |
272 | return true; |
273 | } |
274 | |