Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

alarmserver.cpp

Go to the documentation of this file.
00001 /**********************************************************************
00002 ** Copyright (C) 2000-2002 Trolltech AS.  All rights reserved.
00003 **
00004 ** This file is part of the Qtopia Environment.
00005 **
00006 ** This file may be distributed and/or modified under the terms of the
00007 ** GNU General Public License version 2 as published by the Free Software
00008 ** Foundation and appearing in the file LICENSE.GPL included in the
00009 ** packaging of this file.
00010 **
00011 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00012 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00013 **
00014 ** See http://www.trolltech.com/gpl/ for GPL licensing information.
00015 **
00016 ** Contact info@trolltech.com if any conditions of this licensing are
00017 ** not clear to you.
00018 **
00019 **********************************************************************/
00020 
00021 #include "alarmserver.h"
00022 
00023 #include <qpe/global.h>
00024 #include <qpe/qpeapplication.h>
00025 #include <qpe/qcopenvelope_qws.h>
00026 #include <qpe/timeconversion.h>
00027 
00028 #include <qdir.h>
00029 
00030 #include <sys/types.h>
00031 #include <sys/stat.h>
00032 #include <stdlib.h>
00033 #include <unistd.h>
00034 
00035 
00036 #undef USE_ATD   // not used anymore -- we run opie-alarm on suspend/resume
00037 
00038 
00039 struct timerEventItem
00040 {
00041         time_t UTCtime;
00042         QCString channel, message;
00043         int data;
00044         bool operator==( const timerEventItem &right ) const
00045         {
00046                 return ( UTCtime == right.UTCtime
00047                          && channel == right.channel
00048                          && message == right.message
00049                          && data == right.data );
00050         }
00051 };
00052 
00053 class TimerReceiverObject : public QObject
00054 {
00055 public:
00056         TimerReceiverObject()
00057         { }
00058         ~TimerReceiverObject()
00059         { }
00060         void resetTimer();
00061         void setTimerEventItem();
00062         void deleteTimer();
00063 protected:
00064         void timerEvent( QTimerEvent *te );
00065 
00066 #ifdef USE_ATD
00067 private:
00068         QString atfilename;
00069 #endif
00070 };
00071 
00072 TimerReceiverObject *timerEventReceiver = NULL;
00073 QList<timerEventItem> timerEventList;
00074 timerEventItem *nearestTimerEvent = NULL;
00075 
00076 
00077 // set the timer to go off on the next event in the list
00078 void setNearestTimerEvent()
00079 {
00080         nearestTimerEvent = NULL;
00081         QListIterator<timerEventItem> it( timerEventList );
00082         if ( *it )
00083                 nearestTimerEvent = *it;
00084         for ( ; *it; ++it )
00085                 if ( (*it)->UTCtime < nearestTimerEvent->UTCtime )
00086                         nearestTimerEvent = *it;
00087         if (nearestTimerEvent)
00088                 timerEventReceiver->resetTimer();
00089         else
00090                 timerEventReceiver->deleteTimer();
00091 }
00092 
00093 
00094 //store current state to file
00095 //Simple implementation. Should run on a timer.
00096 
00097 static void saveState()
00098 {
00099         QString savefilename = Global::applicationFileName( "AlarmServer", "saveFile" );
00100         if ( timerEventList.isEmpty() ) {
00101                 unlink( savefilename );
00102                 return ;
00103         }
00104 
00105         QFile savefile(savefilename + ".new");
00106         if ( savefile.open(IO_WriteOnly) ) {
00107                 QDataStream ds( &savefile );
00108 
00109                 //save
00110 
00111                 QListIterator<timerEventItem> it( timerEventList );
00112                 for ( ; *it; ++it ) {
00113                         ds << it.current()->UTCtime;
00114                         ds << it.current()->channel;
00115                         ds << it.current()->message;
00116                         ds << it.current()->data;
00117                 }
00118 
00119 
00120                 savefile.close();
00121                 unlink( savefilename );
00122                 QDir d;
00123                 d.rename(savefilename + ".new", savefilename);
00124 
00125         }
00126 }
00127 
00131 void AlarmServer::initialize()
00132 {
00133         //read autosave file and put events in timerEventList
00134 
00135         QString savefilename = Global::applicationFileName( "AlarmServer", "saveFile" );
00136 
00137         QFile savefile(savefilename);
00138         if ( savefile.open(IO_ReadOnly) ) {
00139                 QDataStream ds( &savefile );
00140                 while ( !ds.atEnd() ) {
00141                         timerEventItem *newTimerEventItem = new timerEventItem;
00142                         ds >> newTimerEventItem->UTCtime;
00143                         ds >> newTimerEventItem->channel;
00144                         ds >> newTimerEventItem->message;
00145                         ds >> newTimerEventItem->data;
00146                         timerEventList.append( newTimerEventItem );
00147                 }
00148                 savefile.close();
00149                 if (!timerEventReceiver)
00150                         timerEventReceiver = new TimerReceiverObject;
00151                 setNearestTimerEvent();
00152         }
00153 }
00154 
00155 
00156 #ifdef USE_ATD
00157 
00158 static const char* atdir = "/var/spool/at/";
00159 
00160 static bool triggerAtd( bool writeHWClock = FALSE )
00161 {
00162         QFile trigger(QString(atdir) + "trigger");
00163         if ( trigger.open(IO_WriteOnly | IO_Raw) ) {
00164                 if ( trigger.writeBlock("\n", 2) != 2 ) {
00165                         QMessageBox::critical( 0, QObject::tr( "Out of Space" ),
00166                                                QObject::tr( "Unable to schedule alarm.\nFree some memory and try again." ) );
00167                         trigger.close();
00168                         QFile::remove
00169                                 ( trigger.name() );
00170                         return FALSE;
00171                 }
00172                 return TRUE;
00173         }
00174         return FALSE;
00175 }
00176 
00177 #else
00178 
00179 static bool writeResumeAt ( time_t wakeup )
00180 {
00181         FILE *fp = ::fopen ( "/var/run/resumeat", "w" );
00182 
00183         if ( fp ) {
00184                 ::fprintf ( fp, "%d\n", (int) wakeup );
00185                 ::fclose ( fp );
00186         }
00187         else
00188                 qWarning ( "Failed to write wakeup time to /var/run/resumeat" );
00189 
00190         return ( fp );
00191 }
00192 
00193 #endif
00194 
00195 void TimerReceiverObject::deleteTimer()
00196 {
00197 #ifdef USE_ATD
00198         if ( !atfilename.isEmpty() ) {
00199                 unlink( atfilename );
00200                 atfilename = QString::null;
00201                 triggerAtd( FALSE );
00202         }
00203 #else
00204         writeResumeAt ( 0 );
00205 #endif
00206 }
00207 
00208 void TimerReceiverObject::resetTimer()
00209 {
00210         const int maxsecs = 2147000;
00211         QDateTime nearest = TimeConversion::fromUTC(nearestTimerEvent->UTCtime);
00212         QDateTime now = QDateTime::currentDateTime();
00213         if ( nearest < now )
00214                 nearest = now;
00215         int secs = TimeConversion::secsTo( now, nearest );
00216         if ( secs > maxsecs ) {
00217                 // too far for millisecond timing
00218                 secs = maxsecs;
00219         }
00220 
00221         // System timer (needed so that we wake from deep sleep),
00222         // from the Epoch in seconds.
00223         //
00224         int at_secs = TimeConversion::toUTC(nearest);
00225         // qDebug("reset timer to %d seconds from Epoch",at_secs);
00226 
00227 #ifdef USE_ATD
00228 
00229         QString fn = atdir + QString::number(at_secs) + "."
00230                      + QString::number(getpid());
00231         if ( fn != atfilename ) {
00232                 QFile atfile(fn + ".new");
00233                 if ( atfile.open(IO_WriteOnly | IO_Raw) ) {
00234                         int total_written;
00235 
00236                         // just wake up and delete the at file
00237                         QString cmd = "#!/bin/sh\nrm " + fn;
00238                         total_written = atfile.writeBlock(cmd.latin1(), cmd.length());
00239                         if ( total_written != int(cmd.length()) ) {
00240                                 QMessageBox::critical( 0, tr("Out of Space"),
00241                                                        tr("Unable to schedule alarm.\n"
00242                                                           "Please free up space and try again") );
00243                                 atfile.close();
00244                                 QFile::remove
00245                                         ( atfile.name() );
00246                                 return ;
00247                         }
00248                         atfile.close();
00249                         unlink( atfilename );
00250                         QDir d;
00251                         d.rename(fn + ".new", fn);
00252                         chmod(fn.latin1(), 0755);
00253                         atfilename = fn;
00254                         triggerAtd( FALSE );
00255                 }
00256                 else {
00257                         qWarning("Cannot open atd file %s", fn.latin1());
00258                 }
00259         }
00260 #else
00261     writeResumeAt ( at_secs );
00262 
00263 #endif
00264 
00265         // Qt timers (does the actual alarm)
00266         // from now in milliseconds
00267         //
00268         qDebug("AlarmServer waiting %d seconds", secs);
00269         startTimer( 1000 * secs + 500 );
00270 }
00271 
00272 void TimerReceiverObject::timerEvent( QTimerEvent * )
00273 {
00274         bool needSave = FALSE;
00275         killTimers();
00276         if (nearestTimerEvent) {
00277                 if ( nearestTimerEvent->UTCtime
00278                         <= TimeConversion::toUTC(QDateTime::currentDateTime()) ) {
00279 #ifndef QT_NO_COP
00280                         QCopEnvelope e( nearestTimerEvent->channel,
00281                                         nearestTimerEvent->message );
00282                         e << TimeConversion::fromUTC( nearestTimerEvent->UTCtime )
00283                         << nearestTimerEvent->data;
00284 #endif
00285 
00286                         timerEventList.remove( nearestTimerEvent );
00287                         needSave = TRUE;
00288                 }
00289                 setNearestTimerEvent();
00290         }
00291         else {
00292                 resetTimer();
00293         }
00294         if ( needSave )
00295                 saveState();
00296 }
00297 
00388 void AlarmServer::addAlarm ( QDateTime when, const QCString& channel,
00389                              const QCString& message, int data)
00390 {
00391         if ( qApp->type() == QApplication::GuiServer ) {
00392                 bool needSave = FALSE;
00393                 // Here we are the server so either it has been directly called from
00394                 // within the server or it has been sent to us from a client via QCop
00395                 if (!timerEventReceiver)
00396                         timerEventReceiver = new TimerReceiverObject;
00397 
00398                 timerEventItem *newTimerEventItem = new timerEventItem;
00399                 newTimerEventItem->UTCtime = TimeConversion::toUTC( when );
00400                 newTimerEventItem->channel = channel;
00401                 newTimerEventItem->message = message;
00402                 newTimerEventItem->data = data;
00403                 // explore the case of already having the event in here...
00404                 QListIterator<timerEventItem> it( timerEventList );
00405                 for ( ; *it; ++it )
00406                         if ( *(*it) == *newTimerEventItem )
00407                                 return ;
00408                 // if we made it here, it is okay to add the item...
00409                 timerEventList.append( newTimerEventItem );
00410                 needSave = TRUE;
00411                 // quicker than using setNearestTimerEvent()
00412                 if ( nearestTimerEvent ) {
00413                         if (newTimerEventItem->UTCtime < nearestTimerEvent->UTCtime) {
00414                                 nearestTimerEvent = newTimerEventItem;
00415                                 timerEventReceiver->killTimers();
00416                                 timerEventReceiver->resetTimer();
00417                         }
00418                 }
00419                 else {
00420                         nearestTimerEvent = newTimerEventItem;
00421                         timerEventReceiver->resetTimer();
00422                 }
00423                 if ( needSave )
00424                         saveState();
00425         }
00426         else {
00427 #ifndef QT_NO_COP
00428                 QCopEnvelope e( "QPE/System", "addAlarm(QDateTime,QCString,QCString,int)" );
00429                 e << when << channel << message << data;
00430 #endif
00431 
00432         }
00433 }
00434 
00448 void AlarmServer::deleteAlarm (QDateTime when, const QCString& channel, const QCString& message, int data)
00449 {
00450         if ( qApp->type() == QApplication::GuiServer) {
00451                 bool needSave = FALSE;
00452                 if ( timerEventReceiver != NULL ) {
00453                         timerEventReceiver->killTimers();
00454 
00455                         // iterate over the list of events
00456                         QListIterator<timerEventItem> it( timerEventList );
00457                         time_t deleteTime = TimeConversion::toUTC( when );
00458                         for ( ; *it; ++it ) {
00459                                 // if its a match, delete it
00460                                 if ( ( (*it)->UTCtime == deleteTime || when.isNull() )
00461                                         && ( channel.isNull() || (*it)->channel == channel )
00462                                         && ( message.isNull() || (*it)->message == message )
00463                                         && ( data == -1 || (*it)->data == data ) ) {
00464                                         // if it's first, then we need to update the timer
00465                                         if ( (*it) == nearestTimerEvent ) {
00466                                                 timerEventList.remove(*it);
00467                                                 setNearestTimerEvent();
00468                                         }
00469                                         else {
00470                                                 timerEventList.remove(*it);
00471                                         }
00472                                         needSave = TRUE;
00473                                 }
00474                         }
00475                         if ( nearestTimerEvent )
00476                                 timerEventReceiver->resetTimer();
00477                 }
00478                 if ( needSave )
00479                         saveState();
00480         }
00481         else {
00482 #ifndef QT_NO_COP
00483                 QCopEnvelope e( "QPE/System", "deleteAlarm(QDateTime,QCString,QCString,int)" );
00484                 e << when << channel << message << data;
00485 #endif
00486 
00487         }
00488 }
00489 
00496 void Global::writeHWClock()
00497 {
00498 #ifdef USE_ATD
00499         if ( !triggerAtd( TRUE ) ) {
00500                 // atd not running? set it ourselves
00501                 system("/sbin/hwclock --systohc"); // ##### UTC?
00502         }
00503 #else
00504         // hwclock is written on suspend
00505 #endif
00506 }

Generated on Sat Nov 5 16:16:31 2005 for OPIE by  doxygen 1.4.2