sdkcreationmw/sdkruntimes/emumenubar/menubar/Push.cpp
changeset 0 b26acd06ea60
child 1 ac50fd48361b
equal deleted inserted replaced
-1:000000000000 0:b26acd06ea60
       
     1 /*
       
     2 * Copyright (c) 2005 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:  Push support
       
    15  *
       
    16 */
       
    17 
       
    18 
       
    19 #include "EcmtMenubar.h"
       
    20 #include "EcmtWin32.h"
       
    21 #include "httpfile.h"
       
    22 
       
    23 #include <e32base.h>
       
    24 #include <apgtask.h>
       
    25 #include <apgcli.h>
       
    26 #include <vwsdef.h>
       
    27 #include <viewcli.h>
       
    28 #include <cmanobserver.h>
       
    29 #include <e32property.h>
       
    30 #include <PSVariables.h>
       
    31 #include <EscapeUtils.h>
       
    32 #include <emulator.h>
       
    33 #include <sacls.h>
       
    34 #include <msvids.h>
       
    35 #include <msvstd.hrh>
       
    36 #include <mmssettings.h>
       
    37 #include <PushLog.h>
       
    38 #include <PushMessage.h>
       
    39 #include <PushDispatcher.h>
       
    40 #include <CPushHandlerBase.h>
       
    41 
       
    42 // We define CWatcherLog locally because CWatcherLog::NewL is not
       
    43 // exported from watcher.dll
       
    44 #undef IMPORT_C
       
    45 #define IMPORT_C
       
    46 #include <watcher.h>
       
    47   
       
    48 // MACROS
       
    49 #define __S8(x) _S8(x)
       
    50 
       
    51 // Some view ids
       
    52 #define KMessagingUid TUid::Uid(0x100058C5)
       
    53 #define KMessagingCentreMainViewUid TVwsViewId(KMessagingUid,TUid::Uid(0x01))
       
    54 #define KMessagingCentreInboxView TVwsViewId(KMessagingUid,TUid::Uid(0x02))
       
    55 
       
    56 // Known push content types
       
    57 typedef enum _TPushMessageType {
       
    58     EWapPush,
       
    59     EMultipart,
       
    60     EMmsMessage
       
    61 } TPushMessageType;
       
    62 
       
    63 typedef struct _PushType {
       
    64     const TText* ext;
       
    65     const TText8* contentType;
       
    66     TPushMessageType msgType;
       
    67     TUint8 wapContentType;
       
    68 } PushType;
       
    69 
       
    70 // WAP encoded content types must have 0x80 bit set
       
    71 const TUint8 WAP_MP_MIX = 0xA3; // application/vnd.wap.multipart.mixed
       
    72 const TUint8 WAP_MP_ALT = 0xA6; // application/vnd.wap.multipart.alternative
       
    73 const TUint8 WAP_MP_REL = 0xB3; // application/vnd.wap.multipart.related
       
    74 static const PushType pushTypes[] = {
       
    75     {_S("sic"),__S8("application/vnd.wap.sic"), EWapPush, 0xAE},
       
    76     {_S("slc"),__S8("application/vnd.wap.slc"), EWapPush, 0xB0},
       
    77     {_S("coc"),__S8("application/vnd.wap.coc"), EWapPush, 0xB2},
       
    78     {_S("mms"),__S8("application/vnd.wap.mms-message"), EMmsMessage, 0},
       
    79     {_S("mpc"),__S8("application/vnd.wap.multipart.mixed"), EMultipart, WAP_MP_MIX},
       
    80     {_S("mpc"),__S8("application/vnd.wap.multipart.related"), EMultipart, WAP_MP_REL},
       
    81     {_S("mpc"),__S8("application/vnd.wap.multipart.alternative"), EMultipart, WAP_MP_ALT}
       
    82 };
       
    83 
       
    84 // --------------------------------------------------------------------------
       
    85 // This class implements MWapPushLog and MConnManObserver interfaces
       
    86 // --------------------------------------------------------------------------
       
    87 
       
    88 class CEcmtMenubar::CWapPushSupport :
       
    89     public MWapPushLog, 
       
    90     public MConnManObserver
       
    91 {
       
    92 public:
       
    93     // MWapPushLog
       
    94     void WPLPrintf(const TDesC&);
       
    95     void WPLPrintfL(CPushMessage&);
       
    96     void WPLLogBinaryAsHex(const TDesC&);
       
    97     void WPLLogError(const TDesC&,TInt );
       
    98 
       
    99     // MConnManObserver
       
   100     void CMOpenConnectionL(TPushConnPoint&);
       
   101     void CMWatcherComplete(CCOWatcherBase&, TInt);
       
   102 };
       
   103 
       
   104 // MWapPushLog
       
   105 void CEcmtMenubar::CWapPushSupport::WPLPrintf(const TDesC&) {}
       
   106 void CEcmtMenubar::CWapPushSupport::WPLPrintfL(CPushMessage&) {}
       
   107 void CEcmtMenubar::CWapPushSupport::WPLLogBinaryAsHex(const TDesC&) {}
       
   108 void CEcmtMenubar::CWapPushSupport::WPLLogError(const TDesC&,TInt ) {}
       
   109 
       
   110 // MConnManObserver
       
   111 void CEcmtMenubar::CWapPushSupport::CMOpenConnectionL(TPushConnPoint&) {}
       
   112 void CEcmtMenubar::CWapPushSupport::CMWatcherComplete(CCOWatcherBase&,TInt) {}
       
   113 
       
   114 // --------------------------------------------------------------------------
       
   115 // CWatcherLog
       
   116 // --------------------------------------------------------------------------
       
   117 CWatcherLog* CWatcherLog::NewL(RFs& aFs)
       
   118 {
       
   119     CWatcherLog* self = new(ELeave)CWatcherLog(aFs);
       
   120     CleanupStack::PushL(self);
       
   121     self->ConstructL();
       
   122     CleanupStack::Pop();
       
   123     return self;
       
   124 }
       
   125 
       
   126 CWatcherLog::CWatcherLog(RFs& aFs) : CBase(), iFs(aFs)
       
   127 {
       
   128 }
       
   129 
       
   130 CWatcherLog::~CWatcherLog()
       
   131 {
       
   132 }
       
   133 
       
   134 void CWatcherLog::ConstructL()
       
   135 {
       
   136 }
       
   137 
       
   138 void CWatcherLog::Printf(TRefByValue<const TDesC16>,...)
       
   139 {
       
   140 }
       
   141 
       
   142 void CWatcherLog::Printf(TRefByValue<const TDesC8>,...)
       
   143 {
       
   144 }
       
   145 
       
   146 TBool CWatcherLog::IsLogging() const
       
   147 {
       
   148     return EFalse;
       
   149 }
       
   150 
       
   151 // --------------------------------------------------------------------------
       
   152 // Some obscure code
       
   153 // --------------------------------------------------------------------------
       
   154 
       
   155 inline void LaunchViewL(const TVwsViewId& aViewId,
       
   156                         TUid aCustomMessageId,
       
   157                         const TDesC8& aCustomMessage)
       
   158 {
       
   159     CVwsSessionWrapper* view = CVwsSessionWrapper::NewLC();
       
   160     view->CreateActivateViewEvent(aViewId, aCustomMessageId, aCustomMessage);
       
   161     CleanupStack::PopAndDestroy(view);
       
   162 }
       
   163 
       
   164 inline void LaunchMmsViewL()
       
   165 {
       
   166     LaunchViewL(KMessagingCentreInboxView, 
       
   167         TUid::Uid(KMsvGlobalInBoxIndexEntryIdValue), 
       
   168         KNullDesC8());
       
   169 }
       
   170 
       
   171 inline void LaunchPushViewL()
       
   172 {
       
   173     // The same view handles Wap Push messages as well as MMS messages
       
   174     LaunchMmsViewL();
       
   175 }
       
   176 
       
   177 inline void InboxStatusNotifyL()
       
   178 {
       
   179     TInt r =  RProperty::Define(KUidSystemCategory, 
       
   180                                 KUidInboxStatus.iUid, 
       
   181                                 RProperty::EInt);
       
   182 
       
   183     if (r == KErrNone)
       
   184     {
       
   185         RProperty::Set(KUidSystemCategory, 
       
   186                        KUidInboxStatus.iUid, 
       
   187                        ESADocumentsInInbox );
       
   188     }
       
   189 }
       
   190 
       
   191 // --------------------------------------------------------------------------
       
   192 // MMS support
       
   193 // --------------------------------------------------------------------------
       
   194 
       
   195 /**
       
   196  * Reads the location of the mmsin directory from localmode.ini
       
   197  * This is a Java-style property file, only in Unicode.
       
   198  * See CMmsWatcher::ReadLocalModeConfigData() method in
       
   199  * S60\mmsengine\mmswatcher\src\mmswatcher.cpp
       
   200  * The algorithm is reproduced here, with all its problems,
       
   201  * because we want it to exactly match what CMmsWatcher does
       
   202  */
       
   203 HBufC* CEcmtMenubar::ReadMmsInDir(RFs& aFs)
       
   204 {
       
   205     HBufC* mmsInBuf = NULL;
       
   206     RFileReadStream reader;
       
   207 
       
   208     // Actually, if localmode.ini file does not exist, the MMS watcher
       
   209     // does not poll the mmsin directory and everything we are doing
       
   210     // here is useless. Should we create localmode.ini file if it 
       
   211     // doesn't exist? But then SDK would have to be restarted because
       
   212     // MMS watcher only attempts to read this file on startup... Hmm.
       
   213     TInt err = reader.Open(aFs,KMmsLocalModeConfigFile,EFileShareReadersOnly);
       
   214     if (err == KErrNone)
       
   215     {
       
   216         TChar delim = 0x000A;
       
   217         TBuf<128> line;
       
   218         while (err == KErrNone)
       
   219         {
       
   220             TRAP(err, reader.ReadL( line, delim ) );
       
   221             if (err == KErrNone)
       
   222             {
       
   223                 TInt length = line.Length();
       
   224                 if (length > 2)
       
   225                 {
       
   226                     // Check for comment line
       
   227                     if (line[0] != '#')
       
   228                     {
       
   229                         // Check for byte order mark
       
   230                         if (line[0] == 0xFEFF)
       
   231                         {
       
   232                             line.Delete( 0, 1 );
       
   233                             length = line.Length();
       
   234                         }
       
   235                         // Drop CR+LF from the end of line
       
   236                         line.Delete(length-2, 2);
       
   237                         TInt sep = line.Locate('=');
       
   238                         if (sep > 0)
       
   239                         {
       
   240                             TPtrC key = line.Left(sep);
       
   241                             if (key.CompareF(KMmsLocalmodeInDirectory) == 0)
       
   242                             {
       
   243                                 mmsInBuf = line.Mid(sep+1).Alloc();
       
   244                                 break;
       
   245                             }
       
   246                         }
       
   247                     }
       
   248                 }
       
   249             }
       
   250         }
       
   251         reader.Close();
       
   252     }
       
   253     return mmsInBuf;
       
   254 }
       
   255 
       
   256 // Returns reference to the mmsin directory 
       
   257 const TDesC& CEcmtMenubar::MmmInDirL()
       
   258 {
       
   259     if (!iMmsInDir)
       
   260     {
       
   261         iMmsInDirBuf = ReadMmsInDir(FsSessionL());
       
   262         if (iMmsInDirBuf)
       
   263         {
       
   264             iMmsInDir = iMmsInDirBuf;
       
   265         }
       
   266         else
       
   267         {
       
   268             iMmsInDir = &KMmsDefaultLocalModeDir;
       
   269         }
       
   270     }
       
   271     return *iMmsInDir;
       
   272 }
       
   273 
       
   274 // Simulates an MMS message
       
   275 void CEcmtMenubar::SimulateMmsL(const TDesC8& aMessageBody)
       
   276 {
       
   277     // First copy the file to the phone's file system
       
   278     const TDesC& mmsDir = MmmInDirL();
       
   279     RFs& fs = FsSessionL();
       
   280 
       
   281     // Make sure the directory exists
       
   282     TUint attr = 0;
       
   283     if (fs.Att(mmsDir,attr) != KErrNone || !(attr & KEntryAttDir))
       
   284     {
       
   285         fs.Delete(mmsDir); // Ignore errors
       
   286         User::LeaveIfError(fs.MkDir(mmsDir));
       
   287     }
       
   288 
       
   289     // Create a temporary file. The extension must be .mms
       
   290     RFile file;
       
   291     TInt err = KErrAlreadyExists;
       
   292     for (TInt i=0; err == KErrAlreadyExists && i<1000; i++)
       
   293     {
       
   294         _LIT(KMmsFilePrefix,"TMP");
       
   295         _LIT(KMmsExt,".mms");
       
   296         TFileName name;
       
   297         name.Copy(mmsDir);
       
   298         name.Append(KMmsFilePrefix());
       
   299         name.AppendFormat(_L("%04d"),i);
       
   300         name.Append(KMmsExt());
       
   301         err = file.Create(fs,name,EFileWrite);
       
   302     }
       
   303 
       
   304     // Write the file
       
   305     User::LeaveIfError(err);
       
   306     err = file.Write(aMessageBody);
       
   307     file.Close();
       
   308     User::LeaveIfError(err);
       
   309 
       
   310     // Open the Messaging application
       
   311     InboxStatusNotifyL();
       
   312     LaunchMmsViewL();
       
   313 }
       
   314 
       
   315 // --------------------------------------------------------------------------
       
   316 // Push support
       
   317 // --------------------------------------------------------------------------
       
   318 
       
   319 /**
       
   320  * Returns a reference to CWatcherLog.
       
   321  */
       
   322 CWatcherLog& CEcmtMenubar::WatcherLogL()
       
   323 {
       
   324     if (!iWatcherLog)
       
   325     {
       
   326         iWatcherLog = CWatcherLog::NewL(FsSessionL());
       
   327     }
       
   328     return *iWatcherLog;
       
   329 }
       
   330 
       
   331 /**
       
   332  * Wap push simulator. Takes care of destroying CPushMessage
       
   333  */
       
   334 void CEcmtMenubar::SimulateWapPushL(CPushMessage* aPushMessage)
       
   335 {
       
   336     TPtrC8 rAppURI;
       
   337     TInt rAppID;
       
   338     TBool rIsAnInt;
       
   339     CPushHandlerBase* appHandlerPtr = NULL;
       
   340 
       
   341     CleanupStack::PushL(aPushMessage);
       
   342     if (!iWapPushSupport) iWapPushSupport = new(ELeave)CWapPushSupport;
       
   343     if (aPushMessage->GetAppIdL(rAppURI, rAppID, rIsAnInt))
       
   344     {
       
   345         if(rIsAnInt)
       
   346         {
       
   347             appHandlerPtr = &PushAppDispatcher::GetHandlerL(rAppID,
       
   348                 *iWapPushSupport, *iWapPushSupport);
       
   349         }
       
   350         else
       
   351         {
       
   352             appHandlerPtr = &PushAppDispatcher::GetHandlerL(rAppURI,
       
   353                 *iWapPushSupport, *iWapPushSupport);
       
   354         }
       
   355     }
       
   356     else
       
   357     {   // If no AppID defined, use the default User Agent
       
   358         appHandlerPtr= &PushAppDispatcher::GetHandlerL(KUserAgentAppHandler,
       
   359             *iWapPushSupport, *iWapPushSupport);
       
   360     }
       
   361 
       
   362     if (appHandlerPtr)
       
   363     {
       
   364         appHandlerPtr->HandleMessageL(aPushMessage);
       
   365         CleanupStack::Pop(aPushMessage);
       
   366     }
       
   367     else
       
   368     {
       
   369         CleanupStack::PopAndDestroy(aPushMessage);
       
   370     }
       
   371     
       
   372     // Show the indicator
       
   373     InboxStatusNotifyL();
       
   374     LaunchPushViewL();
       
   375 }
       
   376 
       
   377 
       
   378 // --------------------------------------------------------------------------
       
   379 // The main routine that does all the Push/MMS work
       
   380 // --------------------------------------------------------------------------
       
   381 
       
   382 /**
       
   383  * Detects whether the file is an MMS or a Wap Push message and
       
   384  * attempts to push it to the phone. Returns ETrue on success,
       
   385  * EFalse on failure or if the file does not seem to contain
       
   386  * push content.
       
   387  */
       
   388 TBool CEcmtMenubar::LoadFileAsPushL(const TDesC& aFileName)
       
   389 {
       
   390     // First check if this is an HTTP response file.
       
   391     ParseHttpResponse* resp = NULL;
       
   392     const PushType* pushType = NULL;
       
   393     char* fname = STRING_ToMultiByteN(aFileName.Ptr(),aFileName.Length());
       
   394     if (fname)
       
   395     {
       
   396         resp = HTTP_ParseFile(fname, HttpFalse);
       
   397         if (resp)
       
   398         {
       
   399             if (HTTP_ResponseStatus(resp) == HTTP_STATUS_CODE_OK)
       
   400             {
       
   401                 const HttpContent* content = HTTP_ResponseContent(resp);
       
   402                 if (content && content->type)
       
   403                 {
       
   404                     for (TInt i=0; i<COUNT(pushTypes) && !pushType; i++)
       
   405                     {
       
   406                         const char* type = (char*)pushTypes[i].contentType;
       
   407                         if (!strcmp(type, content->type))
       
   408                         {
       
   409                             pushType = pushTypes + i;
       
   410                         }
       
   411                     }
       
   412                 }
       
   413             }
       
   414             if (!pushType)
       
   415             {
       
   416                 HTTP_ResponseDelete(resp);
       
   417                 resp = NULL;
       
   418             }
       
   419         }
       
   420         MEM_Free(fname);
       
   421     }
       
   422 
       
   423     // Now check if this file has one of the DRM extensions
       
   424     if (!pushType)
       
   425     {
       
   426         TPtrC fileExt(FileExt(aFileName));
       
   427         for (TInt i=0; i<COUNT(pushTypes) && !pushType; i++)
       
   428         {
       
   429             if (fileExt.CompareF(TPtrC(pushTypes[i].ext)) == 0) {
       
   430                 pushType = pushTypes + i;
       
   431             }
       
   432         }
       
   433     }
       
   434 
       
   435     // If we suspect that this is a push or MMS message, load the file
       
   436     // into a memory buffer
       
   437     HBufC8* msgBody = NULL;
       
   438     if (pushType)
       
   439     {
       
   440         if (resp)
       
   441         {
       
   442             const HttpContent* hc = HTTP_ResponseContent(resp);
       
   443             msgBody = HBufC8::New(hc->size); // No leaving, please
       
   444             if (msgBody)
       
   445             {
       
   446                 msgBody->Des().Append(TPtrC8((TText8*)hc->data, hc->size));
       
   447             }
       
   448             HTTP_ResponseDelete(resp);
       
   449         }
       
   450         else
       
   451         {
       
   452             msgBody = ReadExtFile(aFileName);
       
   453         }
       
   454     }
       
   455 
       
   456     if (msgBody && msgBody->Length() > 0)
       
   457     {
       
   458         // File has been loaded. Do something with it
       
   459         CleanupStack::PushL(msgBody);
       
   460         if (pushType->msgType == EWapPush || 
       
   461             pushType->msgType == EMultipart)
       
   462         {
       
   463             HBufC8* msgHeader = NULL;
       
   464             TUint8 wapContentType = pushType->wapContentType;
       
   465             if (pushType->msgType == EMultipart)
       
   466             {
       
   467                 const TUint8 * msgData = msgBody->Ptr();
       
   468                 TInt msgLen = msgBody->Length();
       
   469                 if (msgLen > 1 && msgData[0] >= 1 && msgData[0] < msgLen && (
       
   470                     msgData[1] == WAP_MP_MIX || 
       
   471                     msgData[1] == WAP_MP_ALT ||
       
   472                     msgData[1] == WAP_MP_REL))
       
   473                 {
       
   474                     // Looks like multipart message contains encoded headers
       
   475                     // Separate body from the headers
       
   476                     HBufC8* msgBody2 = msgBody->Mid(msgData[0]+1,
       
   477                         msgLen-msgData[0]-1).AllocLC();
       
   478                     msgHeader = msgBody->Mid(1,msgData[0]).AllocL();
       
   479 
       
   480                     // Switch to the new body
       
   481                     CleanupStack::Pop(msgBody2);
       
   482                     CleanupStack::PopAndDestroy(msgBody);
       
   483                     msgBody = msgBody2;
       
   484                     msgLen = msgBody->Length();
       
   485                     CleanupStack::PushL(msgBody);
       
   486                     CleanupStack::PushL(msgHeader);
       
   487                 }
       
   488                 else
       
   489                 {
       
   490                     // Assume application/vnd.wap.multipart.mixed
       
   491                     wapContentType = WAP_MP_MIX;
       
   492                 }
       
   493             }
       
   494 
       
   495             if (!msgHeader)
       
   496             {
       
   497                 // We have no headers, allocate a fake one with just
       
   498                 // the content type
       
   499                 msgHeader = HBufC8::NewLC(1);
       
   500                 TPtr8 msgHeaderDes(msgHeader->Des());
       
   501                 msgHeaderDes.SetLength(1);
       
   502                 msgHeaderDes[0] = wapContentType;
       
   503             }
       
   504 
       
   505             CPushMessage* msg = CPushMessage::NewL(msgHeader, msgBody);
       
   506             CleanupStack::Pop(msgHeader);
       
   507             CleanupStack::Pop(msgBody);
       
   508             SimulateWapPushL(msg);
       
   509         }
       
   510         else
       
   511         {
       
   512             SimulateMmsL(*msgBody);
       
   513             CleanupStack::PopAndDestroy(msgBody);
       
   514         }
       
   515 
       
   516         return ETrue;
       
   517     }
       
   518     return EFalse;
       
   519 }
       
   520 
       
   521 /**
       
   522  * Local Variables:
       
   523  * c-basic-offset: 4
       
   524  * indent-tabs-mode: nil
       
   525  * End:
       
   526  */