2 Copyright (c) 2010 Klarlvdalens Datakonsult AB, a KDAB Group company <info@kdab.net>
3 Author: Allen Winter <allen.winter@kdab.com>
4 Copyright (C) 2014 Sergio Martins <iamsergio@gmail.com>
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
16 You should have received a copy of the GNU Library General Public License
17 along with this library; see the file COPYING.LIB. If not, write to
18 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301, USA.
23 This file is part of the API for handling calendar data and provides
24 static functions for dealing with calendar incidence attachments.
27 vCalendar/iCalendar attachment handling.
29 @author Allen Winter \<winter@kde.org\>
31 #include "attachmenthandler.h"
32 #include "calendarsupport/utils.h"
34 #include <ItemFetchJob>
35 #include <QFileDialog>
36 #include <KLocalizedString>
37 #include <KMessageBox>
40 #include <QTemporaryFile>
41 #include <KToolInvocation>
42 #include <KIO/NetAccess>
44 #include "calendarsupport_debug.h"
48 #include <QMimeDatabase>
50 using namespace KCalCore
;
51 using namespace Akonadi
;
53 namespace CalendarSupport
58 QString attachmentName
;
61 class AttachmentHandler::Private
64 Private(QWidget
*parent
)
68 QMap
<KJob
*, ReceivedInfo
> mJobToReceivedInfo
;
69 QPointer
<QWidget
> mParent
;
72 AttachmentHandler::AttachmentHandler(QWidget
*parent
) : QObject(parent
), d(new Private(parent
))
77 AttachmentHandler::~AttachmentHandler()
82 Attachment::Ptr
AttachmentHandler::find(const QString
&attachmentName
,
83 const Incidence::Ptr
&incidence
)
86 return Attachment::Ptr();
89 // get the attachment by name from the incidence
90 const Attachment::List as
= incidence
->attachments();
93 Attachment::List::ConstIterator it
;
94 Attachment::List::ConstIterator
end(as
.constEnd());
96 for (it
= as
.constBegin(); it
!= end
; ++it
) {
97 if ((*it
)->label() == attachmentName
) {
107 i18n("No attachment named \"%1\" found in the incidence.", attachmentName
));
108 return Attachment::Ptr();
112 if (!KIO::NetAccess::exists(a
->uri(), KIO::NetAccess::SourceSide
, d
->mParent
)) {
115 i18n("The attachment \"%1\" is a web link that is inaccessible from this computer. ",
116 QUrl::fromPercentEncoding(a
->uri().toLatin1())));
117 return Attachment::Ptr();
123 Attachment::Ptr
AttachmentHandler::find(const QString
&attachmentName
,
124 const ScheduleMessage::Ptr
&message
)
127 return Attachment::Ptr();
130 Incidence::Ptr incidence
= message
->event().dynamicCast
<Incidence
>();
134 i18n("The calendar invitation stored in this email message is broken in some way. "
135 "Unable to continue."));
136 return Attachment::Ptr();
139 return find(attachmentName
, incidence
);
142 static QTemporaryFile
*s_tempFile
= 0;
144 static QUrl
tempFileForAttachment(const Attachment::Ptr
&attachment
)
149 QStringList patterns
= db
.mimeTypeForName(attachment
->mimeType()).globPatterns();
150 if (!patterns
.empty()) {
151 s_tempFile
= new QTemporaryFile(QDir::tempPath() + QLatin1String("/attachementview_XXXXXX") + patterns
.first().remove(QLatin1Char('*')));
153 s_tempFile
= new QTemporaryFile();
155 s_tempFile
->setAutoRemove(false);
157 s_tempFile
->setPermissions(QFile::ReadUser
);
158 s_tempFile
->write(QByteArray::fromBase64(attachment
->data()));
160 QFile
tf(s_tempFile
->fileName());
161 if (tf
.size() != attachment
->size()) {
162 //whoops. failed to write the entire attachment. return an invalid URL.
168 url
.setPath(s_tempFile
->fileName());
172 bool AttachmentHandler::view(const Attachment::Ptr
&attachment
)
179 if (attachment
->isUri()) {
180 KToolInvocation::invokeBrowser(attachment
->uri());
182 // put the attachment in a temporary file and launch it
183 QUrl tempUrl
= tempFileForAttachment(attachment
);
184 if (tempUrl
.isValid()) {
185 stat
= KRun::runUrl(tempUrl
, attachment
->mimeType(), 0, true);
190 i18n("Unable to create a temporary file for the attachment."));
198 bool AttachmentHandler::view(const QString
&attachmentName
,
199 const Incidence::Ptr
&incidence
)
201 return view(find(attachmentName
, incidence
));
204 void AttachmentHandler::view(const QString
&attachmentName
, const QString
&uid
)
208 ItemFetchJob
*job
= new ItemFetchJob(item
);
209 connect(job
, &ItemFetchJob::result
, this, &AttachmentHandler::slotFinishView
);
211 info
.attachmentName
= attachmentName
;
213 d
->mJobToReceivedInfo
[job
] = info
;
216 bool AttachmentHandler::view(const QString
&attachmentName
,
217 const ScheduleMessage::Ptr
&message
)
219 return view(find(attachmentName
, message
));
222 bool AttachmentHandler::saveAs(const Attachment::Ptr
&attachment
)
224 // get the saveas file name
225 QString saveAsFile
= QFileDialog::getSaveFileName(d
->mParent
, i18n("Save Attachment"), attachment
->label());
226 if (saveAsFile
.isEmpty() ||
227 (QFile(saveAsFile
).exists() &&
228 (KMessageBox::warningYesNo(
230 i18n("%1 already exists. Do you want to overwrite it?",
231 saveAsFile
)) == KMessageBox::No
))) {
236 if (attachment
->isUri()) {
237 // save the attachment url
238 stat
= KIO::NetAccess::file_copy(attachment
->uri(), QUrl::fromLocalFile(saveAsFile
));
240 // put the attachment in a temporary file and save it
241 QUrl tempUrl
= tempFileForAttachment(attachment
);
242 if (tempUrl
.isValid()) {
243 stat
= KIO::NetAccess::file_copy(tempUrl
, QUrl::fromLocalFile(saveAsFile
));
244 if (!stat
&& KIO::NetAccess::lastError()) {
245 KMessageBox::error(d
->mParent
, KIO::NetAccess::lastErrorString());
251 i18n("Unable to create a temporary file for the attachment."));
259 bool AttachmentHandler::saveAs(const QString
&attachmentName
,
260 const Incidence::Ptr
&incidence
)
262 return saveAs(find(attachmentName
, incidence
));
265 void AttachmentHandler::saveAs(const QString
&attachmentName
, const QString
&uid
)
269 ItemFetchJob
*job
= new ItemFetchJob(item
);
270 connect(job
, &ItemFetchJob::result
, this, &AttachmentHandler::slotFinishView
);
273 info
.attachmentName
= attachmentName
;
275 d
->mJobToReceivedInfo
[job
] = info
;
278 bool AttachmentHandler::saveAs(const QString
&attachmentName
,
279 const ScheduleMessage::Ptr
&message
)
281 return saveAs(find(attachmentName
, message
));
284 void AttachmentHandler::slotFinishSaveAs(KJob
*job
)
286 ReceivedInfo info
= d
->mJobToReceivedInfo
[job
];
287 bool success
= false;
289 if (job
->error() != 0) {
290 ItemFetchJob
*fetchJob
= qobject_cast
<ItemFetchJob
*>(job
);
291 const Item::List items
= fetchJob
->items();
292 if (!items
.isEmpty()) {
293 Incidence::Ptr incidence
= CalendarSupport::incidence(items
.first());
294 success
= incidence
&& saveAs(info
.attachmentName
, incidence
);
296 qCWarning(CALENDARSUPPORT_LOG
) << Q_FUNC_INFO
<< "No item found";
299 qCWarning(CALENDARSUPPORT_LOG
) << Q_FUNC_INFO
<< "Job error:" << job
->errorString();
302 Q_EMIT
saveAsFinished(info
.uid
, info
.attachmentName
, success
);
303 d
->mJobToReceivedInfo
.remove(job
);
306 void AttachmentHandler::slotFinishView(KJob
*job
)
308 ReceivedInfo info
= d
->mJobToReceivedInfo
[job
];
309 bool success
= false;
311 if (job
->error() != 0) {
312 ItemFetchJob
*fetchJob
= qobject_cast
<ItemFetchJob
*>(job
);
313 const Item::List items
= fetchJob
->items();
314 if (!items
.isEmpty()) {
315 Incidence::Ptr incidence
= CalendarSupport::incidence(items
.first());
316 success
= incidence
&& view(info
.attachmentName
, incidence
);
318 qCWarning(CALENDARSUPPORT_LOG
) << Q_FUNC_INFO
<< "No item found";
321 qCWarning(CALENDARSUPPORT_LOG
) << Q_FUNC_INFO
<< "Job error:" << job
->errorString();
324 Q_EMIT
viewFinished(info
.uid
, info
.attachmentName
, success
);
325 d
->mJobToReceivedInfo
.remove(job
);
328 } // namespace CalendarSupport