void AlarmDialog::slotCalendarChanged()
{
  Akonadi::Item::List incidences = mCalendar->incidences();
  for ( Akonadi::Item::List::ConstIterator it = incidences.constBegin();
        it != incidences.constEnd(); ++it ) {
    ReminderListItem *item = searchByItem( *it );

    if ( item ) {
      Incidence::Ptr incidence = CalendarSupport::incidence( *it );
      QString displayStr;

      // Yes, alarms can be empty, if someone edited the incidence and removed all alarms
      if ( !incidence->alarms().isEmpty() ) {
        const KDateTime dateTime = triggerDateForIncidence( incidence,
                                                            item->mRemindAt,
                                                            displayStr );

        const QString summary = cleanSummary( incidence->summary() );

        if ( displayStr != item->text( 1 ) || summary != item->text( 0 ) ) {
          item->setText( 1, displayStr );
          item->setText( 0, summary );
        }
      }
    }
  }
}
Beispiel #2
0
void DndFactoryTest::testPasteTodo()
{
  MemoryCalendar::Ptr calendar( new MemoryCalendar( QString() ) );

  DndFactory factory( calendar );

  Todo::Ptr todo( new Todo() );
  todo->setSummary( QLatin1String( "Summary 1" ) );
  todo->setDtDue( KDateTime( QDate( 2010, 8, 9 ) ) );

  Incidence::List incidencesToPaste;
  incidencesToPaste.append( todo );

  QVERIFY( factory.copyIncidences( incidencesToPaste ) );

  const KDateTime newDateTime( QDate( 2011, 1, 1 ), QTime( 10, 10 ) );

  Incidence::List pastedIncidences = factory.pasteIncidences( newDateTime );
  QVERIFY( pastedIncidences.size() == 1 );

  Incidence::Ptr incidence = pastedIncidences.first();

  QVERIFY( incidence->type() == Incidence::TypeTodo );

  // check if a new uid was generated.
  QVERIFY( incidence->uid() != todo->uid() );

  Todo::Ptr pastedTodo = incidence.staticCast<Todo>();

  QVERIFY( pastedTodo->dtDue() == newDateTime );
  QVERIFY( pastedTodo->summary() == todo->summary() );

}
/** static */
KDateTime AlarmDialog::triggerDateForIncidence( const Incidence::Ptr &incidence,
                                                const QDateTime &reminderAt,
                                                QString &displayStr )
{
  KDateTime result;

  if ( incidence->alarms().isEmpty() ) {
    return result;
  }

  Alarm::Ptr alarm = incidence->alarms().first();

  if ( incidence->recurs() ) {
    result = incidence->recurrence()->getNextDateTime(
      KDateTime( reminderAt, KDateTime::Spec::LocalZone( ) ) );

      displayStr = KGlobal::locale()->formatDateTime( result.toLocalZone() );
  }

  if ( !result.isValid() ) {
    result = incidence->dateTime( Incidence::RoleAlarm );
    displayStr = IncidenceFormatter::dateTimeToString( result, false,
                                                       true,
                                                       KDateTime::Spec::LocalZone() );
  }

  return result;
}
Beispiel #4
0
QString Stringify::incidenceStatus( const Incidence::Ptr &incidence )
{
  if ( incidence->status() == Incidence::StatusX ) {
    return incidence->customStatus();
  } else {
    return incidenceStatus( incidence->status() );
  }
}
Beispiel #5
0
void CompatPre32::fixRecurrence( const Incidence::Ptr &incidence )
{
  Recurrence *recurrence = incidence->recurrence();
  if ( recurrence->recurs() &&  recurrence->duration() > 0 ) {
    recurrence->setDuration( recurrence->duration() + incidence->recurrence()->exDates().count() );
  }
  // Call base class method now that everything else is done
  CompatPre35::fixRecurrence( incidence );
}
Beispiel #6
0
void HtmlExport::formatCategories(QTextStream *ts,
                                  const Incidence::Ptr &incidence)
{
    if (!incidence->categoriesStr().isEmpty()) {
        *ts << "    " << cleanChars(incidence->categoriesStr()) << endl;
    } else {
        *ts << "    &nbsp;" << endl;
    }
}
bool AlarmDialog::openIncidenceEditorThroughKOrganizer( const Incidence::Ptr &incidence )
{
  if ( !QDBusConnection::sessionBus().interface()->isServiceRegistered( "org.kde.korganizer" ) ) {
    if ( KToolInvocation::startServiceByDesktopName( "korganizer", QString() ) ) {
      KMessageBox::error(
        this,
        i18nc( "@info",
               "Could not start KOrganizer so editing is not possible." ) );
      return false;
    }
  }
  org::kde::korganizer::Korganizer korganizer(
    "org.kde.korganizer", "/Korganizer", QDBusConnection::sessionBus() );

  kDebug() << "editing incidence " << incidence->summary();
  if ( !korganizer.editIncidence( incidence->uid() ) ) {
    KMessageBox::error(
      this,
      i18nc( "@info",
             "An internal KOrganizer error occurred attempting to modify \"%1\"",
             cleanSummary( incidence->summary() ) ) );
  }

  // get desktop # where korganizer (or kontact) runs
  QString object =
    QDBusConnection::sessionBus().interface()->isServiceRegistered( "org.kde.kontact" ) ?
    "kontact/MainWindow_1" : "korganizer/MainWindow_1";
  QDBusInterface korganizerObj( "org.kde.korganizer", '/' + object );
#ifdef Q_WS_X11
  QDBusReply<int> reply = korganizerObj.call( "winId" );
  if ( reply.isValid() ) {
    int window = reply;
    int desktop = KWindowSystem::windowInfo( window, NET::WMDesktop ).desktop();
    if ( KWindowSystem::currentDesktop() == desktop ) {
      KWindowSystem::minimizeWindow( winId(), false );
    } else {
      KWindowSystem::setCurrentDesktop( desktop );
    }
    KWindowSystem::activateWindow( KWindowSystem::transientFor( window ) );
  }
#elif defined(Q_WS_WIN)
  // WId is a typedef to a void* on windows
  QDBusReply<qlonglong> reply = korganizerObj.call( "winId" );
  if ( reply.isValid() ) {
    qlonglong window = reply;
    KWindowSystem::minimizeWindow( winId(), false );
    KWindowSystem::allowExternalProcessWindowActivation();
    KWindowSystem::activateWindow( reinterpret_cast<WId>(window) );
  }
#else
  // TODO (mac)
#endif
return true;
}
void CalendarBaseTest::createInitialIncidences()
{
    mExpectedSlotResult = true;

    for (int i=0; i<5; ++i) {
        Event::Ptr event = Event::Ptr(new Event());
        event->setUid(QStringLiteral("event") + QString::number(i));
        event->setSummary(QStringLiteral("summary") + QString::number(i));
        event->setDtStart(KDateTime::currentDateTime(KDateTime::UTC));
        mUids.append(event->uid());
        QVERIFY(mCalendar->addEvent(event));
        QTestEventLoop::instance().enterLoop(5);
        QVERIFY(!QTestEventLoop::instance().timeout());
    }
    mOneEventUid = mUids.last();

    for (int i=0; i<5; ++i) {
        Todo::Ptr todo = Todo::Ptr(new Todo());
        todo->setUid(QStringLiteral("todo") + QString::number(i));
        todo->setDtStart(KDateTime::currentDateTime(KDateTime::UTC));
        todo->setSummary(QStringLiteral("summary") + QString::number(i));
        mUids.append(todo->uid());
        QVERIFY(mCalendar->addTodo(todo));
        QTestEventLoop::instance().enterLoop(5);
        QVERIFY(!QTestEventLoop::instance().timeout());
    }
    mOneTodoUid = mUids.last();

    for (int i=0; i<5; ++i) {
        Journal::Ptr journal = Journal::Ptr(new Journal());
        journal->setUid(QStringLiteral("journal") + QString::number(i));
        journal->setSummary(QStringLiteral("summary") + QString::number(i));
        journal->setDtStart(KDateTime::currentDateTime(KDateTime::UTC));
        mUids.append(journal->uid());
        QVERIFY(mCalendar->addJournal(journal));
        QTestEventLoop::instance().enterLoop(5);
        QVERIFY(!QTestEventLoop::instance().timeout());
    }
    mOneJournalUid = mUids.last();

    for (int i=0; i<5; ++i) {
        Incidence::Ptr incidence = Incidence::Ptr(new Event());
        incidence->setUid(QStringLiteral("incidence") + QString::number(i));
        incidence->setSummary(QStringLiteral("summary") + QString::number(i));
        incidence->setDtStart(KDateTime::currentDateTime(KDateTime::UTC));
        mUids.append(incidence->uid());
        QVERIFY(mCalendar->addIncidence(incidence));
        QTestEventLoop::instance().enterLoop(5);
        QVERIFY(!QTestEventLoop::instance().timeout());
    }
    mOneIncidenceUid = mUids.last();
}
void AlarmDialog::addIncidence( const Akonadi::Item &incidenceitem,
                                const QDateTime &reminderAt,
                                const QString &displayText )
{
  Incidence::Ptr incidence = CalendarSupport::incidence( incidenceitem );
  ReminderListItem *item = searchByItem( incidenceitem );
  if ( !item ) {
    item = new ReminderListItem( incidenceitem, mIncidenceTree );
  }
  item->mNotified = false;
  item->mHappening = KDateTime();
  item->mRemindAt = reminderAt;
  item->mTrigger = KDateTime::currentLocalDateTime();
  item->mDisplayText = displayText;
  item->setText( 0, cleanSummary( incidence->summary() ) );

  Event::Ptr event;
  Todo::Ptr todo;

  QString displayStr;
  const KDateTime dateTime = triggerDateForIncidence( incidence, reminderAt,
                                                      displayStr );

  if ( incidence->type() == Incidence::TypeEvent ) {
    item->setIcon( 0, SmallIcon( "view-calendar-day" ) );
  } else if ( incidence->type() == Incidence::TypeTodo ) {
    item->setIcon( 0, SmallIcon( "view-calendar-tasks" ) );
  }

  item->mHappening = dateTime;
  item->setText( 1, displayStr );

  item->setText( 2, IncidenceFormatter::dateTimeToString(
                   item->mTrigger, false, true, KDateTime::Spec::LocalZone() ) );
  QString tip =
    IncidenceFormatter::toolTipStr(
      CalendarSupport::displayName( mCalendar, incidenceitem.parentCollection() ),
      incidence,
      item->mRemindAt.date(), true,
      KDateTime::Spec::LocalZone() );
  if ( !item->mDisplayText.isEmpty() ) {
    tip += "<br>" + item->mDisplayText;
  }
  item->setToolTip( 0, tip );
  item->setToolTip( 1, tip );
  item->setToolTip( 2, tip );
  item->setData( 0, QTreeWidgetItem::UserType, false );

  mIncidenceTree->setCurrentItem( item );
  showDetails();
  slotSave();
}
bool AlarmDialog::openIncidenceEditorNG( const Akonadi::Item &item )
{
  if ( !IncidenceEditorNG::GroupwareIntegration::isActive() ) {
    //TODO: Why do we need this to have a simple editor?
    IncidenceEditorNG::GroupwareIntegration::activate( mCalendar );
  }
  Incidence::Ptr incidence = CalendarSupport::incidence( item );
  IncidenceEditorNG::IncidenceDialog *dialog =
    IncidenceEditorNG::IncidenceDialogFactory::create(
      false, /*doesn't need initial saving*/
      incidence->type(), this );
  dialog->load( item );
  return true;
}
Beispiel #11
0
void DndFactoryTest::testPasteAllDayEvent2()
{

  MemoryCalendar::Ptr calendar( new MemoryCalendar( QString() ) );

  DndFactory factory( calendar );

  Event::Ptr allDayEvent( new Event() );
  allDayEvent->setSummary( QLatin1String( "Summary 2" ) );
  allDayEvent->setDtStart( KDateTime( QDate( 2010, 8, 8 ) ) );
  allDayEvent->setDtEnd( KDateTime( QDate( 2010, 8, 9 ) ) );
  const QString originalUid = allDayEvent->uid();

  Incidence::List incidencesToPaste;
  incidencesToPaste.append( allDayEvent );

  QVERIFY( factory.copyIncidences( incidencesToPaste ) );

  const KDateTime newDateTime( QDate( 2011, 1, 1 ) );
  const uint originalLength = allDayEvent->dtStart().secsTo( allDayEvent->dtEnd() );

  // paste at the new time
  Incidence::List pastedIncidences = factory.pasteIncidences( newDateTime );

  // we only copied one incidence
  QVERIFY( pastedIncidences.size() == 1 );

  Incidence::Ptr incidence = pastedIncidences.first();

  QVERIFY( incidence->type() == Incidence::TypeEvent );

  // check if a new uid was generated.
  QVERIFY( incidence->uid() != originalUid );

  // the new dateTime didn't have time component
  QVERIFY( incidence->allDay() );

  Event::Ptr pastedEvent = incidence.staticCast<Event>();
  const uint newLength = pastedEvent->dtStart().secsTo( pastedEvent->dtEnd() );

  kDebug() << "originalLength was " << originalLength << "; and newLength is "
           << newLength << "; old dtStart was " << allDayEvent->dtStart()
           << " and old dtEnd was " << allDayEvent->dtEnd() << endl
           << "; new dtStart is " << pastedEvent->dtStart()
           << " and new dtEnd is " << pastedEvent->dtEnd();

  QVERIFY( originalLength == newLength );
  QVERIFY( pastedEvent->dtStart() == newDateTime );
  QVERIFY( pastedEvent->summary() == allDayEvent->summary() );
}
Beispiel #12
0
void CompatPre35::fixRecurrence( const Incidence::Ptr &incidence )
{
  Recurrence *recurrence = incidence->recurrence();
  if ( recurrence ) {
    KDateTime start( incidence->dtStart() );
    // kde < 3.5 only had one rrule, so no need to loop over all RRULEs.
    RecurrenceRule *r = recurrence->defaultRRule();
    if ( r && !r->dateMatchesRules( start ) ) {
      recurrence->addExDateTime( start );
    }
  }

  // Call base class method now that everything else is done
  Compat::fixRecurrence( incidence );
}
Beispiel #13
0
void Compat::fixEmptySummary( const Incidence::Ptr &incidence )
{
  // some stupid vCal exporters ignore the standard and use Description
  // instead of Summary for the default field. Correct for this: Copy the
  // first line of the description to the summary (if summary is just one
  // line, move it)
  if ( incidence->summary().isEmpty() && !( incidence->description().isEmpty() ) ) {
    QString oldDescription = incidence->description().trimmed();
    QString newSummary( oldDescription );
    newSummary.remove( QRegExp( "\n.*" ) );
    incidence->setSummary( newSummary );
    if ( oldDescription == newSummary ) {
      incidence->setDescription( "" );
    }
  }
}
Beispiel #14
0
int RecurrenceActions::availableOccurrences( const Incidence::Ptr &incidence,
                                             const KDateTime &selectedOccurrence )
{
  int result = NoOccurrence;

  if ( incidence->recurrence()->recursOn( selectedOccurrence.date(),
                                          selectedOccurrence.timeSpec() ) ) {
    result |= SelectedOccurrence;
  }

  if ( incidence->recurrence()->getPreviousDateTime( selectedOccurrence ).isValid() ) {
    result |= PastOccurrences;
  }

  if ( incidence->recurrence()->getNextDateTime( selectedOccurrence ).isValid() ) {
    result |= FutureOccurrences;
  }

  return result;
}
void AlarmDialog::edit()
{
  ReminderList selection = selectedItems();
  if ( selection.count() != 1 ) {
    return;
  }
  Incidence::Ptr incidence = CalendarSupport::incidence( selection.first()->mIncidence );
  if ( !mCalendar->hasChangeRights( selection.first()->mIncidence ) ) {
    KMessageBox::sorry(
      this,
      i18nc( "@info",
             "\"%1\" is a read-only item so modifications are not possible.",
             cleanSummary( incidence->summary() ) ) );
    return;
  }

#if !defined(KDEPIM_MOBILE_UI)
  openIncidenceEditorNG( selection.first()->mIncidence );
#else
  openIncidenceEditorThroughKOrganizer( incidence );
#endif
}
Beispiel #16
0
void DndFactoryTest::testPasteAllDayEvent()
{

  MemoryCalendar::Ptr calendar( new MemoryCalendar( QString() ) );

  DndFactory factory( calendar );

  Event::Ptr allDayEvent( new Event() );
  allDayEvent->setSummary( QLatin1String( "Summary 1" ) );
  allDayEvent->setDtStart( KDateTime( QDate( 2010, 8, 8 ) ) );
  allDayEvent->setDtEnd( KDateTime( QDate( 2010, 8, 9 ) ) );
  const QString originalUid = allDayEvent->uid();
  const bool originalIsAllDay = allDayEvent->allDay();

  Incidence::List incidencesToPaste;
  incidencesToPaste.append( allDayEvent );

  QVERIFY( factory.copyIncidences( incidencesToPaste ) );

  Incidence::List pastedIncidences = factory.pasteIncidences();
  QVERIFY( pastedIncidences.size() == 1 );

  Incidence::Ptr incidence = pastedIncidences.first();

  QVERIFY( incidence->type() == Incidence::TypeEvent );

  // check if a new uid was generated.
  QVERIFY( incidence->uid() != originalUid );

  // we passed an invalid KDateTime to pasteIncidences() so dates don't change.
  QVERIFY( incidence->allDay() == originalIsAllDay );

  Event::Ptr pastedEvent = incidence.staticCast<Event>();

  QVERIFY( pastedEvent->dtStart() == allDayEvent->dtStart() );
  QVERIFY( pastedEvent->dtEnd() == allDayEvent->dtEnd() );
  QVERIFY( pastedEvent->summary() == allDayEvent->summary() );
}
Beispiel #17
0
void HtmlExport::formatAttendees(QTextStream *ts,
                                 const Incidence::Ptr &incidence)
{
    Attendee::List attendees = incidence->attendees();
    if (attendees.count()) {
        *ts << "<em>";
        *ts << incidence->organizer()->fullName();
        *ts << "</em><br />";
        Attendee::List::ConstIterator it;
        for (it = attendees.constBegin(); it != attendees.constEnd(); ++it) {
            Attendee::Ptr a(*it);
            if (!a->email().isEmpty()) {
                *ts << "<a href=\"mailto:" << a->email();
                *ts << "\">" << cleanChars(a->name()) << "</a>";
            } else {
                *ts << "    " << cleanChars(a->name());
            }
            *ts << "<br />" << endl;
        }
    } else {
        *ts << "    &nbsp;" << endl;
    }
}
Beispiel #18
0
bool HtmlExport::checkSecrecy(const Incidence::Ptr &incidence)
{
    int secrecy = incidence->secrecy();
    if (secrecy == Incidence::SecrecyPublic) {
        return true;
    }
    if (secrecy == Incidence::SecrecyPrivate && !d->mSettings->excludePrivate()) {
        return true;
    }
    if (secrecy == Incidence::SecrecyConfidential &&
            !d->mSettings->excludeConfidential()) {
        return true;
    }
    return false;
}
Beispiel #19
0
void CompatOutlook9::fixAlarms( const Incidence::Ptr &incidence )
{
  if ( !incidence ) {
    return;
  }
  Alarm::List alarms = incidence->alarms();
  Alarm::List::Iterator it;
  for ( it = alarms.begin(); it != alarms.end(); ++it ) {
    Alarm::Ptr al = *it;
    if ( al && al->hasStartOffset() ) {
      Duration offsetDuration = al->startOffset();
      int offs = offsetDuration.asSeconds();
      if ( offs > 0 ) {
        offsetDuration = Duration( -offs );
      }
      al->setStartOffset( offsetDuration );
    }
  }
}
Beispiel #20
0
Incidence::List DndFactory::pasteIncidences( const KDateTime &newDateTime,
                                             const QFlags<PasteFlag> &pasteOptions )
{
  QClipboard *clipboard = QApplication::clipboard();
  Q_ASSERT( clipboard );
  MemoryCalendar::Ptr calendar( createDropCalendar( clipboard->mimeData() ) );
  Incidence::List list;

  if ( !calendar ) {
    kDebug() << "Can't parse clipboard";
    return list;
  }

  // All pasted incidences get new uids, must keep track of old uids,
  // so we can update child's parents
  QHash<QString, Incidence::Ptr> oldUidToNewInc;

  Incidence::List::ConstIterator it;
  const Incidence::List incidences = calendar->incidences();
  for ( it = incidences.constBegin();
        it != incidences.constEnd(); ++it ) {
    Incidence::Ptr incidence = d->pasteIncidence( *it, newDateTime, pasteOptions );
    if ( incidence ) {
      list.append( incidence );
      oldUidToNewInc[(*it)->uid()] = *it;
    }
  }

  // update relations
  for ( it = list.constBegin(); it != list.constEnd(); ++it ) {
    Incidence::Ptr incidence = *it;
    if ( oldUidToNewInc.contains( incidence->relatedTo() ) ) {
      Incidence::Ptr parentInc = oldUidToNewInc[incidence->relatedTo()];
      incidence->setRelatedTo( parentInc->uid() );
    } else {
      // not related to anything in the clipboard
      incidence->setRelatedTo( QString() );
    }
  }

  return list;
}
CallId Scheduler::acceptPublish( const IncidenceBase::Ptr &newIncBase,
                                 ScheduleMessage::Status status,
                                 iTIPMethod method )
{
  if ( newIncBase->type() == IncidenceBase::TypeFreeBusy ) {
    return acceptFreeBusy( newIncBase, method );
  }

  const CallId callId = ++d->mLatestCallId;

  ResultCode resultCode = ResultCodeSuccess;
  QString errorMessage;

  kDebug() << "status=" << Stringify::scheduleMessageStatus( status ); //krazy:exclude=kdebug

  bool emitResult = true;

  Incidence::Ptr newInc = newIncBase.staticCast<Incidence>() ;
  Incidence::Ptr calInc = d->mCalendar->incidence( newIncBase->uid() );
  switch ( status ) {
    case ScheduleMessage::Unknown:
    case ScheduleMessage::PublishNew:
    case ScheduleMessage::PublishUpdate:
      if ( calInc && newInc ) {
        if ( ( newInc->revision() > calInc->revision() ) ||
             ( newInc->revision() == calInc->revision() &&
               newInc->lastModified() > calInc->lastModified() ) ) {
          const QString oldUid = calInc->uid();

          if ( calInc->type() != newInc->type() ) {
            kError() << "assigning different incidence types";
            resultCode = ResultCodeDifferentIncidenceTypes;
            errorMessage = QLatin1String( "Cannot assign two different incidence types" );
          } else {
            IncidenceBase *ci = calInc.data();
            IncidenceBase *ni = newInc.data();
            *ci = *ni;
            calInc->setSchedulingID( newInc->uid(), oldUid );

            Akonadi::Item item = d->mCalendar->itemForIncidenceUid( calInc->uid() );
            item.setPayload<Incidence::Ptr>( calInc );

            if ( item.isValid() ) {
              const int changeId = d->mChanger->modifyIncidence( item );

              if ( changeId >= 0 ) {
                d->mCallIdByChangeId.insert( changeId, callId );
                emitResult = false; // will be emitted in the job result's slot.
              } else {
                resultCode = ResultCodeErrorUpdatingIncidence;
                errorMessage = QLatin1String( "Error while trying to update the incidence" );
              }
            } else {
              resultCode = ResultCodeIncidenceNotFound;
              errorMessage = QLatin1String( "Couldn't find incidence in calendar" );
            }
          }
        } else {
          resultCode = ResultCodeNewIncidenceTooOld;
          errorMessage = QLatin1String( "A newer existing incidence already exists" );
        }
      } else {
        resultCode = ResultCodeInvalidIncidence;
        errorMessage = QLatin1String( "Incidence is invalid" );
      }
      break;
    case ScheduleMessage::Obsolete:
      // Success
      break;
    default:
      resultCode = ResultCodeUnknownStatus;
      errorMessage = QLatin1String( "Unhandled ScheduleMessage status" );
      break;
  }

  if ( emitResult ) {
    deleteTransaction( newIncBase->uid() );
    // Delayed signal, the caller must know this CallId first.
    emitOperationFinished( callId, resultCode, errorMessage );
  }

  return callId;
}
int main( int argc, char **argv )
{
  KAboutData aboutData(
    "testrecurson", 0,
    ki18n( "Tests all dates from 2002 to 2010 to test if the event recurs on each individual date. "
           "This is meant to test the Recurrence::recursOn method for errors." ), "0.1" );
  KCmdLineArgs::init( argc, argv, &aboutData );

  KCmdLineOptions options;
  options.add( "verbose", ki18n( "Verbose output" ) );
  options.add( "+input", ki18n( "Name of input file" ) );
  options.add( "[+output]", ki18n( "optional name of output file for the recurrence dates" ) );
  KCmdLineArgs::addCmdLineOptions( options );

  KComponentData componentData( &aboutData );
  //QCoreApplication app( KCmdLineArgs::qtArgc(), KCmdLineArgs::qtArgv() );

  KCmdLineArgs *args = KCmdLineArgs::parsedArgs();

  if ( args->count() < 1 ) {
    args->usage( "Wrong number of arguments." );
  }

  QString input = args->arg( 0 );
//   kDebug() << "Input file:" << input;

  QTextStream *outstream;
  outstream = 0;
  QString fn( "" );
  if ( args->count() > 1 ) {
    fn = args->arg( 1 );
//     kDebug() << "We have a file name given:" << fn;
  }
  QFile outfile( fn );
  if ( !fn.isEmpty() && outfile.open( QIODevice::WriteOnly ) ) {
//     kDebug() << "Opened output file!!!";
    outstream = new QTextStream( &outfile );
  }

  MemoryCalendar::Ptr cal( new MemoryCalendar( KDateTime::UTC ) );

  FileStorage store( cal, input );
  if ( !store.load() ) return 1;
  QString tz = cal->nonKDECustomProperty( "X-LibKCal-Testsuite-OutTZ" );
  if ( !tz.isEmpty() ) {
    cal->setViewTimeZoneId( tz );
  }

  Incidence::List inc = cal->incidences();

  for ( Incidence::List::Iterator it = inc.begin(); it != inc.end(); ++it ) {
    Incidence::Ptr incidence = *it;

//     kDebug() << " ->" << incidence->summary() << "<-";

//     incidence->recurrence()->dump();

    QDate dt( 1996, 7, 1 );
    if ( outstream ) {
      // Output to file for testing purposes
      int nr = 0;
      while ( dt.year() <= 2020 && nr<=500 ) {
        if ( incidence->recursOn( dt, cal->viewTimeSpec() ) ) {
          (*outstream) << dt.toString( Qt::ISODate ) << endl;
          nr++;
        }
        dt = dt.addDays( 1 );
      }
    } else {
      dt = QDate( 2005, 1, 1 );
      while ( dt.year() < 2007 ) {
        if ( incidence->recursOn( dt, cal->viewTimeSpec() ) ) {
          kDebug() << dt.toString( Qt::ISODate );
        }
        dt = dt.addDays( 1 );
      }
    }
  }

  delete outstream;
  outfile.close();
  return 0;
}
Beispiel #23
0
void CompatPre410::setCreatedToDtStamp( const Incidence::Ptr &incidence, const KDateTime &dtstamp )
{
  if ( dtstamp.isValid() ) {
    incidence->setCreated( dtstamp );
  }
}
Beispiel #24
0
void CompatPre31::fixRecurrence( const Incidence::Ptr &incidence )
{
  CompatPre32::fixRecurrence( incidence );

  Recurrence *recur = incidence->recurrence();
  RecurrenceRule *r = 0;
  if ( recur ) {
    r = recur->defaultRRule();
  }
  if ( recur && r ) {
    int duration = r->duration();
    if ( duration > 0 ) {
      // Backwards compatibility for KDE < 3.1.
      // rDuration was set to the number of time periods to recur,
      // with week start always on a Monday.
      // Convert this to the number of occurrences.
      r->setDuration( -1 );
      QDate end( r->startDt().date() );
      bool doNothing = false;
      // # of periods:
      int tmp = ( duration - 1 ) * r->frequency();
      switch ( r->recurrenceType() ) {
      case RecurrenceRule::rWeekly:
      {
        end = end.addDays( tmp * 7 + 7 - end.dayOfWeek() );
        break;
      }
      case RecurrenceRule::rMonthly:
      {
        int month = end.month() - 1 + tmp;
        end.setDate( end.year() + month / 12, month % 12 + 1, 31 );
        break;
      }
      case RecurrenceRule::rYearly:
      {
        end.setDate( end.year() + tmp, 12, 31 );
        break;
      }
      default:
        doNothing = true;
        break;
      }
      if ( !doNothing ) {
        duration = r->durationTo(
          KDateTime( end, QTime( 0, 0, 0 ), incidence->dtStart().timeSpec() ) );
        r->setDuration( duration );
      }
    }

    /* addYearlyNum */
    // Dates were stored as day numbers, with a fiddle to take account of
    // leap years. Convert the day number to a month.
    QList<int> days = r->byYearDays();
    if ( !days.isEmpty() ) {
      QList<int> months = r->byMonths();
      for ( int i = 0; i < months.size(); ++i ) {
        int newmonth =
          QDate( r->startDt().date().year(), 1, 1 ).addDays( months.at( i ) - 1 ).month();
        if ( !months.contains( newmonth ) ) {
          months.append( newmonth );
        }
      }

      r->setByMonths( months );
      days.clear();
      r->setByYearDays( days );
    }
  }
}
void AlarmDialog::eventNotification()
{
  bool beeped = false;
  bool found = false;

  ReminderList list;

  QTreeWidgetItemIterator it( mIncidenceTree );
  while ( *it ) {
    ReminderListItem *item = static_cast<ReminderListItem *>( *it );
    ++it;
    if ( item->isDisabled() || item->mNotified ) {
      //skip suspended reminders or reminders that have been notified
      continue;
    }
    found = true;
    item->mNotified = true;
    Incidence::Ptr incidence = CalendarSupport::incidence( item->mIncidence );
    Alarm::List alarms = incidence->alarms();
    Alarm::List::ConstIterator ait;
    for ( ait = alarms.constBegin(); ait != alarms.constEnd(); ++ait ) {
      Alarm::Ptr alarm = *ait;
      // FIXME: Check whether this should be done for all multiple alarms
      if ( alarm->type() == Alarm::Procedure ) {
        // FIXME: Add a message box asking whether the procedure should really be executed
        kDebug() << "Starting program: '" << alarm->programFile() << "'";

        QString program = alarm->programFile();

        // if the program name contains spaces escape it
        if ( program.contains( ' ' )   &&
             !( program.startsWith( '\"' ) && program.endsWith( '\"' ) ) ) {
          program = '\"' + program + '\"';
        }

        QProcess::startDetached( program + ' ' + alarm->programArguments() );
      } else if ( alarm->type() == Alarm::Audio ) {
        beeped = true;
        Phonon::MediaObject *player =
          Phonon::createPlayer( Phonon::NotificationCategory, alarm->audioFile() );
        player->setParent( this );
        connect( player, SIGNAL(finished()), player, SLOT(deleteLater()) );
        player->play();
      } else if ( alarm->type() == Alarm::Email ) {
        QString from = CalendarSupport::KCalPrefs::instance()->email();
        Identity id = KOCore::self()->identityManager()->identityForAddress( from );
        QString to;
        if ( alarm->mailAddresses().isEmpty() ) {
          to = from;
        } else {
          const Person::List addresses = alarm->mailAddresses();
          QStringList add;
          for ( Person::List::ConstIterator it = addresses.constBegin();
                it != addresses.constEnd(); ++it ) {
            add << (*it)->fullName();
          }
          to = add.join( ", " );
        }

        QString subject;

        Akonadi::Item parentItem = mCalendar->itemForIncidenceUid( alarm->parentUid() );
        Incidence::Ptr parent = CalendarSupport::incidence( parentItem );

        if ( alarm->mailSubject().isEmpty() ) {
          if ( parent->summary().isEmpty() ) {
            subject = i18nc( "@title", "Reminder" );
          } else {
            subject = i18nc( "@title", "Reminder: %1", cleanSummary( parent->summary() ) );
          }
        } else {
          subject = i18nc( "@title", "Reminder: %1", alarm->mailSubject() );
        }

        QString body =
          IncidenceFormatter::mailBodyStr(
            parent.staticCast<IncidenceBase>(), KSystemTimeZones::local() );
        if ( !alarm->mailText().isEmpty() ) {
          body += '\n' + alarm->mailText();
        }
        //TODO: support attachments
        CalendarSupport::MailClient mailer;
        mailer.send( id, from, to, QString(), subject, body, true, false, QString(),
                     MailTransport::TransportManager::self()->defaultTransportName() );
      }
    }
  }

  if ( !beeped && found ) {
    KNotification::beep();
  }
}
int main( int argc, char **argv )
{
  KAboutData aboutData(
    "testrecurrencenew", 0,
    ki18n( "Load recurrence rules with the new class and print out debug messages" ), "0.1" );
  KCmdLineArgs::init( argc, argv, &aboutData );

  KCmdLineOptions options;
  options.add( "verbose", ki18n( "Verbose output" ) );
  options.add( "+input", ki18n( "Name of input file" ) );
  options.add( "[+output]", ki18n( "optional name of output file for the recurrence dates" ) );
  KCmdLineArgs::addCmdLineOptions( options );

  KComponentData componentData( &aboutData );
  //QCoreApplication app( KCmdLineArgs::qtArgc(), KCmdLineArgs::qtArgv() );

  KCmdLineArgs *args = KCmdLineArgs::parsedArgs();

  if ( args->count() < 1 ) {
    args->usage( "Wrong number of arguments." );
  }

  QString input = args->arg( 0 );
  kDebug() << "Input file:" << input;

  QTextStream *outstream;
  outstream = 0;
  QString fn( "" );
  if ( args->count() > 1 ) {
    fn = args->arg( 1 );
    kDebug() << "We have a file name given:" << fn;
  }
  QFile outfile( fn );
  if ( !fn.isEmpty() && outfile.open( QIODevice::WriteOnly ) ) {
    kDebug() << "Opened output file!!!";
    outstream = new QTextStream( &outfile );
  }

  MemoryCalendar::Ptr cal( new MemoryCalendar( KDateTime::UTC ) );

  KDateTime::Spec viewSpec;
  FileStorage store( cal, input );
  if ( !store.load() ) return 1;
  QString tz = cal->nonKDECustomProperty( "X-LibKCal-Testsuite-OutTZ" );
  if ( !tz.isEmpty() ) {
    viewSpec = KDateTime::Spec( KSystemTimeZones::zone( tz ) );
  }

  Incidence::List inc = cal->incidences();

  for ( Incidence::List::Iterator it = inc.begin(); it != inc.end(); ++it ) {
    Incidence::Ptr incidence = *it;
    kDebug() << "*+*+*+*+*+*+*+*+*+*";
    kDebug() << " ->" << incidence->summary() << "<-";

    incidence->recurrence()->dump();

    KDateTime dt( incidence->recurrence()->endDateTime() );
    int i = 0;
    if ( outstream ) {
      if ( !dt.isValid() ) {
        if ( viewSpec.isValid() ) {
          dt = KDateTime( QDate( 2011, 1, 1 ), QTime( 0, 0, 1 ), viewSpec );
        } else {
          dt = KDateTime( QDate( 2011, 1, 1 ), QTime( 0, 0, 1 ) );
        }
      } else {
        dt = dt.addYears( 2 );
      }
      kDebug() << "-------------------------------------------";
      kDebug() << " *~*~*~*~ Starting with date:" << dumpTime( dt, viewSpec );
      // Output to file for testing purposes
      while ( dt.isValid() && i < 500 ) {
        ++i;
        dt = incidence->recurrence()->getPreviousDateTime( dt );
        if ( dt.isValid() ) {
          (*outstream) << dumpTime( dt, viewSpec ) << endl;
        }
      }
    } else {
      if ( !dt.isValid() ) {
        dt = KDateTime( QDate( 2005, 7, 31 ), QTime( 23, 59, 59 ), KDateTime::Spec::UTC() );
      } else {
        dt = dt.addYears( 2 );
      }
      incidence->recurrence()->dump();
      kDebug() << "-------------------------------------------";
      kDebug() << " *~*~*~*~ Starting with date:" << dumpTime( dt, viewSpec );
      // Output to konsole
      while ( dt.isValid() && i < 50 ) {
        ++i;
        kDebug() << "-------------------------------------------";
        dt = incidence->recurrence()->getPreviousDateTime( dt );
        if ( dt.isValid() ) {
          kDebug() << " *~*~*~*~ Previous date is:" << dumpTime( dt, viewSpec );
        }
      }
    }
  }

  delete outstream;
  outfile.close();
  return 0;
}
Beispiel #27
0
bool CalFilter::filterIncidence( Incidence::Ptr incidence ) const
{
  if ( !d->mEnabled ) {
    return true;
  }

  Todo::Ptr todo = incidence.dynamicCast<Todo>();
  if ( todo ) {
    if ( ( d->mCriteria & HideCompletedTodos ) && todo->isCompleted() ) {
      // Check if completion date is suffently long ago:
      if ( todo->completed().addDays( d->mCompletedTimeSpan ) <
           KDateTime::currentUtcDateTime() ) {
        return false;
      }
    }

    if ( ( d->mCriteria & HideInactiveTodos ) &&
         ( ( todo->hasStartDate() &&
             KDateTime::currentUtcDateTime() < todo->dtStart() ) ||
           todo->isCompleted() ) ) {
      return false;
    }

    if ( d->mCriteria & HideNoMatchingAttendeeTodos ) {
      bool iAmOneOfTheAttendees = false;
      const Attendee::List &attendees = todo->attendees();
      if ( !todo->attendees().isEmpty() ) {
        Attendee::List::ConstIterator it;
        for ( it = attendees.begin(); it != attendees.end(); ++it ) {
          if ( d->mEmailList.contains( ( *it )->email() ) ) {
            iAmOneOfTheAttendees = true;
            break;
          }
        }
      } else {
        // no attendees, must be me only
        iAmOneOfTheAttendees = true;
      }
      if ( !iAmOneOfTheAttendees ) {
        return false;
      }
    }
  }

  if ( d->mCriteria & HideRecurring ) {
    if ( incidence->recurs() ) {
      return false;
    }
  }

  if ( d->mCriteria & ShowCategories ) {
    for ( QStringList::ConstIterator it = d->mCategoryList.constBegin();
          it != d->mCategoryList.constEnd(); ++it ) {
      QStringList incidenceCategories = incidence->categories();
      for ( QStringList::ConstIterator it2 = incidenceCategories.constBegin();
            it2 != incidenceCategories.constEnd(); ++it2 ) {
        if ( ( *it ) == ( *it2 ) ) {
          return true;
        }
      }
    }
    return false;
  } else {
    for ( QStringList::ConstIterator it = d->mCategoryList.constBegin();
          it != d->mCategoryList.constEnd(); ++it ) {
      QStringList incidenceCategories = incidence->categories();
      for ( QStringList::ConstIterator it2 = incidenceCategories.constBegin();
            it2 != incidenceCategories.constEnd(); ++it2 ) {
        if ( ( *it ) == ( *it2 ) ) {
          return false;
        }
      }
    }
    return true;
  }

  return true;
}
CallId Scheduler::acceptRequest( const IncidenceBase::Ptr &incidence,
                                 ScheduleMessage::Status status,
                                 const QString &email )
{
  Incidence::Ptr inc = incidence.staticCast<Incidence>() ;
  if ( !inc ) {
    kWarning() << "Accept what?";
    return -1;
  }

  const CallId callId = ++d->mLatestCallId;
  ResultCode resultCode = ResultCodeSuccess;
  QString errorMessage;

  if ( inc->type() == IncidenceBase::TypeFreeBusy ) {
    emitOperationFinished( callId, ResultCodeSuccess, QString() );
    // reply to this request is handled in korganizer's incomingdialog
    return callId;
  }

  const Incidence::List existingIncidences = d->mCalendar->incidencesFromSchedulingID( inc->uid() );
  kDebug() << "status=" << Stringify::scheduleMessageStatus( status ) //krazy:exclude=kdebug
           << ": found " << existingIncidences.count()
           << " incidences with schedulingID " << inc->schedulingID()
           << "; uid was = " << inc->uid();

  if ( existingIncidences.isEmpty() ) {
    // Perfectly normal if the incidence doesn't exist. This is probably
    // a new invitation.
    kDebug() << "incidence not found; calendar = " << d->mCalendar.data()
             << "; incidence count = " << d->mCalendar->incidences().count();
  }
  Incidence::List::ConstIterator incit = existingIncidences.begin();
  for ( ; incit != existingIncidences.end() ; ++incit ) {
    Incidence::Ptr existingIncidence = *incit;
    kDebug() << "Considering this found event ("
             << ( existingIncidence->isReadOnly() ? "readonly" : "readwrite" )
             << ") :" << d->mFormat->toString( existingIncidence );
    // If it's readonly, we can't possible update it.
    if ( existingIncidence->isReadOnly() ) {
      continue;
    }
    if ( existingIncidence->revision() <= inc->revision() ) {
      // The new incidence might be an update for the found one
      bool isUpdate = true;
      // Code for new invitations:
      // If you think we could check the value of "status" to be RequestNew:  we can't.
      // It comes from a similar check inside libical, where the event is compared to
      // other events in the calendar. But if we have another version of the event around
      // (e.g. shared folder for a group), the status could be RequestNew, Obsolete or Updated.
      kDebug() << "looking in " << existingIncidence->uid() << "'s attendees";
      // This is supposed to be a new request, not an update - however we want to update
      // the existing one to handle the "clicking more than once on the invitation" case.
      // So check the attendee status of the attendee.
      const Attendee::List attendees = existingIncidence->attendees();
      Attendee::List::ConstIterator ait;
      for ( ait = attendees.begin(); ait != attendees.end(); ++ait ) {
        if( (*ait)->email() == email && (*ait)->status() == Attendee::NeedsAction ) {
          // This incidence wasn't created by me - it's probably in a shared folder
          // and meant for someone else, ignore it.
          kDebug() << "ignoring "
                   << existingIncidence->uid() << " since I'm still NeedsAction there";
          isUpdate = false;
          break;
        }
      }
      if ( isUpdate ) {
        if ( existingIncidence->revision() == inc->revision() &&
             existingIncidence->lastModified() > inc->lastModified() ) {
          // This isn't an update - the found incidence was modified more recently
          deleteTransaction( existingIncidence->uid() );
          errorMessage = QLatin1String( "This isn't an update - "
                                        "the found incidence was modified more recently" );
          kDebug() << errorMessage;
          emitOperationFinished( callId, ResultCodeNotUpdate, errorMessage );

          return callId;
        }
        kDebug() << "replacing existing incidence " << existingIncidence->uid();

        bool emitResult = true;
        const QString oldUid = existingIncidence->uid();
        if ( existingIncidence->type() != inc->type() ) {
          errorMessage = QLatin1String( "Cannot assign two different incidence types" );
          resultCode = ResultCodeDifferentIncidenceTypes;
        } else {
          IncidenceBase *existingIncidenceBase = existingIncidence.data();
          IncidenceBase *incBase = inc.data();
          *existingIncidenceBase = *incBase;
          existingIncidence->setSchedulingID( inc->uid(), oldUid );

          Akonadi::Item item = d->mCalendar->itemForIncidenceUid( oldUid );
          item.setPayload<Incidence::Ptr>( existingIncidence );
          if ( item.isValid() ) {
            const int changeId = d->mChanger->modifyIncidence( item );

            if ( changeId >= 0 ) {
              d->mCallIdByChangeId.insert( changeId, callId );
              emitResult = false; // will be emitted in the job result's slot.
            } else {
              resultCode = ResultCodeErrorUpdatingIncidence;
              errorMessage = QLatin1String( "Error while trying to update the incidence" );
            }
          } else {
            resultCode = ResultCodeIncidenceNotFound;
            errorMessage = QLatin1String( "Couldn't find incidence in calendar" );
          }
        }

        if ( emitResult ) {
          deleteTransaction( incidence->uid() );
          emitOperationFinished( callId, resultCode, errorMessage );
        }
        return callId;
      }
    } else {
      // This isn't an update - the found incidence has a bigger revision number

      deleteTransaction( incidence->uid() );

      errorMessage = QLatin1String( "This isn't an update - "
                                    "the found incidence has a bigger revision number" );
      kDebug() << errorMessage;
      emitOperationFinished( callId, ResultCodeNotUpdate, errorMessage );

      return callId;
    }
  }

  // Move the uid to be the schedulingID and make a unique UID
  inc->setSchedulingID( inc->uid(), CalFormat::createUniqueId() );
  // notify the user in case this is an update and we didn't find the to-be-updated incidence
  if ( existingIncidences.count() == 0 && inc->revision() > 0 ) {
    KMessageBox::information(
      0,
      i18nc( "@info",
             "<para>You accepted an invitation update, but an earlier version of the "
             "item could not be found in your calendar.</para>"
             "<para>This may have occurred because:<list>"
             "<item>the organizer did not include you in the original invitation</item>"
             "<item>you did not accept the original invitation yet</item>"
             "<item>you deleted the original invitation from your calendar</item>"
             "<item>you no longer have access to the calendar containing the invitation</item>"
             "</list></para>"
             "<para>This is not a problem, but we thought you should know.</para>" ),
      i18nc( "@title", "Cannot find invitation to be updated" ), "AcceptCantFindIncidence" );
  }
  kDebug() << "Storing new incidence with scheduling uid=" << inc->schedulingID()
           << " and uid=" << inc->uid();
  const int changeId = d->mChanger->createIncidence( inc );

  if ( changeId > 0 ) {
    d->mCallIdByChangeId[changeId] = callId;
  } else {
    emitOperationFinished( callId, ResultCodeErrorCreatingIncidence,
                           QLatin1String( "Error creating incidence" ) );
  }

  return callId;
}
CallId Scheduler::acceptCancel( const IncidenceBase::Ptr &incidence,
                                ScheduleMessage::Status status,
                                const QString &attendee )
{
  Incidence::Ptr inc = incidence.staticCast<Incidence>();
  if ( !inc ) {
    return -1;
  }

  const CallId callId = ++d->mLatestCallId;
  ResultCode resultCode = ResultCodeSuccess;
  QString errorMessage;

  if ( inc->type() == IncidenceBase::TypeFreeBusy ) {
    // reply to this request is handled in korganizer's incomingdialog
    emitOperationFinished( callId, resultCode, errorMessage );
    return callId;
  }

  const Incidence::List existingIncidences = d->mCalendar->incidencesFromSchedulingID( inc->uid() );
  kDebug() << "Scheduler::acceptCancel="
           << Stringify::scheduleMessageStatus( status ) //krazy2:exclude=kdebug
           << ": found " << existingIncidences.count()
           << " incidences with schedulingID " << inc->schedulingID();

  Incidence::List::ConstIterator incit = existingIncidences.begin();
  for ( ; incit != existingIncidences.end() ; ++incit ) {
    Incidence::Ptr i = *incit;
    kDebug() << "Considering this found event ("
             << ( i->isReadOnly() ? "readonly" : "readwrite" )
             << ") :" << d->mFormat->toString( i );

    // If it's readonly, we can't possible remove it.
    if ( i->isReadOnly() ) {
      continue;
    }

    // Code for new invitations:
    // We cannot check the value of "status" to be RequestNew because
    // "status" comes from a similar check inside libical, where the event
    // is compared to other events in the calendar. But if we have another
    // version of the event around (e.g. shared folder for a group), the
    // status could be RequestNew, Obsolete or Updated.
    kDebug() << "looking in " << i->uid() << "'s attendees";

    // This is supposed to be a new request, not an update - however we want
    // to update the existing one to handle the "clicking more than once
    // on the invitation" case. So check the attendee status of the attendee.
    bool isMine = true;
    const Attendee::List attendees = i->attendees();
    Attendee::List::ConstIterator ait;
    for ( ait = attendees.begin(); ait != attendees.end(); ++ait ) {
      if ( (*ait)->email() == attendee &&
           (*ait)->status() == Attendee::NeedsAction ) {
        // This incidence wasn't created by me - it's probably in a shared
        // folder and meant for someone else, ignore it.
        kDebug() << "ignoring " << i->uid()
                 << " since I'm still NeedsAction there";
        isMine = false;
        break;
      }
    }

    if ( isMine ) {
      //TODO_SERGIO: use ItemDeleteJob and make this async.
      kDebug() << "removing existing incidence " << i->uid();

      Akonadi::Item item = d->mCalendar->itemForIncidenceUid( i->uid() );
      bool emitResult = true;
      if ( item.isValid() ) {
        const int changeId = d->mChanger->deleteIncidence( item );

        if ( changeId >= 0 ) {
          d->mCallIdByChangeId.insert( changeId, callId );
          d->mDeletedIncidenceByChangeId.insert( changeId, i );
          emitResult = false; // will be emitted in the job result's slot.
        } else {
          resultCode = ResultCodeErrorDeletingIncidence;
          errorMessage = QLatin1String( "Error while trying to delete the incidence" );
        }
      } else {
        resultCode = ResultCodeIncidenceNotFound;
        errorMessage = QLatin1String( "Couldn't find incidence in calendar" );
      }

      if ( emitResult ) {
        deleteTransaction( incidence->uid() );
        errorMessage = QLatin1String( "Error deleting incidence" );
        emitOperationFinished( callId, resultCode, errorMessage );
      }

      return callId;
    }
  }

  // in case we didn't find the to-be-removed incidence
  if ( existingIncidences.count() > 0 && inc->revision() > 0 ) {
    KMessageBox::error(
      0,
      i18nc( "@info",
             "The event or task could not be removed from your calendar. "
             "Maybe it has already been deleted or is not owned by you. "
             "Or it might belong to a read-only or disabled calendar." ) );
    resultCode = ResultCodeIncidenceNotFound;
    errorMessage = QLatin1String( "Incidence not found" );
  }
  deleteTransaction( incidence->uid() );
  emitOperationFinished( callId, resultCode, errorMessage );

  return callId;
}
CallId Scheduler::acceptReply( const IncidenceBase::Ptr &incidence,
                               ScheduleMessage::Status status,
                               iTIPMethod method )
{
  Q_UNUSED( status );
  if ( incidence->type() == IncidenceBase::TypeFreeBusy ) {
    return acceptFreeBusy( incidence, method );
  }

  const CallId callId = ++d->mLatestCallId;
  ResultCode resultCode = ResultCodeIncidenceOrAttendeeNotFound;
  QString errorMessage;

  Event::Ptr ev = d->mCalendar->event( incidence->uid() );
  Todo::Ptr to = d->mCalendar->todo( incidence->uid() );

  // try harder to find the correct incidence
  if ( !ev && !to ) {
    const Incidence::List list = d->mCalendar->incidences();
    for ( Incidence::List::ConstIterator it=list.constBegin(), end=list.constEnd();
          it != end; ++it ) {
      if ( (*it)->schedulingID() == incidence->uid() ) {
        ev =  ( *it ).dynamicCast<Event>();
        to = ( *it ).dynamicCast<Todo>();
        break;
      }
    }
  }

  if ( ev || to ) {
    //get matching attendee in calendar
    kDebug() << "match found!";
    Attendee::List attendeesIn = incidence->attendees();
    Attendee::List attendeesEv;
    Attendee::List attendeesNew;
    if ( ev ) {
      attendeesEv = ev->attendees();
    }
    if ( to ) {
      attendeesEv = to->attendees();
    }
    Attendee::List::ConstIterator inIt;
    Attendee::List::ConstIterator evIt;
    for ( inIt = attendeesIn.constBegin(); inIt != attendeesIn.constEnd(); ++inIt ) {
      Attendee::Ptr attIn = *inIt;
      bool found = false;
      for ( evIt = attendeesEv.constBegin(); evIt != attendeesEv.constEnd(); ++evIt ) {
        Attendee::Ptr attEv = *evIt;
        if ( attIn->email().toLower() == attEv->email().toLower() ) {
          //update attendee-info
          kDebug() << "update attendee";
          attEv->setStatus( attIn->status() );
          attEv->setDelegate( attIn->delegate() );
          attEv->setDelegator( attIn->delegator() );
          resultCode = ResultCodeSuccess;
          found = true;
        }
      }
      if ( !found && attIn->status() != Attendee::Declined ) {
        attendeesNew.append( attIn );
      }
    }

    bool attendeeAdded = false;
    for ( Attendee::List::ConstIterator it = attendeesNew.constBegin();
          it != attendeesNew.constEnd(); ++it ) {
      Attendee::Ptr attNew = *it;
      QString msg =
        i18nc( "@info", "%1 wants to attend %2 but was not invited.",
               attNew->fullName(),
               ( ev ? ev->summary() : to->summary() ) );
      if ( !attNew->delegator().isEmpty() ) {
        msg = i18nc( "@info", "%1 wants to attend %2 on behalf of %3.",
                     attNew->fullName(),
                     ( ev ? ev->summary() : to->summary() ), attNew->delegator() );
      }
      if ( KMessageBox::questionYesNo(
             0, msg, i18nc( "@title", "Uninvited attendee" ),
             KGuiItem( i18nc( "@option", "Accept Attendance" ) ),
             KGuiItem( i18nc( "@option", "Reject Attendance" ) ) ) != KMessageBox::Yes ) {
        Incidence::Ptr cancel = incidence.dynamicCast<Incidence>();
        if ( cancel ) {
          cancel->addComment(
            i18nc( "@info",
                   "The organizer rejected your attendance at this meeting." ) );
        }
        performTransaction( incidence, iTIPCancel, attNew->fullName() );
        // ### can't delete cancel here because it is aliased to incidence which
        // is accessed in the next loop iteration (CID 4232)
        // delete cancel;
        continue;
      }

      Attendee::Ptr a( new Attendee( attNew->name(), attNew->email(), attNew->RSVP(),
                                     attNew->status(), attNew->role(), attNew->uid() ) );

      a->setDelegate( attNew->delegate() );
      a->setDelegator( attNew->delegator() );
      if ( ev ) {
        ev->addAttendee( a );
      } else if ( to ) {
        to->addAttendee( a );
      }
      resultCode = ResultCodeSuccess;
      attendeeAdded = true;
    }

    // send update about new participants
    if ( attendeeAdded ) {
      bool sendMail = false;
      if ( ev || to ) {
        if ( KMessageBox::questionYesNo(
               0,
               i18nc( "@info",
                      "An attendee was added to the incidence. "
                      "Do you want to email the attendees an update message?" ),
               i18nc( "@title", "Attendee Added" ),
               KGuiItem( i18nc( "@option", "Send Messages" ) ),
               KGuiItem( i18nc( "@option", "Do Not Send" ) ) ) == KMessageBox::Yes ) {
          sendMail = true;
        }
      }

      if ( ev ) {
        ev->setRevision( ev->revision() + 1 );
        if ( sendMail ) {
          performTransaction( ev, iTIPRequest );
        }
      }
      if ( to ) {
        to->setRevision( to->revision() + 1 );
        if ( sendMail ) {
          performTransaction( to, iTIPRequest );
        }
      }
    }

    if ( resultCode == ResultCodeSuccess ) {
      // We set at least one of the attendees, so the incidence changed
      // Note: This should not result in a sequence number bump
      if ( ev ) {
        ev->updated();
      } else if ( to ) {
        to->updated();
      }
    }
    if ( to ) {
      // for VTODO a REPLY can be used to update the completion status of
      // a to-do. see RFC2446 3.4.3
      Todo::Ptr update = incidence.dynamicCast<Todo>();
      Q_ASSERT( update );
      if ( update && ( to->percentComplete() != update->percentComplete() ) ) {
        to->setPercentComplete( update->percentComplete() );
        to->updated();
      }
    }
  } else {
    kError() << "No incidence for scheduling.";
  }

  if ( resultCode == ResultCodeSuccess ) {
    deleteTransaction( incidence->uid() );
  }

  emitOperationFinished( callId, resultCode, errorMessage );

  return callId;
}