예제 #1
0
IncidenceEditorNG::IncidenceDialog *KODialogManager::createDialog(const Akonadi::Item &item)
{
    const KCalCore::Incidence::Ptr incidence = CalendarSupport::incidence(item);
    if (!incidence) {
        return Q_NULLPTR;
    }

    IncidenceEditorNG::IncidenceDialog *dialog =
        IncidenceEditorNG::IncidenceDialogFactory::create(
            /*needs initial saving=*/false,
            incidence->type(), mMainView->incidenceChanger(), mMainView);

    return dialog;
}
예제 #2
0
void MailClient::mailTo( const KCalCore::IncidenceBase::Ptr &incidence,
                         const KPIMIdentities::Identity &identity,
                         const QString &from, bool bccMe,
                         const QString &recipients, const QString &attachment,
                         const QString &mailTransport )
{
  QString subject;

  if ( incidence->type() != KCalCore::Incidence::TypeFreeBusy ) {
    KCalCore::Incidence::Ptr inc = incidence.staticCast<KCalCore::Incidence>() ;
    subject = inc->summary();
  } else {
    subject = i18n( "Free Busy Message" );
  }

  const QString body = KCalUtils::IncidenceFormatter::mailBodyStr( incidence,
                                                                   KSystemTimeZones::local() );

  send( identity, from, recipients, QString(), subject, body, false,
        bccMe, attachment, mailTransport );
}
bool NemoCalendarImportModel::importToMemory(const QString &fileName)
{
    if (!mEventList.isEmpty())
        mEventList.clear();

    beginResetModel();
    KCalCore::MemoryCalendar::Ptr cal(new KCalCore::MemoryCalendar(KDateTime::Spec::LocalZone()));
    importFromFile(fileName, cal);
    KCalCore::Incidence::List incidenceList = cal->incidences();
    for (int i = 0; i < incidenceList.size(); i++) {
        KCalCore::Incidence::Ptr incidence = incidenceList.at(i);
        if (incidence->type() == KCalCore::IncidenceBase::TypeEvent)
            mEventList.append(incidence.staticCast<KCalCore::Event>());
    }
    if (!mEventList.isEmpty())
        qSort(mEventList.begin(), mEventList.end(), incidenceLessThan);

    endResetModel();
    emit countChanged();
    return true;
}
int CalDavClient::removeCommonIncidences(KCalCore::Incidence::List *firstList, KCalCore::Incidence::List *secondList)
{
    QSet<QString> firstListUids;
    for (int i=0; i<firstList->count(); i++) {
        firstListUids.insert(firstList->at(i)->uid());
    }
    QSet<QString> commonUids;
    for (KCalCore::Incidence::List::iterator it = secondList->begin(); it != secondList->end();) {
        KCalCore::Incidence::Ptr incidence = *it;
        if (firstListUids.contains(incidence->uid())) {
            commonUids.insert(incidence->uid());
            it = secondList->erase(it);
        } else {
            ++it;
        }
    }
    int removed = commonUids.count();
    if (removed > 0) {
        for (KCalCore::Incidence::List::iterator it = firstList->begin(); it != firstList->end();) {
            KCalCore::Incidence::Ptr incidence = *it;
            if (commonUids.contains(incidence->uid())) {
                commonUids.remove(incidence->uid());
                it = firstList->erase(it);
            } else {
                ++it;
            }
        }
    }
    return removed;
}
static bool incidenceLessThan(const KCalCore::Incidence::Ptr e1,
                              const KCalCore::Incidence::Ptr e2)
{
    if (e1->dtStart() == e2->dtStart()) {
        int cmp = QString::compare(e1->summary(),
                                   e2->summary(),
                                   Qt::CaseInsensitive);
        if (cmp == 0)
            return QString::compare(e1->uid(), e2->uid()) < 0;
        else
            return cmp < 0;
    } else {
        return e1->dtStart() < e2->dtStart();
    }
}
예제 #6
0
void MailClient::mailOrganizer( const KCalCore::IncidenceBase::Ptr &incidence,
                                const KPIMIdentities::Identity &identity,
                                const QString &from, bool bccMe,
                                const QString &attachment,
                                const QString &sub, const QString &mailTransport )
{
  const QString to = incidence->organizer()->fullName();
  QString subject = sub;

  if ( incidence->type() != KCalCore::Incidence::TypeFreeBusy ) {
    KCalCore::Incidence::Ptr inc = incidence.staticCast<KCalCore::Incidence>();
    if ( subject.isEmpty() ) {
      subject = inc->summary();
    }
  } else {
    subject = i18n( "Free Busy Message" );
  }

  const QString body = KCalUtils::IncidenceFormatter::mailBodyStr( incidence,
                                                                   KSystemTimeZones::local() );

  send( identity, from, to, QString(), subject, body, false, bccMe, attachment, mailTransport );
}
예제 #7
0
QByteArray mailOrganizer( const KCalCore::IncidenceBase::Ptr &incidence,
//                                 const KPIMIdentities::Identity &identity,
                          const QString &from, bool bccMe,
                          const QString &attachment,
                          const QString &sub/*, const QString &mailTransport*/ )
{
    const QString to = incidence->organizer()->fullName();
    QString subject = sub;

    if ( incidence->type() != KCalCore::Incidence::TypeFreeBusy ) {
        KCalCore::Incidence::Ptr inc = incidence.staticCast<KCalCore::Incidence>();
        if ( subject.isEmpty() ) {
            subject = inc->summary();
        }
    } else {
        subject = QString( "Free Busy Message" );
    }

    QString body = KCalUtils::IncidenceFormatter::mailBodyStr( incidence, KSystemTimeZones::local() );

    return createMessage( /*identity, */from, to, QString(), subject, body, false,
                                        bccMe, attachment/*, mailTransport */)->encodedContent();
}
예제 #8
0
Akonadi::Item KolabHelpers::translateFromImap(Kolab::FolderType folderType, const Akonadi::Item &imapItem, bool &ok)
{
    //Avoid trying to convert imap messages
    if (folderType == Kolab::MailType) {
        return imapItem;
    }

    //No payload, probably a flag change or alike, we just pass it through
    if (!imapItem.hasPayload()) {
        return imapItem;
    }
    if (!imapItem.hasPayload<KMime::Message::Ptr>()) {
        qCWarning(KOLABRESOURCE_LOG) << "Payload is not a MessagePtr!";
        Q_ASSERT(false);
        ok = false;
        return imapItem;
    }

    const KMime::Message::Ptr payload = imapItem.payload<KMime::Message::Ptr>();
    const Kolab::KolabObjectReader reader(payload);
    if (checkForErrors(imapItem)) {
        ok = true;
        //We return an error object so the sync keeps working, and we can clean up the mess by simply deleting the object in the application.
        return getErrorItem(folderType, imapItem.remoteId());
    }
    switch (reader.getType()) {
    case Kolab::EventObject:
    case Kolab::TodoObject:
    case Kolab::JournalObject: {
        const KCalCore::Incidence::Ptr incidencePtr = reader.getIncidence();
        if (!incidencePtr) {
            qCWarning(KOLABRESOURCE_LOG) << "Failed to read incidence.";
            ok = false;
            return Akonadi::Item();
        }
        Akonadi::Item newItem(incidencePtr->mimeType());
        newItem.setPayload(incidencePtr);
        newItem.setRemoteId(imapItem.remoteId());
        newItem.setGid(incidencePtr->instanceIdentifier());
        return newItem;
    }
    break;
    case Kolab::NoteObject: {
        const KMime::Message::Ptr note = reader.getNote();
        if (!note) {
            qCWarning(KOLABRESOURCE_LOG) << "Failed to read note.";
            ok = false;
            return Akonadi::Item();
        }
        Akonadi::Item newItem(QStringLiteral("text/x-vnd.akonadi.note"));
        newItem.setPayload(note);
        newItem.setRemoteId(imapItem.remoteId());
        const Akonadi::NoteUtils::NoteMessageWrapper wrapper(note);
        newItem.setGid(wrapper.uid());
        return newItem;
    }
    break;
    case Kolab::ContactObject: {
        Akonadi::Item newItem(KContacts::Addressee::mimeType());
        newItem.setPayload(reader.getContact());
        newItem.setRemoteId(imapItem.remoteId());
        newItem.setGid(reader.getContact().uid());
        return newItem;
    }
    break;
    case Kolab::DistlistObject: {
        KContacts::ContactGroup contactGroup = reader.getDistlist();

        QList<KContacts::ContactGroup::ContactReference> toAdd;
        for (uint index = 0; index < contactGroup.contactReferenceCount(); ++index) {
            const KContacts::ContactGroup::ContactReference &reference = contactGroup.contactReference(index);
            KContacts::ContactGroup::ContactReference ref;
            ref.setGid(reference.uid()); //libkolab set a gid with setUid()
            toAdd << ref;
        }
        contactGroup.removeAllContactReferences();
        foreach (const KContacts::ContactGroup::ContactReference &ref, toAdd) {
            contactGroup.append(ref);
        }

        Akonadi::Item newItem(KContacts::ContactGroup::mimeType());
        newItem.setPayload(contactGroup);
        newItem.setRemoteId(imapItem.remoteId());
        newItem.setGid(contactGroup.id());
        return newItem;
    }
    break;
    default:
        qCWarning(KOLABRESOURCE_LOG) << "Object type not handled";
        ok = false;
        break;
    }
예제 #9
0
void MailClient::mailAttendees( const KCalCore::IncidenceBase::Ptr &incidence,
                                const KPIMIdentities::Identity &identity,
                                bool bccMe, const QString &attachment,
                                const QString &mailTransport )
{
  Q_ASSERT( incidence );
  KCalCore::Attendee::List attendees = incidence->attendees();
  if ( attendees.isEmpty() ) {
    kWarning() << "There are no attendees to e-mail";
    emit finished( ResultNoAttendees, i18n( "There are no attendees to e-mail" ) );
    return;
  }

  const QString from = incidence->organizer()->fullName();
  const QString organizerEmail = incidence->organizer()->email();

  QStringList toList;
  QStringList ccList;
  const int numberOfAttendees = attendees.count();
  for ( int i=0; i<numberOfAttendees; ++i ) {
    KCalCore::Attendee::Ptr a = attendees.at( i );

    const QString email = a->email();
    if ( email.isEmpty() ) {
      continue;
    }

    // In case we (as one of our identities) are the organizer we are sending
    // this mail. We could also have added ourselves as an attendee, in which
    // case we don't want to send ourselves a notification mail.
    if ( organizerEmail == email ) {
      continue;
    }

    // Build a nice address for this attendee including the CN.
    QString tname, temail;
    const QString username = KPIMUtils::quoteNameIfNecessary( a->name() );
    // ignore the return value from extractEmailAddressAndName() because
    // it will always be false since tusername does not contain "@domain".
    KPIMUtils::extractEmailAddressAndName( username, temail/*byref*/, tname/*byref*/ );
    tname += QLatin1String( " <" ) + email + QLatin1Char( '>' );

    // Optional Participants and Non-Participants are copied on the email
    if ( a->role() == KCalCore::Attendee::OptParticipant ||
         a->role() == KCalCore::Attendee::NonParticipant ) {
      ccList << tname;
    } else {
      toList << tname;
    }
  }
  if( toList.isEmpty() && ccList.isEmpty() ) {
    // Not really to be called a groupware meeting, eh
    kWarning() << "There are really no attendees to e-mail";
    emit finished( ResultReallyNoAttendees, i18n( "There are no attendees to e-mail" ) );
    return;
  }
  QString to;
  if ( !toList.isEmpty() ) {
    to = toList.join( QLatin1String( ", " ) );
  }
  QString cc;
  if ( !ccList.isEmpty() ) {
    cc = ccList.join( QLatin1String( ", " ) );
  }

  QString subject;
  if ( incidence->type() != KCalCore::Incidence::TypeFreeBusy ) {
    KCalCore::Incidence::Ptr inc = incidence.staticCast<KCalCore::Incidence>();
    subject = inc->summary();
  } else {
    subject = i18n( "Free Busy Object" );
  }

  const QString body = KCalUtils::IncidenceFormatter::mailBodyStr( incidence,
                                                                   KSystemTimeZones::local() );

  send( identity, from, to, cc, subject, body, false, bccMe, attachment, mailTransport );
}
void IncidenceWhatWhere::save( const KCalCore::Incidence::Ptr &incidence )
{
  Q_ASSERT( incidence );
  incidence->setSummary( mUi->mSummaryEdit->text() );
  incidence->setLocation( mUi->mLocationEdit->text() );
}
void TodoPlugin::processDropEvent( QDropEvent *event )
{
  const QMimeData *md = event->mimeData();

  if ( KABC::VCardDrag::canDecode( md ) ) {
    KABC::Addressee::List contacts;

    KABC::VCardDrag::fromMimeData( md, contacts );

    KABC::Addressee::List::Iterator it;

    QStringList attendees;
    for ( it = contacts.begin(); it != contacts.end(); ++it ) {
      QString email = (*it).fullEmail();
      if ( email.isEmpty() ) {
        attendees.append( (*it).realName() + "<>" );
      } else {
        attendees.append( email );
      }
    }

    interface()->openTodoEditor( i18nc( "@item", "Meeting" ),
                                 QString(), QStringList(), attendees );
    return;
  }

  if ( KCalUtils::ICalDrag::canDecode( event->mimeData() ) ) {
    KCalCore::MemoryCalendar::Ptr cal( new KCalCore::MemoryCalendar( KSystemTimeZones::local() ) );
    if ( KCalUtils::ICalDrag::fromMimeData( event->mimeData(), cal ) ) {
      KCalCore::Incidence::List incidences = cal->incidences();
      Q_ASSERT( incidences.count() );
      if ( !incidences.isEmpty() ) {
        event->accept();
        KCalCore::Incidence::Ptr i = incidences.first();
        QString summary;
        if ( i->type() == KCalCore::Incidence::TypeJournal ) {
          summary = i18nc( "@item", "Note: %1", i->summary() );
        } else {
          summary = i->summary();
        }
        interface()->openTodoEditor( summary, i->description(), QStringList() );
        return;
      }
      // else fall through to text decoding
    }
  }

  if ( md->hasText() ) {
    QString text = md->text();
    interface()->openTodoEditor( text );
    return;
  }

  if ( KPIM::MailList::canDecode( md ) ) {
    KPIM::MailList mails = KPIM::MailList::fromMimeData( md );
    event->accept();
    if ( mails.count() != 1 ) {
      KMessageBox::sorry(
        core(),
        i18nc( "@info", "Dropping multiple mails is not supported." ) );
    } else {
      KPIM::MailSummary mail = mails.first();
      QString txt = i18nc( "@item", "From: %1\nTo: %2\nSubject: %3",
                           mail.from(), mail.to(), mail.subject() );
      QString uri = QLatin1String( "kmail:" ) +
                    QString::number( mail.serialNumber() ) + '/' +
                    mail.messageId();
      KTemporaryFile tf;
      tf.setAutoRemove( true );
      tf.write( event->encodedData( "message/rfc822" ) );
      interface()->openTodoEditor(
        i18nc( "@item", "Mail: %1", mail.subject() ),
        txt, uri, tf.fileName(), QStringList(), "message/rfc822" );
      tf.close();
    }
    return;
  }

  kWarning() << QString( "Cannot handle drop events of type '%1'." ).arg( event->format() );
}
bool NotebookSyncAgent::discardRemoteChanges(KCalCore::Incidence::List *localInserted,
                                             KCalCore::Incidence::List *localModified,
                                             KCalCore::Incidence::List *localDeleted)
{
    NOTEBOOK_FUNCTION_CALL_TRACE;

    // Go through the local inserted, modified and deletions list and:
    // - Discard from them respectively the additions, modifications and deletions that were
    //   created as a result of the last remote sync.
    // - Discard any incidences that have already been deleted on the server. (These will be
    //   deleted locally when the current sync finishes.)
    // - Discard any local modifications that were modified on the server, as the server
    //   modifications take precedence.

    if (!mNotebook) {
        LOG_CRITICAL("no notebook");
        return false;
    }
    bool ok = false;
    QSet<QString> remoteDeletedIncidences = QSet<QString>::fromList(mIncidenceUidsToDelete);

    QStringList additions = mDatabase->additions(mNotebook->uid(), &ok);
    if (!ok) {
        LOG_CRITICAL("Unable to look up last sync additions for notebook:" << mNotebook->uid());
        return false;
    }
    QHash<QString,QString> modifications = mDatabase->modifications(mNotebook->uid(), &ok);
    if (!ok) {
        LOG_CRITICAL("Unable to look up last sync modifications for notebook:" << mNotebook->uid());
        return false;
    }

    for (KCalCore::Incidence::List::iterator it = localInserted->begin(); it != localInserted->end();) {
        const KCalCore::Incidence::Ptr &incidence = *it;
        const QString &uid = incidence->uid();
        if (remoteDeletedIncidences.contains(uid)) {
            LOG_DEBUG("Discarding addition deleted on server:" << uid);
            it = localInserted->erase(it);
        } else if (additions.indexOf(uid) >= 0) {
            if (incidence->lastModified().isValid() && incidence->lastModified() > incidence->created()) {
                // This incidence has been modified since it was added from the server in the last sync,
                // so it's a modification rather than an addition.
                LOG_DEBUG("Moving to modified:" << uid);
                KCalCore::Incidence::Ptr savedIncidence = fetchIncidence(mCalendar, uid);
                if (savedIncidence) {
                    localModified->append(savedIncidence);
                    it = localInserted->erase(it);
                } else {
                    ++it;
                }
            } else {
                LOG_DEBUG("Discarding addition from previous sync:" << uid);
                it = localInserted->erase(it);
            }
        } else {
            ++it;
        }
    }

    QSet<QString> serverModifiedUids;
    for (int i=0; i<mReceivedCalendarResources.count(); i++) {
        serverModifiedUids.insert(Reader::hrefToUid(mReceivedCalendarResources[i].href));
    }
    for (KCalCore::Incidence::List::iterator it = localModified->begin(); it != localModified->end();) {
        KCalCore::Incidence::Ptr sourceIncidence = *it;
        const QString &uid = sourceIncidence->uid();
        if (remoteDeletedIncidences.contains(uid) || serverModifiedUids.contains(uid)) {
            LOG_DEBUG("Discarding modification,"
                      << (remoteDeletedIncidences.contains(uid) ? "was already deleted on server" : "")
                      << (serverModifiedUids.contains(uid) ? "was already modified on server": ""));
            it = localModified->erase(it);
            continue;
        } else if (modifications.contains(uid)) {
            KCalCore::ICalFormat iCalFormat;
            KCalCore::Incidence::Ptr receivedIncidence = iCalFormat.fromString(modifications[uid]);
            if (receivedIncidence.isNull()) {
                LOG_WARNING("Not sending modification, cannot parse the received incidence:" << modifications[uid]);
                it = localModified->erase(it);
                continue;
            }
            // If incidences are the same, then we assume the local incidence was not changed after
            // the remote incidence was received, and thus there are no modifications to report.
            IncidenceHandler::prepareImportedIncidence(receivedIncidence);  // ensure fields are updated as per imported incidences
            if (IncidenceHandler::copiedPropertiesAreEqual(sourceIncidence, receivedIncidence)) {
                LOG_DEBUG("Discarding modification" << uid);
                it = localModified->erase(it);
                continue;
            }
        }

        // The default storage implementation applies the organizer as an attendee by default. Don't do this
        // as it turns the incidence into a scheduled event requiring acceptance/rejection/etc.
        const KCalCore::Person::Ptr organizer = sourceIncidence->organizer();
        if (organizer) {
            Q_FOREACH (const KCalCore::Attendee::Ptr &attendee, sourceIncidence->attendees()) {
                if (attendee->email() == organizer->email() && attendee->fullName() == organizer->fullName()) {
                    LOG_DEBUG("Discarding organizer as attendee" << attendee->fullName());
                    sourceIncidence->deleteAttendee(attendee);
                    break;
                }
            }
        }
        ++it;
    }

    QStringList deletions = mDatabase->deletions(mNotebook->uid(), &ok);
    if (!ok) {
        LOG_CRITICAL("Unable to look up last sync deletions for notebook:" << mNotebook->uid());
        return false;
    }
    for (KCalCore::Incidence::List::iterator it = localDeleted->begin(); it != localDeleted->end();) {
        const QString &uid = (*it)->uid();
        mLocalDeletedUids.insert(uid);
        if (remoteDeletedIncidences.contains(uid) || deletions.indexOf(uid) >= 0) {
            LOG_DEBUG("Discarding deletion" << uid);
            it = localDeleted->erase(it);
        } else {
            ++it;
        }
    }

    return true;
}
예제 #13
0
void IncidenceChanger::Private::onCollectionsLoaded(KJob *job)
{
    Q_ASSERT(!mPendingCreations.isEmpty());
    if (job->error() != 0 || !m_collectionFetchJob) {
        qCritical() << "Error loading collections:" << job->errorString();
        return;
    }

    Q_ASSERT(job == m_collectionFetchJob);
    Akonadi::Collection::List allCollections;
    foreach (const Akonadi::Collection &collection, m_collectionFetchJob->collections()) {
        if (collection.rights() & Akonadi::Collection::CanCreateItem) {
            allCollections << collection;
        }
    }

    m_collectionFetchJob = Q_NULLPTR;
    bool canceled = false;

    // These two will never be true, maybe even assert
    bool noAcl = false;
    bool invalidCollection = false;
    Collection collectionToUse;
    foreach (const Change::Ptr &change, mPendingCreations) {
        mPendingCreations.removeAll(change);

        if (canceled) {
            change->resultCode = ResultCodeUserCanceled;
            continue;
        }

        if (noAcl) {
            change->resultCode = ResultCodePermissions;
            continue;
        }

        if (invalidCollection) {
            change->resultCode = ResultCodeInvalidUserCollection;
            continue;
        }

        if (collectionToUse.isValid()) {
            // We don't show the dialog multiple times
            step2CreateIncidence(change, collectionToUse);
            continue;
        }

        KCalCore::Incidence::Ptr incidence = CalendarUtils::incidence(change->newItem);
        Collection::List candidateCollections = collectionsForMimeType(incidence->mimeType(), allCollections);
        if (candidateCollections.count() == 1 && candidateCollections.first().isValid()) {
            // We only have 1 writable collection, don't bother the user with a dialog
            collectionToUse = candidateCollections.first();
            qCDebug(AKONADICALENDAR_LOG) << "Only one collection exists, will not show collection dialog: " << collectionToUse.displayName();
            step2CreateIncidence(change, collectionToUse);
            continue;
        }

        // Lets ask the user which collection to use:
        int dialogCode;
        QWidget *parent = change->parentWidget;

        const QStringList mimeTypes(incidence->mimeType());
        collectionToUse = CalendarUtils::selectCollection(parent, /*by-ref*/dialogCode,
                          mimeTypes, mDefaultCollection);
        if (dialogCode != QDialog::Accepted) {
            qCDebug(AKONADICALENDAR_LOG) << "User canceled collection choosing";
            change->resultCode = ResultCodeUserCanceled;
            canceled = true;
            cancelTransaction();
            continue;
        }

        if (collectionToUse.isValid() && !hasRights(collectionToUse, ChangeTypeCreate)) {
            qCWarning(AKONADICALENDAR_LOG) << "No ACLs for incidence creation";
            const QString errorMessage = showErrorDialog(ResultCodePermissions, parent);
            change->resultCode = ResultCodePermissions;
            change->errorString = errorMessage;
            noAcl = true;
            cancelTransaction();
            continue;
        }

        // TODO: add unit test for these two situations after reviewing API
        if (!collectionToUse.isValid()) {
            qCritical() << "Invalid collection selected. Can't create incidence.";
            change->resultCode = ResultCodeInvalidUserCollection;
            const QString errorString = showErrorDialog(ResultCodeInvalidUserCollection, parent);
            change->errorString = errorString;
            invalidCollection = true;
            cancelTransaction();
            continue;
        }

        step2CreateIncidence(change, collectionToUse);
    }