mirror of
https://bitbucket.org/smil3y/kde-playground.git
synced 2025-02-24 10:52:52 +00:00
409 lines
16 KiB
C++
409 lines
16 KiB
C++
![]() |
/*
|
||
|
Copyright (c) 2002-2004 Klarälvdalens Datakonsult AB
|
||
|
<info@klaralvdalens-datakonsult.se>
|
||
|
|
||
|
Copyright (C) 2010 Bertjan Broeksema <broeksema@kde.org>
|
||
|
Copyright (C) 2010 Klaralvdalens Datakonsult AB, a KDAB Group company <info@kdab.net>
|
||
|
|
||
|
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 "itiphandlerhelper_p.h"
|
||
|
#include "calendarsettings.h"
|
||
|
#include "utils_p.h"
|
||
|
|
||
|
#include <kcalcore/calendar.h>
|
||
|
#include <kcalcore/icalformat.h>
|
||
|
#include <kcalutils/incidenceformatter.h>
|
||
|
#include <kcalutils/stringify.h>
|
||
|
#include <KDebug>
|
||
|
#include <KLocalizedString>
|
||
|
#include <KMessageBox>
|
||
|
|
||
|
#include <QWidget>
|
||
|
|
||
|
using namespace Akonadi;
|
||
|
|
||
|
QString proposalComment(const KCalCore::Incidence::Ptr &incidence)
|
||
|
{
|
||
|
QString comment;
|
||
|
|
||
|
// TODO: doesn't KCalUtils/IncidenceFormater already provide this?
|
||
|
// if not, it should go there.
|
||
|
|
||
|
switch (incidence->type()) {
|
||
|
case KCalCore::IncidenceBase::TypeEvent:
|
||
|
{
|
||
|
const KDateTime dtEnd = incidence->dateTime(KCalCore::Incidence::RoleDisplayEnd);
|
||
|
comment = i18n("Proposed new meeting time: %1 - %2",
|
||
|
KCalUtils::IncidenceFormatter::dateToString(incidence->dtStart()),
|
||
|
KCalUtils::IncidenceFormatter::dateToString(dtEnd));
|
||
|
}
|
||
|
break;
|
||
|
case KCalCore::IncidenceBase::TypeTodo:
|
||
|
{
|
||
|
kWarning() << "NOT IMPLEMENTED: proposalComment called for to-do.";
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
kWarning() << "NOT IMPLEMENTED: proposalComment called for " << incidence->typeStr();
|
||
|
}
|
||
|
|
||
|
return comment;
|
||
|
}
|
||
|
|
||
|
int ITIPHandlerHelper::askUserIfNeeded(const QString &question,
|
||
|
bool ignoreDefaultAction,
|
||
|
const KGuiItem &buttonYes,
|
||
|
const KGuiItem &buttonNo) const
|
||
|
{
|
||
|
Q_ASSERT_X(!question.isEmpty(), "ITIPHandlerHelper::askUser", "ask what?");
|
||
|
|
||
|
if (ignoreDefaultAction || mDefaultAction == ITIPHandlerHelper::ActionAsk)
|
||
|
return KMessageBox::questionYesNo(mParent, question, i18n("Group Scheduling Email"),
|
||
|
buttonYes, buttonNo);
|
||
|
|
||
|
switch (mDefaultAction) {
|
||
|
case ITIPHandlerHelper::ActionSendMessage:
|
||
|
return KMessageBox::Yes;
|
||
|
case ITIPHandlerHelper::ActionDontSendMessage:
|
||
|
return KMessageBox::No;
|
||
|
default:
|
||
|
Q_ASSERT(false);
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ITIPHandlerHelper::SendResult
|
||
|
ITIPHandlerHelper::sentInvitation(int messageBoxReturnCode,
|
||
|
const KCalCore::Incidence::Ptr &incidence,
|
||
|
KCalCore::iTIPMethod method)
|
||
|
{
|
||
|
// The value represented by messageBoxReturnCode is the answer on a question
|
||
|
// which is a variant of: Do you want to send an email to the attendees?
|
||
|
//
|
||
|
// Where the email contains an invitation, modification notification or
|
||
|
// deletion notification.
|
||
|
|
||
|
if (messageBoxReturnCode == KMessageBox::Yes) {
|
||
|
// We will be sending out a message here. Now make sure there is some summary
|
||
|
// Yes, we do modify the incidence here, but we still keep the Ptr
|
||
|
// semantics, because this change is only for sending and not stored int the
|
||
|
// local calendar.
|
||
|
KCalCore::Incidence::Ptr _incidence(incidence->clone());
|
||
|
if (_incidence->summary().isEmpty()) {
|
||
|
_incidence->setSummary(i18n("<placeholder>No summary given</placeholder>"));
|
||
|
}
|
||
|
|
||
|
// Send the mail
|
||
|
m_status = StatusSendingInvitation;
|
||
|
m_scheduler->performTransaction(_incidence, method);
|
||
|
return ITIPHandlerHelper::ResultSuccess;
|
||
|
|
||
|
} else if (messageBoxReturnCode == KMessageBox::No) {
|
||
|
return ITIPHandlerHelper::ResultCanceled;
|
||
|
} else {
|
||
|
Q_ASSERT(false); // TODO: Figure out if/how this can happen (by closing the dialog with x??)
|
||
|
return ITIPHandlerHelper::ResultCanceled;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool ITIPHandlerHelper::weAreOrganizerOf(const KCalCore::Incidence::Ptr &incidence)
|
||
|
{
|
||
|
const QString email = incidence->organizer()->email();
|
||
|
return Akonadi::CalendarUtils::thatIsMe(email) || email.isEmpty()
|
||
|
|| email == QLatin1String("invalid@email.address");
|
||
|
}
|
||
|
|
||
|
bool ITIPHandlerHelper::weNeedToSendMailFor(const KCalCore::Incidence::Ptr &incidence)
|
||
|
{
|
||
|
if (!weAreOrganizerOf(incidence)) {
|
||
|
kError() << "We should be the organizer of this incidence."
|
||
|
<< "; email= " << incidence->organizer()->email()
|
||
|
<< "; thatIsMe() = " << Akonadi::CalendarUtils::thatIsMe(incidence->organizer()->email());
|
||
|
Q_ASSERT(false);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if (incidence->attendees().isEmpty()) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// At least one attendee
|
||
|
return
|
||
|
incidence->attendees().count() > 1 ||
|
||
|
incidence->attendees().first()->email() != incidence->organizer()->email();
|
||
|
}
|
||
|
|
||
|
ITIPHandlerHelper::ITIPHandlerHelper(QWidget *parent)
|
||
|
: mDefaultAction(ITIPHandlerHelper::ActionAsk)
|
||
|
, mParent(parent)
|
||
|
, m_scheduler(new MailScheduler(parent))
|
||
|
, m_status(StatusNone)
|
||
|
{
|
||
|
connect(m_scheduler, SIGNAL(transactionFinished(Akonadi::Scheduler::Result,QString)),
|
||
|
SLOT(onSchedulerFinished(Akonadi::Scheduler::Result,QString)));
|
||
|
}
|
||
|
|
||
|
ITIPHandlerHelper::~ITIPHandlerHelper()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
void ITIPHandlerHelper::setDialogParent(QWidget *parent)
|
||
|
{
|
||
|
mParent = parent;
|
||
|
}
|
||
|
|
||
|
void ITIPHandlerHelper::setDefaultAction(Action action)
|
||
|
{
|
||
|
mDefaultAction = action;
|
||
|
}
|
||
|
|
||
|
ITIPHandlerHelper::SendResult
|
||
|
ITIPHandlerHelper::sendIncidenceCreatedMessage(KCalCore::iTIPMethod method,
|
||
|
const KCalCore::Incidence::Ptr &incidence)
|
||
|
{
|
||
|
/// When we created the incidence, we *must* be the organizer.
|
||
|
|
||
|
if (!weAreOrganizerOf(incidence)) {
|
||
|
kWarning() << "Creating incidence which has another organizer! Will skip sending invitations."
|
||
|
<< "; email= " << incidence->organizer()->email()
|
||
|
<< "; thatIsMe() = " << Akonadi::CalendarUtils::thatIsMe(incidence->organizer()->email());
|
||
|
return ITIPHandlerHelper::ResultFailAbortUpdate;
|
||
|
}
|
||
|
|
||
|
if (!weNeedToSendMailFor(incidence)) {
|
||
|
return ITIPHandlerHelper::ResultNoSendingNeeded;
|
||
|
}
|
||
|
|
||
|
QString question;
|
||
|
if (incidence->type() == KCalCore::Incidence::TypeEvent) {
|
||
|
question = i18n("The event \"%1\" includes other people.\n"
|
||
|
"Do you want to email the invitation to the attendees?",
|
||
|
incidence->summary());
|
||
|
} else if (incidence->type() == KCalCore::Incidence::TypeTodo) {
|
||
|
question = i18n("The todo \"%1\" includes other people.\n"
|
||
|
"Do you want to email the invitation to the attendees?",
|
||
|
incidence->summary());
|
||
|
} else {
|
||
|
question = i18n("This incidence includes other people. "
|
||
|
"Should an email be sent to the attendees?");
|
||
|
}
|
||
|
|
||
|
const int messageBoxReturnCode = askUserIfNeeded(question, false);
|
||
|
return sentInvitation(messageBoxReturnCode, incidence, method);
|
||
|
}
|
||
|
|
||
|
bool ITIPHandlerHelper::handleIncidenceAboutToBeModified(const KCalCore::Incidence::Ptr &incidence)
|
||
|
{
|
||
|
Q_ASSERT(incidence);
|
||
|
if (!weAreOrganizerOf(incidence)) {
|
||
|
switch (incidence->type()) {
|
||
|
case KCalCore::Incidence::TypeEvent:
|
||
|
{
|
||
|
const QString question =
|
||
|
i18n("You are not the organizer of this event. Editing it will "
|
||
|
"bring your calendar out of sync with the organizer's calendar. "
|
||
|
"Do you really want to edit it?");
|
||
|
const int messageBoxReturnCode = KMessageBox::warningYesNo(mParent, question);
|
||
|
return messageBoxReturnCode != KMessageBox::No;
|
||
|
}
|
||
|
break;
|
||
|
case KCalCore::Incidence::TypeJournal:
|
||
|
case KCalCore::Incidence::TypeTodo:
|
||
|
// Not sure why we handle to-dos differently regarding this
|
||
|
return true;
|
||
|
break;
|
||
|
default:
|
||
|
kError() << "Unknown incidence type: " << incidence->type() << incidence->typeStr();
|
||
|
Q_ASSERT_X(false, "ITIPHandlerHelper::handleIncidenceAboutToBeModified()",
|
||
|
"Unknown incidence type");
|
||
|
return false;
|
||
|
}
|
||
|
} else {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ITIPHandlerHelper::SendResult
|
||
|
ITIPHandlerHelper::sendIncidenceModifiedMessage(KCalCore::iTIPMethod method,
|
||
|
const KCalCore::Incidence::Ptr &incidence,
|
||
|
bool attendeeStatusChanged)
|
||
|
{
|
||
|
// For a modified incidence, either we are the organizer or someone else.
|
||
|
if (weAreOrganizerOf(incidence)) {
|
||
|
if (weNeedToSendMailFor(incidence)) {
|
||
|
const QString question = i18n("You changed the invitation \"%1\".\n"
|
||
|
"Do you want to email the attendees an update message?",
|
||
|
incidence->summary());
|
||
|
|
||
|
const int messageBoxReturnCode = askUserIfNeeded(question, false, KGuiItem(i18n("Send Update")));
|
||
|
return sentInvitation(messageBoxReturnCode, incidence, method);
|
||
|
} else {
|
||
|
return ResultNoSendingNeeded;
|
||
|
}
|
||
|
|
||
|
} else if (incidence->type() == KCalCore::Incidence::TypeTodo) {
|
||
|
|
||
|
if (method == KCalCore::iTIPRequest) {
|
||
|
// This is an update to be sent to the organizer
|
||
|
method = KCalCore::iTIPReply;
|
||
|
}
|
||
|
|
||
|
const QString question = i18n("Do you want to send a status update to the "
|
||
|
"organizer of this task?");
|
||
|
const int messageBoxReturnCode = askUserIfNeeded(question, false, KGuiItem(i18n("Send Update")));
|
||
|
return sentInvitation(messageBoxReturnCode, incidence, method);
|
||
|
|
||
|
} else if (incidence->type() == KCalCore::Incidence::TypeEvent) {
|
||
|
if (attendeeStatusChanged && method == KCalCore::iTIPRequest) {
|
||
|
method = KCalCore::iTIPReply;
|
||
|
const QString question =
|
||
|
i18n("Your status as an attendee of this event changed. "
|
||
|
"Do you want to send a status update to the event organizer?");
|
||
|
const int messageBoxReturnCode = askUserIfNeeded(question, false, KGuiItem(i18n("Send Update")));
|
||
|
return sentInvitation(messageBoxReturnCode, incidence, method);
|
||
|
} else {
|
||
|
return sentInvitation(KMessageBox::Yes, incidence, method);
|
||
|
}
|
||
|
}
|
||
|
Q_ASSERT(false); // Shouldn't happen.
|
||
|
return ResultNoSendingNeeded;
|
||
|
}
|
||
|
|
||
|
ITIPHandlerHelper::SendResult
|
||
|
ITIPHandlerHelper::sendIncidenceDeletedMessage(KCalCore::iTIPMethod method,
|
||
|
const KCalCore::Incidence::Ptr &incidence)
|
||
|
{
|
||
|
Q_ASSERT(incidence);
|
||
|
// For a modified incidence, either we are the organizer or someone else.
|
||
|
if (weAreOrganizerOf(incidence)) {
|
||
|
if (weNeedToSendMailFor(incidence)) {
|
||
|
QString question;
|
||
|
if (incidence->type() == KCalCore::Incidence::TypeEvent) {
|
||
|
question = i18n("You removed the invitation \"%1\".\n"
|
||
|
"Do you want to email the attendees that the event is canceled?",
|
||
|
incidence->summary());
|
||
|
} else if (incidence->type() == KCalCore::Incidence::TypeTodo) {
|
||
|
question = i18n("You removed the invitation \"%1\".\n"
|
||
|
"Do you want to email the attendees that the todo is canceled?",
|
||
|
incidence->summary());
|
||
|
} else if (incidence->type() == KCalCore::Incidence::TypeJournal) {
|
||
|
question = i18n("You removed the invitation \"%1\".\n"
|
||
|
"Do you want to email the attendees that the journal is canceled?",
|
||
|
incidence->summary());
|
||
|
}
|
||
|
|
||
|
const int messageBoxReturnCode = askUserIfNeeded(question, false);
|
||
|
return sentInvitation(messageBoxReturnCode, incidence, method);
|
||
|
} else {
|
||
|
return ResultNoSendingNeeded;
|
||
|
}
|
||
|
|
||
|
} else if (incidence->type() != KCalCore::Incidence::TypeEvent) {
|
||
|
|
||
|
if (method == KCalCore::iTIPRequest) {
|
||
|
// This is an update to be sent to the organizer
|
||
|
method = KCalCore::iTIPReply;
|
||
|
}
|
||
|
|
||
|
const QString question = (incidence->type() == KCalCore::Incidence::TypeTodo) ?
|
||
|
i18n("Do you want to send a status update to the "
|
||
|
"organizer of this task?") :
|
||
|
i18n("Do you want to send a status update to the "
|
||
|
"organizer of this journal?");
|
||
|
|
||
|
const int messageBoxReturnCode = askUserIfNeeded(question, false, KGuiItem(i18n("Send Update")));
|
||
|
return sentInvitation(messageBoxReturnCode, incidence, method);
|
||
|
} else if (incidence->type() == KCalCore::Incidence::TypeEvent) {
|
||
|
|
||
|
const QStringList myEmails = Akonadi::CalendarUtils::allEmails();
|
||
|
bool incidenceAcceptedBefore = false;
|
||
|
foreach(const QString &email, myEmails) {
|
||
|
KCalCore::Attendee::Ptr me = incidence->attendeeByMail(email);
|
||
|
if (me &&
|
||
|
(me->status() == KCalCore::Attendee::Accepted ||
|
||
|
me->status() == KCalCore::Attendee::Delegated)) {
|
||
|
incidenceAcceptedBefore = true;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (incidenceAcceptedBefore) {
|
||
|
QString question = i18n("You had previously accepted an invitation to this event. "
|
||
|
"Do you want to send an updated response to the organizer "
|
||
|
"declining the invitation?");
|
||
|
int messageBoxReturnCode = askUserIfNeeded(question, false, KGuiItem(i18n("Send Update")));
|
||
|
return sentInvitation(messageBoxReturnCode, incidence, method);
|
||
|
} else {
|
||
|
// We did not accept the event before and delete it from our calendar agian,
|
||
|
// so there is no need to notify people.
|
||
|
return ITIPHandlerHelper::ResultNoSendingNeeded;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Q_ASSERT(false); // Shouldn't happen.
|
||
|
return ResultNoSendingNeeded;
|
||
|
}
|
||
|
|
||
|
ITIPHandlerHelper::SendResult
|
||
|
ITIPHandlerHelper::sendCounterProposal(const KCalCore::Incidence::Ptr &oldEvent,
|
||
|
const KCalCore::Incidence::Ptr &newEvent)
|
||
|
{
|
||
|
Q_ASSERT(oldEvent);
|
||
|
Q_ASSERT(newEvent);
|
||
|
|
||
|
if (!oldEvent || !newEvent || *oldEvent == *newEvent)
|
||
|
return ITIPHandlerHelper::ResultNoSendingNeeded;
|
||
|
|
||
|
if (CalendarSettings::self()->outlookCompatCounterProposals()) {
|
||
|
KCalCore::Incidence::Ptr tmp(oldEvent->clone());
|
||
|
tmp->setSummary(i18n("Counter proposal: %1", newEvent->summary()));
|
||
|
tmp->setDescription(newEvent->description());
|
||
|
tmp->addComment(proposalComment(newEvent));
|
||
|
|
||
|
return sentInvitation(KMessageBox::Yes, tmp, KCalCore::iTIPReply);
|
||
|
} else {
|
||
|
return sentInvitation(KMessageBox::Yes, newEvent, KCalCore::iTIPCounter);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void ITIPHandlerHelper::onSchedulerFinished(Akonadi::Scheduler::Result result,
|
||
|
const QString &errorMsg)
|
||
|
{
|
||
|
const bool success = result == MailScheduler::ResultSuccess;
|
||
|
|
||
|
if (m_status == StatusSendingInvitation) {
|
||
|
m_status = StatusNone;
|
||
|
if (!success) {
|
||
|
const QString question(i18n("Sending group scheduling email failed."));
|
||
|
const int code = askUserIfNeeded(question, true, KGuiItem(i18n("Abort Update")));
|
||
|
if (code == KMessageBox::Yes) {
|
||
|
emit finished(ResultFailAbortUpdate, QString());
|
||
|
} else {
|
||
|
emit finished(ResultFailKeepUpdate, QString());
|
||
|
}
|
||
|
return;
|
||
|
} else {
|
||
|
//fall through
|
||
|
}
|
||
|
}
|
||
|
|
||
|
emit finished(success ? ResultSuccess : ResultError,
|
||
|
success ? QString() : i18n("Error: %1", errorMsg));
|
||
|
}
|
||
|
|