Using MMS Client MTM API
The messaging architecture relies on the client/server framework. This
means that a session (an instance of
CMsvSession
) is required
as a channel of communication between the client thread (Client MTM) and the
Message Server thread. This session must exist before Client MTM can be constructed
and its functionality used.
The most important use cases are described in the sections below. Note
that these use cases do not constitute an exhaustive list of the MMS Client
MTM's functionality.
CMmsClientMtm
contains numerous functions
documented in the header file
mmsclient.h
.
Note that a prerequisite of using MMS Client MTM is a good understanding
of the key messaging concepts.
Capabilities required to use MMS Client MTM API are
ReadUserData
,
ReadDeviceData
and
NetworkServices
Use cases
The most important use cases of MMS Client API are the following:
Constructing MMS Client MTM
The first step for using MMS Client MTM API is creating a session with
Message Server. To do this, a class which implements the mixin
MMsvSessionObserver
is
required. An example of such a class is shown below.
class CMtmExample : public CActive, public MMsvSessionObserver
{
...
private: // from MMsvSessionObserver
void HandleSessionEventL(TMsvSessionEvent aEvent, TAny* aArg1, TAny* aArg2, TAny* aArg3);
...
private:
CMsvOperation* iOp;
CMsvSession* iSession; // Session to the messaging server
CClientMtmRegistry* iMtmReg;
CMmsClientMtm* iMmsMtm;
TMsvId iNewMessageId;
};
A session with the Message Server can be created either synchronously (using
CMsvSession::OpenSyncL
)
or asynchronously (using
CMsvSession::OpenAsyncL()
). In each
case, an instance of the
MMSvSessionObserver
derived class
is passed, by reference to the function. (Use of the asynchronous implementation
is recommended to ensure responsiveness of the device.)
void CMtmExample::ConstructL()
{
CActiveScheduler::Add(this);
// Create CMsvSession
// New session is opened asynchronously
iSession = CMsvSession::OpenAsyncL(*this);
}
For asynchronous connections, notification of success is through a call
to the implemented
HandleSessionEventL()
function, with the
argument
aEvent = EMsvServerReady
being passed through. Once
this notification has been received (or the synchronous function has returned),
other messaging objects can be created.
void CMtmExample::HandleSessionEventL(TMsvSessionEvent aEvent, TAny* /*aArg1*/, TAny* /*aArg2*/, TAny* /*aArg3*/)
{
switch (aEvent)
{
// This event tells us that the session has been opened
case EMsvServerReady:
CompleteConstructL();
break;
...
}
}
Accessing MMS Client MTM is done through the Client MTM registry (
CClientMtmRegistry
).
This holds details of all registered client MTMs available on the device.
The registry is constructed with a handle to the session. MMS Client MTM can
then be created through a call to
CClientMtmRegistry::NewMtmL()
,
passing through
KUidMsgTypeMultiMedia
(defined in
mmsconst.h
)
as the MTM UID.
NewMtmL()
returns a
CBaseMtm
pointer
which needs to be cast into the correct type, that is
CMmsClientMtm
.
void CMtmsExampleEngine::CompleteConstructL()
{
// Construct the Client MTM registry
iMtmReg = CClientMtmRegistry::NewL(*iSession);
// Obtain MMS Client MTM from the MTM registry
iMmsMtm = static_cast<CMmsClientMtm*>(iMtmReg->NewMtmL(KUidMsgTypeMultimedia));
}
MMS Client MTM can now be used to access Message Server and create, manipulate,
and send multimedia messages.
Related APIs
-
CBaseMtm
-
CClientMtmRegistry
-
CClientMtmRegistry::NewMtmL()
-
CMmsClientMtm
-
CMsvSession::OpenAsyncL()
-
CMsvSession::OpenSyncL
-
HandleSessionEventL()
-
KUidMsgTypeMultiMedia
-
MMSvSessionObserver
-
MMsvSessionObserver
-
NewMtmL()
Creating an MMS message entry
Once the MMS Client MTM instance has been constructed (see
Constructing MMS Client MTM
), it can be used to create an MMS entry in Message Server.
There is more than one way to create an MMS message entry but the most obvious
way is to use
CMmsClientMtm::CreateMessageL()
. This function
creates an empty message entry as the child of the current context. (The context
is simply the entry on which the MTM actions are performed.) The entry is
created with its visible flag set to false and its in-preparation flag set
to true since at this stage it is empty.
As the entry is created as a child to the current context , it is important
to first set the context appropriately before
CreateMessageL()
is
called. It is usual to create new messages in the drafts folder. To set the
context ,
SwitchCurrentEntryL()
is called with the parent
folder ID (
KMsvDraftEntryId
) passed through.
CMmsClientMtm::CreateMessageL()
is
then called with the required service ID as a parameter. The service ID can
be retrieved by calling
DefaultServiceL()
on the MTM. After
successfully creating the new message entry,
CreateMessageL()
then
sets the new entry as the current context.
TBool CMtmsExampleEngine::CreateNewMessageL()
{
// Set context to the parent folder (Drafts folder)
iMmsMtm->SwitchCurrentEntryL(KMsvDraftEntryId);
iMmsMtm->CreateMessageL(iMmsMtm->DefaultServiceL())
...
At this stage, the created message is empty. To be useful,
the intended message recipient(s) of the message must be set. For MMS entries,
it is also useful to give the message a subject attribute.
CMmsClientMtm::AddAddresseeL()
has a number of overloads
that can be used to set the To, Cc, and Bcc fields of an MMS entry.
CMMsClientMtmL::SetSubjectL()
takes
a descriptor (
TDesC&
) and is used to set the subject.
// Set the recipients (_LIT used only for demonstration purposes)
// "To" recipient.
_LIT(KSamsNumber, "07738123456");
_LIT(KSamsAlias, "Sam");
// Cc recipient
_LIT(KPetesNumber, "07812654321");
iMmsMtm->AddAddresseeL(EMsvRecipientTo, KSamsNumber, KSamsAlias); // To field, alias set
iMmsMtm->AddAddresseeL(EMsvRecipientCc, KPetesNumber); // Cc field, no alias
// Set a message subject
_LIT(KMessageSubject, "MMS Example");
iMmsMtm->SetSubjectL(KMessageSubject);
The next step at this point is to add some text and multimedia object to
the message. How this is done is shown in
Adding an attachment to an MMS message
.
Here, the message is just saved to the drafts folder. To indicate that
the message entry is no longer being amended,
TMsvEntry::SetInPreparation()
can
be set to
EFalse
while
TMsvEntry::SetVisible()
is
set to
ETrue
to ensure the message is displayed in the Messaging
application. Changes to the entry should be committed using
CMsvEntry::ChangeL()
and
the message saved using
CMmsClientMtm::SaveMessageL()
.
SetInPreparation()
and
SetVisible()
need
to be called on the
TMsvEntry
that represents the message
in Message Server. To access this,
Entry()
is called on Client
MTM and then
Entry()
is called on the returned
CMsvEntry
.
TMsvEntry ent = iMmsMtm->Entry().Entry();
// Set InPreparation to false
ent.SetInPreparation(EFalse);
ent.SetVisible(ETrue); // Mark as visible, so this the message can be seen in Drafts
iMmsMtm->Entry().ChangeL(ent); // Commit changes
//Save the changes
iMmsMtm->SaveMessageL();
Related APIs
-
CMMsClientMtmL::SetSubjectL()
-
CMmsClientMtm::AddAddresseeL()
-
CMmsClientMtm::CreateMessageL()
-
CMmsClientMtm::SaveMessageL()
-
CMsvEntry
-
CMsvEntry::ChangeL()
-
CreateMessageL()
-
DefaultServiceL()
-
EFalse
-
ETrue
-
Entry()
-
KMsvDraftEntryId
-
SetInPreparation()
-
SetVisible()
-
SwitchCurrentEntryL()
-
TDesC&
-
TMsvEntry
-
TMsvEntry::SetInPreparation()
-
TMsvEntry::SetVisible()
Adding and amending attributes of an MMS message
There are a number of attributes on a message entry than can be set or
amended. These attributes are properties of the message header but can be
set through Client MTM and include the expiry date on the message, the delivery
time, and priority. As long as the context of the MTM is set to the appropriate
message, setting the values for the properties is simply a case of calling
the correct function. The functions are detailed in the Client MTM header
file (
mmsclient.h
) and enumeration values required by some of the functions
can be found in
mmsconst.h
.
An example showing the message priority being set to high is shown below.
iMmsMtm->SetMessagePriority(EMmsPriorityHigh);
//Save the changes
iMmsMtm->SaveMessageL();
Adding body text to an MMS message
Although
CMmsClientMtm
has a
Body()
function
defined, it should not be used. Body text for an MMS message is treated as
a message attachment and therefore should be set using
CMmsClientMtm::CreateTextAttachmentL()
.
See
Adding attachments to an MMS message
for
further information.
Related APIs
-
Body()
-
CMmsClientMtm
-
CMmsClientMtm::CreateTextAttachmentL()
Adding attachments to an MMS message
All MMS message data (text, images, sounds, and so on) should be sent as
attachments to the message with the required presentation being defined by
a SMIL file (also sent as an attachment). Note, although
CMmsClientMtm
has
a
Body()
function defined, it should not be used - the message
body text is treated as an attachment. Therefore, text should be added using
CMmsClientMtm::CreateTextAttachmentL()
.
virtual void CMmsClientMtm::CreateTextAttachmentL(
CMsvStore& aStore,
TMsvAttachmentId & aAttachmentId,
const TDesC& aText,
const TDesC& aFile,
TBool aConvertParagraphSeparator = ETrue);
The function requires that the message store for the message entry has
been opened ready for editing. A pointer to the open store is then passed
as a parameter. The text required for the message is passed as a descriptor
(
aText
) and a suggestion for a suitable file name is also
needed (SMIL references this filename). If required, the unicode paragraph
separator (character
0x2029
) can be replaced with a line
feed (character
0x000a
). On completion,
aAttachmentId
is
set.
To use
CreateTextAttachmentL()
, the message entry's store
must first be opened.
// Open the entry's store - assume message context set correctly
CMsvStore* store = iMmsMtm->Entry().EditStoreL();
CleanupStack::PushL(store);
// Add the text attachment. _LIT used for demonstration purposes
_LIT(KMMSText, "Thought you'd like to see where I'm staying");
_LIT(KMMSTextFilename, "hello.txt");
iMmsMtm->CreateTextAttachmentL(*store, attachId, KMMSText, KMMSTextFilename);
// Add more attachments or save the message
// Remember to do the appropriate clean up at the end
...
For multimedia attachments,
CMmsClientMtm::CreateAttachment2L()
is
used.
virtual void CreateAttachment2L(
CMsvStore& aStore,
RFile& aFile,
TDesC8& aMimeType,
CMsvMimeHeaders& aMimeHeaders,
CMsvAttachment* aAttachmentInfo,
TMsvAttachmentId& aAttaId);
The function creates an attachment entry and copies the file specified
as a parameter (
aFile
) to an open message store (
aStore
).
The attachment should be passed as a handle to an open file. The MIME type,
for example
"image/jpeg"
for a JPEG image, is passed as a
descriptor. A MIME header (
CMsvMimeHeaders
) for the attachment
is created. A reference to the header is passed to the function so it can
be updated. A
CMsvAttachment
object is created with the parameter
CMsvAttachment::EMsvFile
to
represent the attachment. This is also updated by the
CreateAttachment2L
function.
// Continuation of code above which set a text attachment
// Add an image attachment
// Set the filename for the image
#define KDirPictures PathInfo::ImagesPath()
#define KPhoneRootPath PathInfo::PhoneMemoryRootPath()
_LIT(KFileName, "mmsexample.jpg");
TFileName attachmentFile(KPhoneRootPath);
attachmentFile.Append(KDirPictures);
attachmentFile.Append(KFileName);
// Open the attachment file
RFile attachment;
TInt error = attachment.Open(CCoeEnv::Static()->FsSession(), attachmentFile, EFileShareReadersOnly | EFileRead);
CleanupClosePushL(attachment);
// Check that the attachment file exists.
if(error != KErrNone)
{
_LIT(KFileNotFound, "Attachment file not found!");
attachment.Close();
CleanupStack::PopAndDestroy(attachment);
CleanupStack::PopAndDestroy(store);
return EFalse;
}
else
{
// Mime header
CMsvMimeHeaders* mimeHeaders = CMsvMimeHeaders::NewL();
CleanupStack::PushL(mimeHeaders);
mimeHeaders->SetSuggestedFilenameL(KFileName);
// Represents a single attachment and information about the attachment
CMsvAttachment* attaInfo = CMsvAttachment::NewL(CMsvAttachment::EMsvFile);
CleanupStack::PushL(attaInfo);
// Mime Type
_LIT8(KMimeType, "image/jpeg");
TBufC8<10> mimeType(KMimeType);
// Attachment file must be in a public folder (e.g. c:\Data\images)
iMmsMtm->CreateAttachment2L(
*store,
attachment,
mimeType,
*mimeHeaders,
attaInfo,
attachId );
CleanupStack::Pop(attaInfo); // attaInfo
CleanupStack::PopAndDestroy(mimeHeaders); // mimeHeaders
// If a SMIL file is attached for presentation layout purposes
// then it should be done here before the
// the changes are committed
// Commit the changes and perform the appropriate cleanup
store->CommitL();
attachment.Close();
CleanupStack::PopAndDestroy(attachment);
CleanupStack::PopAndDestroy(store);
// Save the changes
iMmsMtm->SaveMessageL();
}
This example shows how to attach some text and an image to an MMS message.
However, the layout of the message is left to the receiving device. To dictate
how the message should be presented to the recipient, a SMIL file is needed.
An example file is shown below.
<smil xmlns="http://www.w3.org/2000/SMIL20/CR/Language">
<head>
<layout>
<root-layout width="160" height="140"/>
<region id="Image" width="160" height="120" left="0" top="0"/>
<region id = "Text" width="160" height="20" left="100" top="120"/>
</layout>
</head>
<body>
<par dur="10s">
<img src="mmsexample.jpg" region="Image" />
<text src="hello.txt" region="Text" />
</par>
</body>
</smil>
This file indicates that the image should be displayed before the text
in the message.
The SMIL file should be added as an attachment in the same way that the
image was added, that is using
CMmsClientMtm::CreateAttachment2L()
.
In this case, the MIME type should be set to
KMmsApplicationSmil
(defined
in
mmsconst.h
). The SMIL attachment should then be set as the root
attachment using
CMmsClientMtm::SetMessageRootL()
and passing
through the ID (
TMsvAttachmentId
) of the SMIL attachment
set by the
Createattachment2L()
function.
iMmsMtm->SetMessageRootL(smilAttachId);
Note that after setting the root, the changes to the store should be committed
and the message saved.
Related APIs
-
"image/jpeg"
-
0x000a
-
0x2029
-
Body()
-
CMmsClientMtm
-
CMmsClientMtm::CreateAttachment2L()
-
CMmsClientMtm::CreateTextAttachmentL()
-
CMmsClientMtm::SetMessageRootL()
-
CMsvAttachment
-
CMsvAttachment::EMsvFile
-
CMsvMimeHeaders
-
CreateAttachment2L
-
CreateTextAttachmentL()
-
Createattachment2L()
-
KMmsApplicationSmil
-
TMsvAttachmentId
-
aAttachmentId
-
aFile
-
aStore
-
aText
Validating an MMS message
Before sending an MMS message, it is advisable to validate it to ensure
the added data is compliant with the message type. The base class (
CBaseMtm
)
defines the function
ValidateMessage()
and this is implemented
by each MTM to provide type-specific validation. The function takes a
TMsvPartList
parameter
which is a bit-set (flags for this bit-set are defined in
Mmtdef.h
)
indicating the parts to be checked. Not all flags are supported by MMS MTM.
Supported flags are
KMsvMessagePartRecipient
,
KMsvMessagePartOriginator
and
KMsvMessagePartAttachments
. The return value of
ValidateMessage()
is also a
TMsvPartList
bit
set that indicates which parts of the message were invalid.
TBool CMtmsExampleEngine::ValidateMMS()
{
// Context should be set to appropriate message
TMsvPartList msgCheckParts = KMsvMessagePartRecipient | KMsvMessagePartOriginator | KMsvMessagePartAttachments;
TMsvPartList msgFailParts = iMmsMtm->ValidateMessage(msgCheckParts);
return msgFailParts == KMsvMessagePartNone;
}
Related APIs
-
CBaseMtm
-
KMsvMessagePartAttachments
-
KMsvMessagePartOriginator
-
KMsvMessagePartRecipient
-
TMsvPartList
-
ValidateMessage()
Sending an MMS message
Assuming that the MMS message has been created and validated, sending a
message using MMS Client MTM is simply a case of using its
SendL()
function.
The important point to realize is that the ID of the message entry that should
be sent must be set as the context of the MTM. If required, a time can be
set for the sending of the message. The
SendL()
function
is asynchronous and returns a
CMsvOperation
pointer. This
can be used to obtain progress information about the operation before the
active object completes (that is, before the
RunL()
is called).
void CMtmsExampleEngine::SendMMSL()
{
iOp = iMmsMtm->SendL(iStatus);
SetActive();
}
There is also an overload of
CMmsClientMtm::SendL()
that
enables the sending of multiple messages with one operation. An array of message
IDs (
TMsvId
s) is created as a
CMsvEntrySelection
object
and this is passed as a parameter to the
SendL()
function.
Again the function is asynchronous and returns a
CMsvOperation
pointer
to allow progress monitoring.
Related APIs
-
CMmsClientMtm::SendL()
-
CMsvEntrySelection
-
CMsvOperation
-
RunL()
-
SendL()
-
TMsvId
Querying a received MMS message
MMS Client MTM can be used to retrieve information from received MMS messages.
Functions such as
Sender()
,
MessageReceiveTime()
,
NumberOfPreviousSenders()
are
available to use. In each case, the important point is that the context of
the MTM is set correctly using the ID of the message.
The example below shows an incoming message, caught by
MMsvSessionObserver::HandleSessionEventL()
.
The message ID (
TmsvId iNewMessageId
) is
stored as the entry is created in Inbox and then, once the message has been
stored (
aEvent == EMsvEntriesChanged
), the MTM context is
set and the message loaded. Information about the message can then be queried,
for example the sender.
void CMtmsExampleEngine::HandleSessionEventL(TMsvSessionEvent aEvent, TAny* aArg1, TAny* aArg2, TAny* aArg3)
{
switch (aEvent)
{
...
case EMsvEntriesCreated:
if(*(static_cast<TMsvId*>(aArg2)) == KMsvGlobalInBoxIndexEntryId)
{
CMsvEntrySelection* entries = static_cast<CMsvEntrySelection*>(aArg1);
iNewMessageId = entries->At(0);
}
break;
case EMsvEntriesChanged:
if(*(static_cast<TMsvId*>(aArg2)) == KMsvGlobalInBoxIndexEntryId)
{
CMsvEntrySelection* entries = static_cast<CMsvEntrySelection*>(aArg1);
if(iNewMessageId == entries->At(0))
{
iMmsMtm->SwitchCurrentEntryL(iNewMessageId);
iMmsMtm->LoadMessageL();
TPtrC sender = iMmsMtm->Sender();
// Use the sender information
...
}
}
break;
...
}
}
Further information about the general messaging concepts that are needed
to understand this example can be found in the SDK documentation and at
Nokia Developer
.
It is important to note that an MMS entry does not have a message body
as the message text is sent as an attachment and therefore the Client MTM's
Body()
function
should not be used. However, further information about the message text and
attachments can be obtained through the message entry's store. The general
procedure is to use
CMsvStore::AttachmentManagerL()
. The
example below shows how the message text could be retrieved.
CMsvEntry* entry = iSession->GetEntryL(iNewMessageId);
CleanupStack::PushL(entry);
CMsvStore* store = entry->ReadStoreL();
if(store!= NULL)
{
CleanupStack::PushL(store);
MMsvAttachmentManager& attManager = store->AttachmentManagerL();
_LIT8(KMimeBuf, "text/plain");
TBuf8<10>mimeBuf(KMimeBuf);
// Cycle through the attachments
for(TInt i=0; i<attManager.AttachmentCount(); i++)
{
CMsvAttachment* attachment = attManager.GetAttachmentInfoL(i);
CleanupStack::PushL(attachment);
// Test to see if we have a text file
if(mimeBuf.CompareF(attachment->MimeType())== 0)
{
RFile file = attManager.GetAttachmentFileL(i);
// The file can then be read using the normal file functionality
// After reading, the file should be closed
...
}
CleanupStack::PopandDestroy(attachment);
}
Cleanupstack::PopAndDestroy(store);
}
CleanupStack::PopAndDestroy(entry);
This aspect of message querying falls outside the scope of MMS Client MTM
and therefore is not covered in detail here but is included for completeness.
Related APIs
-
Body()
-
CMsvStore::AttachmentManagerL()
-
MMsvSessionObserver::HandleSessionEventL()
-
MessageReceiveTime()
-
NumberOfPreviousSenders()
-
Sender()
Responding to (replying/forwarding) a received message
An obvious requirement of a messaging client is to be able to reply to
or forward received messages. MMS Client MTM provides
CMmsClientMtm::ReplyL()
and
CMmsClientMtm::ForwardL()
for
this purpose. Both functions are asynchronous and return a
CMsvOperation
pointer
to allow the monitoring of the progress of the function and ultimately to
provide the ID(
TMsvId
) of the newly created message.
To use the functions, the message to be replied to/forwarded must be set
as the context. The functions take as parameters the ID (
TMsvId
)
of the folder in which the new message should be created, a list (
TMsvPartList
)
of the elements of the original message that should be copied to the new message,
and a
TRequestStatus
reference. (Note that not all elements
of
TMsvPartList
are supported, see
mmsclient.h
for
further information.) An example of using
CClientMtm::ReplyL()
is
shown here but
CMmsClientMtm::ForwardL()
can be used similarly.
void CMtmsExampleEngine::ReplyL()
{
iMmsMtm->SwitchCurrentEntryL(iMessageToReplyTo);
iMmsMtm->LoadMessageL();
// Add the description of the received message to the new (reply) message
// Note the Recipient address is automatically set to the sender
// KMsvMessagePartRecipient is only needed for reply to all
TMsvPartList msgCheckParts = KMsvMessagePartDescription;
iOp = iMmsMtm->ReplyL(KMsvDraftEntryId,msgCheckParts,iStatus);
SetActive();
}
On completion (
RunL()
being called), the ID of the newly
created message is retrieved using
CMsvOperation::Progress()
.
A package buffer is used to transfer this information. If the creation of
the reply/forward message was not successful, the ID will be set to
KMsvNullIndexEntryId
.
Once the operation has completed, the message can be modified and saved, or
sent, using the usual functions.
void CMtmsExampleEngine::RunL()
{
if(iStatus.Int() == KErrNone)
{
// Retrieve the id of the created message
// Id is returned in a package buffer
TPckgBuf<TMsvId> pkg;
pkg.Copy( iOp->ProgressL());
TMsvId indexEntry = pkg();
if(indexEntry != KMsvNullIndexEntryId)
{
// Set the context to the new message
iMmsMtm->SwitchCurrentEntryL(indexEntry);
iMmsMtm->LoadMessageL();
// Here add further recipients, subject, attachments
// to the message
...
// Commit the changes and save the Message
TMsvEntry ent = iMmsMtm->Entry().Entry();
ent.SetReadOnly(EFalse);
// Set InPreparation to false
ent.SetInPreparation(EFalse);
ent.SetVisible(ETrue); // mark as visible
iMmsMtm->Entry().ChangeL(ent); // Commit changes
//Save the changes
iMmsMtm->SaveMessageL();
}
}
}
Related APIs
-
CClientMtm::ReplyL()
-
CMmsClientMtm::ForwardL()
-
CMmsClientMtm::ReplyL()
-
CMsvOperation
-
CMsvOperation::Progress()
-
KMsvNullIndexEntryId
-
RunL()
-
TMsvId
-
TMsvPartList
-
TRequestStatus
Cleaning up of resources
Once all of the required operations have been carried out, the appropriate
destruction of resources should be carried out. Obviously the resources used
are application specific but in general require at least Client MTM, the MTM
registry and the session. They should be deleted in the reverse order to which
they were created.
CMtmsExampleEngine::~CMtmsExampleEngine()
{
// For this particular example cleanup
Cancel(); // Active Object
delete iOp;
// For general use of the MMS Client MTM
delete iMmsMtm; // CMmsClientMtm
delete iMtmReg; // CClientMtmRegistry
delete iSession; // CMsvSession
}
Error handling
The leave mechanism of Symbian platform is used to handle error conditions on
method calls. In addition, messaging defines a series of panics; these are
detailed in Symbian OS reference » System panic reference » MSGS.
Related APIs
-
CMmsClientMtm
-
CMsvSession
-
NetworkServices
-
ReadDeviceData
-
ReadUserData