Chris@208
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
Chris@208
|
2
|
Chris@208
|
3 /*
|
Chris@208
|
4 Sonic Visualiser
|
Chris@208
|
5 An audio file viewer and annotation editor.
|
Chris@208
|
6 Centre for Digital Music, Queen Mary, University of London.
|
Chris@208
|
7 This file copyright 2007 QMUL.
|
Chris@208
|
8
|
Chris@208
|
9 This program is free software; you can redistribute it and/or
|
Chris@208
|
10 modify it under the terms of the GNU General Public License as
|
Chris@208
|
11 published by the Free Software Foundation; either version 2 of the
|
Chris@208
|
12 License, or (at your option) any later version. See the file
|
Chris@208
|
13 COPYING included with this distribution for more information.
|
Chris@208
|
14 */
|
Chris@208
|
15
|
Chris@208
|
16 #include "RemoteFile.h"
|
Chris@208
|
17 #include "base/TempDirectory.h"
|
Chris@208
|
18 #include "base/Exceptions.h"
|
Chris@208
|
19
|
Chris@208
|
20 #include <QHttp>
|
Chris@208
|
21 #include <QFtp>
|
Chris@208
|
22 #include <QFileInfo>
|
Chris@208
|
23 #include <QDir>
|
Chris@208
|
24 #include <QApplication>
|
Chris@208
|
25 #include <QProgressDialog>
|
Chris@208
|
26
|
Chris@208
|
27 #include <iostream>
|
Chris@208
|
28
|
Chris@208
|
29 int
|
Chris@208
|
30 RemoteFile::m_count = 0;
|
Chris@208
|
31
|
Chris@208
|
32 QMutex
|
Chris@208
|
33 RemoteFile::m_fileCreationMutex;
|
Chris@208
|
34
|
Chris@208
|
35 RemoteFile::RemoteFile(QUrl url) :
|
Chris@208
|
36 m_ftp(0),
|
Chris@208
|
37 m_http(0),
|
Chris@208
|
38 m_localFile(0),
|
Chris@208
|
39 m_ok(false),
|
Chris@208
|
40 m_done(false),
|
Chris@208
|
41 m_progressDialog(0)
|
Chris@208
|
42 {
|
Chris@208
|
43 if (!canHandleScheme(url)) {
|
Chris@208
|
44 std::cerr << "RemoteFile::RemoteFile: ERROR: Unsupported scheme in URL \"" << url.toString().toStdString() << "\"" << std::endl;
|
Chris@208
|
45 return;
|
Chris@208
|
46 }
|
Chris@208
|
47
|
Chris@208
|
48 m_localFilename = createLocalFile(url);
|
Chris@208
|
49 if (m_localFilename == "") return;
|
Chris@208
|
50 m_localFile = new QFile(m_localFilename);
|
Chris@208
|
51 m_localFile->open(QFile::WriteOnly);
|
Chris@208
|
52
|
Chris@208
|
53 QString scheme = url.scheme().toLower();
|
Chris@208
|
54
|
Chris@208
|
55 if (scheme == "http") {
|
Chris@208
|
56
|
Chris@208
|
57 m_http = new QHttp(url.host(), url.port(80));
|
Chris@208
|
58 connect(m_http, SIGNAL(done(bool)), this, SLOT(done(bool)));
|
Chris@208
|
59 connect(m_http, SIGNAL(dataReadProgress(int, int)),
|
Chris@208
|
60 this, SLOT(dataReadProgress(int, int)));
|
Chris@208
|
61 m_http->get(url.path(), m_localFile);
|
Chris@208
|
62 m_ok = true;
|
Chris@208
|
63
|
Chris@208
|
64 } else if (scheme == "ftp") {
|
Chris@208
|
65
|
Chris@208
|
66 m_ftp = new QFtp;
|
Chris@208
|
67 connect(m_ftp, SIGNAL(done(bool)), this, SLOT(done(bool)));
|
Chris@208
|
68 connect(m_ftp, SIGNAL(dataTransferProgress(qint64, qint64)),
|
Chris@208
|
69 this, SLOT(dataTransferProgress(qint64, qint64)));
|
Chris@208
|
70 m_ftp->connectToHost(url.host(), url.port(21));
|
Chris@208
|
71
|
Chris@208
|
72 QString username = url.userName();
|
Chris@208
|
73 if (username == "") {
|
Chris@208
|
74 username = "anonymous";
|
Chris@208
|
75 }
|
Chris@208
|
76
|
Chris@208
|
77 QString password = url.password();
|
Chris@208
|
78 if (password == "") {
|
Chris@208
|
79 password = QString("%1@%2").arg(getenv("USER")).arg(getenv("HOST"));
|
Chris@208
|
80 }
|
Chris@208
|
81
|
Chris@208
|
82 QStringList path = url.path().split('/');
|
Chris@208
|
83 for (QStringList::iterator i = path.begin(); i != path.end(); ) {
|
Chris@208
|
84 QString bit = *i;
|
Chris@208
|
85 ++i;
|
Chris@208
|
86 if (i != path.end()) {
|
Chris@208
|
87 m_ftp->cd(*i);
|
Chris@208
|
88 } else {
|
Chris@208
|
89 m_ftp->get(*i, m_localFile);
|
Chris@208
|
90 }
|
Chris@208
|
91 }
|
Chris@208
|
92
|
Chris@208
|
93 m_ok = true;
|
Chris@208
|
94 }
|
Chris@208
|
95
|
Chris@208
|
96 if (m_ok) {
|
Chris@208
|
97 m_progressDialog = new QProgressDialog(tr("Downloading %1...").arg(url.toString()), tr("Cancel"), 0, 100);
|
Chris@208
|
98 m_progressDialog->show();
|
Chris@208
|
99 }
|
Chris@208
|
100 }
|
Chris@208
|
101
|
Chris@208
|
102 RemoteFile::~RemoteFile()
|
Chris@208
|
103 {
|
Chris@208
|
104 delete m_ftp;
|
Chris@208
|
105 delete m_http;
|
Chris@208
|
106 delete m_localFile;
|
Chris@208
|
107 delete m_progressDialog;
|
Chris@208
|
108 }
|
Chris@208
|
109
|
Chris@208
|
110 bool
|
Chris@208
|
111 RemoteFile::canHandleScheme(QUrl url)
|
Chris@208
|
112 {
|
Chris@208
|
113 QString scheme = url.scheme().toLower();
|
Chris@208
|
114 return (scheme == "http" || scheme == "ftp");
|
Chris@208
|
115 }
|
Chris@208
|
116
|
Chris@208
|
117 void
|
Chris@208
|
118 RemoteFile::wait()
|
Chris@208
|
119 {
|
Chris@208
|
120 while (!m_done) {
|
Chris@208
|
121 QApplication::processEvents();
|
Chris@208
|
122 }
|
Chris@208
|
123 }
|
Chris@208
|
124
|
Chris@208
|
125 bool
|
Chris@208
|
126 RemoteFile::isOK() const
|
Chris@208
|
127 {
|
Chris@208
|
128 return m_ok;
|
Chris@208
|
129 }
|
Chris@208
|
130
|
Chris@208
|
131 bool
|
Chris@208
|
132 RemoteFile::isDone() const
|
Chris@208
|
133 {
|
Chris@208
|
134 return m_done;
|
Chris@208
|
135 }
|
Chris@208
|
136
|
Chris@208
|
137 QString
|
Chris@208
|
138 RemoteFile::getLocalFilename() const
|
Chris@208
|
139 {
|
Chris@208
|
140 return m_localFilename;
|
Chris@208
|
141 }
|
Chris@208
|
142
|
Chris@208
|
143 QString
|
Chris@208
|
144 RemoteFile::getErrorString() const
|
Chris@208
|
145 {
|
Chris@208
|
146 return m_errorString;
|
Chris@208
|
147 }
|
Chris@208
|
148
|
Chris@208
|
149 void
|
Chris@208
|
150 RemoteFile::dataReadProgress(int done, int total)
|
Chris@208
|
151 {
|
Chris@208
|
152 dataTransferProgress(done, total);
|
Chris@208
|
153 }
|
Chris@208
|
154
|
Chris@208
|
155 void
|
Chris@208
|
156 RemoteFile::dataTransferProgress(qint64 done, qint64 total)
|
Chris@208
|
157 {
|
Chris@208
|
158 int percent = int((double(done) / double(total)) * 100.0 - 0.1);
|
Chris@208
|
159 emit progress(percent);
|
Chris@208
|
160
|
Chris@208
|
161 m_progressDialog->setValue(percent);
|
Chris@208
|
162 }
|
Chris@208
|
163
|
Chris@208
|
164 void
|
Chris@208
|
165 RemoteFile::done(bool error)
|
Chris@208
|
166 {
|
Chris@208
|
167 //!!! need to identify 404s etc in the return headers
|
Chris@208
|
168
|
Chris@208
|
169 emit progress(100);
|
Chris@208
|
170 m_ok = !error;
|
Chris@208
|
171 if (error) {
|
Chris@208
|
172 if (m_http) {
|
Chris@208
|
173 m_errorString = m_http->errorString();
|
Chris@208
|
174 } else if (m_ftp) {
|
Chris@208
|
175 m_errorString = m_ftp->errorString();
|
Chris@208
|
176 }
|
Chris@208
|
177 }
|
Chris@208
|
178
|
Chris@208
|
179 delete m_localFile;
|
Chris@208
|
180 m_localFile = 0;
|
Chris@208
|
181
|
Chris@208
|
182 delete m_progressDialog;
|
Chris@208
|
183 m_progressDialog = 0;
|
Chris@208
|
184
|
Chris@208
|
185 if (m_ok) {
|
Chris@208
|
186 QFileInfo fi(m_localFilename);
|
Chris@208
|
187 if (!fi.exists()) {
|
Chris@208
|
188 m_errorString = tr("Failed to create local file %1").arg(m_localFilename);
|
Chris@208
|
189 m_ok = false;
|
Chris@208
|
190 } else if (fi.size() == 0) {
|
Chris@208
|
191 m_errorString = tr("File contains no data!");
|
Chris@208
|
192 m_ok = false;
|
Chris@208
|
193 }
|
Chris@208
|
194 }
|
Chris@208
|
195 m_done = true;
|
Chris@208
|
196 }
|
Chris@208
|
197
|
Chris@208
|
198 QString
|
Chris@208
|
199 RemoteFile::createLocalFile(QUrl url)
|
Chris@208
|
200 {
|
Chris@208
|
201 //!!! should we actually put up dialogs for these errors? or propagate an exception?
|
Chris@208
|
202
|
Chris@208
|
203 QDir dir;
|
Chris@208
|
204 try {
|
Chris@208
|
205 dir = TempDirectory::getInstance()->getSubDirectoryPath("download");
|
Chris@208
|
206 } catch (DirectoryCreationFailed f) {
|
Chris@208
|
207 std::cerr << "RemoteFile::createLocalFile: ERROR: Failed to create temporary directory: " << f.what() << std::endl;
|
Chris@208
|
208 return "";
|
Chris@208
|
209 }
|
Chris@208
|
210
|
Chris@208
|
211 QString filepart = url.path().section('/', -1, -1,
|
Chris@208
|
212 QString::SectionSkipEmpty);
|
Chris@208
|
213
|
Chris@208
|
214 QString extension = filepart.section('.', -1);
|
Chris@208
|
215 QString base = filepart;
|
Chris@208
|
216 if (extension != "") {
|
Chris@208
|
217 base = base.left(base.length() - extension.length() - 1);
|
Chris@208
|
218 }
|
Chris@208
|
219 if (base == "") base = "remote";
|
Chris@208
|
220
|
Chris@208
|
221 QString filename;
|
Chris@208
|
222
|
Chris@208
|
223 if (extension == "") {
|
Chris@208
|
224 filename = base;
|
Chris@208
|
225 } else {
|
Chris@208
|
226 filename = QString("%1.%2").arg(base).arg(extension);
|
Chris@208
|
227 }
|
Chris@208
|
228
|
Chris@208
|
229 QString filepath(dir.filePath(filename));
|
Chris@208
|
230
|
Chris@208
|
231 std::cerr << "RemoteFile::createLocalFile: URL is \"" << url.toString().toStdString() << "\", dir is \"" << dir.path().toStdString() << "\", base \"" << base.toStdString() << "\", extension \"" << extension.toStdString() << "\", filebase \"" << filename.toStdString() << "\", filename \"" << filepath.toStdString() << "\"" << std::endl;
|
Chris@208
|
232
|
Chris@208
|
233 m_fileCreationMutex.lock();
|
Chris@208
|
234 ++m_count;
|
Chris@208
|
235
|
Chris@208
|
236 if (QFileInfo(filepath).exists() ||
|
Chris@208
|
237 !QFile(filepath).open(QFile::WriteOnly)) {
|
Chris@208
|
238
|
Chris@208
|
239 std::cerr << "RemoteFile::createLocalFile: Failed to create local file \""
|
Chris@208
|
240 << filepath.toStdString() << "\" for URL \""
|
Chris@208
|
241 << url.toString().toStdString() << "\" (or file already exists): appending suffix instead" << std::endl;
|
Chris@208
|
242
|
Chris@208
|
243
|
Chris@208
|
244 if (extension == "") {
|
Chris@208
|
245 filename = QString("%1_%2").arg(base).arg(m_count);
|
Chris@208
|
246 } else {
|
Chris@208
|
247 filename = QString("%1_%2.%3").arg(base).arg(m_count).arg(extension);
|
Chris@208
|
248 }
|
Chris@208
|
249 filepath = dir.filePath(filename);
|
Chris@208
|
250
|
Chris@208
|
251 if (QFileInfo(filepath).exists() ||
|
Chris@208
|
252 !QFile(filepath).open(QFile::WriteOnly)) {
|
Chris@208
|
253
|
Chris@208
|
254 std::cerr << "RemoteFile::createLocalFile: ERROR: Failed to create local file \""
|
Chris@208
|
255 << filepath.toStdString() << "\" for URL \""
|
Chris@208
|
256 << url.toString().toStdString() << "\" (or file already exists)" << std::endl;
|
Chris@208
|
257
|
Chris@208
|
258 m_fileCreationMutex.unlock();
|
Chris@208
|
259 return "";
|
Chris@208
|
260 }
|
Chris@208
|
261 }
|
Chris@208
|
262
|
Chris@208
|
263 m_fileCreationMutex.unlock();
|
Chris@208
|
264
|
Chris@208
|
265 std::cerr << "RemoteFile::createLocalFile: url "
|
Chris@208
|
266 << url.toString().toStdString() << " -> local filename "
|
Chris@208
|
267 << filepath.toStdString() << std::endl;
|
Chris@208
|
268
|
Chris@208
|
269 return filepath;
|
Chris@208
|
270 }
|