comparison data/fileio/FileSource.cpp @ 762:3b2409646cc0 qt5

Get FileSource building
author Chris Cannam
date Mon, 11 Mar 2013 13:42:01 +0000
parents 579b2da21e7a
children 2b3a8ae04597
comparison
equal deleted inserted replaced
761:dc87569a196e 762:3b2409646cc0
18 #include "base/TempDirectory.h" 18 #include "base/TempDirectory.h"
19 #include "base/Exceptions.h" 19 #include "base/Exceptions.h"
20 #include "base/ProgressReporter.h" 20 #include "base/ProgressReporter.h"
21 #include "system/System.h" 21 #include "system/System.h"
22 22
23 #include <QHttp> 23 #include <QNetworkAccessManager>
24 #include <QFtp> 24 #include <QNetworkReply>
25 #include <QFileInfo> 25 #include <QFileInfo>
26 #include <QDir> 26 #include <QDir>
27 #include <QCoreApplication> 27 #include <QCoreApplication>
28 #include <QHttpResponseHeader>
29 28
30 #include <iostream> 29 #include <iostream>
31 #include <cstdlib> 30 #include <cstdlib>
32 31
33 #include <unistd.h> 32 #include <unistd.h>
34 33
35 //#define DEBUG_FILE_SOURCE 1 34 #define DEBUG_FILE_SOURCE 1
36 35
37 int 36 int
38 FileSource::m_count = 0; 37 FileSource::m_count = 0;
39 38
40 QMutex 39 QMutex
66 --urlExtantCountMap[url]; 65 --urlExtantCountMap[url];
67 std::cerr << "FileSource: Now " << urlExtantCountMap[url] << " for this url, " << extantCount << " total" << std::endl; 66 std::cerr << "FileSource: Now " << urlExtantCountMap[url] << " for this url, " << extantCount << " total" << std::endl;
68 } 67 }
69 #endif 68 #endif
70 69
70 static QNetworkAccessManager nm;
71
71 FileSource::FileSource(QString fileOrUrl, ProgressReporter *reporter, 72 FileSource::FileSource(QString fileOrUrl, ProgressReporter *reporter,
72 QString preferredContentType) : 73 QString preferredContentType) :
73 m_url(fileOrUrl, QUrl::StrictMode), 74 m_url(fileOrUrl, QUrl::StrictMode),
74 m_ftp(0),
75 m_http(0),
76 m_localFile(0), 75 m_localFile(0),
76 m_reply(0),
77 m_preferredContentType(preferredContentType), 77 m_preferredContentType(preferredContentType),
78 m_ok(false), 78 m_ok(false),
79 m_lastStatus(0), 79 m_lastStatus(0),
80 m_resource(fileOrUrl.startsWith(':')), 80 m_resource(fileOrUrl.startsWith(':')),
81 m_remote(isRemote(fileOrUrl)), 81 m_remote(isRemote(fileOrUrl)),
96 std::cerr << "FileSource::FileSource(" << fileOrUrl << "): url <" << m_url.toString() << ">" << std::endl; 96 std::cerr << "FileSource::FileSource(" << fileOrUrl << "): url <" << m_url.toString() << ">" << std::endl;
97 incCount(m_url.toString()); 97 incCount(m_url.toString());
98 #endif 98 #endif
99 99
100 if (!canHandleScheme(m_url)) { 100 if (!canHandleScheme(m_url)) {
101 SVDEBUG << "FileSource::FileSource: ERROR: Unsupported scheme in URL \"" << m_url.toString() << "\"" << endl; 101 std::cerr << "FileSource::FileSource: ERROR: Unsupported scheme in URL \"" << m_url.toString() << "\"" << std::endl;
102 m_errorString = tr("Unsupported scheme in URL"); 102 m_errorString = tr("Unsupported scheme in URL");
103 return; 103 return;
104 } 104 }
105 105
106 init(); 106 init();
108 if (!isRemote() && 108 if (!isRemote() &&
109 !isAvailable()) { 109 !isAvailable()) {
110 #ifdef DEBUG_FILE_SOURCE 110 #ifdef DEBUG_FILE_SOURCE
111 std::cerr << "FileSource::FileSource: Failed to open local file with URL \"" << m_url.toString() << "\"; trying again assuming filename was encoded" << std::endl; 111 std::cerr << "FileSource::FileSource: Failed to open local file with URL \"" << m_url.toString() << "\"; trying again assuming filename was encoded" << std::endl;
112 #endif 112 #endif
113 m_url = QUrl::fromEncoded(fileOrUrl.toAscii()); 113 m_url = QUrl::fromEncoded(fileOrUrl.toLatin1());
114 init(); 114 init();
115 } 115 }
116 116
117 if (isRemote() && 117 if (isRemote() &&
118 (fileOrUrl.contains('%') || 118 (fileOrUrl.contains('%') ||
136 // longer associating a filename with this url in the 136 // longer associating a filename with this url in the
137 // refcount map -- or createCacheFile will think we've 137 // refcount map -- or createCacheFile will think we've
138 // already done all the work and no request will be sent 138 // already done all the work and no request will be sent
139 deleteCacheFile(); 139 deleteCacheFile();
140 140
141 m_url.setEncodedUrl(fileOrUrl.toAscii()); 141 m_url = QUrl::fromEncoded(fileOrUrl.toLatin1());
142 142
143 m_ok = false; 143 m_ok = false;
144 m_done = false; 144 m_done = false;
145 m_lastStatus = 0; 145 m_lastStatus = 0;
146 init(); 146 init();
151 emit statusAvailable(); 151 emit statusAvailable();
152 emit ready(); 152 emit ready();
153 } 153 }
154 154
155 #ifdef DEBUG_FILE_SOURCE 155 #ifdef DEBUG_FILE_SOURCE
156 SVDEBUG << "FileSource::FileSource(string) exiting" << endl; 156 std::cerr << "FileSource::FileSource(string) exiting" << std::endl;
157 #endif 157 #endif
158 } 158 }
159 159
160 FileSource::FileSource(QUrl url, ProgressReporter *reporter) : 160 FileSource::FileSource(QUrl url, ProgressReporter *reporter) :
161 m_url(url), 161 m_url(url),
162 m_ftp(0),
163 m_http(0),
164 m_localFile(0), 162 m_localFile(0),
163 m_reply(0),
165 m_ok(false), 164 m_ok(false),
166 m_lastStatus(0), 165 m_lastStatus(0),
167 m_resource(false), 166 m_resource(false),
168 m_remote(isRemote(url.toString())), 167 m_remote(isRemote(url.toString())),
169 m_done(false), 168 m_done(false),
170 m_leaveLocalFile(false), 169 m_leaveLocalFile(false),
171 m_reporter(reporter), 170 m_reporter(reporter),
172 m_refCounted(false) 171 m_refCounted(false)
173 { 172 {
174 #ifdef DEBUG_FILE_SOURCE 173 #ifdef DEBUG_FILE_SOURCE
175 SVDEBUG << "FileSource::FileSource(" << url.toString() << ") [as url]" << endl; 174 std::cerr << "FileSource::FileSource(" << url.toString() << ") [as url]" << std::endl;
176 incCount(m_url.toString()); 175 incCount(m_url.toString());
177 #endif 176 #endif
178 177
179 if (!canHandleScheme(m_url)) { 178 if (!canHandleScheme(m_url)) {
180 SVDEBUG << "FileSource::FileSource: ERROR: Unsupported scheme in URL \"" << m_url.toString() << "\"" << endl; 179 std::cerr << "FileSource::FileSource: ERROR: Unsupported scheme in URL \"" << m_url.toString() << "\"" << std::endl;
181 m_errorString = tr("Unsupported scheme in URL"); 180 m_errorString = tr("Unsupported scheme in URL");
182 return; 181 return;
183 } 182 }
184 183
185 init(); 184 init();
186 185
187 #ifdef DEBUG_FILE_SOURCE 186 #ifdef DEBUG_FILE_SOURCE
188 SVDEBUG << "FileSource::FileSource(url) exiting" << endl; 187 std::cerr << "FileSource::FileSource(url) exiting" << std::endl;
189 #endif 188 #endif
190 } 189 }
191 190
192 FileSource::FileSource(const FileSource &rf) : 191 FileSource::FileSource(const FileSource &rf) :
193 QObject(), 192 QObject(),
194 m_url(rf.m_url), 193 m_url(rf.m_url),
195 m_ftp(0),
196 m_http(0),
197 m_localFile(0), 194 m_localFile(0),
195 m_reply(0),
198 m_ok(rf.m_ok), 196 m_ok(rf.m_ok),
199 m_lastStatus(rf.m_lastStatus), 197 m_lastStatus(rf.m_lastStatus),
200 m_resource(rf.m_resource), 198 m_resource(rf.m_resource),
201 m_remote(rf.m_remote), 199 m_remote(rf.m_remote),
202 m_done(false), 200 m_done(false),
203 m_leaveLocalFile(false), 201 m_leaveLocalFile(false),
204 m_reporter(rf.m_reporter), 202 m_reporter(rf.m_reporter),
205 m_refCounted(false) 203 m_refCounted(false)
206 { 204 {
207 #ifdef DEBUG_FILE_SOURCE 205 #ifdef DEBUG_FILE_SOURCE
208 SVDEBUG << "FileSource::FileSource(" << m_url.toString() << ") [copy ctor]" << endl; 206 std::cerr << "FileSource::FileSource(" << m_url.toString() << ") [copy ctor]" << std::endl;
209 incCount(m_url.toString()); 207 incCount(m_url.toString());
210 #endif 208 #endif
211 209
212 if (!canHandleScheme(m_url)) { 210 if (!canHandleScheme(m_url)) {
213 SVDEBUG << "FileSource::FileSource: ERROR: Unsupported scheme in URL \"" << m_url.toString() << "\"" << endl; 211 std::cerr << "FileSource::FileSource: ERROR: Unsupported scheme in URL \"" << m_url.toString() << "\"" << std::endl;
214 m_errorString = tr("Unsupported scheme in URL"); 212 m_errorString = tr("Unsupported scheme in URL");
215 return; 213 return;
216 } 214 }
217 215
218 if (!isRemote()) { 216 if (!isRemote()) {
219 m_localFilename = rf.m_localFilename; 217 m_localFilename = rf.m_localFilename;
220 } else { 218 } else {
221 QMutexLocker locker(&m_mapMutex); 219 QMutexLocker locker(&m_mapMutex);
222 #ifdef DEBUG_FILE_SOURCE 220 #ifdef DEBUG_FILE_SOURCE
223 SVDEBUG << "FileSource::FileSource(copy ctor): ref count is " 221 std::cerr << "FileSource::FileSource(copy ctor): ref count is "
224 << m_refCountMap[m_url] << endl; 222 << m_refCountMap[m_url] << std::endl;
225 #endif 223 #endif
226 if (m_refCountMap[m_url] > 0) { 224 if (m_refCountMap[m_url] > 0) {
227 m_refCountMap[m_url]++; 225 m_refCountMap[m_url]++;
228 #ifdef DEBUG_FILE_SOURCE 226 #ifdef DEBUG_FILE_SOURCE
229 std::cerr << "raised it to " << m_refCountMap[m_url] << std::endl; 227 std::cerr << "raised it to " << m_refCountMap[m_url] << std::endl;
237 } 235 }
238 236
239 m_done = true; 237 m_done = true;
240 238
241 #ifdef DEBUG_FILE_SOURCE 239 #ifdef DEBUG_FILE_SOURCE
242 SVDEBUG << "FileSource::FileSource(" << m_url.toString() << ") [copy ctor]: note: local filename is \"" << m_localFilename << "\"" << endl; 240 std::cerr << "FileSource::FileSource(" << m_url.toString() << ") [copy ctor]: note: local filename is \"" << m_localFilename << "\"" << std::endl;
243 #endif 241 #endif
244 242
245 #ifdef DEBUG_FILE_SOURCE 243 #ifdef DEBUG_FILE_SOURCE
246 SVDEBUG << "FileSource::FileSource(copy ctor) exiting" << endl; 244 std::cerr << "FileSource::FileSource(copy ctor) exiting" << std::endl;
247 #endif 245 #endif
248 } 246 }
249 247
250 FileSource::~FileSource() 248 FileSource::~FileSource()
251 { 249 {
378 #ifdef DEBUG_FILE_SOURCE 376 #ifdef DEBUG_FILE_SOURCE
379 std::cerr << "FileSource::init: Don't have local copy of \"" 377 std::cerr << "FileSource::init: Don't have local copy of \""
380 << m_url.toString() << "\", retrieving" << std::endl; 378 << m_url.toString() << "\", retrieving" << std::endl;
381 #endif 379 #endif
382 380
383 if (scheme == "http") { 381 if (scheme == "http" || scheme == "https" || scheme == "ftp") {
384 initHttp(); 382 initRemote();
385 #ifdef DEBUG_FILE_SOURCE 383 #ifdef DEBUG_FILE_SOURCE
386 std::cerr << "FileSource: initHttp succeeded" << std::endl; 384 std::cerr << "FileSource: initRemote returned" << std::endl;
387 #endif 385 #endif
388 } else if (scheme == "ftp") {
389 initFtp();
390 } else { 386 } else {
391 m_remote = false; 387 m_remote = false;
392 m_ok = false; 388 m_ok = false;
393 } 389 }
394 } 390 }
428 } 424 }
429 } 425 }
430 } 426 }
431 427
432 void 428 void
433 FileSource::initHttp() 429 FileSource::initRemote()
434 { 430 {
435 m_ok = true; 431 m_ok = true;
436 int port = m_url.port(); 432
437 m_http = new QHttp(m_url.host(), port < 0 ? 80 : port); 433 QNetworkRequest req;
438 connect(m_http, SIGNAL(done(bool)), this, SLOT(done(bool))); 434 req.setUrl(m_url);
439 connect(m_http, SIGNAL(dataReadProgress(int, int)), 435
440 this, SLOT(dataReadProgress(int, int))); 436 if (m_preferredContentType != "") {
441 connect(m_http, SIGNAL(responseHeaderReceived(const QHttpResponseHeader &)),
442 this, SLOT(httpResponseHeaderReceived(const QHttpResponseHeader &)));
443
444 // I don't quite understand this. url.path() returns a path
445 // without percent encoding; for example, spaces appear as
446 // literal spaces. This generally won't work if sent to the
447 // server directly. You can retrieve a correctly encoded URL
448 // from QUrl using url.toEncoded(), but that gives you the
449 // whole URL; there doesn't seem to be any way to retrieve
450 // only an encoded path. Furthermore there doesn't seem to be
451 // any way to convert a retrieved path into an encoded path
452 // without explicitly specifying that you don't want the path
453 // separators ("/") to be encoded. (Besides being painful to
454 // manage, I don't see how this can work correctly in any case
455 // where a percent-encoded "/" is supposed to appear within a
456 // path element?) There also seems to be no way to retrieve
457 // the path plus query string, i.e. everything that I need to
458 // send to the HTTP server. And no way for QHttp to take a
459 // QUrl argument. I'm obviously missing something.
460
461 // So, two ways to do this: query the bits from the URL,
462 // encode them individually, and glue them back together
463 // again...
464 /*
465 QString path = QUrl::toPercentEncoding(m_url.path(), "/");
466 QList<QPair<QString, QString> > query = m_url.queryItems();
467 if (!query.empty()) {
468 QStringList q2;
469 for (QList<QPair<QString, QString> >::iterator i = query.begin();
470 i != query.end(); ++i) {
471 q2.push_back(QString("%1=%3")
472 .arg(QString(QUrl::toPercentEncoding(i->first)))
473 .arg(QString(QUrl::toPercentEncoding(i->second))));
474 }
475 path = QString("%1%2%3")
476 .arg(path).arg("?")
477 .arg(q2.join("&"));
478 }
479 */
480
481 // ...or, much simpler but relying on knowledge about the
482 // scheme://host/path/path/query etc format of the URL, we can
483 // get the whole URL ready-encoded and then split it on "/" as
484 // appropriate...
485
486 QString path = "/" + QString(m_url.toEncoded()).section('/', 3);
487
488 #ifdef DEBUG_FILE_SOURCE
489 SVDEBUG << "FileSource: path is \""
490 << path << "\"" << endl;
491 #endif
492
493 if (m_preferredContentType == "") {
494 m_http->get(path, m_localFile);
495 } else {
496 #ifdef DEBUG_FILE_SOURCE 437 #ifdef DEBUG_FILE_SOURCE
497 std::cerr << "FileSource: indicating preferred content type of \"" 438 std::cerr << "FileSource: indicating preferred content type of \""
498 << m_preferredContentType << "\"" << std::endl; 439 << m_preferredContentType << "\"" << std::endl;
499 #endif 440 #endif
500 QHttpRequestHeader header("GET", path); 441 req.setRawHeader
501 header.setValue("Host", m_url.host()); 442 ("Accept",
502 header.setValue("Accept", QString("%1, */*").arg(m_preferredContentType)); 443 QString("%1, */*").arg(m_preferredContentType).toLatin1());
503 m_http->request(header, 0, m_localFile); 444 }
504 } 445
505 } 446 m_reply = nm.get(req);
506 447
507 void 448 connect(m_reply, SIGNAL(readyRead()),
508 FileSource::initFtp() 449 this, SLOT(readyRead()));
509 { 450 connect(m_reply, SIGNAL(error(QNetworkReply::NetworkError)),
510 m_ok = true; 451 this, SLOT(replyFailed(QNetworkReply::NetworkError)));
511 m_ftp = new QFtp; 452 connect(m_reply, SIGNAL(finished()),
512 connect(m_ftp, SIGNAL(done(bool)), this, SLOT(done(bool))); 453 this, SLOT(replyFinished()));
513 connect(m_ftp, SIGNAL(commandFinished(int, bool)), 454 connect(m_reply, SIGNAL(metadataChanged()),
514 this, SLOT(ftpCommandFinished(int, bool))); 455 this, SLOT(metadataChanged()));
515 connect(m_ftp, SIGNAL(dataTransferProgress(qint64, qint64)), 456 connect(m_reply, SIGNAL(downloadProgress(qint64, qint64)),
516 this, SLOT(dataTransferProgress(qint64, qint64))); 457 this, SLOT(downloadProgress(qint64, qint64)));
517 m_ftp->connectToHost(m_url.host(), m_url.port(21));
518
519 QString username = m_url.userName();
520 if (username == "") {
521 username = "anonymous";
522 }
523
524 QString password = m_url.password();
525 if (password == "") {
526 password = QString("%1@%2").arg(getenv("USER")).arg(getenv("HOST"));
527 }
528
529 m_ftp->login(username, password);
530
531 QString dirpath = m_url.path().section('/', 0, -2);
532 QString filename = m_url.path().section('/', -1);
533
534 if (dirpath == "") dirpath = "/";
535 m_ftp->cd(dirpath);
536 m_ftp->get(filename, m_localFile);
537 } 458 }
538 459
539 void 460 void
540 FileSource::cleanup() 461 FileSource::cleanup()
541 { 462 {
542 if (m_done) { 463 if (m_done) {
543 delete m_localFile; // does not actually delete the file 464 delete m_localFile; // does not actually delete the file
544 m_localFile = 0; 465 m_localFile = 0;
545 } 466 }
546 m_done = true; 467 m_done = true;
547 if (m_http) { 468 if (m_reply) {
548 QHttp *h = m_http; 469 QNetworkReply *r = m_reply;
549 m_http = 0; 470 m_reply = 0;
550 h->abort(); 471 r->abort();
551 h->deleteLater(); 472 r->deleteLater();
552 }
553 if (m_ftp) {
554 QFtp *f = m_ftp;
555 m_ftp = 0;
556 f->abort();
557 f->deleteLater();
558 } 473 }
559 if (m_localFile) { 474 if (m_localFile) {
560 delete m_localFile; // does not actually delete the file 475 delete m_localFile; // does not actually delete the file
561 m_localFile = 0; 476 m_localFile = 0;
562 } 477 }
574 bool 489 bool
575 FileSource::canHandleScheme(QUrl url) 490 FileSource::canHandleScheme(QUrl url)
576 { 491 {
577 // Note that a "scheme" with length 1 is probably a DOS drive letter 492 // Note that a "scheme" with length 1 is probably a DOS drive letter
578 QString scheme = url.scheme().toLower(); 493 QString scheme = url.scheme().toLower();
579 return (scheme == "http" || scheme == "ftp" || 494 return (scheme == "http" || scheme == "https" ||
580 scheme == "file" || scheme == "qrc" || 495 scheme == "ftp" || scheme == "file" || scheme == "qrc" ||
581 scheme == "" || scheme.length() == 1); 496 scheme == "" || scheme.length() == 1);
582 } 497 }
583 498
584 bool 499 bool
585 FileSource::isAvailable() 500 FileSource::isAvailable()
587 waitForStatus(); 502 waitForStatus();
588 bool available = true; 503 bool available = true;
589 if (!m_ok) available = false; 504 if (!m_ok) available = false;
590 else available = (m_lastStatus / 100 == 2); 505 else available = (m_lastStatus / 100 == 2);
591 #ifdef DEBUG_FILE_SOURCE 506 #ifdef DEBUG_FILE_SOURCE
592 SVDEBUG << "FileSource::isAvailable: " << (available ? "yes" : "no") 507 std::cerr << "FileSource::isAvailable: " << (available ? "yes" : "no")
593 << endl; 508 << std::endl;
594 #endif 509 #endif
595 return available; 510 return available;
596 } 511 }
597 512
598 void 513 void
606 521
607 void 522 void
608 FileSource::waitForData() 523 FileSource::waitForData()
609 { 524 {
610 while (m_ok && !m_done) { 525 while (m_ok && !m_done) {
611 // SVDEBUG << "FileSource::waitForData: calling QApplication::processEvents" << endl; 526 // std::cerr << "FileSource::waitForData: calling QApplication::processEvents" << std::endl;
612 QCoreApplication::processEvents(); 527 QCoreApplication::processEvents();
613 usleep(10000); 528 usleep(10000);
614 } 529 }
615 } 530 }
616 531
683 { 598 {
684 return m_errorString; 599 return m_errorString;
685 } 600 }
686 601
687 void 602 void
688 FileSource::dataReadProgress(int done, int total) 603 FileSource::readyRead()
689 { 604 {
690 dataTransferProgress(done, total); 605 m_localFile->write(m_reply->readAll());
691 } 606 }
692 607
693 void 608 void
694 FileSource::httpResponseHeaderReceived(const QHttpResponseHeader &resp) 609 FileSource::metadataChanged()
695 { 610 {
696 #ifdef DEBUG_FILE_SOURCE 611 #ifdef DEBUG_FILE_SOURCE
697 SVDEBUG << "FileSource::httpResponseHeaderReceived" << endl; 612 std::cerr << "FileSource::metadataChanged" << std::endl;
698 #endif 613 #endif
699 614
700 if (resp.statusCode() / 100 == 3) { 615 if (!m_reply) {
701 QString location = resp.value("Location"); 616 std::cerr << "WARNING: FileSource::metadataChanged() called without a reply object being known to us" << std::endl;
702 #ifdef DEBUG_FILE_SOURCE 617 return;
703 SVDEBUG << "FileSource::responseHeaderReceived: redirect to \"" 618 }
704 << location << "\" received" << endl; 619
620 int status =
621 m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
622
623 if (status / 100 == 3) {
624 QString location = m_reply->header
625 (QNetworkRequest::LocationHeader).toString();
626 #ifdef DEBUG_FILE_SOURCE
627 std::cerr << "FileSource::metadataChanged: redirect to \""
628 << location << "\" received" << std::endl;
705 #endif 629 #endif
706 if (location != "") { 630 if (location != "") {
707 QUrl newUrl(location); 631 QUrl newUrl(location);
708 if (newUrl != m_url) { 632 if (newUrl != m_url) {
709 cleanup(); 633 cleanup();
721 return; 645 return;
722 } 646 }
723 } 647 }
724 } 648 }
725 649
726 m_lastStatus = resp.statusCode(); 650 m_lastStatus = status;
727 if (m_lastStatus / 100 >= 4) { 651 if (m_lastStatus / 100 >= 4) {
728 m_errorString = QString("%1 %2") 652 m_errorString = QString("%1 %2")
729 .arg(resp.statusCode()).arg(resp.reasonPhrase()); 653 .arg(status)
730 #ifdef DEBUG_FILE_SOURCE 654 .arg(m_reply->attribute
731 SVDEBUG << "FileSource::responseHeaderReceived: " 655 (QNetworkRequest::HttpReasonPhraseAttribute).toString());
732 << m_errorString << endl; 656 #ifdef DEBUG_FILE_SOURCE
657 std::cerr << "FileSource::metadataChanged: "
658 << m_errorString << std::endl;
733 #endif 659 #endif
734 } else { 660 } else {
735 #ifdef DEBUG_FILE_SOURCE 661 #ifdef DEBUG_FILE_SOURCE
736 SVDEBUG << "FileSource::responseHeaderReceived: " 662 std::cerr << "FileSource::metadataChanged: "
737 << m_lastStatus << endl; 663 << m_lastStatus << std::endl;
738 #endif 664 #endif
739 if (resp.hasContentType()) m_contentType = resp.contentType(); 665 m_contentType =
666 m_reply->header(QNetworkRequest::ContentTypeHeader).toString();
740 } 667 }
741 emit statusAvailable(); 668 emit statusAvailable();
742 } 669 }
743 670
744 void 671 void
745 FileSource::ftpCommandFinished(int id, bool error) 672 FileSource::downloadProgress(qint64 done, qint64 total)
746 {
747 #ifdef DEBUG_FILE_SOURCE
748 std::cerr << "FileSource::ftpCommandFinished(" << id << ", " << error << ")" << std::endl;
749 #endif
750
751 if (!m_ftp) return;
752
753 QFtp::Command command = m_ftp->currentCommand();
754
755 if (!error) {
756 #ifdef DEBUG_FILE_SOURCE
757 SVDEBUG << "FileSource::ftpCommandFinished: success for command "
758 << command << endl;
759 #endif
760 return;
761 }
762
763 if (command == QFtp::ConnectToHost) {
764 m_errorString = tr("Failed to connect to FTP server");
765 } else if (command == QFtp::Login) {
766 m_errorString = tr("Login failed");
767 } else if (command == QFtp::Cd) {
768 m_errorString = tr("Failed to change to correct directory");
769 } else if (command == QFtp::Get) {
770 m_errorString = tr("FTP download aborted");
771 }
772
773 m_lastStatus = 400; // for done()
774 }
775
776 void
777 FileSource::dataTransferProgress(qint64 done, qint64 total)
778 { 673 {
779 int percent = int((double(done) / double(total)) * 100.0 - 0.1); 674 int percent = int((double(done) / double(total)) * 100.0 - 0.1);
780 emit progress(percent); 675 emit progress(percent);
781 } 676 }
782 677
789 m_ok = false; 684 m_ok = false;
790 m_errorString = tr("Download cancelled"); 685 m_errorString = tr("Download cancelled");
791 } 686 }
792 687
793 void 688 void
794 FileSource::done(bool error) 689 FileSource::replyFinished()
795 { 690 {
796 emit progress(100); 691 emit progress(100);
797 692
798 #ifdef DEBUG_FILE_SOURCE 693 #ifdef DEBUG_FILE_SOURCE
799 std::cerr << "FileSource::done(" << error << ")" << std::endl; 694 std::cerr << "FileSource::replyFinished()" << std::endl;
800 #endif 695 #endif
801 696
802 if (m_done) return; 697 if (m_done) return;
803 698
804 if (error) { 699 bool error = (m_lastStatus / 100 >= 4);
805 if (m_http) {
806 m_errorString = m_http->errorString();
807 } else if (m_ftp) {
808 m_errorString = m_ftp->errorString();
809 }
810 }
811
812 if (m_lastStatus / 100 >= 4) {
813 error = true;
814 }
815 700
816 cleanup(); 701 cleanup();
817 702
818 if (!error) { 703 if (!error) {
819 QFileInfo fi(m_localFilename); 704 QFileInfo fi(m_localFilename);
841 726
842 void 727 void
843 FileSource::deleteCacheFile() 728 FileSource::deleteCacheFile()
844 { 729 {
845 #ifdef DEBUG_FILE_SOURCE 730 #ifdef DEBUG_FILE_SOURCE
846 SVDEBUG << "FileSource::deleteCacheFile(\"" << m_localFilename << "\")" << endl; 731 std::cerr << "FileSource::deleteCacheFile(\"" << m_localFilename << "\")" << std::endl;
847 #endif 732 #endif
848 733
849 cleanup(); 734 cleanup();
850 735
851 if (m_localFilename == "") { 736 if (m_localFilename == "") {
882 #ifdef DEBUG_FILE_SOURCE 767 #ifdef DEBUG_FILE_SOURCE
883 std::cerr << "FileSource::deleteCacheFile: ERROR: Failed to delete file \"" << m_localFilename << "\"" << std::endl; 768 std::cerr << "FileSource::deleteCacheFile: ERROR: Failed to delete file \"" << m_localFilename << "\"" << std::endl;
884 #endif 769 #endif
885 } else { 770 } else {
886 #ifdef DEBUG_FILE_SOURCE 771 #ifdef DEBUG_FILE_SOURCE
887 SVDEBUG << "FileSource::deleteCacheFile: Deleted cache file \"" << m_localFilename << "\"" << endl; 772 std::cerr << "FileSource::deleteCacheFile: Deleted cache file \"" << m_localFilename << "\"" << std::endl;
888 #endif 773 #endif
889 m_localFilename = ""; 774 m_localFilename = "";
890 } 775 }
891 776
892 m_fileCreationMutex.unlock(); 777 m_fileCreationMutex.unlock();
899 { 784 {
900 { 785 {
901 QMutexLocker locker(&m_mapMutex); 786 QMutexLocker locker(&m_mapMutex);
902 787
903 #ifdef DEBUG_FILE_SOURCE 788 #ifdef DEBUG_FILE_SOURCE
904 SVDEBUG << "FileSource::createCacheFile: refcount is " << m_refCountMap[m_url] << endl; 789 std::cerr << "FileSource::createCacheFile: refcount is " << m_refCountMap[m_url] << std::endl;
905 #endif 790 #endif
906 791
907 if (m_refCountMap[m_url] > 0) { 792 if (m_refCountMap[m_url] > 0) {
908 m_refCountMap[m_url]++; 793 m_refCountMap[m_url]++;
909 m_localFilename = m_remoteLocalMap[m_url]; 794 m_localFilename = m_remoteLocalMap[m_url];