mmsengine/mmswatcher/src/mmswatcher.cpp
changeset 0 72b543305e3a
child 26 ebe688cedc25
equal deleted inserted replaced
-1:000000000000 0:72b543305e3a
       
     1 /*
       
     2 * Copyright (c) 2002-2007 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:  
       
    15 *     Mms event watcher
       
    16 *
       
    17 */
       
    18 
       
    19 
       
    20 
       
    21 // INCLUDE FILES
       
    22 #include    <msvapi.h>
       
    23 #include    <msvids.h>
       
    24 #include    <msvuids.h>
       
    25 #include    <e32math.h>
       
    26 #include    <apparc.h>
       
    27 #include    <mtclreg.h>
       
    28 #include    <bacntf.h>
       
    29 #include    <centralrepository.h>
       
    30 #include    <CoreApplicationUIsSDKCRKeys.h>
       
    31 #include    <implementationproxy.h>
       
    32 
       
    33 #include    "mmsconst.h"
       
    34 #include    "mmsservercommon.h"
       
    35 #include    "mmscmds.h"
       
    36 #include    "mmswatcher.h"
       
    37 #include    "watcher.h"
       
    38 #include    "mmsclient.h"
       
    39 #include    "mmserrors.h"
       
    40 #include    "mmssettings.h" // for message variation directory
       
    41 #include    "MmsEnginePrivateCRKeys.h"
       
    42 #include    "mmscenrepobserver.h"
       
    43 #include    "mmspollingtimer.h"
       
    44 #include    "mmswatcherdebuglogging.h"
       
    45 #include    "mmssettings.h"
       
    46 
       
    47 // EXTERNAL DATA STRUCTURES
       
    48 
       
    49 // EXTERNAL FUNCTION PROTOTYPES  
       
    50 
       
    51 // CONSTANTS
       
    52 
       
    53 // MACROS
       
    54 
       
    55 // LOCAL CONSTANTS AND MACROS
       
    56 const TInt KPauseTime = 10 * KMmsMillion; // 10 s
       
    57 const TInt KMmsMessageGranularity = 5;
       
    58 const TInt KMmsStartDelay = 2 * KMmsMillion; // 2 s
       
    59 const TInt KMmsMediaAvailableDelay = 3 * KMmsMillion; // 3 s
       
    60 const TInt KMmsMessageVariationDelay = 5 * KMmsMillion; // 5 s
       
    61 const TInt KMmsDiskFullPause = 300 * KMmsMillion; // 5 min
       
    62 #ifdef __WINS__
       
    63 const TInt KMmsDefaultPollingInterval = 3 * KMmsMillion; 
       
    64 const TInt KMmsTidBuffer = 18;
       
    65 const TInt KMmsRowBufferLength = 128;
       
    66 #endif
       
    67 
       
    68 // MODULE DATA STRUCTURES
       
    69 
       
    70 // LOCAL FUNCTION PROTOTYPES
       
    71 
       
    72 // ==================== LOCAL FUNCTIONS ====================
       
    73 
       
    74 //
       
    75 // MmsWatcher is an ECOM plugin
       
    76 //
       
    77 
       
    78 const TImplementationProxy ImplementationTable[] = 
       
    79 	{
       
    80 	IMPLEMENTATION_PROXY_ENTRY(0x10005948, CMmsWatcher::NewL)
       
    81 	};
       
    82 
       
    83 EXPORT_C const TImplementationProxy* ImplementationGroupProxy(TInt& aTableCount)
       
    84 	{
       
    85 	aTableCount = sizeof(ImplementationTable) / sizeof(TImplementationProxy);
       
    86 	return ImplementationTable;
       
    87 	}
       
    88 
       
    89 // ================= MEMBER FUNCTIONS =======================
       
    90 
       
    91 // Helper class constructor and destructor
       
    92 CMmsPushEntry::CMmsPushEntry():
       
    93     iData( NULL ),
       
    94     iStatus( 0 ),
       
    95     iOperation( 0 )
       
    96     {
       
    97     }
       
    98 
       
    99 CMmsPushEntry::~CMmsPushEntry()
       
   100     {
       
   101     delete iData;
       
   102     delete iOperation;
       
   103     }
       
   104 
       
   105 // ---------------------------------------------------------
       
   106 // CMmsWatcher::CMmsWatcher
       
   107 // ---------------------------------------------------------
       
   108 //
       
   109 CMmsWatcher::CMmsWatcher(
       
   110     TInt aPriority,
       
   111     CWatcherLog& aLog)
       
   112     : CActive( aPriority ),
       
   113     iService( KMsvNullIndexEntryId ),
       
   114     iNotificationFolder( KMsvNullIndexEntryId ),
       
   115     iState( 0 ),
       
   116     iLog( aLog ),
       
   117     iLastError( KErrNone ),
       
   118     iSession( NULL ),
       
   119     iQueuedMessages( NULL ),
       
   120     iOperation( NULL )
       
   121     {
       
   122     CActiveScheduler::Add(this);
       
   123     }
       
   124 
       
   125 // ---------------------------------------------------------
       
   126 // CMmsWatcher::ConstructL
       
   127 // ---------------------------------------------------------
       
   128 //
       
   129 void CMmsWatcher::ConstructL()
       
   130     {
       
   131     LOG(_L("ConstructL"));
       
   132 
       
   133     //
       
   134     // ConstructL basically creates some member objects and 
       
   135     // starts a couple of observers
       
   136     //
       
   137     
       
   138     iEvents = KMmsReasonBoot;
       
   139     iQueuedMessages = new(ELeave) CArrayPtrFlat<CMmsPushEntry>( KMmsMessageGranularity );
       
   140     iState = EStartup;
       
   141     iMediaAvailable = ETrue;
       
   142     iMmsVersion = KMmsDefaultVersion;
       
   143 
       
   144     User::LeaveIfError( iTimer.CreateLocal() );
       
   145     User::LeaveIfError( iFs.Connect() );
       
   146 
       
   147     // Offline state observer
       
   148     iOfflineObserver = CMmsCenRepObserver::NewL();
       
   149     iOfflineObserver->SubscribeNotification(
       
   150         KCRUidCoreApplicationUIs,
       
   151         KCoreAppUIsNetworkConnectionAllowed,
       
   152         this );
       
   153 
       
   154 #ifdef __WINS__ // Support for localmode in WINS emulator
       
   155     iLocalModeIn = KMmsDefaultLocalModeDir;
       
   156     iPollingInterval = 0; 
       
   157     ReadLocalModeConfigData();
       
   158 #endif
       
   159 
       
   160     // CEnvironmentChangeNotifier detects changes in system time.
       
   161     // This is needed to run garbage collection if the user moves
       
   162     // system time too much towards future.
       
   163     // Task scheduler can handle short changes, but if the change is a large one,
       
   164     // task scheduler does not reschedule the entry, and we must do it ourselves.
       
   165   	iNotifier = CEnvironmentChangeNotifier::NewL(
       
   166   	    CActive::EPriorityLow, 
       
   167   	    TCallBack( EnvironmentChanged, this ) );
       
   168 	iNotifier->Start();
       
   169 
       
   170     //
       
   171     // NOTE: message server session is created just before used (in garbage 
       
   172     // collection). This ensures that MessageServer has properly booted.
       
   173     //
       
   174 
       
   175     // A little delay before any real actions in order to ensure everything
       
   176     // else is properly up and running.
       
   177     // iTimer cannot be active because it was just created
       
   178     iTimer.After( iStatus, KMmsStartDelay ); // 2 s - even this may be to much
       
   179     SetActive();
       
   180 #ifndef _NO_MMSS_LOGGING_
       
   181     if ( IsActive() )
       
   182         {
       
   183         LOG(_L("MMS watcher is now active" ));
       
   184         }
       
   185     else
       
   186         {
       
   187         LOG(_L("MMS watcher is NOT active" ));
       
   188         }
       
   189 #endif
       
   190     LOG(_L("End of ConstructL"));
       
   191     }
       
   192 
       
   193 // ---------------------------------------------------------
       
   194 // CMmsWatcher::NewL
       
   195 // ---------------------------------------------------------
       
   196 //
       
   197 CMmsWatcher* CMmsWatcher::NewL( TAny* aWatcherParams )
       
   198     {
       
   199     TWatcherParams* params = reinterpret_cast<TWatcherParams*>( aWatcherParams );
       
   200 	CMmsWatcher* self = new (ELeave) CMmsWatcher( EPriorityStandard, params->iLog );
       
   201     CleanupStack::PushL( self );
       
   202     self->ConstructL();
       
   203     CleanupStack::Pop( self );
       
   204     return self;
       
   205     }
       
   206     
       
   207 // ---------------------------------------------------------
       
   208 // CMmsWatcher::~CMmsWatcher
       
   209 // ---------------------------------------------------------
       
   210 //
       
   211 CMmsWatcher::~CMmsWatcher()
       
   212     {
       
   213     //
       
   214     // Watchers should be running all the time
       
   215     // 
       
   216     LOG(_L("Destructor called"));
       
   217 
       
   218     Cancel();
       
   219     delete iOperation; // unfinished garbage collection...
       
   220     if ( iQueuedMessages )
       
   221         {
       
   222         iQueuedMessages->ResetAndDestroy();
       
   223         }
       
   224     delete iQueuedMessages;
       
   225     iTimer.Close();
       
   226     iFs.Close();
       
   227     delete iSession;
       
   228     delete iNotifier;
       
   229     delete iOfflineObserver;
       
   230 #ifdef __WINS__ // Support for localmode polling in WINS emulator
       
   231     if( iPollingTimer )
       
   232         {
       
   233         delete iPollingTimer;
       
   234         }
       
   235 #endif
       
   236     }
       
   237 
       
   238 // ---------------------------------------------------------
       
   239 // CMmsWatcher::HandleCenRepNotificationL
       
   240 // ---------------------------------------------------------
       
   241 //
       
   242 void CMmsWatcher::HandleCenRepNotificationL(
       
   243     const TUid /*aRepositoryUid*/, // not needed currently because only one observer
       
   244     const TInt32 /*aKey*/,         // not needed currently because only one observer
       
   245     const TInt aValue )
       
   246     {
       
   247     // Offline state has changed.
       
   248     // If switch has been from offline to online -> invoke GarbageCollection
       
   249     LOG2(_L("Offline state: %d"), aValue );
       
   250 
       
   251     if( aValue != ECoreAppUIsNetworkConnectionAllowed )
       
   252         {
       
   253         // Now in offline -> nothing to do
       
   254         return;
       
   255         }
       
   256     else // back in online
       
   257         {
       
   258         iEvents |= KMmsReasonNetworkAllowed;
       
   259         TRequestStatus* status = &iStatus;
       
   260         if( iState != EStartup && iState != EMessageVariation )
       
   261             {
       
   262             iState = EGarbageCollection;
       
   263             }
       
   264         if( !IsActive() )
       
   265             {
       
   266             iStatus = KRequestPending;
       
   267             SetActive();
       
   268             User::RequestComplete( status, KErrNone );
       
   269             }
       
   270         }
       
   271     }
       
   272 
       
   273 
       
   274 // ---------------------------------------------------------
       
   275 // CMmsWatcher::HandleSessionEventL
       
   276 // ---------------------------------------------------------
       
   277 //
       
   278 void CMmsWatcher::HandleSessionEventL(
       
   279     TMsvSessionEvent aEvent,
       
   280     TAny* aArg1,
       
   281     TAny* aArg2,
       
   282     TAny* /*aArg3*/)
       
   283     {
       
   284     // CMmsSession requires as a parameter a class that implements
       
   285     // session observer interface (this function). Therefore this
       
   286     // function must always exist, though it may return immediately
       
   287     // without doing anything.
       
   288 
       
   289     // This function is needed to watch events related to moving
       
   290     // the message store in systems where the message store can
       
   291     // be moved to a memory card.
       
   292 
       
   293     // For test purposes, we use this as a test callback.
       
   294     // This function is called every time an entry changes.
       
   295 
       
   296     // we check what happened, and if an entry appears in
       
   297     // sent folder, we know that it has been sent to MMSC, and
       
   298     // we try to fetch it back.
       
   299 
       
   300     if ( aEvent == EMsvGeneralError )
       
   301         {
       
   302         return;
       
   303         }
       
   304 
       
   305 #ifdef __WINS__
       
   306     TMsvId parentId = KMsvNullIndexEntryId;
       
   307     if( aArg2 )
       
   308         {
       
   309         parentId = *(TMsvId*)aArg2;
       
   310         }
       
   311 
       
   312     CMsvEntrySelection* entries = NULL;
       
   313     if( aArg1 )
       
   314         {
       
   315         entries = STATIC_CAST(CMsvEntrySelection*, aArg1);
       
   316         }
       
   317 #endif
       
   318 
       
   319     TRequestStatus* status = &iStatus;
       
   320 
       
   321 #ifdef __WINS__
       
   322     TInt oldState = iState;
       
   323 #endif
       
   324 
       
   325     switch (aEvent)
       
   326         {
       
   327         case EMsvCloseSession:
       
   328             LOG(_L("Session event EMsvCloseSession"));
       
   329             // fall through on purpose
       
   330         case EMsvServerTerminated:
       
   331             LOG(_L("Session event EMsvServerTerminated"));
       
   332             if ( iSession )
       
   333                 {
       
   334                 delete iSession;
       
   335                 iSession = NULL;
       
   336                 // if we have deleted the session, we get no more
       
   337                 // events. We don't know when to restart.
       
   338                 }
       
   339             break;
       
   340         case EMsvMediaChanged:
       
   341             {
       
   342             // MessageStore drive has changed.
       
   343             LOG(_L("Session event EMsvMediaChanged"));
       
   344             LOG3(_L("- from drive %d to drive %d"), *(TInt*) aArg1, *(TInt*) aArg2 );
       
   345             iMediaAvailable = ETrue;
       
   346             iMessageDrive = *(TInt*) aArg2;
       
   347             if( *(TInt*) aArg1 != *(TInt*) aArg2 )
       
   348                 {
       
   349                 iEvents |= KMmsReasonMessageStoreChanged;
       
   350                 }
       
   351             // CenRep values for all entries must be updated
       
   352             // The ids of the MMS folders must be synchronized even if the drive has not changed
       
   353             // as we get this event when backup/restore happens, and in some case the restored
       
   354             // folder ids may be different from those in central repository (if restore is done
       
   355             // from a different phone or after phone has been flashed)
       
   356             GetMessagingEntriesL( ETrue );
       
   357             if( iEvents != 0 )
       
   358                 {
       
   359                 if ( iState != EStartup && iState != EMessageVariation )
       
   360                     {
       
   361                     iState = EGarbageCollection;
       
   362                     }
       
   363                 if ( !IsActive() )
       
   364                     {
       
   365                     iStatus = KRequestPending;
       
   366                     SetActive();
       
   367                     User::RequestComplete( status, KErrNone );
       
   368                     }
       
   369                 else
       
   370                     {
       
   371                     // if timer is running, cancel it because it is obvious
       
   372                     // that we have waited long enough and can start garbage
       
   373                     // collection now.
       
   374                     // Cancelling timer should bring us back to RunL()
       
   375                     LOG(_L("- already active, cancelling timer to speed up the process"));
       
   376                     iTimer.Cancel();
       
   377                     }
       
   378                 }
       
   379             break;
       
   380             }
       
   381         case EMsvMediaUnavailable:
       
   382             {
       
   383             LOG(_L("Session event EMsvMediaUnavailable"));
       
   384             LOG2(_L("- Drive %d no longer available"), *(TInt*) aArg1 );
       
   385             iMediaAvailable = EFalse;
       
   386             if ( *(TInt*) aArg1 == iMessageDrive )
       
   387                 {
       
   388                 iMediaUnavailableTime.UniversalTime();
       
   389                 }
       
   390             break;
       
   391             }
       
   392         case EMsvMediaAvailable:
       
   393             {
       
   394             LOG(_L("Session event EMsvMediaAvailable"));
       
   395             LOG2(_L("- Drive %d again available"), *(TInt*) aArg1 );
       
   396             // MessageStore has become available again. This could be due to
       
   397             // insertion of MMC card or after backup/restore operation 
       
   398             // has finished
       
   399             iMediaAvailable = ETrue;
       
   400             if ( !(iEvents & KMmsReasonMessageStoreChanged) )
       
   401                 {
       
   402                 iEvents |= KMmsReasonHotswap;
       
   403                 iEvents |= KMmsReasonBackupEnded;
       
   404                 }
       
   405             if( iState != EStartup && iState != EMessageVariation )
       
   406                 {
       
   407                 iState = EGarbageCollection;
       
   408                 }
       
   409             if( !IsActive() )
       
   410                 {
       
   411                 // Delay here to prevent EMsvMediaAvailable from triggering
       
   412                 // Garbage collection when message store is moved to another drive.
       
   413                 // When message store is moved, the store is copied first.
       
   414                 // After the copy is complete, we get EMsvMediaAvailable event,
       
   415                 // but we must not start garbage collection on the original drive
       
   416                 // because the message store is about to be changed.
       
   417                 //
       
   418                 // 3 s delay - we are cautious
       
   419                 // if we are not active, timer cannot be running - no need to cancel
       
   420                 iTimer.After( iStatus, KMmsMediaAvailableDelay ); 
       
   421                 SetActive();
       
   422                 }
       
   423             break;
       
   424             }
       
   425         case EMsvMediaIncorrect:
       
   426             {
       
   427             LOG(_L("Session event EMsvMediaIncorrect"));
       
   428             LOG2(_L("- Incorrect disk in drive %d"), *(TInt*) aArg1 );
       
   429             break;
       
   430             }
       
   431         case EMsvServerReady:
       
   432             {
       
   433             LOG(_L("Session event EMsvServerReady"));
       
   434             break;
       
   435             }
       
   436 #ifdef __WINS__
       
   437         case EMsvEntriesCreated:
       
   438         case EMsvEntriesMoved:
       
   439             {
       
   440             // 
       
   441             // These events are relevant in Localmode only
       
   442             // 
       
   443             if ( parentId != KMsvSentEntryId )
       
   444                 {
       
   445                 // only sent items are interesting
       
   446                 return;
       
   447                 }
       
   448             
       
   449             // Get localmode setting from CenRep
       
   450             TBool localMode = EFalse;
       
   451             TInt retval = KErrNone;
       
   452             TRAP( retval, 
       
   453                 {
       
   454                 localMode = LocalModeL();
       
   455                 });
       
   456             #ifndef _NO_MMSS_LOGGING_
       
   457             if( retval != KErrNone )
       
   458                 {
       
   459                 LOG(_L("ERROR connecting CenRep, defaulting to normal mode"));
       
   460                 }
       
   461             #endif
       
   462             if( localMode == EFalse )
       
   463                 {
       
   464                 // Only localmode case is interesting
       
   465                 return;
       
   466                 }
       
   467             
       
   468             // Now invoke the server mtm to fetch it.
       
   469             // We queue the entry, set ourselves complete and
       
   470             // Let the RunL initiate the fetching.
       
   471             // We don't do anything unless the entry was MMS entry
       
   472             // Then get a list of files in MMSC directory, and
       
   473             // create notifications for them.
       
   474             // This will probably produce extra notifications,
       
   475             // but it is good to test that notifications about
       
   476             // unexisting messages or duplicates won't mess 
       
   477             // up the system.
       
   478             // Messages should be fetched one at a time, so that
       
   479             // there should not be too many conflicts.
       
   480             TInt notifications = 0;
       
   481             TInt size = 1;
       
   482             TEntry entry;
       
   483             TInt err = KErrNone;
       
   484             CDir* fileList = NULL;
       
   485             err = iFs.Entry( iLocalModeIn, entry );
       
   486             if ( err == KErrNone )
       
   487                 {
       
   488                 err = iFs.SetSessionPath( iLocalModeIn );
       
   489                 TFindFile finder( iFs );
       
   490                 _LIT( KWild, "*.mms" );
       
   491                 if ( err == KErrNone )
       
   492                     {
       
   493                     err = finder.FindWildByPath( KWild, NULL, fileList );
       
   494                     }
       
   495                 if ( err == KErrNone )
       
   496                     {
       
   497                     notifications = fileList->Count();
       
   498                     }
       
   499                 TInt i;
       
   500                 for (i = 0; i < notifications; i++ )
       
   501                     {
       
   502                     // generate notification from filename and file size
       
   503                     TParse fullEntry;
       
   504                     fullEntry.Set( ( ( *fileList )[i] ).iName, &iLocalModeIn, NULL );
       
   505                     TBuf8<KMaxFileName> buffer;
       
   506                     buffer.Copy( fullEntry.FullName() );
       
   507                     RFile file;
       
   508                     err = file.Open(iFs, fullEntry.FullName(), EFileShareAny );
       
   509                     if (err == KErrNone )
       
   510                         {
       
   511                         err = file.Size(size);
       
   512                         }
       
   513                     file.Close();
       
   514                     HBufC8 * notif = CreateNotificationL(buffer, size);
       
   515                     CleanupStack::PushL( notif );
       
   516                     TBool found = EFalse;
       
   517                     TInt i = 0;
       
   518                     while ( found == EFalse && i < iQueuedMessages->Count() ) 
       
   519                         {
       
   520                         if ( iQueuedMessages->At(i)->iData->Compare(*notif) == 0 )
       
   521                             {
       
   522                             found = ETrue;
       
   523                             }
       
   524                         i++;
       
   525                         }
       
   526                     if (! found )
       
   527                         {
       
   528                         CMmsPushEntry* newEntry = new( ELeave )CMmsPushEntry;
       
   529                         newEntry->iData = notif;
       
   530                         newEntry->iStatus = EWaiting;
       
   531                         newEntry->iOperation = NULL;
       
   532                         CleanupStack::Pop( notif );
       
   533                         CleanupStack::PushL( newEntry );
       
   534                         iQueuedMessages->AppendL( newEntry );
       
   535                         // notif has gone to our member...
       
   536                         CleanupStack::Pop( newEntry );
       
   537                         }
       
   538                     else
       
   539                         {
       
   540                         // get rid of notif
       
   541                         CleanupStack::PopAndDestroy( notif );
       
   542                         }
       
   543                     iState = EScheduling;
       
   544                     }
       
   545                 }
       
   546 
       
   547             if ( oldState == EWaiting && notifications > 0)
       
   548                 {
       
   549                 // if we are not currently sending something to server,
       
   550                 // we must declare ourselves complete in order to get back to
       
   551                 // RunL.
       
   552                 // Actually we should be active already, but 
       
   553                 // we say so just in case (to prevent stray signal)
       
   554                 if ( !IsActive() )
       
   555                     {
       
   556                     iStatus = KRequestPending;
       
   557                     SetActive();
       
   558                     User::RequestComplete( status, KErrNone );
       
   559                     }
       
   560                 }
       
   561             break;
       
   562             }
       
   563 #endif // __WINS__
       
   564 
       
   565         default:
       
   566             break;
       
   567         }
       
   568     }
       
   569 
       
   570 // ---------------------------------------------------------
       
   571 // CMmsWatcher::EnvironmentChanged
       
   572 // ---------------------------------------------------------
       
   573 //
       
   574 TInt CMmsWatcher::EnvironmentChanged(TAny* aThis )
       
   575 	{
       
   576 	CMmsWatcher* self = reinterpret_cast<CMmsWatcher*>(aThis);
       
   577 	self->HandleEnvironmentChange();
       
   578 	return KErrNone;
       
   579 	}
       
   580 
       
   581 // ---------------------------------------------------------
       
   582 // CMmsWatcher::HandleEnvironmentChange
       
   583 // ---------------------------------------------------------
       
   584 //
       
   585 void CMmsWatcher::HandleEnvironmentChange()
       
   586     {
       
   587 
       
   588   	TInt changes = iNotifier->Change();
       
   589 	if ( changes & EChangesSystemTime )
       
   590         {
       
   591 #ifndef _NO_MMSS_LOGGING_
       
   592         LOG(_L("System time Change"));
       
   593         TTime time;
       
   594 		time.UniversalTime();
       
   595 		TDateTime due(time.DateTime());
       
   596 		LOG7( _L("- system time is now: [%02d/%02d/%d] @ %02d:%02d:%02d"),
       
   597 		    due.Day(), (TInt)due.Month() + 1, due.Year(), due.Hour(), due.Minute(), due.Second());
       
   598 #endif
       
   599         iEvents |= KMmsReasonEnvironmentTimeChanged;
       
   600         TRequestStatus* status = &iStatus;
       
   601         if ( iState != EStartup && iState != EMessageVariation )
       
   602             {
       
   603             iState = EGarbageCollection;
       
   604             }
       
   605 
       
   606         if ( !IsActive() )
       
   607             {
       
   608             iStatus = KRequestPending;
       
   609             SetActive();
       
   610             User::RequestComplete( status, KErrNone );
       
   611             }
       
   612         }
       
   613     }
       
   614 
       
   615 // ---------------------------------------------------------
       
   616 // CMmsWatcher::Dequeue
       
   617 // ---------------------------------------------------------
       
   618 //
       
   619 void CMmsWatcher::Dequeue()
       
   620     {
       
   621     delete iQueuedMessages->At( 0 );
       
   622     iQueuedMessages->Delete( 0 );
       
   623     iQueuedMessages->Compress();
       
   624     }
       
   625 
       
   626 // ---------------------------------------------------------
       
   627 // CMmsWatcher::RemoveSent
       
   628 // ---------------------------------------------------------
       
   629 //
       
   630 void CMmsWatcher::RemoveSent()
       
   631     {
       
   632     LOG(_L("RemoveSent called"));
       
   633     while (iQueuedMessages->Count() > 0 &&
       
   634         iQueuedMessages->At(0)->iStatus != EWaiting )
       
   635         {
       
   636         // done, delete
       
   637         Dequeue();
       
   638         }
       
   639     }
       
   640 
       
   641 // ---------------------------------------------------------
       
   642 // CMmsWatcher::HandleNextInQueueL
       
   643 // ---------------------------------------------------------
       
   644 //
       
   645 void CMmsWatcher::HandleNextInQueueL()
       
   646     {
       
   647     // access to first entry in queue need not be protected by
       
   648     // semaphore:
       
   649     // This function is called only after we have decided
       
   650     // that there is at least one entry.
       
   651     // Entries are removed only when we get to the RunL
       
   652     // the next time (we are still in DoRunL now).
       
   653     // Adding new entries to the end of the array does not hurt us.
       
   654     // Removing and adding entries must be mutally exclusive,
       
   655     // as entries are added to the end and removed from the beginning.
       
   656 
       
   657     LOG(_L("HandleNextInQueueL"));
       
   658     
       
   659     if( !iSession )
       
   660         {
       
   661         // if we have lost our session, we must try to get a new one
       
   662         OpenSessionL();
       
   663         }
       
   664         
       
   665     // If there was no service entry when we were started, we must
       
   666     // check if one has appeared now. Otherwise message server does
       
   667     // not know where to send the request
       
   668 
       
   669     if( iService == KMsvNullIndexEntryId || 
       
   670         iNotificationFolder == KMsvNullIndexEntryId )
       
   671         {
       
   672         GetMessagingEntriesL();
       
   673         }
       
   674 
       
   675     if( iService == KMsvNullIndexEntryId || 
       
   676         iNotificationFolder == KMsvNullIndexEntryId )
       
   677         {
       
   678         // Something really weird is going on.
       
   679         User::Leave( KErrNotFound );
       
   680         }
       
   681 
       
   682     TMsvId entryId = CreateEntryL( iNotificationFolder );
       
   683 
       
   684     CMsvEntrySelection* selection = new ( ELeave ) CMsvEntrySelection;
       
   685     CleanupStack::PushL( selection );
       
   686 
       
   687     // Now we have an entry that says: local service, MMS MTM
       
   688     if ( entryId != KMsvNullIndexEntryId )
       
   689         {
       
   690         selection->AppendL( entryId );
       
   691         }
       
   692     else
       
   693         {
       
   694         selection->AppendL( iService );
       
   695         }
       
   696   
       
   697     iQueuedMessages->At(0)->iStatus = EScheduling;
       
   698     TWatcherParameters parameters; // initialized to zero
       
   699     TWatcherParametersBuf paramPack( parameters );
       
   700 
       
   701     iQueuedMessages->At(0)->iOperation = iSession->TransferCommandL(
       
   702         *selection, EMmsDecodePushedMessage, paramPack, iStatus );
       
   703 
       
   704     CleanupStack::PopAndDestroy( selection );
       
   705     SetActive();
       
   706     }
       
   707     
       
   708 // ---------------------------------------------------------
       
   709 // CMmsWatcher::RunL()
       
   710 // ---------------------------------------------------------
       
   711 //
       
   712 void CMmsWatcher::RunL()
       
   713     {
       
   714     LOG2(_L("RunL (iStatus = %d)"), iStatus.Int());
       
   715 
       
   716     iLastError = iStatus.Int();
       
   717     if ( iLastError == KErrCancel )
       
   718         {
       
   719         // cancel occurs only if a new event cancels timer
       
   720         iLastError = KErrNone;
       
   721         }
       
   722 
       
   723     // when we get here after doing garbage collection,
       
   724     // the operation can go
       
   725     if( iOperation )
       
   726         {
       
   727         if( iOperation->iStatus == KRequestPending )
       
   728             {
       
   729             LOG(_L("- operation still pending"));
       
   730             // 5 second delay needed for message variation
       
   731             iTimer.After( iStatus, KMmsMessageVariationDelay );
       
   732             SetActive();
       
   733             return;
       
   734             }
       
   735         else
       
   736             {
       
   737             LOG(_L("- operation completed"));
       
   738             if( iLastError == KErrNone )
       
   739                 {
       
   740                 iLastError = iOperation->iStatus.Int();
       
   741                 }
       
   742             delete iOperation;
       
   743             iOperation = NULL;
       
   744             }
       
   745         }
       
   746 
       
   747     // Now we check if Garbage collection was successful.
       
   748     // If not, old events must be retried
       
   749 
       
   750     TBool onlineEvent = iEvents & KMmsReasonNetworkAllowed;
       
   751 
       
   752     if ( iLastError != KErrNone )
       
   753         {
       
   754         // We combine all flags in case we are getting loads of events
       
   755         // faster than we can handle them.
       
   756         iEvents |= iOldEvents;
       
   757         }
       
   758 
       
   759     // clear these now to prevent endless loop.
       
   760     iOldEvents = 0;
       
   761 
       
   762     // If we have got error in the range KMsvMediaUnavailable - KMsvIndexRestore
       
   763     // we must wait until we get media available event, otherwise we are in trouble.
       
   764     if ( iLastError <= (TInt) KMsvMediaUnavailable &&
       
   765         iLastError >= (TInt) KMsvIndexRestore  && !iMediaAvailable )
       
   766         {
       
   767         // media is not available, no use to retry until we get media available event.
       
   768         // If media is available, it is worth retrying in 10 s.
       
   769         return;
       
   770         }
       
   771 
       
   772     if ( iLastError == KMmsErrorOfflineMode && !onlineEvent )
       
   773         {
       
   774         // if we are not yet online, wait for event before retrying
       
   775         return;
       
   776         }
       
   777 
       
   778     TRAPD( error, DoRunL() );
       
   779     if( error )
       
   780         {
       
   781         LOG2(_L("DoRunL error %d"), error );
       
   782         // An error occurred - try again after a while
       
   783         TInt pause = KPauseTime; // default 10 s
       
   784         if ( error == KErrDiskFull )
       
   785             {
       
   786             pause = KMmsDiskFullPause; // 5 min
       
   787             }
       
   788         LOG2(_L("- Retry after %d seconds"), pause/KMmsMillion );
       
   789         iTimer.Cancel();
       
   790         iTimer.After(iStatus, pause);
       
   791         if ( !IsActive() )
       
   792             {
       
   793             SetActive();
       
   794             }
       
   795         } // error
       
   796 
       
   797     iLastError = error;
       
   798 
       
   799     // Handle next in queue sets us active again, if there
       
   800     // are more pushed messages to be sent to Server MTM.
       
   801     // If there is nothing to send, we are not active.
       
   802     // In that case the callback must call HandleNextInQueueL()
       
   803     // to start the active loop.
       
   804     }
       
   805 
       
   806 
       
   807 // ---------------------------------------------------------
       
   808 // CMmsWatcher::DoRunL()
       
   809 // ---------------------------------------------------------
       
   810 //
       
   811 void CMmsWatcher::DoRunL()
       
   812     {
       
   813     LOG2(_L("DoRunL, state == %d"), iState);
       
   814     switch ( iState )
       
   815         {
       
   816         case EStartup:
       
   817             // Make sure no error in status
       
   818             StartupL();
       
   819             iState = EMessageVariation;
       
   820             break;
       
   821         case EMessageVariation:
       
   822             {
       
   823             // Message variation is tried every time because watchers are no started
       
   824             // so late that first boot indicator is always off.
       
   825             // Precreated messages are in private directory and cannot be accessed
       
   826             // by outsiders except by those that have ALL FILES capability
       
   827             MessageVariationL();                
       
   828             iState = EGarbageCollection;
       
   829 #ifdef __WINS__
       
   830             // Support for localmode polling in WINS emulator is started here if needed
       
   831             if( iPollingInterval >= KMmsDefaultPollingInterval ) // ReadLocalModeConfigDataL might have changed it
       
   832                 {
       
   833                 iPollingTimer = CMmsPollingTimer::NewL();
       
   834                 iPollingTimer->Start( this, iPollingInterval );
       
   835                 }
       
   836 #endif
       
   837             break;
       
   838             }
       
   839         case EGarbageCollection:
       
   840             GarbageCollectionL();
       
   841             iState = EScheduling;
       
   842             break;
       
   843         case EScheduling:
       
   844             {
       
   845             TInt count = 0;
       
   846             if ( iLastError != KErrNone )
       
   847                 {
       
   848                 LOG2(_L("iLastError %d"), iLastError );
       
   849                 // I assume only the first one has been tried and failed.
       
   850                 // However, we retry all.
       
   851                 count = iQueuedMessages->Count();
       
   852                 TInt i;
       
   853                 for ( i = 0; i < count; i++ )
       
   854                     {
       
   855                     iQueuedMessages->At( i )->iStatus = EWaiting;
       
   856                     }
       
   857                 // Leave here, and RunL will retry after a pause
       
   858                 User::Leave( iLastError );
       
   859                 }
       
   860 
       
   861             // Now we must check if there is anything to send to 
       
   862             // MMS server mtm
       
   863             if (iQueuedMessages->Count() > 0)
       
   864                 {
       
   865                 RemoveSent();
       
   866                 }
       
   867             count = iQueuedMessages->Count();
       
   868             // If there is anything left, queue the next one
       
   869             if ( count > 0 )
       
   870                 {
       
   871                 HandleNextInQueueL();
       
   872                 }
       
   873             else if ( iEvents != 0 )
       
   874                 {
       
   875                 iState = EGarbageCollection;
       
   876                 iStatus = KRequestPending;
       
   877                 TRequestStatus* status = &iStatus;
       
   878                 SetActive();
       
   879                 User::RequestComplete( status, KErrNone );
       
   880                 }
       
   881             else
       
   882                 {
       
   883                 // If there is nothing left, continue waiting
       
   884                 iState = EWaiting;
       
   885                 }
       
   886             break;
       
   887             }
       
   888         case EWaiting:
       
   889             iStatus = KErrNone;
       
   890             break;
       
   891         default:
       
   892             __ASSERT_DEBUG(EFalse, gPanic(EMmsUnknownState));
       
   893             break;
       
   894         }
       
   895     }
       
   896 
       
   897 // ---------------------------------------------------------
       
   898 // CMmsWatcher::DoCancel
       
   899 // ---------------------------------------------------------
       
   900 //
       
   901 void CMmsWatcher::DoCancel()
       
   902     {
       
   903     LOG(_L("DoCancel"));
       
   904 
       
   905     iTimer.Cancel();
       
   906     if ( iOperation )
       
   907         {
       
   908         iOperation->Cancel();
       
   909         }
       
   910     // only one operation at a time is active
       
   911     if ( iQueuedMessages->Count() > 0 && 
       
   912         iQueuedMessages->At(0)->iOperation )
       
   913         {
       
   914         iQueuedMessages->At(0)->iOperation->Cancel();
       
   915         }
       
   916 
       
   917     iState = EInvalid;
       
   918     }
       
   919 
       
   920 // ---------------------------------------------------------
       
   921 // CMmsWatcher::StartupL()
       
   922 // ---------------------------------------------------------
       
   923 //
       
   924 void CMmsWatcher::StartupL()
       
   925     {
       
   926     LOG(_L("StartupL"));
       
   927     TInt error = KErrNone;
       
   928     
       
   929     iMessageDrive = EDriveC; // default
       
   930     // Open session to MessageServer
       
   931     TRAP( error, OpenSessionL() );
       
   932     // We ignore the error. If the session could not be opened now,
       
   933     // it will be retried later
       
   934     error = KErrNone;
       
   935     
       
   936     // Get serviceId and NotificationFolderId from MMS settings
       
   937     TRAP( error, GetMessagingEntriesL() );
       
   938     if( error )
       
   939         {
       
   940         LOG(_L("- ERROR reading settings"));
       
   941         }
       
   942     
       
   943     // Complete in order to get back to RunL
       
   944     iStatus = KRequestPending;
       
   945     TRequestStatus* status = &iStatus;
       
   946     SetActive();
       
   947     User::RequestComplete( status, KErrNone );
       
   948     LOG(_L("- End of StartupL"));
       
   949     }
       
   950 
       
   951 // ---------------------------------------------------------
       
   952 // CMmsWatcher::GarbageCollectionL()
       
   953 // ---------------------------------------------------------
       
   954 //
       
   955 void CMmsWatcher::GarbageCollectionL()
       
   956     {
       
   957     LOG(_L("GarbageCollectionL"));
       
   958 
       
   959     // Open session in case the message server has died
       
   960     // but we have received an event from elsewhere    
       
   961     if( !iSession )
       
   962         {
       
   963         // if we have lost our session, we must try to get a new one
       
   964         OpenSessionL();
       
   965         }
       
   966 
       
   967     if ( iService != KMsvNullIndexEntryId )
       
   968         {
       
   969         // if there is no service, there is no garbage either...
       
   970         CMsvEntrySelection* selection = new( ELeave ) CMsvEntrySelection;
       
   971         CleanupStack::PushL( selection );
       
   972         selection->AppendL( iService );
       
   973         // Start Garbage collection
       
   974         TMMSGarbageCollectionParameters parameters; // initialized to zero
       
   975         parameters.iReasonFlags = iEvents;
       
   976         parameters.iMediaUnavailableTime = iMediaUnavailableTime;
       
   977         TMMSGarbageCollectionParametersBuf paramPack( parameters );
       
   978         LOG(_L("Invoking garbage collection"));
       
   979         iOperation = iSession->TransferCommandL(
       
   980             *selection, EMmsGarbageCollection, paramPack, iStatus );
       
   981         CleanupStack::PopAndDestroy( selection );
       
   982         // These events were handled.
       
   983         iOldEvents = iEvents; 
       
   984         iEvents = 0;
       
   985         iMediaUnavailableTime = 0;
       
   986         SetActive();
       
   987         }
       
   988     LOG(_L("- End of GarbageCollectionL"));
       
   989     }
       
   990 
       
   991 // ---------------------------------------------------------
       
   992 // CMmsWatcher::MessageVariationL()
       
   993 // ---------------------------------------------------------
       
   994 //
       
   995 void CMmsWatcher::MessageVariationL()
       
   996     {
       
   997     LOG(_L("MessageVariationL"));
       
   998     if( !iSession )
       
   999         {
       
  1000         // if we have lost our session, we must try to get a new one
       
  1001         OpenSessionL();
       
  1002         }
       
  1003 
       
  1004     // If there is no service, it must be created first
       
  1005     if( iService == KMsvNullIndexEntryId )
       
  1006         {
       
  1007         LOG(_L("no service - must create one"));
       
  1008         GetMessagingEntriesL();
       
  1009         }
       
  1010     CMsvEntrySelection* selection = new(ELeave) CMsvEntrySelection;
       
  1011     CleanupStack::PushL( selection );
       
  1012     selection->AppendL( iService );
       
  1013     LOG(_L("Invoking message variation"));
       
  1014     iOperation = iSession->TransferCommandL(
       
  1015         *selection, EMmsMessageGeneration, TPtrC8(), iStatus );
       
  1016     CleanupStack::PopAndDestroy( selection );
       
  1017     SetActive();
       
  1018 
       
  1019     LOG(_L("End of MessageVariationL"));
       
  1020     }
       
  1021 
       
  1022 // ---------------------------------------------------------
       
  1023 // CMmsWatcher::CreateEntryL()
       
  1024 // ---------------------------------------------------------
       
  1025 //
       
  1026 TMsvId CMmsWatcher::CreateEntryL( TMsvId aFolder )
       
  1027     {
       
  1028     TMsvId entryId = KMsvNullIndexEntryId;
       
  1029 
       
  1030     if ( aFolder == KMsvNullIndexEntryId )
       
  1031         {
       
  1032         // no folder no entry
       
  1033         return entryId;
       
  1034         }
       
  1035     
       
  1036     if( !iSession )
       
  1037         {
       
  1038         // if we have lost our session, we must try to get a new one
       
  1039         OpenSessionL();
       
  1040         }
       
  1041     CMsvEntry* cEntry = iSession->GetEntryL( aFolder );
       
  1042     CleanupStack::PushL( cEntry ); // ***
       
  1043 
       
  1044     TMsvEntry entry;
       
  1045     entry.iType = KUidMsvMessageEntry;
       
  1046     entry.iMtm = KUidMsgTypeMultimedia;
       
  1047     entry.SetVisible( ETrue );
       
  1048     // If we want to put data here, InPreparation must be set to false first
       
  1049     entry.SetInPreparation( EFalse );
       
  1050     entry.iServiceId = KMsvLocalServiceIndexEntryId;
       
  1051     entry.iRelatedId = iService;
       
  1052     entry.iMtmData2 = KMmsNotificationBinary;
       
  1053     cEntry->CreateL( entry );
       
  1054     entryId = entry.Id();
       
  1055 
       
  1056     //
       
  1057     // Stream 
       
  1058     // 1) length of the data as 32 bit integer
       
  1059     // 2) pushed message data
       
  1060     // into created entry's stream  
       
  1061     //
       
  1062     cEntry->SetEntryL( entryId );
       
  1063     CMsvStore* store = cEntry->EditStoreL();
       
  1064     CleanupStack::PushL( store );   // ***
       
  1065     RMsvWriteStream outs;
       
  1066     outs.AssignLC( *store, KUidBinaryNotificationStream ); // ***
       
  1067     outs.WriteUint32L( iQueuedMessages->At(0)->iData->Size() );
       
  1068     outs.WriteL( *iQueuedMessages->At(0)->iData );
       
  1069     outs.CommitL();
       
  1070     outs.Close();
       
  1071     store->CommitL();
       
  1072     CleanupStack::PopAndDestroy( &outs ); // close outs
       
  1073     CleanupStack::PopAndDestroy( store );
       
  1074     CleanupStack::PopAndDestroy( cEntry );
       
  1075 
       
  1076     return entryId;
       
  1077     }
       
  1078 
       
  1079 // ---------------------------------------------------------
       
  1080 // CMmsWatcher::OpenSessionL()
       
  1081 // ---------------------------------------------------------
       
  1082 //
       
  1083 void CMmsWatcher::OpenSessionL()
       
  1084     {
       
  1085     LOG(_L("Opening session"));
       
  1086     if ( !iSession )
       
  1087         {
       
  1088         // leaves if session cannot be opened
       
  1089         iSession = CMsvSession::OpenSyncL( *this );
       
  1090         }
       
  1091         
       
  1092     TRAPD( error2, iMessageDrive = iSession->CurrentDriveL() );
       
  1093     if( error2 != KErrNone )
       
  1094         {
       
  1095         // Using default
       
  1096         iMessageDrive = EDriveC;
       
  1097         }
       
  1098     }
       
  1099 
       
  1100 // ---------------------------------------------------------
       
  1101 // CMmsWatcher::CreateNotificationL()
       
  1102 // ---------------------------------------------------------
       
  1103 //
       
  1104 #ifdef __WINS__
       
  1105 HBufC8* CMmsWatcher::CreateNotificationL(TDesC8& aUrl, TInt aSize)
       
  1106     {
       
  1107     // for test purposes aUrl will contain the filename.
       
  1108     TInt position = 0;
       
  1109     CBufFlat* encodeBuffer = CBufFlat::NewL( 0x400 );
       
  1110     CleanupStack::PushL( encodeBuffer ); // ***
       
  1111     encodeBuffer->ResizeL( 0 );
       
  1112     encodeBuffer->ResizeL( 0x400 );
       
  1113 
       
  1114     // encode message type
       
  1115     encodeBuffer->Write( position, &KMmsAssignedMessageType, 1 );
       
  1116     position++;
       
  1117     encodeBuffer->Write( position, &KMmsMessageTypeMNotificationInd, 1 );
       
  1118     position++;
       
  1119 
       
  1120     // encode tid
       
  1121     encodeBuffer->Write( position, &KMmsAssignedTID, 1 );
       
  1122     position++;
       
  1123 
       
  1124     // generate random TID
       
  1125     TPtrC8 cid;
       
  1126     TBufC8<KMmsTidBuffer> target;
       
  1127     TTime now;
       
  1128     now.UniversalTime();
       
  1129     TInt random = 0;
       
  1130 
       
  1131     // we don't generate a true random TID: We generate the
       
  1132     // TID from the URL so that if we generate a notification
       
  1133     // twice from the same file, we get the same TID and the
       
  1134     // same URL. This way we can test the pruning function in
       
  1135     // server MTM
       
  1136 
       
  1137     TInt i;
       
  1138     for ( i = 0; i < aUrl.Length(); i++ )
       
  1139         {
       
  1140         random += aUrl[ i ];
       
  1141         }
       
  1142 
       
  1143     target.Des().Num( random );
       
  1144     cid.Set( target.Des() );
       
  1145     
       
  1146     TInt length = cid.Length();
       
  1147     encodeBuffer->Write( position, cid, length );
       
  1148     position += length;
       
  1149     encodeBuffer->Write( position, &KMmsNull, 1 );
       
  1150     position++;
       
  1151 
       
  1152     encodeBuffer->Write( position, &KMmsAssignedMmsVersion, 1 );
       
  1153     position++;
       
  1154     TUint8 version = iMmsVersion | 0x80;
       
  1155     encodeBuffer->Write( position, &version, 1 );
       
  1156     position++;
       
  1157 
       
  1158     // from is optional - we don't care
       
  1159 
       
  1160     // message class
       
  1161     encodeBuffer->Write( position, &KMmsAssignedMessageClass, 1 );
       
  1162     position++;
       
  1163     encodeBuffer->Write( position, &KMmsMessageClassPersonal, 1 );
       
  1164     position++;
       
  1165 
       
  1166     // message size
       
  1167     encodeBuffer->Write( position, &KMmsAssignedMessageSize, 1 );
       
  1168     position++;
       
  1169 
       
  1170     TUint8 byte;
       
  1171     const TInt KConst4 = 4;
       
  1172     const TInt KConst8 = 8;
       
  1173     TUint8 array[KConst4];
       
  1174 
       
  1175     if ( aSize <= 0x7f )
       
  1176         {
       
  1177         byte = ( TInt8 ) aSize;
       
  1178         byte |= 0x80;
       
  1179         encodeBuffer->Write( position, &byte, 1);
       
  1180         position++;
       
  1181         }
       
  1182     else
       
  1183         {
       
  1184 
       
  1185         length = KConst4;
       
  1186 
       
  1187         TUint temp = aSize;
       
  1188         byte = TInt8( ( temp >> 24 ) & 0xFF );
       
  1189 
       
  1190         while ( byte == 0 && length > 0 )
       
  1191             {
       
  1192             length--;
       
  1193             temp = temp << KConst8;
       
  1194             byte = TInt8( ( temp >> 24 ) & 0xFF );
       
  1195             }
       
  1196 
       
  1197         for ( i = 0; i < length; i++ )
       
  1198             {
       
  1199             array[i] = TInt8( ( temp >> ( KConst8 * (3 - i) ) ) & 0xFF );
       
  1200             }
       
  1201 
       
  1202         // write short length
       
  1203         encodeBuffer->Write( position, &length, 1 );
       
  1204         position++;
       
  1205 
       
  1206         // write as many bytes as were non-zero
       
  1207         // There will be always at least one byte in the array
       
  1208         // because aSize > 127 if we are here
       
  1209         encodeBuffer->Write( position, &array[0], length );
       
  1210         position+= length;
       
  1211         }
       
  1212 
       
  1213     // expiry
       
  1214 
       
  1215     const TUint KTenHours = 10 * 60 * 60; // 10 hours
       
  1216     TUint temp = KTenHours;
       
  1217     encodeBuffer->Write( position, &KMmsAssignedExpiry, 1 );
       
  1218     position++;
       
  1219 
       
  1220     // calculate value length
       
  1221 
       
  1222     length = KConst4;
       
  1223     byte = TInt8( ( temp >> 24 ) & 0xFF );
       
  1224 
       
  1225     while ( byte == 0 && length > 0 )
       
  1226        {
       
  1227        length--;
       
  1228        temp = temp << KConst8;
       
  1229        byte = TInt8( ( temp >> 24 ) & 0xFF );
       
  1230        }
       
  1231 
       
  1232     // now add short length and absolute/relative token
       
  1233 
       
  1234     length += 2;
       
  1235 
       
  1236     encodeBuffer->Write( position, &length, 1 );
       
  1237     position++;
       
  1238 
       
  1239     encodeBuffer->Write( position, &KMmsRelativeToken, 1 );
       
  1240     position++;
       
  1241 
       
  1242     length -= 2; // actual integer length 
       
  1243 
       
  1244     for (i = 0; i < length; i++)
       
  1245         {
       
  1246         array[i] = TInt8( ( temp >> ( KConst8 * (3 - i) ) ) & 0xFF );
       
  1247         }
       
  1248 
       
  1249     // write short length
       
  1250     encodeBuffer->Write( position, &length, 1 );
       
  1251     position++;
       
  1252 
       
  1253     // write as many bytes as were non-zero
       
  1254     encodeBuffer->Write( position, &array[0], length );
       
  1255     position+= length;
       
  1256 
       
  1257     // And now the salt of the notification:
       
  1258     // the actual location of the message.
       
  1259 
       
  1260     encodeBuffer->Write( position, &KMmsAssignedContentLocation, 1 );
       
  1261     position++;
       
  1262 
       
  1263     // Check if we need a Quote (This does not mean the quoted string.)
       
  1264     if ( aUrl[0] >= 0x80 )
       
  1265         {
       
  1266         encodeBuffer->Write( position, &KMmsQuote, 1 );
       
  1267         position++;
       
  1268         }
       
  1269 
       
  1270     length = aUrl.Length();
       
  1271     encodeBuffer->Write( position, aUrl, length );
       
  1272     position += length;
       
  1273 
       
  1274     encodeBuffer->Write( position, &KMmsNull, 1 );
       
  1275     position++;
       
  1276 
       
  1277     // DONE.
       
  1278 
       
  1279     TPtrC8 ptr;
       
  1280     encodeBuffer->ResizeL( position );
       
  1281     ptr.Set( encodeBuffer->Ptr(0).Left( position ) );
       
  1282     HBufC8* result = ptr.AllocL();
       
  1283     CleanupStack::PopAndDestroy( encodeBuffer );
       
  1284 
       
  1285     return result;
       
  1286     }
       
  1287 #else
       
  1288 HBufC8* CMmsWatcher::CreateNotificationL(TDesC8& /*aUrl*/, TInt /*aSize*/)
       
  1289     {
       
  1290     User::Leave( KErrNotSupported );
       
  1291     return NULL; // this is actually unnecessary as we always leave.
       
  1292     }
       
  1293 #endif    
       
  1294 
       
  1295 // ---------------------------------------------------------
       
  1296 // CMmsWatcher::GetMessagingEntriesL
       
  1297 // ---------------------------------------------------------
       
  1298 //
       
  1299 void CMmsWatcher::GetMessagingEntriesL( const TBool aMessageStoreHasChanged )
       
  1300     {
       
  1301     LOG(_L("ReadMessagingEntriesL"));
       
  1302     // Connect CenRep
       
  1303     CMmsSettings* settings = CMmsSettings::NewL();
       
  1304     CleanupStack::PushL( settings ); // ***
       
  1305     settings->LoadSettingsL();
       
  1306     iMmsVersion = settings->MmsVersion();
       
  1307     
       
  1308     if( aMessageStoreHasChanged == EFalse )
       
  1309         {
       
  1310         // Read entries from CenRep
       
  1311         iService = settings->Service();
       
  1312         iNotificationFolder = settings->NotificationFolder();        
       
  1313         }
       
  1314     else 
       
  1315         {
       
  1316         // MessageStore has changed 
       
  1317         // -> CenRep values are false and have to be updated
       
  1318         iService = KMsvNullIndexEntryId;
       
  1319         iNotificationFolder = KMsvNullIndexEntryId;
       
  1320         }
       
  1321     
       
  1322     // If entries are null, create them to MessageStore
       
  1323     if( iSession &&
       
  1324         ( iService == KMsvNullIndexEntryId || 
       
  1325         iNotificationFolder == KMsvNullIndexEntryId ) )
       
  1326         {
       
  1327         LOG(_L("- No service exist or message store changed"));
       
  1328         LOG(_L("- Must update service id or create new"));
       
  1329         settings->CreateNewServiceL( *iSession );
       
  1330         iService = settings->Service();
       
  1331         iNotificationFolder = settings->NotificationFolder();
       
  1332 
       
  1333         // Retest
       
  1334         if( iService == KMsvNullIndexEntryId || 
       
  1335         iNotificationFolder == KMsvNullIndexEntryId )
       
  1336             {
       
  1337             LOG(_L("- ERROR: Still no service or notification folder"));
       
  1338             }
       
  1339         settings->SaveSettingsL();
       
  1340         }
       
  1341     
       
  1342     // Cleanup
       
  1343     CleanupStack::PopAndDestroy( settings );
       
  1344     }
       
  1345 
       
  1346 //
       
  1347 // Following methods are only in WINS compilations
       
  1348 // for testing purposes
       
  1349 //
       
  1350 #ifdef __WINS__
       
  1351 // ---------------------------------------------------------
       
  1352 // CMmsWatcher::LocalModeL
       
  1353 // ---------------------------------------------------------
       
  1354 //
       
  1355 TBool CMmsWatcher::LocalModeL()
       
  1356     {
       
  1357     CRepository* repository = CRepository::NewL( KUidMmsServerMtm );
       
  1358     CleanupStack::PushL( repository );
       
  1359     TInt temp = 0;
       
  1360     TInt retval = repository->Get( KMmsEngineLocalMode, temp );
       
  1361     CleanupStack::PopAndDestroy( repository );
       
  1362     if( retval == KErrNone )
       
  1363         {
       
  1364         return (TBool)temp;
       
  1365         }
       
  1366     else
       
  1367         {
       
  1368         LOG(_L("- ERROR reading localmode key from CenRep, assuming normal mode"));
       
  1369         return EFalse;
       
  1370         }
       
  1371     }
       
  1372 
       
  1373 // ---------------------------------------------------------
       
  1374 // CMmsWatcher::ReadLocalModeConfigData
       
  1375 // ---------------------------------------------------------
       
  1376 //
       
  1377 void CMmsWatcher::ReadLocalModeConfigData()
       
  1378     {
       
  1379     RFileReadStream reader;
       
  1380     TInt err = reader.Open( iFs, KMmsLocalModeConfigFile, EFileShareReadersOnly );
       
  1381     if( err != KErrNone )
       
  1382         {
       
  1383         reader.Close();
       
  1384         return;
       
  1385         }
       
  1386 
       
  1387     TChar delim = 0x000A;
       
  1388     TBuf<KMmsRowBufferLength> rowBuffer;
       
  1389     FOREVER
       
  1390         {
       
  1391         TRAP( err, reader.ReadL( rowBuffer, delim ) );
       
  1392         if( err == KErrEof )
       
  1393             {
       
  1394             reader.Close();
       
  1395             return;
       
  1396             }
       
  1397         TInt length = rowBuffer.Length();
       
  1398         if( length > 2 )
       
  1399             {
       
  1400             // Check for comment line
       
  1401             if( rowBuffer[0] == 0x0023 ) // 0x23 == '#'
       
  1402                 {
       
  1403                 continue;
       
  1404                 }
       
  1405             // Check for start of file (BOM)
       
  1406             if( rowBuffer[0] == 0xFEFF )
       
  1407                 {
       
  1408                 rowBuffer.Delete( 0, 1 );
       
  1409                 length = rowBuffer.Length();
       
  1410                 }
       
  1411             // Drop CR+LF from the end of line
       
  1412             rowBuffer.Delete( length - 2, 2 );
       
  1413   
       
  1414             TInt separatorPosition = 0;
       
  1415             _LIT( KSeparator, "=" );
       
  1416             separatorPosition = rowBuffer.Find( KSeparator );
       
  1417             if( separatorPosition > 0 )
       
  1418                 {
       
  1419                 if( rowBuffer.Left( separatorPosition ).CompareF( KMmsLocalmodeInDirectory ) == 0 )
       
  1420                     {
       
  1421                     iLocalModeIn = rowBuffer.Mid( separatorPosition+1 );
       
  1422                     }
       
  1423                 if( rowBuffer.Left( separatorPosition ).CompareF(
       
  1424                     KMmsLocalmodePollingInterval ) == 0 )
       
  1425                     {
       
  1426                     TLex16 lex;
       
  1427                     lex.Assign( rowBuffer.Mid( separatorPosition+1 ) );
       
  1428                     lex.Val( iPollingInterval );
       
  1429                     iPollingInterval *= KMmsMillion;
       
  1430                     }
       
  1431                 }
       
  1432             }
       
  1433         }
       
  1434     }
       
  1435 
       
  1436 #endif // __WINS__ emulator polling support
       
  1437 
       
  1438 
       
  1439 // ================= OTHER EXPORTED FUNCTIONS ==============
       
  1440 
       
  1441 //
       
  1442 // ---------------------------------------------------------
       
  1443 // Panic implements
       
  1444 // panic, for debug version only
       
  1445 //
       
  1446 GLDEF_C void gPanic(
       
  1447     TMmsPanic aPanic ) // error number enumerations
       
  1448     {
       
  1449     _LIT( KMmsPanic,"MMS" );
       
  1450     User::Panic( KMmsPanic, aPanic );
       
  1451     }
       
  1452 
       
  1453 //  End of File