incidencedefaults.cpp 15 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/*
  Copyright (C) 2010 Bertjan Broeksema <broeksema@kde.org>
  Copyright (c) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>

  This library is free software; you can redistribute it and/or modify it
  under the terms of the GNU Library General Public License as published by
  the Free Software Foundation; either version 2 of the License, or (at your
  option) any later version.

  This library is distributed in the hope that it will be useful, but WITHOUT
  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
  License for more details.

  You should have received a copy of the GNU Library General Public License
  along with this library; see the file COPYING.LIB.  If not, write to the
  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  02110-1301, USA.
*/

#include <config-enterprise.h>

#include "incidencedefaults.h"
#include "alarmpresets.h"

#include <CalendarSupport/KCalPrefs>
#include <akonadi/calendar/calendarsettings.h>

#include <KContacts/Addressee>

#include <KCalCore/Event>
#include <KCalCore/Todo>
#include <KCalCore/Journal>
#include <KCalCore/Alarm>

#include <KEmailAddress>
#include <KIO/Job>
#include <KIO/StoredTransferJob>
#include "incidenceeditor_debug.h"
#include <KLocalizedString>

#include <QUrl>
#include <QFile>

using namespace CalendarSupport;
using namespace IncidenceEditorNG;
using namespace KCalCore;

Laurent Montel's avatar
Laurent Montel committed
49
namespace IncidenceEditorNG {
50
51
52
53
54
55
56
57
enum {
    UNSPECIFED_PRIORITY = 0
};

class IncidenceDefaultsPrivate
{
public:
    /// Members
Laurent Montel's avatar
Laurent Montel committed
58
    KCalCore::Attachment::List mAttachments;
59
    QVector<KCalCore::Attendee::Ptr> mAttendees;
Laurent Montel's avatar
Laurent Montel committed
60
61
62
63
64
65
    QStringList mEmails;
    QString mGroupWareDomain;
    KCalCore::Incidence::Ptr mRelatedIncidence;
    KDateTime mStartDt;
    KDateTime mEndDt;
    bool mCleanupTemporaryFiles;
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93

    /// Methods
    KCalCore::Person::Ptr organizerAsPerson() const;
    KCalCore::Attendee::Ptr organizerAsAttendee(const KCalCore::Person::Ptr &organizer) const;

    void todoDefaults(const KCalCore::Todo::Ptr &todo) const;
    void eventDefaults(const KCalCore::Event::Ptr &event) const;
    void journalDefaults(const KCalCore::Journal::Ptr &journal) const;
};
}

KCalCore::Person::Ptr IncidenceDefaultsPrivate::organizerAsPerson() const
{
    const QString invalidEmail = IncidenceDefaults::invalidEmailAddress();

    KCalCore::Person::Ptr organizer(new KCalCore::Person);
    organizer->setName(i18nc("@label", "no (valid) identities found"));
    organizer->setEmail(invalidEmail);

    if (mEmails.isEmpty()) {
        // Don't bother any longer, either someone forget to call setFullEmails, or
        // the user has no identities configured.
        return organizer;
    }

    if (!mGroupWareDomain.isEmpty()) {
        // Check if we have an identity with an email that ends with the groupware
        // domain.
Laurent Montel's avatar
Laurent Montel committed
94
        for (const QString &fullEmail : qAsConst(mEmails)) {
95
96
97
98
99
100
101
102
103
104
105
106
107
108
            QString name;
            QString email;
            const bool success = KEmailAddress::extractEmailAddressAndName(fullEmail, email, name);
            if (success && email.endsWith(mGroupWareDomain)) {
                organizer->setName(name);
                organizer->setEmail(email);
                break;
            }
        }
    }

    if (organizer->email() == invalidEmail) {
        // Either, no groupware was used, or we didn't find a groupware email address.
        // Now try to
Laurent Montel's avatar
Laurent Montel committed
109
        for (const QString &fullEmail : qAsConst(mEmails)) {
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
            QString name;
            QString email;
            const bool success = KEmailAddress::extractEmailAddressAndName(fullEmail, email, name);
            if (success) {
                organizer->setName(name);
                organizer->setEmail(email);
                break;
            }
        }
    }

    return organizer;
}

KCalCore::Attendee::Ptr IncidenceDefaultsPrivate::organizerAsAttendee(
    const KCalCore::Person::Ptr &organizer) const
{
Laurent Montel's avatar
Laurent Montel committed
127
128
    KCalCore::Attendee::Ptr organizerAsAttendee(new KCalCore::Attendee(QLatin1String(
                                                                           ""), QLatin1String("")));
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
    // Really, the appropriate values (even the fall back values) should come from
    // organizer. (See organizerAsPerson for more details).
    organizerAsAttendee->setName(organizer->name());
    organizerAsAttendee->setEmail(organizer->email());
    // NOTE: Don't set the status to None, this value is not supported by the attendee
    //       editor atm.
    organizerAsAttendee->setStatus(KCalCore::Attendee::Accepted);
    organizerAsAttendee->setRole(KCalCore::Attendee::ReqParticipant);
    return organizerAsAttendee;
}

void IncidenceDefaultsPrivate::eventDefaults(const KCalCore::Event::Ptr &event) const
{
    KDateTime startDT;
    if (mStartDt.isValid()) {
        startDT = mStartDt;
    } else {
        startDT = KDateTime::currentLocalDateTime();

        if (KCalPrefs::instance()->startTime().isValid()) {
            startDT.setTime(KCalPrefs::instance()->startTime().time());
        }
    }

    const QTime defaultDurationTime = KCalPrefs::instance()->defaultDuration().time();
Laurent Montel's avatar
Laurent Montel committed
154
155
    const int defaultDuration = defaultDurationTime.hour() * 3600
                                +defaultDurationTime.minute() * 60;
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182

    const KDateTime endDT = mEndDt.isValid() ? mEndDt : startDT.addSecs(defaultDuration);

    event->setDtStart(startDT);
    event->setDtEnd(endDT);
    event->setTransparency(KCalCore::Event::Opaque);

    if (KCalPrefs::instance()->defaultEventReminders()) {
        event->addAlarm(AlarmPresets::defaultAlarm(AlarmPresets::BeforeStart));
    }
}

void IncidenceDefaultsPrivate::journalDefaults(const KCalCore::Journal::Ptr &journal) const
{
    const KDateTime startDT = mStartDt.isValid() ? mStartDt : KDateTime::currentLocalDateTime();
    journal->setDtStart(startDT);
    journal->setAllDay(true);
}

void IncidenceDefaultsPrivate::todoDefaults(const KCalCore::Todo::Ptr &todo) const
{
    KCalCore::Todo::Ptr relatedTodo = mRelatedIncidence.dynamicCast<KCalCore::Todo>();
    if (relatedTodo) {
        todo->setCategories(relatedTodo->categories());
    }

    if (mEndDt.isValid()) {
Laurent Montel's avatar
Laurent Montel committed
183
        todo->setDtDue(mEndDt, true /** first */);
184
    } else if (relatedTodo && relatedTodo->hasDueDate()) {
Laurent Montel's avatar
Laurent Montel committed
185
        todo->setDtDue(relatedTodo->dtDue(true), true /** first */);
186
187
188
189
        todo->setAllDay(relatedTodo->allDay());
    } else if (relatedTodo) {
        todo->setDtDue(KDateTime());
    } else {
Laurent Montel's avatar
Laurent Montel committed
190
        todo->setDtDue(KDateTime::currentLocalDateTime().addDays(1), true /** first */);
191
192
193
194
195
196
    }

    if (mStartDt.isValid()) {
        todo->setDtStart(mStartDt);
    } else if (relatedTodo && !relatedTodo->hasStartDate()) {
        todo->setDtStart(KDateTime());
Laurent Montel's avatar
Laurent Montel committed
197
198
    } else if (relatedTodo && relatedTodo->hasStartDate()
               && relatedTodo->dtStart() <= todo->dtDue()) {
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
        todo->setDtStart(relatedTodo->dtStart());
        todo->setAllDay(relatedTodo->allDay());
    } else if (!mEndDt.isValid() || (KDateTime::currentLocalDateTime() < mEndDt)) {
        todo->setDtStart(KDateTime::currentLocalDateTime());
    } else {
        todo->setDtStart(mEndDt.addDays(-1));
    }

    todo->setCompleted(false);
    todo->setPercentComplete(0);

    // I had a bunch of to-dos and couldn't distinguish between those that had priority '5'
    // because I wanted, and those that had priority '5' because it was set by default
    // and I forgot to unset it.
    // So don't be smart and try to guess a good default priority for the user, just use unspecified.
    todo->setPriority(UNSPECIFED_PRIORITY);

    if (KCalPrefs::instance()->defaultTodoReminders()) {
        todo->addAlarm(AlarmPresets::defaultAlarm(AlarmPresets::BeforeEnd));
    }
}

/// IncidenceDefaults

IncidenceDefaults::IncidenceDefaults(bool cleanupAttachmentTemporaryFiles)
    : d_ptr(new IncidenceDefaultsPrivate)
{
    d_ptr->mCleanupTemporaryFiles = cleanupAttachmentTemporaryFiles;
}

IncidenceDefaults::IncidenceDefaults(const IncidenceDefaults &other)
    : d_ptr(new IncidenceDefaultsPrivate)
{
    *d_ptr = *other.d_ptr;
}

IncidenceDefaults::~IncidenceDefaults()
{
    delete d_ptr;
}

IncidenceDefaults &IncidenceDefaults::operator=(const IncidenceDefaults &other)
{
    if (&other != this) {
        *d_ptr = *other.d_ptr;
    }
    return *this;
}

void IncidenceDefaults::setAttachments(const QStringList &attachments,
                                       const QStringList &attachmentMimetypes,
Laurent Montel's avatar
Laurent Montel committed
250
                                       const QStringList &attachmentLabels, bool inlineAttachment)
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
{
    Q_D(IncidenceDefaults);
    d->mAttachments.clear();

    QStringList::ConstIterator it;
    int i = 0;
    for (it = attachments.constBegin(); it != attachments.constEnd(); ++it, ++i) {
        if (!(*it).isEmpty()) {
            QString mimeType;
            if (attachmentMimetypes.count() > i) {
                mimeType = attachmentMimetypes[ i ];
            }

            KCalCore::Attachment::Ptr attachment;
            if (inlineAttachment) {
Laurent Montel's avatar
Laurent Montel committed
266
                auto job = KIO::storedGet(QUrl::fromUserInput(*it));
267
268
                if (job->exec()) {
                    const QByteArray data = job->data();
Laurent Montel's avatar
Laurent Montel committed
269
270
271
                    attachment
                        = KCalCore::Attachment::Ptr(new KCalCore::Attachment(data.toBase64(),
                                                                             mimeType));
272
273
274
275
276
277
278
279
280
281
282

                    if (i < attachmentLabels.count()) {
                        attachment->setLabel(attachmentLabels[ i ]);
                    }
                } else {
                    qCCritical(INCIDENCEEDITOR_LOG) << "Error downloading uri " << *it
                                                    << job->errorString();
                }

                if (d_ptr->mCleanupTemporaryFiles) {
                    QFile file(*it);
Laurent Montel's avatar
Laurent Montel committed
283
284
285
                    if (!file.remove()) {
                        qCCritical(INCIDENCEEDITOR_LOG) << "Uname to remove file " << *it;
                    }
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
                }
            } else {
                attachment = KCalCore::Attachment::Ptr(new KCalCore::Attachment(*it, mimeType));
                if (i < attachmentLabels.count()) {
                    attachment->setLabel(attachmentLabels[ i ]);
                }
            }

            if (attachment) {
                if (attachment->label().isEmpty()) {
                    if (attachment->isUri()) {
                        attachment->setLabel(attachment->uri());
                    } else {
                        attachment->setLabel(
                            i18nc("@label attachment contains binary data", "[Binary data]"));
                    }
                }
                d->mAttachments << attachment;
                attachment->setShowInline(inlineAttachment);
            }
        }
    }
}

void IncidenceDefaults::setAttendees(const QStringList &attendees)
{
    Q_D(IncidenceDefaults);
    d->mAttendees.clear();
    QStringList::ConstIterator it;
    for (it = attendees.begin(); it != attendees.end(); ++it) {
        QString name, email;
        KContacts::Addressee::parseEmailAddress(*it, name, email);
        d->mAttendees << KCalCore::Attendee::Ptr(
Laurent Montel's avatar
Laurent Montel committed
319
            new KCalCore::Attendee(name, email, true, KCalCore::Attendee::NeedsAction));
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
    }
}

void IncidenceDefaults::setFullEmails(const QStringList &fullEmails)
{
    Q_D(IncidenceDefaults);
    d->mEmails = fullEmails;
}

void IncidenceDefaults::setGroupWareDomain(const QString &domain)
{
    Q_D(IncidenceDefaults);
    d->mGroupWareDomain = domain;
}

void IncidenceDefaults::setRelatedIncidence(const KCalCore::Incidence::Ptr &incidence)
{
    Q_D(IncidenceDefaults);
    d->mRelatedIncidence = incidence;
}

void IncidenceDefaults::setStartDateTime(const KDateTime &startDT)
{
    Q_D(IncidenceDefaults);
    d->mStartDt = startDT;
}

void IncidenceDefaults::setEndDateTime(const KDateTime &endDT)
{
    Q_D(IncidenceDefaults);
    d->mEndDt = endDT;
}

void IncidenceDefaults::setDefaults(const KCalCore::Incidence::Ptr &incidence) const
{
    Q_D(const IncidenceDefaults);

    // First some general defaults
    incidence->setSummary(QString(), false);
    incidence->setLocation(QString(), false);
    incidence->setCategories(QStringList());
    incidence->setSecrecy(KCalCore::Incidence::SecrecyPublic);
    incidence->setStatus(KCalCore::Incidence::StatusNone);
    incidence->setAllDay(false);
    incidence->setCustomStatus(QString());
    incidence->setResources(QStringList());
    incidence->setPriority(0);

    if (d->mRelatedIncidence) {
        incidence->setRelatedTo(d->mRelatedIncidence->uid());
    }

    incidence->clearAlarms();
    incidence->clearAttachments();
    incidence->clearAttendees();
    incidence->clearComments();
    incidence->clearContacts();
    incidence->clearRecurrence();
    incidence->clearTempFiles();

    const KCalCore::Person::Ptr organizerAsPerson = d->organizerAsPerson();
#ifdef KDEPIM_ENTERPRISE_BUILD
    incidence->addAttendee(d->organizerAsAttendee(organizerAsPerson));
#endif
Laurent Montel's avatar
Laurent Montel committed
384
    for (const KCalCore::Attendee::Ptr &attendee : qAsConst(d->mAttendees)) {
385
386
387
388
389
390
391
        incidence->addAttendee(attendee);
    }
    // Ical standard: No attendees -> must not have an organizer!
    if (incidence->attendeeCount()) {
        incidence->setOrganizer(organizerAsPerson);
    }

Laurent Montel's avatar
Laurent Montel committed
392
    for (const KCalCore::Attachment::Ptr &attachment : qAsConst(d->mAttachments)) {
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
        incidence->addAttachment(attachment);
    }

    switch (incidence->type()) {
    case KCalCore::Incidence::TypeEvent:
        d->eventDefaults(incidence.dynamicCast<KCalCore::Event>());
        break;
    case KCalCore::Incidence::TypeTodo:
        d->todoDefaults(incidence.dynamicCast<KCalCore::Todo>());
        break;
    case KCalCore::Incidence::TypeJournal:
        d->journalDefaults(incidence.dynamicCast<KCalCore::Journal>());
        break;
    default:
        qCDebug(INCIDENCEEDITOR_LOG) << "Unsupported incidence type, keeping current values. Type: "
                                     << static_cast<int>(incidence->type());
    }
}

/** static */
IncidenceDefaults IncidenceDefaults::minimalIncidenceDefaults(bool cleanupAttachmentTempFiles)
{
    IncidenceDefaults defaults(cleanupAttachmentTempFiles);

    // Set the full emails manually here, to avoid that we get dependencies on
    // KCalPrefs all over the place.
    defaults.setFullEmails(CalendarSupport::KCalPrefs::instance()->fullEmails());

    // NOTE: At some point this should be generalized. That is, we now use the
    //       freebusy url as a hack, but this assumes that the user has only one
    //       groupware account. Which doesn't have to be the case necessarily.
    //       This method should somehow depend on the calendar selected to which
    //       the incidence is added.
    if (CalendarSupport::KCalPrefs::instance()->useGroupwareCommunication()) {
        defaults.setGroupWareDomain(
            QUrl(Akonadi::CalendarSettings::self()->freeBusyRetrieveUrl()).host());
    }
    return defaults;
}

/** static */
QString IncidenceDefaults::invalidEmailAddress()
{
    static const QString invalidEmail(i18nc("@label invalid email address marker",
                                            "invalid@email.address"));
    return invalidEmail;
}