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

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

Generated by  doxygen 1.6.2