author | kergoth <kergoth> | 2002-01-25 22:14:26 (UTC) |
---|---|---|
committer | kergoth <kergoth> | 2002-01-25 22:14:26 (UTC) |
commit | 15318cad33835e4e2dc620d033e43cd930676cdd (patch) (side-by-side diff) | |
tree | c2fa0399a2c47fda8e2cd0092c73a809d17f68eb /library/alarmserver.cpp | |
download | opie-15318cad33835e4e2dc620d033e43cd930676cdd.zip opie-15318cad33835e4e2dc620d033e43cd930676cdd.tar.gz opie-15318cad33835e4e2dc620d033e43cd930676cdd.tar.bz2 |
Initial revision
-rw-r--r-- | library/alarmserver.cpp | 376 |
1 files changed, 376 insertions, 0 deletions
diff --git a/library/alarmserver.cpp b/library/alarmserver.cpp new file mode 100644 index 0000000..a1a7142 --- a/dev/null +++ b/library/alarmserver.cpp @@ -0,0 +1,376 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qtopia Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include <qdir.h> +#include <qfile.h> +#include <qmessagebox.h> +#include <qtextstream.h> + + +#include "qpeapplication.h" +#include "global.h" +#include "resource.h" + +#if defined(Q_WS_QWS) && !defined(QT_NO_COP) +#include "qcopenvelope_qws.h" +#endif +#include "alarmserver.h" +#include <qpe/timeconversion.h> + +#include <sys/types.h> +#include <sys/stat.h> + +#include <stdlib.h> +#include <unistd.h> + +struct timerEventItem { + time_t UTCtime; + QCString channel, message; + int data; + bool operator==( const timerEventItem &right ) const + { + return ( UTCtime == right.UTCtime + && channel == right.channel + && message == right.message + && data == right.data ); + } +}; + +class TimerReceiverObject : public QObject +{ +public: + TimerReceiverObject() { } + ~TimerReceiverObject() { } + void resetTimer(); + void setTimerEventItem(); + void deleteTimer(); +protected: + void timerEvent( QTimerEvent *te ); +private: + QString atfilename; +}; + +TimerReceiverObject *timerEventReceiver = NULL; +QList<timerEventItem> timerEventList; +timerEventItem *nearestTimerEvent = NULL; + + +// set the timer to go off on the next event in the list +void setNearestTimerEvent() +{ + nearestTimerEvent = NULL; + QListIterator<timerEventItem> it( timerEventList ); + if ( *it ) + nearestTimerEvent = *it; + for ( ; *it; ++it ) + if ( (*it)->UTCtime < nearestTimerEvent->UTCtime ) + nearestTimerEvent = *it; + if (nearestTimerEvent) + timerEventReceiver->resetTimer(); + else + timerEventReceiver->deleteTimer(); +} + + +//store current state to file +//Simple implementation. Should run on a timer. + +static void saveState() +{ + QString savefilename = Global::applicationFileName( "AlarmServer", "saveFile" ); + if ( timerEventList.isEmpty() ) { + unlink( savefilename ); + return; + } + + QFile savefile(savefilename+".new"); + if ( savefile.open(IO_WriteOnly) ) { + QDataStream ds( &savefile ); + + //save + + QListIterator<timerEventItem> it( timerEventList ); + for ( ; *it; ++it ) { + ds << it.current()->UTCtime; + ds << it.current()->channel; + ds << it.current()->message; + ds << it.current()->data; + } + + + savefile.close(); + unlink( savefilename ); + QDir d; d.rename(savefilename+".new",savefilename); + + } +} + +/*! + Sets up the alarm server. Restoring to previous state (session management). + */ +void AlarmServer::initialize() +{ + //read autosave file and put events in timerEventList + + QString savefilename = Global::applicationFileName( "AlarmServer", "saveFile" ); + + QFile savefile(savefilename); + if ( savefile.open(IO_ReadOnly) ) { + QDataStream ds( &savefile ); + while ( !ds.atEnd() ) { + timerEventItem *newTimerEventItem = new timerEventItem; + ds >> newTimerEventItem->UTCtime; + ds >> newTimerEventItem->channel; + ds >> newTimerEventItem->message; + ds >> newTimerEventItem->data; + timerEventList.append( newTimerEventItem ); + } + savefile.close(); + if (!timerEventReceiver) + timerEventReceiver = new TimerReceiverObject; + setNearestTimerEvent(); + } +} + + + + +static const char* atdir = "/var/spool/at/"; + +static bool triggerAtd( bool writeHWClock = FALSE ) +{ + QFile trigger(QString(atdir) + "trigger"); + if ( trigger.open(IO_WriteOnly|IO_Raw) ) { + + const char* data = +#ifdef QT_QWS_CUSTOM + //custom atd only writes HW Clock if we write a 'W' + ( writeHWClock ) ? "W\n" : +#endif + data = "\n"; + int len = strlen(data); + int total_written = trigger.writeBlock(data,len); + if ( total_written != len ) { + QMessageBox::critical( 0, QObject::tr( "Out of Space" ), + QObject::tr( "Unable to schedule alarm.\nFree some memory and try again." ) ); + trigger.close(); + QFile::remove( trigger.name() ); + return FALSE; + } + return TRUE; + } + return FALSE; +} + +void TimerReceiverObject::deleteTimer() +{ + if ( !atfilename.isEmpty() ) { + unlink( atfilename ); + atfilename = QString::null; + triggerAtd( FALSE ); + } +} + +void TimerReceiverObject::resetTimer() +{ + const int maxsecs = 2147000; + int total_written; + QDateTime nearest = TimeConversion::fromUTC(nearestTimerEvent->UTCtime); + QDateTime now = QDateTime::currentDateTime(); + int secs = TimeConversion::secsTo( now, nearest ); + if ( secs > maxsecs ) { + // too far for millisecond timing + secs = maxsecs; + } + + // System timer (needed so that we wake from deep sleep), + // from the Epoch in seconds. + // + int at_secs = TimeConversion::toUTC(nearest); + // qDebug("reset timer to %d seconds from Epoch",at_secs); + QString fn = atdir + QString::number(at_secs) + "." + + QString::number(getpid()); + if ( fn != atfilename ) { + QFile atfile(fn+".new"); + if ( atfile.open(IO_WriteOnly|IO_Raw) ) { + // just wake up and delete the at file + QString cmd = "#!/bin/sh\nrm " + fn; + total_written = atfile.writeBlock(cmd.latin1(),cmd.length()); + if ( total_written != int(cmd.length()) ) { + QMessageBox::critical( 0, tr("Out of Space"), + tr("Unable to schedule alarm.\n" + "Please free up space and try again") ); + atfile.close(); + QFile::remove( atfile.name() ); + return; + } + atfile.close(); + unlink( atfilename ); + QDir d; d.rename(fn+".new",fn); + chmod(fn.latin1(),0755); + atfilename = fn; + triggerAtd( FALSE ); + } else { + qWarning("Cannot open atd file %s",fn.latin1()); + } + } + // Qt timers (does the actual alarm) + // from now in milliseconds + // + qDebug("AlarmServer waiting %d seconds",secs); + startTimer( 1000 * secs + 500 ); +} + +void TimerReceiverObject::timerEvent( QTimerEvent * ) +{ + bool needSave = FALSE; + killTimers(); + if (nearestTimerEvent) { + if ( nearestTimerEvent->UTCtime + <= TimeConversion::toUTC(QDateTime::currentDateTime()) ) { + QCopEnvelope e( nearestTimerEvent->channel, + nearestTimerEvent->message ); + e << TimeConversion::fromUTC( nearestTimerEvent->UTCtime ) + << nearestTimerEvent->data; + timerEventList.remove( nearestTimerEvent ); + needSave = TRUE; + } + setNearestTimerEvent(); + } else { + resetTimer(); + } + if ( needSave ) + saveState(); +} + +/*! + \class AlarmServer alarmserver.h + \brief The AlarmServer class provides alarms to be scheduled. + + Applications which wish to be informed when a certain time instant + passes use the functions of AlarmServer to request so. +*/ + +/*! + Schedules an alarm for \a when. Soon after this time, + \a message will be sent to \a channel, with \a data as + a parameter. \a message must be of the form "someMessage(int)". + + \sa deleteAlarm() +*/ +void AlarmServer::addAlarm ( QDateTime when, const QCString& channel, + const QCString& message, int data) +{ + if ( qApp->type() == QApplication::GuiServer ) { + bool needSave = FALSE; + // Here we are the server so either it has been directly called from + // within the server or it has been sent to us from a client via QCop + if (!timerEventReceiver) + timerEventReceiver = new TimerReceiverObject; + + timerEventItem *newTimerEventItem = new timerEventItem; + newTimerEventItem->UTCtime = TimeConversion::toUTC( when ); + newTimerEventItem->channel = channel; + newTimerEventItem->message = message; + newTimerEventItem->data = data; + // explore the case of already having the event in here... + QListIterator<timerEventItem> it( timerEventList ); + for ( ; *it; ++it ) + if ( *(*it) == *newTimerEventItem ) + return; + // if we made it here, it is okay to add the item... + timerEventList.append( newTimerEventItem ); + needSave = TRUE; + // quicker than using setNearestTimerEvent() + if ( nearestTimerEvent ) { + if (newTimerEventItem->UTCtime < nearestTimerEvent->UTCtime) { + nearestTimerEvent = newTimerEventItem; + timerEventReceiver->killTimers(); + timerEventReceiver->resetTimer(); + } + } else { + nearestTimerEvent = newTimerEventItem; + timerEventReceiver->resetTimer(); + } + if ( needSave ) + saveState(); + } else { + QCopEnvelope e( "QPE/System", "addAlarm(QDateTime,QCString,QCString,int)" ); + e << when << channel << message << data; + } +} + +/*! + Deletes previously scheduled alarms which match \a when, \a channel, \a message, + and \a data. + + Passing null values for \a when, \a channel, or \a message indicates "any". + Passing -1 for \a data indicates "any". + + \sa deleteAlarm() +*/ +void AlarmServer::deleteAlarm (QDateTime when, const QCString& channel, const QCString& message, int data) +{ + if ( qApp->type() == QApplication::GuiServer) { + bool needSave = FALSE; + if ( timerEventReceiver != NULL ) { + timerEventReceiver->killTimers(); + + // iterate over the list of events + QListIterator<timerEventItem> it( timerEventList ); + time_t deleteTime = TimeConversion::toUTC( when ); + for ( ; *it; ++it ) { + // if its a match, delete it + if ( ( (*it)->UTCtime == deleteTime || when.isNull() ) + && ( channel.isNull() || (*it)->channel == channel ) + && ( message.isNull() || (*it)->message == message ) + && ( data==-1 || (*it)->data == data ) ) + { + // if it's first, then we need to update the timer + if ( (*it) == nearestTimerEvent ) { + timerEventList.remove(*it); + setNearestTimerEvent(); + } else { + timerEventList.remove(*it); + } + needSave = TRUE; + } + } + if ( nearestTimerEvent ) + timerEventReceiver->resetTimer(); + } + if ( needSave ) + saveState(); + } else { + QCopEnvelope e( "QPE/System", "deleteAlarm(QDateTime,QCString,QCString,int)" ); + e << when << channel << message << data; + } +} + +/*! + Writes the system clock to the hardware clock. +*/ +void Global::writeHWClock() +{ + if ( !triggerAtd( TRUE ) ) { + // atd not running? set it ourselves + system("/sbin/hwclock --systohc"); // ##### UTC? + } +} |