fix small bug(wildcard), and change some comments
[mdictionary] / src / plugins / xdxf / XdxfDictDownloader.cpp
1 /*******************************************************************************
2
3     This file is part of mDictionary.
4
5     mDictionary is free software: you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation, either version 3 of the License, or
8     (at your option) any later version.
9
10     mDictionary is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with mDictionary.  If not, see <http://www.gnu.org/licenses/>.
17
18     Copyright 2010 Comarch S.A.
19
20 *******************************************************************************/
21 /*!
22     \file XdxfDictDownloader.cpp
23     \author Mateusz Półrola <mateusz.polrola@comarch.com>
24 */
25
26 #include "XdxfDictDownloader.h"
27 #include "XdxfDictDownloadProgressDialog.h"
28 #include <QDebug>
29 #include <QProcess>
30 #include <bzlib.h>
31 #include <libtar.h>
32 #include <stdio.h>
33 #include <fcntl.h>
34
35 typedef void BZFILE;
36
37 XdxfDictDownloader::XdxfDictDownloader(QObject *parent) :
38     QObject(parent) {
39     parentDialog = 0;
40     progressDialog = 0;
41     manager = new QNetworkAccessManager(this);
42
43     connect(manager, SIGNAL(finished(QNetworkReply*)),
44             this, SLOT(dictListReceived(QNetworkReply*)));
45     connect(&http, SIGNAL(finished()),
46             this, SLOT(processFinished()));
47     connect(&http, SIGNAL(error(QString)),
48             this, SLOT(downloadingError(QString)));
49     connect(&http, SIGNAL(progress(qint64,qint64)),
50             this, SLOT(updateDownloadProgress(qint64,qint64)));
51 }
52
53
54 void XdxfDictDownloader::download(QWidget *parent) {
55     parentDialog = parent;
56     aborted = false;
57
58     manager->get(QNetworkRequest(QUrl("http://xdxf.revdanica.com/down/")));
59
60     progressDialog = new XdxfDictDownloadProgressDialog(parent);
61
62     connect(progressDialog, SIGNAL(cancelDownloading()),
63             this, SLOT(breakDownloading()));
64     connect(this, SIGNAL(downloadProgress(float)),
65             progressDialog, SLOT(updateProgress(float)));
66
67     progressDialog->setText(tr("Downloading dictionaries list"));
68     progressDialog->show();
69 }
70
71
72 QString XdxfDictDownloader::downloadedFile() {
73     return _downloadedFile;
74 }
75
76
77 void XdxfDictDownloader::updateDownloadProgress(qint64 downloaded,
78                                                 qint64 total)   {
79     Q_EMIT downloadProgress(float(downloaded) / float(total));
80 }
81
82
83 void XdxfDictDownloader::downloadingError(QString error) {
84     breakDownloading();
85     Q_EMIT notify(Notify::Error, error);
86 }
87
88
89 void XdxfDictDownloader::breakDownloading() {
90     //if user cancel downloading we kill all running processes, hide progress dialog and set flag that user cancel downloading.
91     aborted = true;
92     http.kill();
93
94     if(progressDialog && progressDialog->isVisible()) {
95         progressDialog->accept();
96     }
97 }
98
99
100 void XdxfDictDownloader::processFinished() {
101     //first check if user cancel downloading
102     if(aborted) return;
103
104     if(!extract("/tmp/" + _fileName)) {
105         Q_EMIT notify(Notify::Error,
106                 "Error while extracting dictionary archive");
107         return;
108     }
109     downloadComplete();
110 }
111
112
113 void XdxfDictDownloader::downloadComplete() {
114     if(aborted) return;
115     // Downloaded tar file name is different than extracted folder so we need
116     // some clean directory to identify extracted files
117     QDir dir("/tmp/mdict");
118     QString dictDirName = dir.entryList().at(2);
119
120     // Dict is in /tmp/mdict/<extracted directory>/dict.xdxf
121     QFile dictFile("/tmp/mdict/" + dictDirName + "/dict.xdxf");
122     dictFile.copy(QDir::homePath() + "/.mdictionary/" + dictDirName + ".xdxf");
123     QFile::remove("/tmp/" + _fileName);
124     QFile::remove("/tmp/" + _fileName.replace(QRegExp(".bz2$"), ""));
125
126     _downloadedFile = QDir::homePath() + "/.mdictionary/" + dictDirName + ".xdxf";
127
128     progressDialog->accept();
129     delete progressDialog;
130     progressDialog = 0;
131
132     emit fileDownloaded(_downloadedFile);
133 }
134
135
136 void XdxfDictDownloader::dictListReceived(QNetworkReply *reply) {
137     progressDialog->accept();
138     if(aborted)
139         return;
140     if(reply->error() != QNetworkReply::NoError) {
141         Q_EMIT notify(Notify::Error, reply->errorString());
142         return;
143     }
144
145     QString page(QString::fromUtf8(reply->readAll()));
146
147     // You can look at http://xdxf.revdanica.com/down/, we need to get table
148     // with dictionaries entries following regexp match its begining
149     QRegExp regOuter("<td>Icon</td><td>Name</td><td>Archive filename</td><td>Archive file size</td><td>Dict file size</td><td>Number of articles</td><td>From</td><td>To</td><td>Submitted by</td><td>Submition date</td></tr>(.*)</table>");
150     regOuter.setMinimal(true);
151     if(!regOuter.indexIn(page))
152         return;
153
154     // Cutting each entry and creating coresponded DownloadDict object
155     page = regOuter.capturedTexts().at(1);
156     QRegExp regInner("<tr>.*</tr>");
157     regInner.setMinimal(true);
158     int pos = 0;
159
160     while ((pos = regInner.indexIn(page, pos)) != -1) {
161         DownloadDict temp = DownloadDict(regInner.cap(0));
162         if(!temp.fromLang().isEmpty())
163             dicts.append(temp);
164         pos += regInner.matchedLength();
165     }
166
167     XdxfDictSelectDialog selectDialog(dicts, parentDialog);
168
169     if(selectDialog.exec()==QDialog::Accepted) {
170
171         progressDialog->setText(tr("Downloading dictionary"));
172         progressDialog->show();
173
174         QString url = selectDialog.link();
175
176         _fileName = url.split('/').last();
177
178         QProcess clean;
179         clean.start("rm -rf /tmp/mdict");
180         clean.waitForFinished(-1);
181         clean.start("mkdir /tmp/mdict");
182         clean.waitForFinished(-1);
183
184         http.download(QUrl(url), "/tmp/" + _fileName);
185     }
186 }
187
188 bool XdxfDictDownloader::extract(QString file) {
189     // Extracting bz2
190     FILE * archive = fopen(file.toStdString().c_str(), "rb");
191     if (archive == 0)
192         return false;
193     int err;
194     BZFILE * afterbzFile = BZ2_bzReadOpen(&err, archive, 0, 0, 0, 0);
195     if(err != BZ_OK) {
196         BZ2_bzReadClose(&err, afterbzFile);
197         return false;
198     }
199
200     FILE * tarfile = fopen(file.replace(QRegExp(".bz2$"), "").
201             toStdString().c_str(), "w");
202
203     int bufflen = 100;
204     char buff[bufflen];
205     while(err == BZ_OK) {
206         int len = BZ2_bzRead(&err, afterbzFile, buff, bufflen);
207         if(fwrite(buff, 1, len, tarfile) != len)
208             return false;
209     }
210     BZ2_bzReadClose(&err, afterbzFile);
211     fclose(tarfile);
212     fclose(archive);
213
214     // Extracting tar
215     #ifndef Q_WS_MAEMO_5
216     TAR *t;
217     char * tarfname = new char[file.replace(QRegExp(".bz2%"), "").size()+1];
218     strcpy(tarfname, file.replace(QRegExp(".bz2%"), "").toStdString().c_str());
219
220     err = tar_open(&t, tarfname, 0, O_RDONLY, 0, 0);
221     if(err == -1)
222         return false;
223
224     err = tar_extract_all(t, "/tmp/mdict/");
225     if(err == -1) {
226         return false;
227     }
228     tar_close(t);
229     #else
230     QProcess tar;
231     tar.start("tar -xvf " + file.replace(QRegExp(".bz2%"), "") + " -C /tmp/mdict");
232     tar.waitForFinished(-1);
233     #endif
234
235     return true;
236 }
237
238