Symbian端彩信讀取初探
上周由于項目需要對彩信讀取進行了預研,雖然并未涉及彩信的攔截,只是對Symbian S60手機收件箱中的彩信和彩信通知的內容進行提取并分析,但是也算是趟了下之前一直沒有搞過的彩信這渾水,小結一下。為了體現分析過程的邏輯性,下文并非是由簡入繁,而是采用由已知到未知的說明過程來進行。
彩信和彩信通知的區別
正如前面博文《Symbian OS中的消息存儲與常用操作》中提及的那樣,手機中的各種消息都是以數據項(Entry)形式供程序操作,鑒于Nokia之前的SDK有眾多API采用非公開的方式,很多東西碰上了只能拼命的試,試通了就算OK了,短信就是這個樣子的,自從Cxt將發送短信的代碼調通后,目前用的代碼基本都是他那份原型。寫了這么多只想說雖然手機中的各種消息都是以數據項形式給出的,但是數據項又由文件夾類型、消息類型、附件類型和服務類型的數據項,我們所指的消息如短信、彩信和郵箱乃至用戶自定義的一些消息等等都是消息類型的數據項即KuidMsvMessageEntry類型。既然消息類型的數據項這么多,那么如何區分呢,這就靠各自不同的Mtm類型,由于SDK沒有系統性闡述,我們雖然已經知道短信的類型是KUidMsgTypeSMS
,但是彩信的Mtm類型值到底是什么,它跟彩信通知是否是有區分的,我們不得而知。
沒辦法只能通過數據項的通用操作,對手機中已存的彩信和彩信通知進行讀取后進行分析內容,才得知彩信和彩信通知是兩個完全不同的Mtm類型值,一個是0x100058E1,另一個是0x100059C8,后來通過google搜索才知道前者的宏定義類型為KuidMsgTypeMultimedia,后者的宏定義類型為KUidMsgMMSNotification,兩者在mmsconst.h頭文件中有定義。
同樣使用通用的數據項操作,我們可以獲取彩信和彩信通知消息數據項的消息存儲
CMsvStore和附件情況,兩者的CMsvStore都是有數據的(SizeL()函數返回都是大于0的),但是卻沒有文本體(HasBodyTextL()返回都是Efalse);另外彩信都是有附件的,而彩信通知一般是沒有附件的。
因為附件本身也是數據項(KuidMsvAttachmentEntry類型的數據項),所以我們可以更進一步通過通用的數據項操作將彩信的所有附件全部都讀取出來。而附件類型由文件類型、鏈接類型和數據項類型三種,通常彩信中的附件都是文件類型的附件,我們用以下代碼來演示將附件拷貝出來
CMsvStore* inboxStore= iSmsMtm->Entry().ReadStoreL();
CleanupStack::PushL(inboxStore);
MMsvAttachmentManager& attachManager = inboxStore->AttachmentManagerL();
TInt attachmentCount = attachManager.AttachmentCount();
for(TInt i=0;i< attachmentCount;i++)
{
CMsvAttachment *attachment = attachManager.GetAttachmentInfoL(i);
CleanupStack::PushL(attachment);
if(type != CMsvAttachment::EMsvMessageEntry)
{
TFileName newPath(_L("c:\\data\\"));
newPath.AppendNum(aMessageId);
newPath.Append(_L("LLF"));
newPath.Append(attachment->AttachmentName());
RFile file = attachManager.GetAttachmentFileL(i);
TInt size(0);
file.Size(size);
HBufC8 *buf = HBufC8::NewLC(size);
TPtr8 ptrBuf(buf->Des());
file.Read(ptrBuf, size);
RFile newFile;
User::LeaveIfError(newFile.Replace(iFs, newPath, EFileWrite));
newFile.Write(ptrBuf);
newFile.Close();
CleanupStack::PopAndDestroy(buf);
}
CleanupStack::PopAndDestroy();
}
CleanupStack::PopAndDestroy();
為了更加直觀的區分各個附件隸屬于不同的消息,為此以消息ID打頭并加LLF來區分附件的各個文件,一條家庭生活報的彩信,我獲取到13個附件的截圖如下
其中有smil文件,有圖片文件,也有文本文件。
使用通用的數據項操作方法,借助SDK我們對彩信和彩信通知的內容區別和內容分析只能到這里了。
彩信的內容分析
顯然如果僅僅知道以上內容還是不夠的,困擾我們的
CMsvStore里面到底有些什么東西呢?暫時從代碼里面走出去,我們來參閱下Nokia發布的一份難得的中文文檔《CH_How_To_Create_MMS_Services_v4_0.pdf》(詳見附件),正如短信有短信的PDU一樣,彩信也是有其PDU的,這個PDU就在這個文檔的第五部分,在這里就不詳述了,從里面截個圖過來說明下問題。
由這個MMS的PDU,我們可以猜想下附件就是Message Body,而
CMsvStore是否就是MMS Header的內容呢?
幸好現在Nokia將Symbian開源了,否則這個猜想是沒有辦法揭開了,通過Symbian網站上的源代碼瀏覽器,我們可以搜到彩信相關的源代碼位于sf\app\messaging文件夾下,但是這個里面除了彩信之外,短信也有,郵箱也有,到底該如何找到需要的彩信呢,我們知道短信其實也有短信頭的,在SDK中有提供CSmsHeader
,懷疑彩信也應該有這么頭才是,于是用C*Header搜索文件夾,過來能夠搜索到一個mmsheaders.h頭文件中有一個CMmsHeaders,找到了這個離勝利就不遠了,聯想到短信讀取時有一個CSmsClientMtm::LoadMessageL()函數,索性就找找有沒有一個CMmsClientMtm::LoadMessageL()函數的,通過sf\app\messaging\mmsengine\clientmtm\src文件加下的mmsclient.cpp果然能找到這個函數,其源代碼如下
// ---------------------------------------------------------
// CMmsClientMtm::LoadMessageL
// Loads the multimedia message
// ---------------------------------------------------------
//
void CMmsClientMtm::LoadMessageL()
{
// First we should assert that iMsvEntry is not NULL, and panic, if it is
__ASSERT_DEBUG( iMsvEntry, gPanic( EMmsNoCMsvEntrySet ) );
// LoadMessageL should only be supported for message entries.
if ( iMsvEntry->Entry().iType.iUid != KUidMsvMessageEntryValue )
{
iAttributes->Reset();
iMmsHeaders->Reset();
iAddresseeList->Reset();
return;
}
// Old data must be reset first....
iAttributes->Reset();
// load the correct data
// get read-only message store
CMsvStore* store = iMsvEntry->ReadStoreL();
CleanupStack::PushL( store );
// restore headers of multimedia message
// Attachment info is not restored.
// It makes no sense to cache the attachment info as new attachments
// can be added with the help of the attachment magager without
// informing MMS Client MTM of the additions.
// Caller must use attachment manager to get attachment info.
iMmsHeaders->RestoreL( *store );
RestoreAttributesL( *store );
CleanupStack::PopAndDestroy( store );
store = NULL;
// Build the iAddresseeList up
BuildAddresseeListL();
}
注意源碼中紅色字體部分,我是英盲,所以也不管這個restore是啥意思,直接看CMmsHeaders里面的頭文件定義和源碼
頭文件定義
/**
* Internalize the headers.
* @param aStore CMsvStore
*/
IMPORT_C void RestoreL( CMsvStore& aStore );
其實看了頭文件里面的定義注釋,初始化頭,參數是
CMsvStore我們就知道是怎么回事了,不過既然有源碼,那就還是貼下源碼,至于分析我就不做了,反正跟短信讀取CSmsHeader一樣,操作這個CMmsHeaders。
// ---------------------------------------------------------
// CMmsHeaders::RestoreL
//
// ---------------------------------------------------------
//
EXPORT_C void CMmsHeaders::RestoreL(
CMsvStore& aStore )
{
RMsvReadStream stream;
Reset( NULL ); // all old pointers are deleted here
if ( aStore.IsPresentL( KUidMmsHeaderStream ) )
{
stream.OpenLC( aStore, KUidMmsHeaderStream ); // pushes 'stream' to the stack
InternalizeL( stream );
CleanupStack::PopAndDestroy( &stream ); // close stream
}
// restore MMBox header streams if present
if ( aStore.IsPresentL( KUidMMsElementDescriptorStream ) )
{
stream.OpenLC( aStore, KUidMMsElementDescriptorStream ); // pushes 'stream' to the stack
iElementDescriptor = new( ELeave )CMmsElementDescriptor;
iElementDescriptor->InternalizeL( stream );
CleanupStack::PopAndDestroy( &stream ); // close stream
}
if ( aStore.IsPresentL( KUidMMsMMBoxMessageHeaderStream ) )
{
stream.OpenLC( aStore, KUidMMsMMBoxMessageHeaderStream ); // pushes 'stream' to the stack
iMmBoxMessageHeaders = CMmsMMBoxMessageHeaders::NewL();
iMmBoxMessageHeaders->InternalizeL( stream );
CleanupStack::PopAndDestroy( &stream ); // close stream
}
if ( aStore.IsPresentL( KUidMMsMMBoxViewHeadersStream ) )
{
stream.OpenLC( aStore, KUidMMsMMBoxViewHeadersStream ); // pushes 'stream' to the stack
iMmBoxViewHeaders = new( ELeave )CMmsMMBoxViewHeaders;
iMmBoxViewHeaders->InternalizeL( stream );
CleanupStack::PopAndDestroy( &stream ); // close stream
}
// Extended notification also restored here
TInt length = 0; // string length
// Completeness indicator is not saved or restored.
// If we have stored the text, it normally indicates that the message is not complete
if ( aStore.IsPresentL( KUidMMsExtendedNotificationStream ) )
{
stream.OpenLC( aStore, KUidMMsExtendedNotificationStream ); // pushes 'stream' to the stack
length = stream.ReadInt32L();
if ( length > 0 )
{
iExtendedNotificationText = HBufC::NewL( stream, length );
}
CleanupStack::PopAndDestroy( &stream ); // close stream
}
if ( aStore.IsPresentL( KUidMmsApplicationInfoStream ) )
{
stream.OpenLC( aStore, KUidMmsApplicationInfoStream ); // pushes 'stream' to the stack
length = stream.ReadInt32L();
if ( length > 0 )
{
iApplicationId = HBufC::NewL( stream, length );
}
length = stream.ReadInt32L();
if ( length > 0 )
{
iReplyToApplicationId = HBufC::NewL( stream, length );
}
length = stream.ReadInt32L();
if ( length > 0 )
{
iApplicationInfo = HBufC8::NewL( stream, length );
}
CleanupStack::PopAndDestroy( &stream ); // close stream
}
if ( aStore.IsPresentL( KUidMmsReserved ) )
{
stream.OpenLC( aStore, KUidMmsReserved ); // pushes 'stream' to the stack
iRecommendedRetrievalMode = stream.ReadInt32L();
length = stream.ReadInt32L();
if ( length > 0 )
{
iRecommendedRetrievalModeText = HBufC16::NewL( stream, length );
}
length = stream.ReadInt32L();
if ( length > 0 )
{
iReplaceCancelId = HBufC8::NewL( stream, length );
}
iCancelStatus = stream.ReadInt32L();
CleanupStack::PopAndDestroy( &stream ); // close stream
}
}
一來由于時間倉促,二來開源的代碼頭文件和相關庫等要拷入工程中去,所以具體的編碼調試驗證就留給以后正式要用的時候再進行了。
彩信通知的內容分析
以上對彩信的內容分析算是告一個段落了,我們再回過頭來看看這個彩信通知,這個消息類型的數據項其mtm為KUidMsgMMSNotification
,那么這個客戶端的MTm到底是什么,繼續搜索源碼,發現在sf\app\messaging\mmsengine\clientmtm\src有一個mmsnotificationclient.cpp其內部正好是CmmsNotificationClientMtm。本來以為其會跟彩信一樣比較容易看出結果來,誰知道這個類的源碼看了下,感覺有點殘缺的味道,里面也有用到彩信的頭CMmsHeaders,因為CMmsHeaders就沒有去深入,這下也只能打住了。而且還有一個疑問,如何通過這個彩信通知來編程實現手動去獲取彩信,又是一個比較繁瑣的問題,搜了下源碼貌似跟sf\app\messaging\mobilemessaging\mmsui\notmtmsrc文件下的源碼有關??磥磉@趟渾水不太清啊,就此打住了。
暫時將Symbian端的彩信讀取分析到這里。以后有機會再繼續趟這渾水。
按照常規,由于貼圖不會搞,如果需要詳盡文檔,請下載以下word文檔和諾基亞官方文檔rar的鏈接
彩信初探.rar
注意:
目前在6730機子上對草稿箱彩信進行試驗時發現
編輯的彩信假如沒有經過發送,那么通過之前的attachment->AttachmentName()無法獲得附件的文件名;但是在N81等機子上是能夠獲取到的。雖然通過attachment->AttachmentName()無法獲取,但是目前發現通過attachment->FilePath()卻可以得到完整的文件路徑,為此附件文件名的獲取,假設attachment->AttachmentName()獲取不到,那么將采用attachment->FilePath()獲取文件路徑后進行文件名提取的方法來實現比較可靠一些。
posted on 2010-07-28 21:16
frank.sunny 閱讀(2551)
評論(0) 編輯 收藏 引用 所屬分類:
symbian 開發