/* * adcalendar.cpp - calendar file access * Program: KAlarm's alarm daemon (kalarmd) * Copyright (c) 2001, 2004-2006 by David Jarvie * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include "adcalendar.moc" TQValueList ADCalendar::mCalendars; ADCalendar::EventsMap ADCalendar::mEventsHandled; ADCalendar::EventsMap ADCalendar::mEventsPending; TQStringList ADCalendar::mCalendarUrls; // never delete or reorder anything in this list! ADCalendar::ADCalendar(const TQString& url, const TQCString& appname) : KCal::CalendarLocal(TQString::fromLatin1("UTC")), mUrlString(url), mAppName(appname), mLoaded(false), mLoadedConnected(false), mUnregistered(false), mEnabled(true) { ADCalendar* cal = getCalendar(url); if (cal) { kdError(5900) << "ADCalendar::ADCalendar(" << url << "): calendar already exists" << endl; assert(0); } mUrlIndex = mCalendarUrls.findIndex(url); // get unique index for this URL if (mUrlIndex < 0) { mUrlIndex = static_cast(mCalendarUrls.count()); mCalendarUrls.append(url); } loadFile(false); mCalendars.append(this); } ADCalendar::~ADCalendar() { clearEventsHandled(); mCalendars.remove(this); } /****************************************************************************** * Load the calendar file. */ bool ADCalendar::loadFile(bool reset) { if (reset) clearEventsHandled(); if (!mTempFileName.isNull()) { // Don't try to load the file if already downloading it kdError(5900) << "ADCalendar::loadFile(): already downloading another file\n"; return false; } mLoaded = false; KURL url(mUrlString); if (url.isLocalFile()) { // It's a local file loadLocalFile(url.path()); emit loaded(this, mLoaded); } else { // It's a remote file. Download to a temporary file before loading it KTempFile tempFile; mTempFileName = tempFile.name(); KURL dest; dest.setPath(mTempFileName); TDEIO::FileCopyJob* job = TDEIO::file_copy(url, dest, -1, true); connect(job, TQT_SIGNAL(result(TDEIO::Job*)), TQT_SLOT(slotDownloadJobResult(TDEIO::Job*))); } return true; } void ADCalendar::slotDownloadJobResult(TDEIO::Job *job) { if (job->error()) { KURL url(mUrlString); kdDebug(5900) << "Error downloading calendar from " << url.prettyURL() << endl; job->showErrorDialog(0); } else { kdDebug(5900) << "--- Downloaded to " << mTempFileName << endl; loadLocalFile(mTempFileName); } unlink(TQFile::encodeName(mTempFileName)); mTempFileName = TQString(); emit loaded(this, mLoaded); } void ADCalendar::loadLocalFile(const TQString& filename) { mLoaded = load(filename); if (!mLoaded) kdDebug(5900) << "ADCalendar::loadLocalFile(): Error loading calendar file '" << filename << "'\n"; else clearEventsHandled(true); // remove all events which no longer exist from handled list } bool ADCalendar::setLoadedConnected() { if (mLoadedConnected) return true; mLoadedConnected = true; return false; } /****************************************************************************** * Check whether all the alarms for the event with the given ID have already * been handled. */ bool ADCalendar::eventHandled(const KCal::Event* event, const TQValueList& alarmtimes) { EventsMap::ConstIterator it = mEventsHandled.find(EventKey(event->uid(), mUrlIndex)); if (it == mEventsHandled.end()) return false; int oldCount = it.data().alarmTimes.count(); int count = alarmtimes.count(); for (int i = 0; i < count; ++i) { if (alarmtimes[i].isValid() && (i >= oldCount // is it an additional alarm? || !it.data().alarmTimes[i].isValid() // or has it just become due? || (it.data().alarmTimes[i].isValid() // or has it changed? && alarmtimes[i] != it.data().alarmTimes[i]))) return false; // this alarm has changed } return true; } /****************************************************************************** * Remember that the event with the given ID has been handled. * It must already be in the pending list. */ void ADCalendar::setEventHandled(const TQString& eventID) { kdDebug(5900) << "ADCalendar::setEventHandled(" << eventID << ")\n"; EventKey key(eventID, mUrlIndex); // Remove it from the pending list, and add it to the handled list EventsMap::Iterator it = mEventsPending.find(key); if (it != mEventsPending.end()) { setEventInMap(mEventsHandled, key, it.data().alarmTimes, it.data().eventSequence); mEventsPending.remove(it); } } /****************************************************************************** * Remember that the specified alarms for the event with the given ID have been * notified to KAlarm, but no reply has come back yet. */ void ADCalendar::setEventPending(const KCal::Event* event, const TQValueList& alarmtimes) { if (event) { kdDebug(5900) << "ADCalendar::setEventPending(" << event->uid() << ")\n"; EventKey key(event->uid(), mUrlIndex); setEventInMap(mEventsPending, key, alarmtimes, event->revision()); } } /****************************************************************************** * Add a specified entry to the events pending or handled list. */ void ADCalendar::setEventInMap(EventsMap& map, const EventKey& key, const TQValueList& alarmtimes, int sequence) { EventsMap::Iterator it = map.find(key); if (it != map.end()) { // Update the existing entry for the event it.data().alarmTimes = alarmtimes; it.data().eventSequence = sequence; } else map.insert(key, EventItem(sequence, alarmtimes)); } /****************************************************************************** * Clear all memory of events handled for the calendar. */ void ADCalendar::clearEventsHandled(bool nonexistentOnly) { clearEventMap(mEventsPending, nonexistentOnly); clearEventMap(mEventsHandled, nonexistentOnly); } /****************************************************************************** * Clear the events pending or handled list of all events handled for the calendar. */ void ADCalendar::clearEventMap(EventsMap& map, bool nonexistentOnly) { for (EventsMap::Iterator it = map.begin(); it != map.end(); ) { if (it.key().calendarIndex == mUrlIndex && (!nonexistentOnly || !event(it.key().eventID))) { EventsMap::Iterator i = it; ++it; // prevent iterator becoming invalid with remove() map.remove(i); } else ++it; } } /****************************************************************************** * Look up the calendar with the specified full calendar URL. */ ADCalendar* ADCalendar::getCalendar(const TQString& calendarURL) { if (!calendarURL.isEmpty()) { for (ConstIterator it = begin(); it != end(); ++it) { if ((*it)->urlString() == calendarURL) return *it; } } return 0; }