examples/ForumNokia/SMSExample/Engine/src/SmsEngine.cpp

00001 /*
00002  * Copyright � 2008 Nokia Corporation.
00003  */
00004 
00005 #include "SMSEngine.h"
00006 #include <msvids.h> // Folder Ids
00007 #include <txtrich.h> // CRichText
00008 #include <smut.h>
00009 #include <eikdef.h>
00010 #include <eikenv.h>
00011 #include <rsendas.h>
00012 #include <rsendasmessage.h>
00013 
00014 #include "SmsEnginePanics.pan"
00015 
00016 
00017 #ifdef __WINS__
00018 const TMsvId KObservedFolderId = KMsvDraftEntryId;
00019 #else
00020 const TMsvId KObservedFolderId =  KMsvGlobalInBoxIndexEntryId;
00021 #endif
00022 
00023 const TMsvId KInbox = KMsvGlobalInBoxIndexEntryId;
00024 const TMsvId KOutbox = KMsvGlobalOutBoxIndexEntryId;
00025 const TMsvId KDrafts = KMsvDraftEntryId;
00026 
00027 const TInt KDelayTime = 1000*3000;
00028 const TInt KErrMsgLength = 20;
00029 
00030 _LIT(KEmptyMsg,"");
00031 
00032 //  CONSTRUCTION AND DESTRUCTION
00033 EXPORT_C CSmsEngine* CSmsEngine::NewL(MSmsEngineObserver& aObserver)
00034     {
00035     CSmsEngine* self = CSmsEngine::NewLC(aObserver);
00036     CleanupStack::Pop( self );
00037     return self;
00038     }
00039 
00040 EXPORT_C CSmsEngine* CSmsEngine::NewLC(MSmsEngineObserver& aObserver)
00041     {
00042     CSmsEngine* self = new( ELeave ) CSmsEngine(aObserver);
00043     CleanupStack::PushL( self );
00044     self->ConstructL();
00045     return self;
00046     }
00047 
00048 EXPORT_C CSmsEngine::~CSmsEngine()
00049     {
00050     delete iMsvEntry;
00051     iMsvEntry = NULL;
00052 
00053     delete iMsvSession;
00054     iMsvSession = NULL;
00055 
00056     delete iEngine;
00057     iEngine = NULL;
00058     }
00059 
00060 CSmsEngine::CSmsEngine(MSmsEngineObserver& aObserver) : iObserver(aObserver)
00061     {
00062     }
00063 
00064 void CSmsEngine::ConstructL()
00065     {
00066     iAutomaticDelete = EFalse;
00067 
00068     iListeningForIncoming = ETrue;
00069 
00070     iEngine = CSMSExampleMtmsEngine::NewL(*this);
00071 
00072     // SMS automatic receiving needs a session to the messaging server
00073     iMsvSession = CMsvSession::OpenAsyncL(*this);
00074     }
00075 
00076 //listening for incoming message
00077 void CSmsEngine::HandleSessionEventL(TMsvSessionEvent aEvent, TAny* aArg1,
00078                                            TAny* aArg2, TAny* /*aArg3*/)
00079     {
00080     switch (aEvent)
00081         {
00082             //One way to make sure that the message has been sent
00083             //is to watch the sent items folder.
00084             //The sent SMS could also be deleted here
00085 
00086             //case EMsvEntriesMoved:
00087             //{
00088             //Check if our message has gone to the sent items
00089             //if (aArg2 && (*(static_cast<TMsvId*>(aArg2)) == KMsvSentEntryId) )
00090             //    {
00091             //    CMsvEntrySelection* entries =
00092             //      static_cast<CMsvEntrySelection*>(aArg1);
00093 
00094                 //Note: this doesn't work if the message has been waiting
00095                 //to be sent and has been sent after a boot.
00096                 //In that case the deletion should be done when the server is
00097                 //ready again and the sent items (and also drafts) is searched.
00098             //    if (entries && iSentMessageId == entries->At(0))
00099             //        {
00100             //        Model().State(ESmsEngineSent);
00101                     //if it's our message and we're supposed to delete it
00102             //        if( iAutomaticDeleteFromSentItems ) //note a new flag
00103             //            {
00104             //            iMsvSession->RemoveEntry(iSentMessageId);
00105             //            }
00106             //        }
00107             //    iObserver.MessageSent();
00108             //    }
00109             //break;
00110             //}
00111         case EMsvServerReady:
00112             // Initialise iMsvEntry
00113             if (!iMsvEntry)
00114                 {
00115                 iMsvEntry = CMsvEntry::NewL(*iMsvSession, KInbox,
00116                                             TMsvSelectionOrdering());
00117 
00118 
00119                 //Sent SMS might be left to drafts if the phone was booted during
00120                 //SMS sending.
00121 
00122                 //Engine could also be used for retrieving a response for
00123                 //a message. Response could arrive after phone has been booted
00124                 //so it should be checked here.
00125                 //Now that we're ready to handle messages we could check
00126                 //if there's a response in the inbox.
00127                 //This could be the case only if the message has been
00128                 //sent and the phone has been booted while waiting.
00129 
00130                 //The same applies to sending and deleting the sent message
00131                 //Sent message could be left in the sent items if the phone
00132                 //was booted before the sent message had been removed.
00133 
00134                 //for these situations the engine should be implemented as a
00135                 //state machine and engines state should be checked on initialization.
00136                 //Of course there might be multiple clients (for example if engine
00137                 //implementation would be a server) so there's a need to
00138                 //have own state of each client (as in server session).
00139 
00140                 //implementation could be something like
00141                 //TSmsEngineState state = Model().State();
00142 
00143                 //if( state == ESmsEngineSending )
00144                 //  {
00145 
00146                     //Make sure that the sent message will be deleted.
00147                     //TBool found(EFalse);
00148 
00149                     //TRAPD(error, SearchForSentMessageFromSentMessagesL(found) );
00150 
00151                     //if ( !found )
00152                     //  {
00153                         //If the sent message is stuck in drafts
00154                     //  TRAP(error, SearchForSentMessageFromDraftsL(found) );
00155                         //If this is the case then resend!
00156                     //  }
00157 
00158                     //if the message is somehow mystically lost,
00159                     //then it's handled as the message has been sent.
00160                     //if( !found )
00161                     //  {
00162                     //  Model().State(ESmsEngineSMSSent);
00163                     //  }
00164                 //  }
00165 
00166                 }
00167             break;
00168 
00169         case EMsvEntriesCreated:
00170             // Only look for changes in the Inbox
00171             if (aArg2 &&  *(static_cast<TMsvId*>(aArg2)) == KObservedFolderId)
00172                 {
00173                 CMsvEntrySelection* entries =
00174                                     static_cast<CMsvEntrySelection*>(aArg1);
00175                 if( entries->Count() >= 1 )
00176                     {
00177                     iNewMessageId = entries->At(0);
00178                     }
00179                 else
00180                     {
00181                     Panic(ESmsEngineInternal);
00182                     }
00183                 }
00184             break;
00185 
00186         case EMsvEntriesChanged:
00187             //Look for changes. When using the emulator observed folder is
00188             //drafts, otherwise inbox.
00189             //Also a check for the iListeningForIncoming is made
00190             if (aArg2 &&  *(static_cast<TMsvId*>(aArg2)) == KObservedFolderId
00191                       && iListeningForIncoming )
00192                 {
00193                 CMsvEntrySelection* entries =
00194                                     static_cast<CMsvEntrySelection*>(aArg1);
00195 
00196                 //improvement for the case of receiving a response
00197 
00198                 //When the phone is booted and the message has arrived before
00199                 //application has started it only receives notification of
00200                 //changes
00201                 //in the inbox (when the user reads the message!), not the
00202                 //creation where these id is initialized.
00203                 //therefore we check when changes occur that if the iNewMessageID
00204                 //is -1 we make client handle the response.
00205                 //Check the id of the message (iNewMessageId is set
00206                 //in case of EMsvEntriesCreated)
00207 
00208                 //code could be something like:
00209                 //if ( entries && (iNewMessageId == entries->At(0) || iNewMessageId == -1) )
00210 
00211                 if( entries->Count() < 1 )
00212                 {
00213                     Panic(ESmsEngineInternal);
00214                 }
00215                 else if (iNewMessageId == entries->At(0))
00216                     {
00217 
00218                     if( !iMsvEntry )
00219                         {
00220                         Panic(ESmsEngineNotInitialized);
00221                         return;
00222                         }
00223 
00224                     // Set entry context to the new message
00225                     iMsvEntry->SetEntryL(iNewMessageId);
00226 
00227                     // Check the type of the arrived message and that the
00228                     // message is complete.
00229                     // only SMS's are our consern.
00230                     if ( iMsvEntry->Entry().iMtm != KUidMsgTypeSMS ||
00231                          !iMsvEntry->Entry().Complete() )
00232                         {
00233                         return;
00234                         }
00235 
00236                     // Read-only store.
00237                     CMsvStore* store = iMsvEntry->ReadStoreL();
00238                     CleanupStack::PushL(store);
00239 
00240                     // Get address of received message.
00241                     TBuf<KSmsMessageLength> iAddress(
00242                                                    iMsvEntry->Entry().iDetails
00243                                                    );
00244 
00245                     if (store->HasBodyTextL())
00246                         {
00247                         CRichText* richText = CRichText::NewL(
00248                            CEikonEnv::Static()->SystemParaFormatLayerL(),
00249                            CEikonEnv::Static()->SystemCharFormatLayerL());
00250                         CleanupStack::PushL(richText);
00251                         store->RestoreBodyTextL(*richText);
00252                         const TInt length = richText->DocumentLength();
00253 
00254                         TBuf<KSmsMessageLength> number;
00255                         TPtrC ptr = richText->Read(0, length);
00256 
00257                         //iMessage = ptr;
00258                         iMessage.Copy(ptr);
00259                         //iLogView->DrawTextL( address );
00260                         CleanupStack::PopAndDestroy(richText);
00261 
00262 
00263                         iObserver.MessageReceived(iAddress, iMessage);
00264 
00265                         }
00266                     else
00267                         {
00268                         iObserver.MessageReceived(iAddress, KEmptyMsg);
00269                         }
00270 
00271                     CleanupStack::PopAndDestroy(store);
00272 
00273                     // Automatic delete setting
00274                     if ( iAutomaticDelete )
00275                         {
00276                         // Ncnlist seems to panic if there is no time to play arrived
00277                         // message tone before deletion.
00278                         //Codescanner gives a critical
00279                         User::After(KDelayTime);
00280 
00281                         iMsvSession->RemoveEntry(iNewMessageId);
00282 
00283                         iObserver.MessageDeleted();
00284                         }
00285                     }
00286                 }
00287             break;
00288 
00289         default:
00290             break;
00291         }
00292     }
00293 
00294 //callback from CSMSExampleMtmsEngine
00295 void CSmsEngine::HandleMessageSentL(TInt aError)
00296     {
00297     if (aError == KErrNone)
00298         {
00299         iObserver.MessageSent();
00300         }
00301     else // If there was some error sending the SMS
00302         {
00303         iObserver.SmsEngineError(aError);
00304         }
00305     }
00306 
00307 //sending a sms
00308 EXPORT_C void CSmsEngine::SendSmsL(const TDesC& aAddr, const TDesC& aMsg)
00309     {
00310     TInt err (KErrNone);
00311     
00312     TRAP(err, SendSmsInThirdEditionL(aAddr, aMsg));
00313     
00314     if( err )
00315         {
00316         iObserver.SmsEngineError(err);
00317         }
00318      else
00319         {
00320         iObserver.SendingMessage();
00321         }
00322     }
00323 
00324 //Sending the sms in third edition with RSendAs
00325 void CSmsEngine::SendSmsInThirdEditionL(const TDesC& aAddr, const TDesC& aMsg)
00326     {
00327     RSendAs sendAs;
00328     User::LeaveIfError(sendAs.Connect());
00329     CleanupClosePushL(sendAs);
00330 
00331     RSendAsMessage sendAsMessage;
00332     sendAsMessage.CreateL(sendAs, KUidMsgTypeSMS);
00333     CleanupClosePushL(sendAsMessage);
00334 
00335     // prepare the message
00336     sendAsMessage.AddRecipientL(aAddr, RSendAsMessage::ESendAsRecipientTo);
00337     sendAsMessage.SetBodyTextL(aMsg);
00338 
00339     // send the message
00340     sendAsMessage.SendMessageAndCloseL();
00341 
00342     // sendAsMessage (already closed)
00343     CleanupStack::Pop();
00344 
00345     // sendAs
00346     CleanupStack::PopAndDestroy();
00347     }
00348 
00349 //setting the received message notyfication on/off
00350 EXPORT_C void CSmsEngine::ListenforIncomingSms(TBool aListening)
00351     {
00352     // the iMsvSession could be opened in here when needed
00353     // now the flag only indicates that do we notify the client
00354     iListeningForIncoming = aListening;
00355     }
00356 
00357 //setting the automatic deletion of received message on/off
00358 EXPORT_C void CSmsEngine::SetAutomaticDeletetion(TBool aDeletion)
00359     {
00360     // automatic deletion for incoming message isn't done if
00361     // iListeningForIncoming is false
00362     iAutomaticDelete = aDeletion;
00363     }
00364 
00365 //getting messages from a folder
00366 EXPORT_C void CSmsEngine::GetFolderSMSMessageInformationL(TMsvId aFolderID,
00367                                                 CDesCArrayFlat*& aAddresses,
00368                                                 CDesCArrayFlat*& aMessages)
00369     {
00370     iEngine->GetFolderSMSMessageInformationL(aFolderID, aAddresses, aMessages);
00371     }
00372 
00373 //getting messageids from a folder after having called
00374 //GetFolderSMSMessageInformationL
00375 EXPORT_C RArray<TMsvId>* CSmsEngine::GetMessageIds()
00376     {
00377     return iEngine->GetMessageIds();
00378     }
00379 
00380 //Copying a message to specified folder
00381 EXPORT_C void CSmsEngine::CopyMessageL( TMsvId aMessageId, TMsvId aFolder )
00382     {
00383     return iEngine->CopyMessageL(aMessageId, aFolder);
00384     }
00385 
00386 //Moving a message to specified folder
00387 EXPORT_C void CSmsEngine::MoveToFolderL( TMsvId aMessageId,  TMsvId aFolder )
00388     {
00389     iEngine->MoveToFolderL(aMessageId, aFolder);
00390     }
00391 
00392 //Deleting a message from specified folder
00393 EXPORT_C void CSmsEngine::DeleteMessageL( TMsvId aMessageId )
00394     {
00395     iEngine->DeleteMessageL(aMessageId);
00396     }
00397 
00398 // End of file

Generated by  doxygen 1.6.2