Qtopia library API Documentation

alarmserver.cpp

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 <qdir.h>
00022 #include <qfile.h>
00023 #include <qmessagebox.h>
00024 #include <qtextstream.h>
00025 
00026 
00027 #include <qpe/qpeapplication.h>
00028 #include "global.h"
00029 #include "resource.h"
00030 
00031 #include <qpe/qcopenvelope_qws.h>
00032 #include "alarmserver.h"
00033 #include <qpe/timeconversion.h>
00034 
00035 #include <sys/types.h>
00036 #include <sys/stat.h>
00037 
00038 #include <stdlib.h>
00039 #include <unistd.h>
00040 
00041 
00042 #undef USE_ATD   // not used anymore -- we run opie-alarm on suspend/resume
00043 
00044 
00045 struct timerEventItem
00046 {
00047     time_t UTCtime;
00048     QCString channel, message;
00049     int data;
00050     bool operator==( const timerEventItem &right ) const
00051     {
00052         return ( UTCtime == right.UTCtime
00053                  && channel == right.channel
00054                  && message == right.message
00055                  && data == right.data );
00056     }
00057 };
00058 
00059 class TimerReceiverObject : public QObject
00060 {
00061 public:
00062     TimerReceiverObject()
00063     { }
00064     ~TimerReceiverObject()
00065     { }
00066     void resetTimer();
00067     void setTimerEventItem();
00068     void deleteTimer();
00069 protected:
00070     void timerEvent( QTimerEvent *te );
00071 
00072 #ifdef USE_ATD
00073 private:
00074     QString atfilename;
00075 #endif
00076 };
00077 
00078 TimerReceiverObject *timerEventReceiver = NULL;
00079 QList<timerEventItem> timerEventList;
00080 timerEventItem *nearestTimerEvent = NULL;
00081 
00082 
00083 // set the timer to go off on the next event in the list
00084 void setNearestTimerEvent()
00085 {
00086     nearestTimerEvent = NULL;
00087     QListIterator<timerEventItem> it( timerEventList );
00088     if ( *it )
00089         nearestTimerEvent = *it;
00090     for ( ; *it; ++it )
00091         if ( (*it)->UTCtime < nearestTimerEvent->UTCtime )
00092             nearestTimerEvent = *it;
00093     if (nearestTimerEvent)
00094         timerEventReceiver->resetTimer();
00095     else
00096         timerEventReceiver->deleteTimer();
00097 }
00098 
00099 
00100 //store current state to file
00101 //Simple implementation. Should run on a timer.
00102 
00103 static void saveState()
00104 {
00105     QString savefilename = Global::applicationFileName( "AlarmServer", "saveFile" );
00106     if ( timerEventList.isEmpty() ) {
00107         unlink( savefilename );
00108         return ;
00109     }
00110 
00111     QFile savefile(savefilename + ".new");
00112     if ( savefile.open(IO_WriteOnly) ) {
00113         QDataStream ds( &savefile );
00114 
00115         //save
00116 
00117         QListIterator<timerEventItem> it( timerEventList );
00118         for ( ; *it; ++it ) {
00119             ds << it.current()->UTCtime;
00120             ds << it.current()->channel;
00121             ds << it.current()->message;
00122             ds << it.current()->data;
00123         }
00124 
00125 
00126         savefile.close();
00127         unlink( savefilename );
00128         QDir d;
00129         d.rename(savefilename + ".new", savefilename);
00130 
00131     }
00132 }
00133 
00137 void AlarmServer::initialize()
00138 {
00139     //read autosave file and put events in timerEventList
00140 
00141     QString savefilename = Global::applicationFileName( "AlarmServer", "saveFile" );
00142 
00143     QFile savefile(savefilename);
00144     if ( savefile.open(IO_ReadOnly) ) {
00145         QDataStream ds( &savefile );
00146         while ( !ds.atEnd() ) {
00147             timerEventItem *newTimerEventItem = new timerEventItem;
00148             ds >> newTimerEventItem->UTCtime;
00149             ds >> newTimerEventItem->channel;
00150             ds >> newTimerEventItem->message;
00151             ds >> newTimerEventItem->data;
00152             timerEventList.append( newTimerEventItem );
00153         }
00154         savefile.close();
00155         if (!timerEventReceiver)
00156             timerEventReceiver = new TimerReceiverObject;
00157         setNearestTimerEvent();
00158     }
00159 }
00160 
00161 
00162 #ifdef USE_ATD
00163 
00164 static const char* atdir = "/var/spool/at/";
00165 
00166 static bool triggerAtd( bool writeHWClock = FALSE )
00167 {
00168     QFile trigger(QString(atdir) + "trigger");
00169     if ( trigger.open(IO_WriteOnly | IO_Raw) ) {
00170         if ( trigger.writeBlock("\n", 2) != 2 ) {
00171             QMessageBox::critical( 0, QObject::tr( "Out of Space" ),
00172                                    QObject::tr( "Unable to schedule alarm.\nFree some memory and try again." ) );
00173             trigger.close();
00174             QFile::remove
00175                 ( trigger.name() );
00176             return FALSE;
00177         }
00178         return TRUE;
00179     }
00180     return FALSE;
00181 }
00182 
00183 #else
00184 
00185 static bool writeResumeAt ( time_t wakeup )
00186 {
00187     FILE *fp = ::fopen ( "/var/run/resumeat", "w" );
00188 
00189     if ( fp ) {
00190         ::fprintf ( fp, "%d\n", (int) wakeup );
00191         ::fclose ( fp );
00192     }
00193     else
00194         qWarning ( "Failed to write wakeup time to /var/run/resumeat" );
00195 
00196     return ( fp );
00197 }
00198 
00199 #endif
00200 
00201 void TimerReceiverObject::deleteTimer()
00202 {
00203 #ifdef USE_ATD
00204     if ( !atfilename.isEmpty() ) {
00205         unlink( atfilename );
00206         atfilename = QString::null;
00207         triggerAtd( FALSE );
00208     }
00209 #else
00210     writeResumeAt ( 0 );
00211 #endif
00212 }
00213 
00214 void TimerReceiverObject::resetTimer()
00215 {
00216     const int maxsecs = 2147000;
00217     QDateTime nearest = TimeConversion::fromUTC(nearestTimerEvent->UTCtime);
00218     QDateTime now = QDateTime::currentDateTime();
00219     if ( nearest < now )
00220         nearest = now;
00221     int secs = TimeConversion::secsTo( now, nearest );
00222     if ( secs > maxsecs ) {
00223         // too far for millisecond timing
00224         secs = maxsecs;
00225     }
00226 
00227     // System timer (needed so that we wake from deep sleep),
00228     // from the Epoch in seconds.
00229     //
00230     int at_secs = TimeConversion::toUTC(nearest);
00231     // qDebug("reset timer to %d seconds from Epoch",at_secs);
00232 
00233 #ifdef USE_ATD
00234 
00235     QString fn = atdir + QString::number(at_secs) + "."
00236                  + QString::number(getpid());
00237     if ( fn != atfilename ) {
00238         QFile atfile(fn + ".new");
00239         if ( atfile.open(IO_WriteOnly | IO_Raw) ) {
00240             int total_written;
00241 
00242             // just wake up and delete the at file
00243             QString cmd = "#!/bin/sh\nrm " + fn;
00244             total_written = atfile.writeBlock(cmd.latin1(), cmd.length());
00245             if ( total_written != int(cmd.length()) ) {
00246                 QMessageBox::critical( 0, tr("Out of Space"),
00247                                        tr("Unable to schedule alarm.\n"
00248                                           "Please free up space and try again") );
00249                 atfile.close();
00250                 QFile::remove
00251                     ( atfile.name() );
00252                 return ;
00253             }
00254             atfile.close();
00255             unlink( atfilename );
00256             QDir d;
00257             d.rename(fn + ".new", fn);
00258             chmod(fn.latin1(), 0755);
00259             atfilename = fn;
00260             triggerAtd( FALSE );
00261         }
00262         else {
00263             qWarning("Cannot open atd file %s", fn.latin1());
00264         }
00265     }
00266 #else
00267     writeResumeAt ( at_secs );
00268 
00269 #endif
00270 
00271     // Qt timers (does the actual alarm)
00272     // from now in milliseconds
00273     //
00274     qDebug("AlarmServer waiting %d seconds", secs);
00275     startTimer( 1000 * secs + 500 );
00276 }
00277 
00278 void TimerReceiverObject::timerEvent( QTimerEvent * )
00279 {
00280     bool needSave = FALSE;
00281     killTimers();
00282     if (nearestTimerEvent) {
00283         if ( nearestTimerEvent->UTCtime
00284                 <= TimeConversion::toUTC(QDateTime::currentDateTime()) ) {
00285 #ifndef QT_NO_COP
00286             QCopEnvelope e( nearestTimerEvent->channel,
00287                             nearestTimerEvent->message );
00288             e << TimeConversion::fromUTC( nearestTimerEvent->UTCtime )
00289             << nearestTimerEvent->data;
00290 #endif
00291 
00292             timerEventList.remove( nearestTimerEvent );
00293             needSave = TRUE;
00294         }
00295         setNearestTimerEvent();
00296     }
00297     else {
00298         resetTimer();
00299     }
00300     if ( needSave )
00301         saveState();
00302 }
00303 
00394 void AlarmServer::addAlarm ( QDateTime when, const QCString& channel,
00395                              const QCString& message, int data)
00396 {
00397     if ( qApp->type() == QApplication::GuiServer ) {
00398         bool needSave = FALSE;
00399         // Here we are the server so either it has been directly called from
00400         // within the server or it has been sent to us from a client via QCop
00401         if (!timerEventReceiver)
00402             timerEventReceiver = new TimerReceiverObject;
00403 
00404         timerEventItem *newTimerEventItem = new timerEventItem;
00405         newTimerEventItem->UTCtime = TimeConversion::toUTC( when );
00406         newTimerEventItem->channel = channel;
00407         newTimerEventItem->message = message;
00408         newTimerEventItem->data = data;
00409         // explore the case of already having the event in here...
00410         QListIterator<timerEventItem> it( timerEventList );
00411         for ( ; *it; ++it )
00412             if ( *(*it) == *newTimerEventItem )
00413                 return ;
00414         // if we made it here, it is okay to add the item...
00415         timerEventList.append( newTimerEventItem );
00416         needSave = TRUE;
00417         // quicker than using setNearestTimerEvent()
00418         if ( nearestTimerEvent ) {
00419             if (newTimerEventItem->UTCtime < nearestTimerEvent->UTCtime) {
00420                 nearestTimerEvent = newTimerEventItem;
00421                 timerEventReceiver->killTimers();
00422                 timerEventReceiver->resetTimer();
00423             }
00424         }
00425         else {
00426             nearestTimerEvent = newTimerEventItem;
00427             timerEventReceiver->resetTimer();
00428         }
00429         if ( needSave )
00430             saveState();
00431     }
00432     else {
00433 #ifndef QT_NO_COP
00434         QCopEnvelope e( "QPE/System", "addAlarm(QDateTime,QCString,QCString,int)" );
00435         e << when << channel << message << data;
00436 #endif
00437 
00438     }
00439 }
00440 
00454 void AlarmServer::deleteAlarm (QDateTime when, const QCString& channel, const QCString& message, int data)
00455 {
00456     if ( qApp->type() == QApplication::GuiServer) {
00457         bool needSave = FALSE;
00458         if ( timerEventReceiver != NULL ) {
00459             timerEventReceiver->killTimers();
00460 
00461             // iterate over the list of events
00462             QListIterator<timerEventItem> it( timerEventList );
00463             time_t deleteTime = TimeConversion::toUTC( when );
00464             for ( ; *it; ++it ) {
00465                 // if its a match, delete it
00466                 if ( ( (*it)->UTCtime == deleteTime || when.isNull() )
00467                         && ( channel.isNull() || (*it)->channel == channel )
00468                         && ( message.isNull() || (*it)->message == message )
00469                         && ( data == -1 || (*it)->data == data ) ) {
00470                     // if it's first, then we need to update the timer
00471                     if ( (*it) == nearestTimerEvent ) {
00472                         timerEventList.remove(*it);
00473                         setNearestTimerEvent();
00474                     }
00475                     else {
00476                         timerEventList.remove(*it);
00477                     }
00478                     needSave = TRUE;
00479                 }
00480             }
00481             if ( nearestTimerEvent )
00482                 timerEventReceiver->resetTimer();
00483         }
00484         if ( needSave )
00485             saveState();
00486     }
00487     else {
00488 #ifndef QT_NO_COP
00489         QCopEnvelope e( "QPE/System", "deleteAlarm(QDateTime,QCString,QCString,int)" );
00490         e << when << channel << message << data;
00491 #endif
00492 
00493     }
00494 }
00495 
00502 void Global::writeHWClock()
00503 {
00504 #ifdef USE_ATD
00505     if ( !triggerAtd( TRUE ) ) {
00506         // atd not running? set it ourselves
00507         system("/sbin/hwclock --systohc"); // ##### UTC?
00508     }
00509 #else
00510     // hwclock is written on suspend
00511 #endif
00512 }
KDE Logo
This file is part of the documentation for OPIE Version 1.5.5.
Documentation copyright © 1997-2003 the KDE developers. 2003 OPIE developers
Generated on Tue Feb 10 20:24:02 2004 by doxygen 1.3.5 written by Dimitri van Heesch, © 1997-2001