summaryrefslogtreecommitdiff
path: root/library/alarmserver.cpp
authorkergoth <kergoth>2002-01-25 22:14:26 (UTC)
committer kergoth <kergoth>2002-01-25 22:14:26 (UTC)
commit15318cad33835e4e2dc620d033e43cd930676cdd (patch) (unidiff)
treec2fa0399a2c47fda8e2cd0092c73a809d17f68eb /library/alarmserver.cpp
downloadopie-15318cad33835e4e2dc620d033e43cd930676cdd.zip
opie-15318cad33835e4e2dc620d033e43cd930676cdd.tar.gz
opie-15318cad33835e4e2dc620d033e43cd930676cdd.tar.bz2
Initial revision
Diffstat (limited to 'library/alarmserver.cpp') (more/less context) (ignore 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 @@
1/**********************************************************************
2** Copyright (C) 2000 Trolltech AS. All rights reserved.
3**
4** This file is part of Qtopia Environment.
5**
6** This file may be distributed and/or modified under the terms of the
7** GNU General Public License version 2 as published by the Free Software
8** Foundation and appearing in the file LICENSE.GPL included in the
9** packaging of this file.
10**
11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
12** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13**
14** See http://www.trolltech.com/gpl/ for GPL licensing information.
15**
16** Contact info@trolltech.com if any conditions of this licensing are
17** not clear to you.
18**
19**********************************************************************/
20
21#include <qdir.h>
22#include <qfile.h>
23#include <qmessagebox.h>
24#include <qtextstream.h>
25
26
27#include "qpeapplication.h"
28#include "global.h"
29#include "resource.h"
30
31#if defined(Q_WS_QWS) && !defined(QT_NO_COP)
32#include "qcopenvelope_qws.h"
33#endif
34#include "alarmserver.h"
35#include <qpe/timeconversion.h>
36
37#include <sys/types.h>
38#include <sys/stat.h>
39
40#include <stdlib.h>
41#include <unistd.h>
42
43struct timerEventItem {
44 time_t UTCtime;
45 QCString channel, message;
46 int data;
47 bool operator==( const timerEventItem &right ) const
48 {
49 return ( UTCtime == right.UTCtime
50 && channel == right.channel
51 && message == right.message
52 && data == right.data );
53 }
54};
55
56class TimerReceiverObject : public QObject
57{
58public:
59 TimerReceiverObject() { }
60 ~TimerReceiverObject() { }
61 void resetTimer();
62 void setTimerEventItem();
63 void deleteTimer();
64protected:
65 void timerEvent( QTimerEvent *te );
66private:
67 QString atfilename;
68};
69
70TimerReceiverObject *timerEventReceiver = NULL;
71QList<timerEventItem> timerEventList;
72timerEventItem *nearestTimerEvent = NULL;
73
74
75// set the timer to go off on the next event in the list
76void setNearestTimerEvent()
77{
78 nearestTimerEvent = NULL;
79 QListIterator<timerEventItem> it( timerEventList );
80 if ( *it )
81 nearestTimerEvent = *it;
82 for ( ; *it; ++it )
83 if ( (*it)->UTCtime < nearestTimerEvent->UTCtime )
84 nearestTimerEvent = *it;
85 if (nearestTimerEvent)
86 timerEventReceiver->resetTimer();
87 else
88 timerEventReceiver->deleteTimer();
89}
90
91
92//store current state to file
93//Simple implementation. Should run on a timer.
94
95static void saveState()
96{
97 QString savefilename = Global::applicationFileName( "AlarmServer", "saveFile" );
98 if ( timerEventList.isEmpty() ) {
99 unlink( savefilename );
100 return;
101 }
102
103 QFile savefile(savefilename+".new");
104 if ( savefile.open(IO_WriteOnly) ) {
105 QDataStream ds( &savefile );
106
107 //save
108
109 QListIterator<timerEventItem> it( timerEventList );
110 for ( ; *it; ++it ) {
111 ds << it.current()->UTCtime;
112 ds << it.current()->channel;
113 ds << it.current()->message;
114 ds << it.current()->data;
115 }
116
117
118 savefile.close();
119 unlink( savefilename );
120 QDir d; d.rename(savefilename+".new",savefilename);
121
122 }
123}
124
125/*!
126 Sets up the alarm server. Restoring to previous state (session management).
127 */
128void AlarmServer::initialize()
129{
130 //read autosave file and put events in timerEventList
131
132 QString savefilename = Global::applicationFileName( "AlarmServer", "saveFile" );
133
134 QFile savefile(savefilename);
135 if ( savefile.open(IO_ReadOnly) ) {
136 QDataStream ds( &savefile );
137 while ( !ds.atEnd() ) {
138 timerEventItem *newTimerEventItem = new timerEventItem;
139 ds >> newTimerEventItem->UTCtime;
140 ds >> newTimerEventItem->channel;
141 ds >> newTimerEventItem->message;
142 ds >> newTimerEventItem->data;
143 timerEventList.append( newTimerEventItem );
144 }
145 savefile.close();
146 if (!timerEventReceiver)
147 timerEventReceiver = new TimerReceiverObject;
148 setNearestTimerEvent();
149 }
150}
151
152
153
154
155static const char* atdir = "/var/spool/at/";
156
157static bool triggerAtd( bool writeHWClock = FALSE )
158{
159 QFile trigger(QString(atdir) + "trigger");
160 if ( trigger.open(IO_WriteOnly|IO_Raw) ) {
161
162 const char* data =
163#ifdef QT_QWS_CUSTOM
164 //custom atd only writes HW Clock if we write a 'W'
165 ( writeHWClock ) ? "W\n" :
166#endif
167 data = "\n";
168 int len = strlen(data);
169 int total_written = trigger.writeBlock(data,len);
170 if ( total_written != len ) {
171 QMessageBox::critical( 0, QObject::tr( "Out of Space" ),
172 QObject::tr( "Unable to schedule alarm.\nFree some memory and try again." ) );
173 trigger.close();
174 QFile::remove( trigger.name() );
175 return FALSE;
176 }
177 return TRUE;
178 }
179 return FALSE;
180}
181
182void TimerReceiverObject::deleteTimer()
183{
184 if ( !atfilename.isEmpty() ) {
185 unlink( atfilename );
186 atfilename = QString::null;
187 triggerAtd( FALSE );
188 }
189}
190
191void TimerReceiverObject::resetTimer()
192{
193 const int maxsecs = 2147000;
194 int total_written;
195 QDateTime nearest = TimeConversion::fromUTC(nearestTimerEvent->UTCtime);
196 QDateTime now = QDateTime::currentDateTime();
197 int secs = TimeConversion::secsTo( now, nearest );
198 if ( secs > maxsecs ) {
199 // too far for millisecond timing
200 secs = maxsecs;
201 }
202
203 // System timer (needed so that we wake from deep sleep),
204 // from the Epoch in seconds.
205 //
206 int at_secs = TimeConversion::toUTC(nearest);
207 // qDebug("reset timer to %d seconds from Epoch",at_secs);
208 QString fn = atdir + QString::number(at_secs) + "."
209 + QString::number(getpid());
210 if ( fn != atfilename ) {
211 QFile atfile(fn+".new");
212 if ( atfile.open(IO_WriteOnly|IO_Raw) ) {
213 // just wake up and delete the at file
214 QString cmd = "#!/bin/sh\nrm " + fn;
215 total_written = atfile.writeBlock(cmd.latin1(),cmd.length());
216 if ( total_written != int(cmd.length()) ) {
217 QMessageBox::critical( 0, tr("Out of Space"),
218 tr("Unable to schedule alarm.\n"
219 "Please free up space and try again") );
220 atfile.close();
221 QFile::remove( atfile.name() );
222 return;
223 }
224 atfile.close();
225 unlink( atfilename );
226 QDir d; d.rename(fn+".new",fn);
227 chmod(fn.latin1(),0755);
228 atfilename = fn;
229 triggerAtd( FALSE );
230 } else {
231 qWarning("Cannot open atd file %s",fn.latin1());
232 }
233 }
234 // Qt timers (does the actual alarm)
235 // from now in milliseconds
236 //
237 qDebug("AlarmServer waiting %d seconds",secs);
238 startTimer( 1000 * secs + 500 );
239}
240
241void TimerReceiverObject::timerEvent( QTimerEvent * )
242{
243 bool needSave = FALSE;
244 killTimers();
245 if (nearestTimerEvent) {
246 if ( nearestTimerEvent->UTCtime
247 <= TimeConversion::toUTC(QDateTime::currentDateTime()) ) {
248 QCopEnvelope e( nearestTimerEvent->channel,
249 nearestTimerEvent->message );
250 e << TimeConversion::fromUTC( nearestTimerEvent->UTCtime )
251 << nearestTimerEvent->data;
252 timerEventList.remove( nearestTimerEvent );
253 needSave = TRUE;
254 }
255 setNearestTimerEvent();
256 } else {
257 resetTimer();
258 }
259 if ( needSave )
260 saveState();
261}
262
263/*!
264 \class AlarmServer alarmserver.h
265 \brief The AlarmServer class provides alarms to be scheduled.
266
267 Applications which wish to be informed when a certain time instant
268 passes use the functions of AlarmServer to request so.
269*/
270
271/*!
272 Schedules an alarm for \a when. Soon after this time,
273 \a message will be sent to \a channel, with \a data as
274 a parameter. \a message must be of the form "someMessage(int)".
275
276 \sa deleteAlarm()
277*/
278void AlarmServer::addAlarm ( QDateTime when, const QCString& channel,
279 const QCString& message, int data)
280{
281 if ( qApp->type() == QApplication::GuiServer ) {
282 bool needSave = FALSE;
283 // Here we are the server so either it has been directly called from
284 // within the server or it has been sent to us from a client via QCop
285 if (!timerEventReceiver)
286 timerEventReceiver = new TimerReceiverObject;
287
288 timerEventItem *newTimerEventItem = new timerEventItem;
289 newTimerEventItem->UTCtime = TimeConversion::toUTC( when );
290 newTimerEventItem->channel = channel;
291 newTimerEventItem->message = message;
292 newTimerEventItem->data = data;
293 // explore the case of already having the event in here...
294 QListIterator<timerEventItem> it( timerEventList );
295 for ( ; *it; ++it )
296 if ( *(*it) == *newTimerEventItem )
297 return;
298 // if we made it here, it is okay to add the item...
299 timerEventList.append( newTimerEventItem );
300 needSave = TRUE;
301 // quicker than using setNearestTimerEvent()
302 if ( nearestTimerEvent ) {
303 if (newTimerEventItem->UTCtime < nearestTimerEvent->UTCtime) {
304 nearestTimerEvent = newTimerEventItem;
305 timerEventReceiver->killTimers();
306 timerEventReceiver->resetTimer();
307 }
308 } else {
309 nearestTimerEvent = newTimerEventItem;
310 timerEventReceiver->resetTimer();
311 }
312 if ( needSave )
313 saveState();
314 } else {
315 QCopEnvelope e( "QPE/System", "addAlarm(QDateTime,QCString,QCString,int)" );
316 e << when << channel << message << data;
317 }
318}
319
320/*!
321 Deletes previously scheduled alarms which match \a when, \a channel, \a message,
322 and \a data.
323
324 Passing null values for \a when, \a channel, or \a message indicates "any".
325 Passing -1 for \a data indicates "any".
326
327 \sa deleteAlarm()
328*/
329void AlarmServer::deleteAlarm (QDateTime when, const QCString& channel, const QCString& message, int data)
330{
331 if ( qApp->type() == QApplication::GuiServer) {
332 bool needSave = FALSE;
333 if ( timerEventReceiver != NULL ) {
334 timerEventReceiver->killTimers();
335
336 // iterate over the list of events
337 QListIterator<timerEventItem> it( timerEventList );
338 time_t deleteTime = TimeConversion::toUTC( when );
339 for ( ; *it; ++it ) {
340 // if its a match, delete it
341 if ( ( (*it)->UTCtime == deleteTime || when.isNull() )
342 && ( channel.isNull() || (*it)->channel == channel )
343 && ( message.isNull() || (*it)->message == message )
344 && ( data==-1 || (*it)->data == data ) )
345 {
346 // if it's first, then we need to update the timer
347 if ( (*it) == nearestTimerEvent ) {
348 timerEventList.remove(*it);
349 setNearestTimerEvent();
350 } else {
351 timerEventList.remove(*it);
352 }
353 needSave = TRUE;
354 }
355 }
356 if ( nearestTimerEvent )
357 timerEventReceiver->resetTimer();
358 }
359 if ( needSave )
360 saveState();
361 } else {
362 QCopEnvelope e( "QPE/System", "deleteAlarm(QDateTime,QCString,QCString,int)" );
363 e << when << channel << message << data;
364 }
365}
366
367/*!
368 Writes the system clock to the hardware clock.
369*/
370void Global::writeHWClock()
371{
372 if ( !triggerAtd( TRUE ) ) {
373 // atd not running? set it ourselves
374 system("/sbin/hwclock --systohc"); // ##### UTC?
375 }
376}