summaryrefslogtreecommitdiff
path: root/library/alarmserver.cpp
Unidiff
Diffstat (limited to 'library/alarmserver.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--library/alarmserver.cpp519
1 files changed, 288 insertions, 231 deletions
diff --git a/library/alarmserver.cpp b/library/alarmserver.cpp
index 5e4dd18..2ea4025 100644
--- a/library/alarmserver.cpp
+++ b/library/alarmserver.cpp
@@ -39,15 +39,20 @@
39#include <unistd.h> 39#include <unistd.h>
40 40
41struct timerEventItem { 41
42 time_t UTCtime; 42#undef USE_ATD // not used anymore -- we run opie-alarm on suspend/resume
43 QCString channel, message; 43
44 int data; 44
45 bool operator==( const timerEventItem &right ) const 45struct timerEventItem
46 { 46{
47 return ( UTCtime == right.UTCtime 47 time_t UTCtime;
48 && channel == right.channel 48 QCString channel, message;
49 && message == right.message 49 int data;
50 && data == right.data ); 50 bool operator==( const timerEventItem &right ) const
51 } 51 {
52 return ( UTCtime == right.UTCtime
53 && channel == right.channel
54 && message == right.message
55 && data == right.data );
56 }
52}; 57};
53 58
@@ -55,13 +60,18 @@ class TimerReceiverObject : public QObject
55{ 60{
56public: 61public:
57 TimerReceiverObject() { } 62 TimerReceiverObject()
58 ~TimerReceiverObject() { } 63 { }
59 void resetTimer(); 64 ~TimerReceiverObject()
60 void setTimerEventItem(); 65 { }
61 void deleteTimer(); 66 void resetTimer();
67 void setTimerEventItem();
68 void deleteTimer();
62protected: 69protected:
63 void timerEvent( QTimerEvent *te ); 70 void timerEvent( QTimerEvent *te );
71
72#ifdef USE_ATD
64private: 73private:
65 QString atfilename; 74 QString atfilename;
75#endif
66}; 76};
67 77
@@ -74,15 +84,15 @@ timerEventItem *nearestTimerEvent = NULL;
74void setNearestTimerEvent() 84void setNearestTimerEvent()
75{ 85{
76 nearestTimerEvent = NULL; 86 nearestTimerEvent = NULL;
77 QListIterator<timerEventItem> it( timerEventList ); 87 QListIterator<timerEventItem> it( timerEventList );
78 if ( *it ) 88 if ( *it )
79 nearestTimerEvent = *it; 89 nearestTimerEvent = *it;
80 for ( ; *it; ++it ) 90 for ( ; *it; ++it )
81 if ( (*it)->UTCtime < nearestTimerEvent->UTCtime ) 91 if ( (*it)->UTCtime < nearestTimerEvent->UTCtime )
82 nearestTimerEvent = *it; 92 nearestTimerEvent = *it;
83 if (nearestTimerEvent) 93 if (nearestTimerEvent)
84 timerEventReceiver->resetTimer(); 94 timerEventReceiver->resetTimer();
85 else 95 else
86 timerEventReceiver->deleteTimer(); 96 timerEventReceiver->deleteTimer();
87} 97}
88 98
@@ -93,30 +103,31 @@ void setNearestTimerEvent()
93static void saveState() 103static void saveState()
94{ 104{
95 QString savefilename = Global::applicationFileName( "AlarmServer", "saveFile" ); 105 QString savefilename = Global::applicationFileName( "AlarmServer", "saveFile" );
96 if ( timerEventList.isEmpty() ) { 106 if ( timerEventList.isEmpty() ) {
97 unlink( savefilename ); 107 unlink( savefilename );
98 return; 108 return ;
99 } 109 }
100 110
101 QFile savefile(savefilename+".new"); 111 QFile savefile(savefilename + ".new");
102 if ( savefile.open(IO_WriteOnly) ) { 112 if ( savefile.open(IO_WriteOnly) ) {
103 QDataStream ds( &savefile ); 113 QDataStream ds( &savefile );
104 114
105 //save 115 //save
106 116
107 QListIterator<timerEventItem> it( timerEventList ); 117 QListIterator<timerEventItem> it( timerEventList );
108 for ( ; *it; ++it ) { 118 for ( ; *it; ++it ) {
109 ds << it.current()->UTCtime; 119 ds << it.current()->UTCtime;
110 ds << it.current()->channel; 120 ds << it.current()->channel;
111 ds << it.current()->message; 121 ds << it.current()->message;
112 ds << it.current()->data; 122 ds << it.current()->data;
113 } 123 }
114 124
115 125
116 savefile.close(); 126 savefile.close();
117 unlink( savefilename ); 127 unlink( savefilename );
118 QDir d; d.rename(savefilename+".new",savefilename); 128 QDir d;
129 d.rename(savefilename + ".new", savefilename);
119 130
120 } 131 }
121} 132}
122 133
@@ -126,28 +137,28 @@ static void saveState()
126void AlarmServer::initialize() 137void AlarmServer::initialize()
127{ 138{
128 //read autosave file and put events in timerEventList 139 //read autosave file and put events in timerEventList
129 140
130 QString savefilename = Global::applicationFileName( "AlarmServer", "saveFile" ); 141 QString savefilename = Global::applicationFileName( "AlarmServer", "saveFile" );
131 142
132 QFile savefile(savefilename); 143 QFile savefile(savefilename);
133 if ( savefile.open(IO_ReadOnly) ) { 144 if ( savefile.open(IO_ReadOnly) ) {
134 QDataStream ds( &savefile ); 145 QDataStream ds( &savefile );
135 while ( !ds.atEnd() ) { 146 while ( !ds.atEnd() ) {
136 timerEventItem *newTimerEventItem = new timerEventItem; 147 timerEventItem *newTimerEventItem = new timerEventItem;
137 ds >> newTimerEventItem->UTCtime; 148 ds >> newTimerEventItem->UTCtime;
138 ds >> newTimerEventItem->channel; 149 ds >> newTimerEventItem->channel;
139 ds >> newTimerEventItem->message; 150 ds >> newTimerEventItem->message;
140 ds >> newTimerEventItem->data; 151 ds >> newTimerEventItem->data;
141 timerEventList.append( newTimerEventItem ); 152 timerEventList.append( newTimerEventItem );
153 }
154 savefile.close();
155 if (!timerEventReceiver)
156 timerEventReceiver = new TimerReceiverObject;
157 setNearestTimerEvent();
142 } 158 }
143 savefile.close();
144 if (!timerEventReceiver)
145 timerEventReceiver = new TimerReceiverObject;
146 setNearestTimerEvent();
147 }
148} 159}
149 160
150 161
151 162#ifdef USE_ATD
152 163
153static const char* atdir = "/var/spool/at/"; 164static const char* atdir = "/var/spool/at/";
@@ -155,101 +166,138 @@ static const char* atdir = "/var/spool/at/";
155static bool triggerAtd( bool writeHWClock = FALSE ) 166static bool triggerAtd( bool writeHWClock = FALSE )
156{ 167{
157 QFile trigger(QString(atdir) + "trigger"); 168 QFile trigger(QString(atdir) + "trigger");
158 if ( trigger.open(IO_WriteOnly|IO_Raw) ) { 169 if ( trigger.open(IO_WriteOnly | IO_Raw) ) {
159 if ( trigger.writeBlock("\n",2) != 2 ) { 170 if ( trigger.writeBlock("\n", 2) != 2 ) {
160 QMessageBox::critical( 0, QObject::tr( "Out of Space" ), 171 QMessageBox::critical( 0, QObject::tr( "Out of Space" ),
161 QObject::tr( "Unable to schedule alarm.\nFree some memory and try again." ) ); 172 QObject::tr( "Unable to schedule alarm.\nFree some memory and try again." ) );
162 trigger.close(); 173 trigger.close();
163 QFile::remove( trigger.name() ); 174 QFile::remove
164 return FALSE; 175 ( trigger.name() );
176 return FALSE;
177 }
178 return TRUE;
179 }
180 return FALSE;
181}
182
183#else
184
185static bool writeResumeAt ( time_t wakeup )
186{
187 FILE *fp = ::fopen ( "/var/run/resumeat", "w" );
188
189 if ( fp ) {
190 ::fprintf ( fp, "%d\n", (int) wakeup );
191 ::fclose ( fp );
165 } 192 }
166 return TRUE; 193 else
167 } 194 qWarning ( "Failed to write wakeup time to /var/run/resumeat" );
168 return FALSE; 195
196 return ( fp );
169} 197}
170 198
199#endif
200
171void TimerReceiverObject::deleteTimer() 201void TimerReceiverObject::deleteTimer()
172{ 202{
173 if ( !atfilename.isEmpty() ) { 203#ifdef USE_ATD
174 unlink( atfilename ); 204 if ( !atfilename.isEmpty() ) {
175 atfilename = QString::null; 205 unlink( atfilename );
176 triggerAtd( FALSE ); 206 atfilename = QString::null;
177 } 207 triggerAtd( FALSE );
208 }
209#else
210 writeResumeAt ( 0 );
211#endif
178} 212}
179 213
180void TimerReceiverObject::resetTimer() 214void TimerReceiverObject::resetTimer()
181{ 215{
182 const int maxsecs = 2147000; 216 const int maxsecs = 2147000;
183 int total_written; 217 QDateTime nearest = TimeConversion::fromUTC(nearestTimerEvent->UTCtime);
184 QDateTime nearest = TimeConversion::fromUTC(nearestTimerEvent->UTCtime); 218 QDateTime now = QDateTime::currentDateTime();
185 QDateTime now = QDateTime::currentDateTime(); 219 if ( nearest < now )
186 if ( nearest < now ) 220 nearest = now;
187 nearest = now; 221 int secs = TimeConversion::secsTo( now, nearest );
188 int secs = TimeConversion::secsTo( now, nearest ); 222 if ( secs > maxsecs ) {
189 if ( secs > maxsecs ) { 223 // too far for millisecond timing
190 // too far for millisecond timing 224 secs = maxsecs;
191 secs = maxsecs; 225 }
192 } 226
193 227 // System timer (needed so that we wake from deep sleep),
194 // System timer (needed so that we wake from deep sleep), 228 // from the Epoch in seconds.
195 // from the Epoch in seconds. 229 //
196 // 230 int at_secs = TimeConversion::toUTC(nearest);
197 int at_secs = TimeConversion::toUTC(nearest); 231 // qDebug("reset timer to %d seconds from Epoch",at_secs);
198 // qDebug("reset timer to %d seconds from Epoch",at_secs); 232
199 QString fn = atdir + QString::number(at_secs) + "." 233#ifdef USE_ATD
200 + QString::number(getpid()); 234
201 if ( fn != atfilename ) { 235 QString fn = atdir + QString::number(at_secs) + "."
202 QFile atfile(fn+".new"); 236 + QString::number(getpid());
203 if ( atfile.open(IO_WriteOnly|IO_Raw) ) { 237 if ( fn != atfilename ) {
204 // just wake up and delete the at file 238 QFile atfile(fn + ".new");
205 QString cmd = "#!/bin/sh\nrm " + fn; 239 if ( atfile.open(IO_WriteOnly | IO_Raw) ) {
206 total_written = atfile.writeBlock(cmd.latin1(),cmd.length()); 240 int total_written;
207 if ( total_written != int(cmd.length()) ) { 241
208 QMessageBox::critical( 0, tr("Out of Space"), 242 // just wake up and delete the at file
209 tr("Unable to schedule alarm.\n" 243 QString cmd = "#!/bin/sh\nrm " + fn;
210 "Please free up space and try again") ); 244 total_written = atfile.writeBlock(cmd.latin1(), cmd.length());
211 atfile.close(); 245 if ( total_written != int(cmd.length()) ) {
212 QFile::remove( atfile.name() ); 246 QMessageBox::critical( 0, tr("Out of Space"),
213 return; 247 tr("Unable to schedule alarm.\n"
214 } 248 "Please free up space and try again") );
215 atfile.close(); 249 atfile.close();
216 unlink( atfilename ); 250 QFile::remove
217 QDir d; d.rename(fn+".new",fn); 251 ( atfile.name() );
218 chmod(fn.latin1(),0755); 252 return ;
219 atfilename = fn; 253 }
220 triggerAtd( FALSE ); 254 atfile.close();
221 } else { 255 unlink( atfilename );
222 qWarning("Cannot open atd file %s",fn.latin1()); 256 QDir d;
257 d.rename(fn + ".new", fn);
258 chmod(fn.latin1(), 0755);
259 atfilename = fn;
260 triggerAtd( FALSE );
261 }
262 else {
263 qWarning("Cannot open atd file %s", fn.latin1());
264 }
223 } 265 }
224 } 266#else
225 // Qt timers (does the actual alarm) 267 writeResumeAt ( at_secs );
226 // from now in milliseconds 268
227 // 269#endif
228 qDebug("AlarmServer waiting %d seconds",secs); 270
229 startTimer( 1000 * secs + 500 ); 271 // Qt timers (does the actual alarm)
272 // from now in milliseconds
273 //
274 qDebug("AlarmServer waiting %d seconds", secs);
275 startTimer( 1000 * secs + 500 );
230} 276}
231 277
232void TimerReceiverObject::timerEvent( QTimerEvent * ) 278void TimerReceiverObject::timerEvent( QTimerEvent * )
233{ 279{
234 bool needSave = FALSE; 280 bool needSave = FALSE;
235 killTimers(); 281 killTimers();
236 if (nearestTimerEvent) { 282 if (nearestTimerEvent) {
237 if ( nearestTimerEvent->UTCtime 283 if ( nearestTimerEvent->UTCtime
238 <= TimeConversion::toUTC(QDateTime::currentDateTime()) ) { 284 <= TimeConversion::toUTC(QDateTime::currentDateTime()) ) {
239#ifndef QT_NO_COP 285#ifndef QT_NO_COP
240 QCopEnvelope e( nearestTimerEvent->channel, 286 QCopEnvelope e( nearestTimerEvent->channel,
241 nearestTimerEvent->message ); 287 nearestTimerEvent->message );
242 e << TimeConversion::fromUTC( nearestTimerEvent->UTCtime ) 288 e << TimeConversion::fromUTC( nearestTimerEvent->UTCtime )
243 << nearestTimerEvent->data; 289 << nearestTimerEvent->data;
244#endif 290#endif
245 timerEventList.remove( nearestTimerEvent ); 291
246 needSave = TRUE; 292 timerEventList.remove( nearestTimerEvent );
293 needSave = TRUE;
294 }
295 setNearestTimerEvent();
247 } 296 }
248 setNearestTimerEvent(); 297 else {
249 } else { 298 resetTimer();
250 resetTimer(); 299 }
251 } 300 if ( needSave )
252 if ( needSave ) 301 saveState();
253 saveState();
254} 302}
255 303
@@ -257,5 +305,5 @@ void TimerReceiverObject::timerEvent( QTimerEvent * )
257 \class AlarmServer alarmserver.h 305 \class AlarmServer alarmserver.h
258 \brief The AlarmServer class allows alarms to be scheduled and unscheduled. 306 \brief The AlarmServer class allows alarms to be scheduled and unscheduled.
259 307
260 Applications can schedule alarms with addAlarm() and can 308 Applications can schedule alarms with addAlarm() and can
261 unschedule alarms with deleteAlarm(). When the time for an alarm 309 unschedule alarms with deleteAlarm(). When the time for an alarm
@@ -263,10 +311,10 @@ void TimerReceiverObject::timerEvent( QTimerEvent * )
263 message is sent on the specified channel (optionally with 311 message is sent on the specified channel (optionally with
264 additional data). 312 additional data).
265 313
266 Scheduling an alarm using this class is important (rather just using 314 Scheduling an alarm using this class is important (rather just using
267 a QTimer) since the machine may be asleep and needs to get woken up using 315 a QTimer) since the machine may be asleep and needs to get woken up using
268 the Linux kernel which implements this at the kernel level to minimize 316 the Linux kernel which implements this at the kernel level to minimize
269 battery usage while asleep. 317 battery usage while asleep.
270 318
271 \ingroup qtopiaemb 319 \ingroup qtopiaemb
272 \sa QCopEnvelope 320 \sa QCopEnvelope
@@ -277,53 +325,56 @@ void TimerReceiverObject::timerEvent( QTimerEvent * )
277 the alarm goes off, the \link qcop.html QCop\endlink \a message will 325 the alarm goes off, the \link qcop.html QCop\endlink \a message will
278 be sent to \a channel, with \a data as a parameter. 326 be sent to \a channel, with \a data as a parameter.
279 327
280 If this function is called with exactly the same data as a previous 328 If this function is called with exactly the same data as a previous
281 call the subsequent call is ignored, so there is only ever one alarm 329 call the subsequent call is ignored, so there is only ever one alarm
282 with a given set of parameters. 330 with a given set of parameters.
283 331
284 \sa deleteAlarm() 332 \sa deleteAlarm()
285*/ 333*/
286void AlarmServer::addAlarm ( QDateTime when, const QCString& channel, 334void AlarmServer::addAlarm ( QDateTime when, const QCString& channel,
287 const QCString& message, int data) 335 const QCString& message, int data)
288{ 336{
289 if ( qApp->type() == QApplication::GuiServer ) { 337 if ( qApp->type() == QApplication::GuiServer ) {
290 bool needSave = FALSE; 338 bool needSave = FALSE;
291 // Here we are the server so either it has been directly called from 339 // Here we are the server so either it has been directly called from
292 // within the server or it has been sent to us from a client via QCop 340 // within the server or it has been sent to us from a client via QCop
293 if (!timerEventReceiver) 341 if (!timerEventReceiver)
294 timerEventReceiver = new TimerReceiverObject; 342 timerEventReceiver = new TimerReceiverObject;
295 343
296 timerEventItem *newTimerEventItem = new timerEventItem; 344 timerEventItem *newTimerEventItem = new timerEventItem;
297 newTimerEventItem->UTCtime = TimeConversion::toUTC( when ); 345 newTimerEventItem->UTCtime = TimeConversion::toUTC( when );
298 newTimerEventItem->channel = channel; 346 newTimerEventItem->channel = channel;
299 newTimerEventItem->message = message; 347 newTimerEventItem->message = message;
300 newTimerEventItem->data = data; 348 newTimerEventItem->data = data;
301 // explore the case of already having the event in here... 349 // explore the case of already having the event in here...
302 QListIterator<timerEventItem> it( timerEventList ); 350 QListIterator<timerEventItem> it( timerEventList );
303 for ( ; *it; ++it ) 351 for ( ; *it; ++it )
304 if ( *(*it) == *newTimerEventItem ) 352 if ( *(*it) == *newTimerEventItem )
305 return; 353 return ;
306 // if we made it here, it is okay to add the item... 354 // if we made it here, it is okay to add the item...
307 timerEventList.append( newTimerEventItem ); 355 timerEventList.append( newTimerEventItem );
308 needSave = TRUE; 356 needSave = TRUE;
309 // quicker than using setNearestTimerEvent() 357 // quicker than using setNearestTimerEvent()
310 if ( nearestTimerEvent ) { 358 if ( nearestTimerEvent ) {
311 if (newTimerEventItem->UTCtime < nearestTimerEvent->UTCtime) { 359 if (newTimerEventItem->UTCtime < nearestTimerEvent->UTCtime) {
312 nearestTimerEvent = newTimerEventItem; 360 nearestTimerEvent = newTimerEventItem;
313 timerEventReceiver->killTimers(); 361 timerEventReceiver->killTimers();
314 timerEventReceiver->resetTimer(); 362 timerEventReceiver->resetTimer();
315 } 363 }
316 } else { 364 }
317 nearestTimerEvent = newTimerEventItem; 365 else {
318 timerEventReceiver->resetTimer(); 366 nearestTimerEvent = newTimerEventItem;
367 timerEventReceiver->resetTimer();
368 }
369 if ( needSave )
370 saveState();
319 } 371 }
320 if ( needSave ) 372 else {
321 saveState();
322 } else {
323#ifndef QT_NO_COP 373#ifndef QT_NO_COP
324 QCopEnvelope e( "QPE/System", "addAlarm(QDateTime,QCString,QCString,int)" ); 374 QCopEnvelope e( "QPE/System", "addAlarm(QDateTime,QCString,QCString,int)" );
325 e << when << channel << message << data; 375 e << when << channel << message << data;
326#endif 376#endif
327 } 377
378 }
328} 379}
329 380
@@ -331,52 +382,54 @@ void AlarmServer::addAlarm ( QDateTime when, const QCString& channel,
331 Deletes previously scheduled alarms which match \a when, \a channel, 382 Deletes previously scheduled alarms which match \a when, \a channel,
332 \a message, and \a data. 383 \a message, and \a data.
333 384
334 Passing null values for \a when, \a channel, or for the \link 385 Passing null values for \a when, \a channel, or for the \link
335 qcop.html QCop\endlink \a message, acts as a wildcard meaning "any". 386 qcop.html QCop\endlink \a message, acts as a wildcard meaning "any".
336 Similarly, passing -1 for \a data indicates "any". 387 Similarly, passing -1 for \a data indicates "any".
337 388
338 If there is no matching alarm, nothing happens. 389 If there is no matching alarm, nothing happens.
339 390
340 \sa addAlarm() 391 \sa addAlarm()
341 392
342*/ 393*/
343void AlarmServer::deleteAlarm (QDateTime when, const QCString& channel, const QCString& message, int data) 394void AlarmServer::deleteAlarm (QDateTime when, const QCString& channel, const QCString& message, int data)
344{ 395{
345 if ( qApp->type() == QApplication::GuiServer) { 396 if ( qApp->type() == QApplication::GuiServer) {
346 bool needSave = FALSE; 397 bool needSave = FALSE;
347 if ( timerEventReceiver != NULL ) { 398 if ( timerEventReceiver != NULL ) {
348 timerEventReceiver->killTimers(); 399 timerEventReceiver->killTimers();
349 400
350 // iterate over the list of events 401 // iterate over the list of events
351 QListIterator<timerEventItem> it( timerEventList ); 402 QListIterator<timerEventItem> it( timerEventList );
352 time_t deleteTime = TimeConversion::toUTC( when ); 403 time_t deleteTime = TimeConversion::toUTC( when );
353 for ( ; *it; ++it ) { 404 for ( ; *it; ++it ) {
354 // if its a match, delete it 405 // if its a match, delete it
355 if ( ( (*it)->UTCtime == deleteTime || when.isNull() ) 406 if ( ( (*it)->UTCtime == deleteTime || when.isNull() )
356 && ( channel.isNull() || (*it)->channel == channel ) 407 && ( channel.isNull() || (*it)->channel == channel )
357 && ( message.isNull() || (*it)->message == message ) 408 && ( message.isNull() || (*it)->message == message )
358 && ( data==-1 || (*it)->data == data ) ) 409 && ( data == -1 || (*it)->data == data ) ) {
359 { 410 // if it's first, then we need to update the timer
360 // if it's first, then we need to update the timer 411 if ( (*it) == nearestTimerEvent ) {
361 if ( (*it) == nearestTimerEvent ) { 412 timerEventList.remove(*it);
362 timerEventList.remove(*it); 413 setNearestTimerEvent();
363 setNearestTimerEvent(); 414 }
364 } else { 415 else {
365 timerEventList.remove(*it); 416 timerEventList.remove(*it);
366 } 417 }
367 needSave = TRUE; 418 needSave = TRUE;
419 }
420 }
421 if ( nearestTimerEvent )
422 timerEventReceiver->resetTimer();
368 } 423 }
369 } 424 if ( needSave )
370 if ( nearestTimerEvent ) 425 saveState();
371 timerEventReceiver->resetTimer();
372 } 426 }
373 if ( needSave ) 427 else {
374 saveState();
375 } else {
376#ifndef QT_NO_COP 428#ifndef QT_NO_COP
377 QCopEnvelope e( "QPE/System", "deleteAlarm(QDateTime,QCString,QCString,int)" ); 429 QCopEnvelope e( "QPE/System", "deleteAlarm(QDateTime,QCString,QCString,int)" );
378 e << when << channel << message << data; 430 e << when << channel << message << data;
379#endif 431#endif
380 } 432
433 }
381} 434}
382 435
@@ -386,7 +439,11 @@ void AlarmServer::deleteAlarm (QDateTime when, const QCString& channel, const QC
386void Global::writeHWClock() 439void Global::writeHWClock()
387{ 440{
388 if ( !triggerAtd( TRUE ) ) { 441#ifdef USE_ATD
389 // atd not running? set it ourselves 442 if ( !triggerAtd( TRUE ) ) {
390 system("/sbin/hwclock --systohc"); // ##### UTC? 443 // atd not running? set it ourselves
391 } 444 system("/sbin/hwclock --systohc"); // ##### UTC?
445 }
446#else
447 // hwclock is written on suspend
448#endif
392} 449}