summaryrefslogtreecommitdiff
path: root/library/alarmserver.cpp
Side-by-side diff
Diffstat (limited to 'library/alarmserver.cpp') (more/less context) (show whitespace changes)
-rw-r--r--library/alarmserver.cpp376
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?
+ }
+}