This page describes how to update software that uses the messaging APIs from previous releases to work with Symbian OS v9.1. The changes described are a consequence of introducing Platform Security. These changes break both source and binary compatibility, and include the addition and removal of APIs.
Note. Some messaging APIs require the caller to have certain security capabilities. For a description, see Platform Security in the OS Guide.
This page covers the following topics:
Messaging Clients - migrate because of changes in the messaging framework and MTM APIs for handling attachments, and for service settings
MTM Providers - migrate because of changes to the framework classes, relating to attachments, SendAs support, and security capability support.
SendAs Clients - the SendAs API has been completely redesigned, requiring changes to applications or UI platforms that use it.
BIO Message Parser Plugins - migrate because of changes affecting how they are located and loaded.
v9.1 changes the messaging client APIs in two major areas: attachment handling and configuration settings. The following sections, for each of these areas, give an overview of the messaging framework changes, and then discuss the impact on particular MTMs.
This section describes:
In previous versions of messaging, clients could use the
HasDirectoryL()
and GetFilePath()
functions of
CMsvEntry
and CMsvServerEntry
to
directly read and write to the directories where attachment files for messages
were stored.
From v9.1, the message store is moved to a file system location that is
private to the message server, which means that these APIs can no longer have
direct access to these directories. Clients that handle attachments must move
to using a new attachment manager class
MMsvAttachmentManager
.
An attachment manager object for a message entry can be obtained from
the entry's store (CMsvStore
) object (shown below). Some
MTMs, such as email, provide higher-level APIs that supply an attachment
manager to the client, so that the client does not need to directly access the
store object.
MMsvAttachmentManager
provides member functions
for creating, removing, and retrieving attachments for a message entry.
Information about an attachment is encapsulated in a
CMsvAttachment
object.
The API permits an attachment to be one of three types (defined in
CMsvAttachment::TMsvAttachmentType()
):
File attachments: file-based attachments that are copied to or created in the message store.
Linked file attachments: file-based attachments for which the message server does not hold a copy of the file, but simply stores a reference to a file stored elsewhere.
Message entry attachments: these are existing message entries that can be registered as attachments of another message entry.
MMsvAttachmentManager
defines the functions
AddAttachmentL()
, AddLinkedAttachmentL()
and
AddEntryAsAttachmentL()
to add attachments for each of these
types. Additionally, a CreateAttachmentL()
function creates a new
attachment file into which the client can write.
Every attachment is given an ID (unique within the scope of the message entry) by the attachment manager by which it can be referenced. Attachments may also have the following attributes:
Attachment name: the filename to display to the user when listing attachments
File size
MIME type
Completed flag, which can be used to indicate if the attachment is in preparation
Additionally, a set of MIME headers can be associated with an
attachment. This is done through a CMsvMimeHeaders
class,
which represents a number of common MIME headers in a single object. The MIME
header data can be associated with an attachment and stored and restored using
the CMsvMimeHeaders::StoreL()
and
CMsvMimeHeaders::RestoreL()
member functions.
In addition to these standard attributes, additional information can be
stored for attachments with a message (see
CMsvAttachment::SetDesC8AttributeL()
and
CMsvAttachment::SetIntAttributeL()
). For example, the OBEX
MTM stores OBEX headers with each attachment.
The following sections illustrate some of the key uses of the API to create, retrieve, and remove attachments:
The following code adds a file attachment, and sets its description (just the file name in this case) and size attributes.
Note: All the MMsvAttachmentManager functions that modify the attachments for an entry are asynchronous, so should be called as part of an active object request function.
/* Active object request function to add an attachment.
Arguments:
aEntry – entry to make attachment for
aAttachPath – path to file to attach
aSize – size of attachment in bytes
*/
void CFoo::AttachFileL(CMsvEntry& aEntry, const TFileName& aAttachPath, TInt aSize)
{
// get attachment manager from the entry's store
iStore = aEntry.EditStoreL();
MMsvAttachmentManager& attachMan = iStore->AttachmentManagerL();
// create a new attachment attributes object
CMsvAttachment* attachmentInfo = CMsvAttachment::NewL(CMsvAttachment::EMsvFile);
CleanupStack::PushL(attachmentInfo);
// set the attachment name and size attributes
TParse fparse;
User::LeaveIfError(fparse.Set(aAttachPath,NULL,NULL));
attachmentInfo->SetAttachmentNameL(fparse.NameAndExt());
attachmentInfo->SetSize(aSize);
// add the attachment
attachMan.AddAttachmentL(aAttachPath, attachmentInfo, iStatus);
// ownership of attachmentInfo is transferred to attachMan, so don't delete
CleanupStack::Pop(attachmentInfo);
SetActive();
}
The associated RunL should commit the store on successful completion:
iStore->CommitL();
The following code uses the
MMsvAttachmentManager
AttachmentCount()
and
GetAttachmentInfoL()
functions to get each attachment for a
message entry in turn. It then calls the various
CMsvAttachment
accessor functions to get the attachment
attributes, and to access the attachment file itself:
// get store for entry
CMsvStore* store = entry->ReadStoreL();
CleanupStack::PushL(store);
// get number of attachments
TInt numAttach = attachMan.AttachmentCount();
// loop through attachments
for (int i=0; i<numAttach; i++)
{
// get attachment attributes for indexed attachment
CMsvAttachment* attachInfo = attachMan.GetAttachmentInfoL(i);
CleanupStack::PushL(attachInfo);
// get attachment's name
const TDesC& attachName = attachInfo->AttachmentName();
// get attachment's size
TInt attachSize = attachInfo->Size();
// get attachment's type, and test if it's of a file type
CMsvAttachment::TMsvAttachmentType attachType = attachInfo->Type();
TBool fileTypeAttachment = (attachType == CMsvAttachment::EMsvFile || attachType == CMsvAttachment::EMsvLinkedFile);
// get attachment's filepath, if attachment is of a file type
if (fileTypeAttachment)
{
const TDesC& attachPath = attachInfo->FilePath();
}
// get MIME type
const TDesC8& attachMType = attachInfo->MimeType();
// get completeness flag
TBool complete = attachInfo->Complete();
// get attachment file, if attachment is of a file type
if (fileTypeAttachment)
{
RFile attachFile = attachMan.GetAttachmentFileL(i);
// ... do something with attachment, then tidy up
attachFile.Close();
}
CleanupStack::PopAndDestroy(attachInfo);
}
CleanupStack::PopAndDestroy(store);
The following code removes an attachment from a message, using
MMsvAttachmentManager::RemoveAttachmentL()
.
/* Active object request function to remove specified attachment.
Arguments:
aEntry – entry from which to remove attachment
aNum – index of attachment to remove
*/
void CFoo::RemoveAttachL(CMsvEntry& aEntry, TInt aNum)
{
// get attachment manager from the entry's store
iStore = aEntry.EditStoreL();
MMsvAttachmentManager& attachMan =
iStore->AttachmentManagerL();
// remove attachment with index aNum
attachMan.RemoveAttachmentL(aNum,iStatus);
SetActive();
}
The associated RunL should commit the store:
iStore->CommitL();
This section describes how the email (POP/SMTP/IMAP) MTM (CImEmailMessage) API changes for attachment handling.
CImEmailMessage
previously had functions to add,
retrieve, and remove attachments. Clients should now use the attachment manager
API for these tasks. To get an attachment manager, use the new
CImEmailMessage
function:
MMsvAttachmentManager& AttachmentManager()
Details of the now deprecated functions and the equivalent to migrate to are given below:
|
MImURITranslator
defines member functions,
implemented in CImEmailMessage
, for getting the attachment
file corresponding to a relative URI in a MHTML message. From v9.1, the class
has a new member function
GetUniversalResourceIdentifierFileHandle()
, which returns a file
handle to the referenced file.
From v9.1 the client MTM (CBaseMtm
) changes, and
the CreateAttachmentL()
and DeleteAttachmentL()
functions are deprecated, and are replaced with new overloads of
CreateAttachmentL()
, CreateLinkedAttachmentL()
and
CreateMessageAttachmentL()
functions. All the functions are
implemented for the SMTP Client MTM.
For the POP3 and IMAP4 Client MTMs, the new functions are implemented
to leave with KErrNotSupported
.
The handling of attachments for the OBEX MTMs (infrared and Bluetooth) has changed, and clients should migrate to using the new API as discussed in the following sections:
Previously, to add an attachment, a client created an attachment entry and added the attachment file directly to a directory under the attachment entry. A separate attachment entry was required for each attachment file.
Clients should now instead:
Get an attachment manager
(MMsvAttachmentManager
) for the message entry, using
CMsvStore::AttachmentManagerL()
.
Use MMsvAttachmentManager::AddAttachmentL()
to add attachments
Commit the store.
Previously, the OBEX MTM had special support for adding attachments
as linked files, consisting of the following CObexClientMtm
functions:
CObexClientMtm::StartFileNameExternaliseL()
CObexClientMtm::ExternaliseFileNameL()
CObexClientMtm::ExternaliseFileNameAndHeadersL()
CObexClientMtm::CommitFileNameExternaliseL()
CObexClientMtm::InvokeSyncFunctionL(
) with
a TSyncCmds
argument
and the utility class CObexMtmFileNameExternaliser
.
These are now all deprecated, and clients should instead:
Get an attachment manager
(MMsvAttachmentManager
) for the entry, using
CMsvStore::AttachmentManagerL()
.
Use
MMsvAttachmentManager::AddLinkedAttachmentL()
to add
linked attachments
To add headers to an attachment, use the new member function
CObexHeaderList::ExportToAttachmentL()
. Headers can be
retrieved using the new member function
CObexHeaderList::ImportFromAttachmentL()
.
From v9.1 the client MTM (CBaseMtm
) changes, and
the CreateAttachmentL()
and DeleteAttachmentL()
functions are deprecated, and are replaced with new overloads of
CreateAttachmentL()
, and the
CreateLinkedAttachmentL()
and
CreateMessageAttachmentL()
functions.
For the OBEX client MTMs, the default implementations of these
functions are available, except for CreateMessageAttachmentL()
,
which leaves with KErrNotSupported
.
Previously, configuration settings, such as email account information, were stored in a message store file associated with a service entry. This has changed for two platform security related reasons:
To allow more precise control over access to settings. In
particular, certain sensitive settings fields, such as login names and
passwords, require the client to have the
Read
/WriteDeviceData
security capabilities.
The Message Store can be on removable media, which could be removed from the device and read or tampered with. From v9.1, to protect sensitive settings, service settings are always stored on the device.
To eliminate these risks, the settings information is now stored in the Central Repository (which always remains on the device.) The use of the Central Repository is transparent to clients, which access the settings information through wrapper APIs provided by the MTMs.
Previously, the CMsvDefaultServices
class could be used to
access a list of default services per MTM. This list was stored in a message
store. This class is now deprecated, and new functions provided in
CBaseMtm
to get, change and remove default service IDs:
virtual TMsvId DefaultServiceL() const;
virtual void RemoveDefaultServiceL();
virtual void ChangeDefaultServiceL(const TMsvId& aService);
Note: Email (see below) provides functions in the higher level CEmailAccounts API for managing default accounts.
CEmailAccounts
has been changed in v9.1, so that
the creation of IMAP and POP accounts is now separate from the creation of SMTP
accounts (used to push or send mail).
The new class allows messaging clients to create, retrieve, edit, and delete email accounts. Account creation and deletion are described further in:
The old TPOP3AccountId
API is replaced with
TPopAccount
and TSmtpAccount
.
The old TIMAP4AccountId
API is replaced with
TImapAccount
and TSmtpAccount
.
An account encapsulates:
settings for the POP, IMAP or SMTP service, accessed through
CImPop3Settings
, CImImap4Settings
or
CImSmtpSettings
, respectively.
IAP (Internet account settings) preferences for each of the
services, accessed through CImIAPPreferences
.
Clients previously used store/restore functions on these settings
objects to access and save settings in a message store object associated with a
service entry. These store/restore functions are now deprecated, and clients
should use instead the CEmailAccounts
functions:
Create<protocol>AccountL
Get<protocol>AccountsL
Delete<protocol>AccountL
Load<protocol>SettingsL
PopulateDefault<protocol>SettingsL
Save<protocol>SettingsL
where <protocol>
is one of the following, depending
on the function:
Pop
Imap
Smtp
PopIap
ImapIap
SmtpIap.
The new simple classes, TPopAccount
,
TImapAccount
and TSmtpAccount
are
used with these functions to identify particular accounts.
The notion of default IMAP and POP accounts has been removed (along with any associated APIs), only SMTP has a default account, which can be manipulated with these functions:
DefaultSmtpAccountL
SetDefaultSmtpAccountL
Licensees can customize default account settings used for a phone by
editing the central repository initialisation files (in
common\generic\messaging\email\clientmtms\group\
).
For more details, see Interface breaks for Device provisioning, ECOM, EZlib, Graphics services, Java, Log engine, Messaging, Multimedia, and Networking.
The following example code creates a new IMAP email account. The account uses the default settings and IAP preferences, apart from the login name and password, which are set explicitly.
// create settings objects
CImImap4Settings* imapSet = new (ELeave) CImImap4Settings;
CleanupStack::PushL(imapSet);
CImIAPPreferences* imapIap = CImIAPPreferences::NewLC();
// populate the setting objects with default values
CEmailAccounts* account = CEmailAccounts::NewLC();
account->PopulateDefaultIMAPSettingsL(*imapSet, *imapIap);
// update settings
imapSet->SetLoginNameL(KLoginName);
imapSet->SetPasswordL(KPassword);
// create IMAP account
TImapAccount imapAccount = account->CreateIMAPAccountL(accountName, *imapSet, *imapIap, EFalse);
CleanupStack::PopAndDestroy(3);
To iterate through all accounts, you can get a list of identifiers
using Get<protocol>AccountsL
. For example:
CEmailAccounts* accounts = CEmailAccounts::NewLC();
RArray<TPOPAccount> popAccounts;
CleanupClosePushL(popAccount);
accounts->GetPOPAccountsL(popAccount);
See Email Settings for a list of <protocol>.
The new CSmsAccount
class enables messaging
clients to edit the SMS account settings (there is expected to be only one
account on a device). Clients previously used store/restore functions on the
CSmsSettings
objects to access and save settings in a message
store object associated with a service entry. These store/restore functions are
now deprecated, and clients should use instead the CSmsAccount
functions.
The following example loads the existing account settings, does an update, and saves the settings.
// load existing settings
CSmsSettings* smsSet = CSmsSettings::NewLC();
CSmsAccount* account = CSmsAccount::NewLC();
account->LoadSettingsL(*smsSet);
// update settings
smsSet->SetReplyQuoted(ETrue);
// save settings
account->SaveSettingsL(*smsSet);
CleanupStack::PopAndDestroy(2);
The rest of this section describes:
The SMS settings can hold a configuration for one or more SMS service
centres. Previously, the configured service centres could be accessed through
CSmsSettings
member functions, which encapsulated the
service centre address in a CSmsNumber
object. These functions are
now deprecated, and clients should use instead a new set of
CSmsSettings
member functions, as listed below:
|
SMS service centre details are now encapsulated in
CSmsServiceCenter
objects, and the new functions now
access these objects.
The following code loads the service settings, and gets the details for each configured service centre.
// load settings
CSmsSettings* smsSet = CSmsSettings::NewLC();
CSmsAccount* account = CSmsAccount::NewLC();
account->LoadSettingsL(*smsSet);
// loop through service centres
TInt numSC = smsSet->ServiceCenterCount();
for (int i=0; i<numSC; i++)
{
// get centre details
CSmsServiceCenter& sc = smsSet->GetServiceCenter(i);
// get name and address of the centre
TPtrC address = sc.Address();
TPtrC name = sc.Name();
}
An SMS service can have configuration settings that control the scheduled sending of messages. These configuration settings are in four parts:
General settings: CMsvScheduleSettings
Off -peak times: CMsvOffPeakTimes
, holding
TMsvOffPeakTime
objects
Send error actions: CMsvSendErrorActions
,
holding TMsvSendErrorAction
objects
System agent actions: CMsvSysAgentActions
,
holding TMsvSysAgentConditionAction
objects
These settings were previously stored in the SMS service entry using
RestoreL
/StoreL
functions on the above classes. These
functions are now deprecated, and clients should use the new
CSmsAccount
functions to initialise and edit the settings:
void InitialiseDefaultSettingsL(CMsvScheduleSettings& aScheduleSettings, CMsvOffPeakTimes& aOffPeakTimes, CMsvSendErrorActions& aErrorActions, CMsvSysAgentActions& aSysAgentActions);
void LoadSettingsL(CMsvScheduleSettings& aScheduleSettings, CMsvOffPeakTimes& aOffPeakTimes, CMsvSendErrorActions& aErrorActions, CMsvSysAgentActions& aSysAgentActions);
void SaveSettingsL(const CMsvScheduleSettings& aScheduleSettings, const CMsvOffPeakTimes& aOffPeakTimes, const CMsvSendErrorActions& aErrorActions, const CMsvSysAgentActions& aSysAgentActions) const;
The following example loads the scheduled send settings, updates one of the parameters, and saves the updated settings.
// create an SMS account object
CSmsAccount *smsAccount = CSmsAccount::NewLC();
// create objects for schedule send settings
CMsvSysAgentActions *sysAgtActions = new (ELeave) CMsvSysAgentActions;
CleanupStack::PushL(sysAgtActions);
CMsvSendErrorActions *sendErrorActions = CMsvSendErrorActions::NewLC();
CMsvOffPeakTimes *offPeakTimes = new (ELeave) CMsvOffPeakTimes;
CleanupStack::PushL(offPeakTimes);
CMsvScheduleSettings *scheduleSettings = CMsvScheduleSettings::NewLC();
// load the schedule send settings
smsAccount->LoadSettingsL(*scheduleSettings, *offPeakTimes, *sendErrorActions, *sysAgtActions);
// do an update
TTimeIntervalSeconds interval(5);
scheduleSettings->SetShortInterval(interval);
// save updated settings
smsAccount->SaveSettingsL(*scheduleSettings, *offPeakTimes, *sendErrorActions, *sysAgtActions);
CleanupStack::PopAndDestroy(5);
The System Agent component is removed from v9.1. This causes a change
in the TMsvSysAgentConditionAction
class, which
encapsulates a condition that must be satisfied before a message sending
attempt.
The TMsvSysAgentConditionAction::iCondition
member changes
from being a system agent condition, TSysAgentCondition
, to being
of a new type, TMsvCondition
. This defines a condition
that a Publish and Subscribe property must satisfy.
Clients should identify the Publish and Subscribe property that is
equivalent to the System Agent condition that was previously used, and change
their code to set a TMsvCondition
object appropriately.
This is a source compatible break with no migration path (all 9.0 clients must change regardless of the configuration macro settings).
An OBEX (Bluetooth/infrared) MTM service previously had one setting, a
password, which was accessed using
CObexClientMtm::SetPasswordL()
and
GetPasswordLC
.
From v9.1, these functions are deprecated, and no replacement member functions are provided.
From v9.1, the message server's message store, previously located in
\
System\Mail\
, is private to the message server, and
its files cannot be directly accessed by other applications. This may cause
changes for clients in the following areas:
Previously, clients could use MessageServer
class
functions to get the current message store drive and to test if there is a mail
store on a particular drive. These functions now require that the caller has
the AllFiles security capability, or is running in the message server process.
From v9.1, clients should use these new functions instead:
to check if a drive contains the message store, use
CMsvSession::DriveContainsStoreL()
.
to get the drive that contains the message store, use
CMsvSession::CurrentDriveL()
.
Previously, an application could copy or delete the store using file
system functions. This is not possible in v9.1, and clients should instead use
the following new functions on CMsvSession
:
CMsvOperation* CopyStoreL(const TDriveUnit& aDrive,
TRequestStatus& aStatus);
CMsvOperation* DeleteStoreL(const TDriveUnit& aDrive,
TRequestStatus& aStatus);
Previously, a phone's messaging application could check if the
message server had deleted a corrupt message store on start-up by checking if
the file \System\Mail\storedeleted.tmp
existed.
From v9.1, this is not possible, and applications should use instead
the function CMsvSession::GetAndClearIndexCorruptFlagL()
.
This section discusses how authors of message type module (MTM) plugins should migrate to v9.1. It covers:
MTMs are DLLs, and must therefore follow the general rule for DLLs under platform security that a process cannot load a DLL with a smaller set of capabilities than itself. Client-side, UI Data, and User Interface MTM DLLs are loaded by email client processes. To make these DLLs available to all clients, it should have the maximum capabilities, as follows:
CAPABILITY All -TCB
Server-side MTMs are loaded by the message server, and must have the capabilities that it requires, as follows:
CAPABILITY ReadDeviceData WriteDevicedata ProtServ NetworkControl NetworkServices LocalServices ReaduserData
Because of the altered file system layout for data caging, the
location of an MTM's registration resource file must change to be in the
resource\messaging\mtm
directory. This can be done by changing the
mmp file that builds the registration file as follows:
#ifdef __SECURE_DATA__
START RESOURCE txtmtm.rss
TARGETPATH resource\messaging\mtm
END
#else
RESOURCE txtmtm.rss
#endif // __SECURE_DATA__
This uses the __SECURE_DATA__
macro, which is defined
for v9.1, to conditionally put the compiled registration resource file in the
correct location.
The main resource, MTM_INFO_FILE
, used to describe the
MTM properties has changed for v9.1. To update your resource file, change the
MTM_COMPONENT
structure members to be
MTM_COMPONENT_V2
, and for each structure:
Remove the specific_uid member
Change the version member to be:
version = VERSION_V2 {};
add a member filename that specifies the filename of the MTM DLL
(The loader will assume a path of sys\bin\
. For migration
purposes, a full filename such as \system\libs\somemtm.dll
can be
given, so that the loader can find binaries that haven't yet been migrated).
For example,
MTM_COMPONENT_V2
{
human_readable_name = "TextMTM server MTM";
component_uid = KUidMtmServerComponentVal;
entry_point = 1;
version = VERSION_V2 {};
filename = "txts.dll";
}
The reason for these changes is that with platform security, the message server cannot scan the protected system binary directory for files with a particular UID.
Remember that if you want to be able to use the same resource file with both v9.1 and pre-v9.1 OS releases, you can use macro conditionals, such as
#ifdef __MESSAGING_API_V2__
....
#endif
within the resource file.
With the introduction of platform security, individual MTMs are required to specify the additional security capabilities that messaging clients require in order to send messages by that MTM. These capabilities must be set in the registration resource file that describes the MTM's properties.
This is done using the new resource structure
MTM_SECURITY_CAPABILITY_SET
. This has a single array member
capabilities that specifies the required capabilities: each value should be a
capability as defined in TCapability
in
e32capability.h
. For example, this resource specifies that the
client must have the local services (e.g. Bluetooth) capability:
RESOURCE MTM_SECURITY_CAPABILITY_SET
{
capabilities = { ECapabilityLocalServices };
}
An MTM_SECURITY_CAPABILITY_SET
must be the third
resource in the registration file (following the MTM_INFO_FILE
and
MTM_CAPABILITIES
resources), even if the MTM requires no
additional capabilities to be defined.
This means if the resource does not already define an
MTM_CAPABILITIES
structure, it must now do so.
MTM_CAPABILITIES
has nothing to do with platform security, but
specifies flags used by SendAs
. If the MTM can support
SendAs
, it should define the resource as:
RESOURCE MTM_CAPABILITIES
{
send_capability=1;
body_capability=1;
}
If the MTM doesn't support SendAs, use the following:
RESOURCE MTM_CAPABILITIES
{
}
UI and UI Data MTMs have resource files to specify their UI resources.
Previously, these were built to the \system\data
directory. From
v9.1, this should be changed to \resource\messaging\
, e.g.:
START RESOURCE txti.rss
HEADER
#ifdef __SECURE_DATA__
TARGETPATH \resource\messaging
#else
TARGETPATH \system\data
#endif // __SECURE_DATA__
END
MTMs implement the GetResourceFileName
functions on
CBaseMtmUiData
and CBaseMtmUi
to pass
the path of the resource files to the framework. From v9.1, the framework will
assume the file is in z:\resource\messaging\
unless a path to
another location is specified.
UI Data MTMs typically also build an mbm
file. You should
also change the mmp
file to build this to
\resource\messaging\
.
If the UI Data MTM calls
CBaseMtmUiData::CreateBitmapsL()
, change the call to
specify the new path of the mbm
file.
The SendAs API has changed for platform security (see SendAs Clients), and the MTM APIs change in a number of areas to support this, as explained in the following sections:
As seen above, platsec changes the way that the messaging framework
handles attachments. CBaseMtm
has attachment handling
functions, intended for use by the SendAs API, which also change. If your MTM
overrides the default implementation of these functions, you will need to
change your MTM implementation.
These functions are deprecated:
IMPORT_C virtual void CreateAttachmentL(TMsvId& aAttachmentId, TFileName& aDirectory);
IMPORT_C virtual void DeleteAttachmentL(TMsvId aMessageId, TMsvId aAttachmentId);
These new functions handle attachments. They include the new
TUint aCharset
parameter, which provides the IANA character set:
virtual void AddAttachmentL(const TDesC& aFilePath, const TDesC8& aMimeType, const TUint aCharset, TRequestStatus& aStatus);
virtual void AddAttachmentL(RFile& aFile, const TDesC8& aMimeType, const TUint aCharset, TRequestStatus& aStatus);
virtual void AddLinkedAttachmentL(const TDesC& aFilePath, const TDesC8& aMimeType, const TUint aCharset, TRequestStatus& aStatus);
virtual void CreateAttachmentL(const TDesC& aFileName, RFile& aAttachmentFile, const TDesC8& aMimeType, const TUint aCharset, TRequestStatus& aStatus);
There is no replacement for DeleteAttachmentL()
, as the
new SendAs API does not require this function.
The CBaseMtm
API previously had no generic
support for specifying whether addresses are of To:, Cc:, or Bcc: types. To
enable this, the following functions are added:
void CBaseMtm::AddAddresseeL(TMtmRecipientType aType, const TDesC& aRealAddress)
void CBaseMtm::AddAddresseeL(TMtmRecipientType aType, const TDesC& aRealAddress, const TDesC& aAlias)
where TMtmRecipientType
is a flag indicating the address
type. The default implementation for these functions is to leave with
KErrNotSupported
. MTMs that support address types should implement
these functions. To support this, the CBaseMtm::iAddresseeList
data member has changed from being a plain string array into a new list type,
CBaseMtmRecipientList
, which allows the address type to be stored
together with the address itself. The AddresseeList()
function has
changed to return a const CBaseMtmRecipientList&
rather than a
const CDesCArray&
.
The new functions, as well as the existing
AddAddresseeL()
overloads, can be implemented to append to this
list, e.g.:
// existing overload, assume default is use a To address type
void CFooClientMtm::AddAddresseeL(const TDesC& aRealAddress)
{
iAddresseeList->AppendL(EMtmRecipientTo, aRealAddress);
}
// existing overload, assume default is use a To address type
void CFooClientMtm::AddAddresseeL(const TDesC& aRealAddress, const TDesC& aAlias)
{
AddAddresseeL(EMtmRecipientTo, aRealAddress, aAlias);
}
// new overload specifying address type (no alias)
void CFooClientMtm::AddAddresseeL(TMtmRecipientType aType, const TDesC& aRealAddress)
{
iAddresseeList->AppendL(aType, aRealAddress);
}
// new overload specifying address type (with alias)
void CFooClientMtm::AddAddresseeL(TMtmRecipientType aType, const TDesC& aRealAddress, const TDesC& aAlias)
{
HBufC* address = HBufC::NewLC(aRealAddress.Length()+aAlias.Length()+iFormatString->Length());
address->Des().Format(*iFormatString,&aAlias,&aRealAddress);
iAddresseeList->AppendL(aType, address->Des());
CleanupStack::PopAndDestroy(); // address
}
It is recommended that an MTM silently accepts Cc: recipients as To:
recipients if Cc: recipients are not supported. MTMs should reject (with an
error of KErrNotSupported
) Bcc: recipients if they do not support
Bcc: recipients.
An MTM can specify to clients whether it supports address types using
a new capability, KUidMtmQuerySupportsRecipientTypeValue
, defined
in MTMDEF.HRH
. Implementations of QueryCapability
in
the client MTM, UI MTM, and UI Data MTM should be updated to handle this
capability.
The Send-As server sends messages using the
CBaseMtm::InvokeAsyncFunctionL()
API with a new generic
command ID KMTMStandardFunctionsSendMessage
.
MTMs that support SendAs must support this command. When it is
called, the implementation of InvokeAsyncFunction
L must return an
instance of a class that implements the new
CMsvSendOperation
interface. The purpose of this interface
is to provide information to the UI in a generic format about the progress of
the sending operation. The MTM implements in its CMsvSendOperation
derived-class the function:
virtual const TDesC8& TranslateProgress(const TDesC8& aProgress)=0;
whose purpose is to convert the MTM's native progress data into the
standard progress structure,
CMsvSendOperation::TSendOperationProgress
.
The Send-As server will also require the UI MTM API to be extended to
allow non-trusted client applications to send messages. It must implement the
new CBaseMtmUi
function:
virtual CMsvOperation* ConfirmSendL(TRequestStatus& aStatus, const CMsvEntrySelection& aSelection, const TSecurityInfo& aClientInfo);
Typically this will launch a dialog that will query the user to
confirm the send request. The TSecurityInfo
parameter provides the
security properties of the process that requested the send.
As discussed in Configuration settings, configuration settings for Symbian supplied MTMs have been moved from the message store to the central repository to improve the security of these settings. Writers of MTMs can also move their settings, though this is not compulsory. The following sections describe how to move these settings:
The central repository has a simple two tier structure:
At the highest level, a UID is used to identify a single repository. Each MTM should have its own repository.
Each repository can contain up to 232
settings, where each setting is enumerated by a 32-bit identifier. Settings can
be signed integers (TInt
), floating point values
(TReal
), and strings (TDesC
).
MTM settings typically require more structure than a flat list: for example, you may want to store multiple groups of settings for multiple services. When using the central repository, this extra structure is encoded in the setting keys using bit fields. The repository API provides helpful functions to retrieve keys that match particular bitmask patterns.
For example, for an MTM with multiple services, the 32 bit key could be structured as follows:
|
where:
service flag: indicates whether the key refers to a setting for a particular MTM service, or is global to the MTM.
account ID: identifier for the MTM service to which the setting belongs. For MTMs that don’t have multiple services, this field isn't necessary.
Note: This isn't the same as the message server's TMsvId entry ID for the service, which is a 32 bit value. Instead, account IDs can be allocated in a simple sequence by the MTM class that accesses the repository.
setting group: identifier for the group of settings. A group
typically corresponds to a class that represents related settings. For example,
for SMTP, there are two groups, one for SMTP specific settings
(CImSmtpSettings
fields) and one for IAP preferences
(CImIAPPreferences
fields). MTMs that have one group don't need
this field.
setting field: identifier for the setting field, e.g. login name.
Note that scheduled send settings are now stored in the central repository. For MTMs that support scheduled send, this imposes the following conditions:
the UID used for the repository must be the same as the MTM UID to allow the scheduled send code to get its settings from the repository
IDs in the range 0x10000 to 0x90000 should be kept free for
scheduled send to store its settings (see
TMsvScheduleSettingsUtils
).
A repository is created by a repository definition file being present
in the repository file area (z:\private\10202BE9\
). An MTM should
define such a file for its repository.
Considerations in creating such a file include:
The [Main]
section of the file specifies settings
that are always present. The Email MTM, for example, uses this member function
to store the default values for account settings. Other settings can be created
dynamically by the MTM as required.
In the [PlatSec]
section of the file, you can
specify capabilities required by clients to access the settings. The Symbian
pattern is to require WriteDeviceData
to write to settings,
ReadDeviceData
to read sensitive settings, and no capabilities to
read other settings.
A simple example of such a file is given below:
cenrep
version 1
[PlatSec]
# default security policies for repository
cap_rd=AlwaysPass cap_wr=WriteDeviceData
[Main]
#one setting, a writable string with value "foo".
0x00000000 string foo 1
The MTM's bld.inf
should export the file to the central
repository file area.
#ifdef __MESSAGING_API_V2__
[10005247].txt z:\private\10202BE9\[10005247].txt
#endif
For ROM-based MTMs, the file can then be put into the correct place in the ROM from the IBY file:
#ifdef __MESSAGING_API_V2__
data=EPOCROOT##epoc32\data\Z\private\10202BE9\[10005247].txt
private\10202BE9\[10005247].txt
#endif
An MTM's repository access class is responsible for creating,
deleting, saving and retrieving settings from the repository. Licensees and
partners may find CEmailAccounts
or
CSmsAccount
suitable models for writing a new repository
access class.
SDK users can find the CMTMTxtSettings
at
..\examples\Messaging\TextMTM
in the set of SDK examples.
All functions that use CMsvStore
StoreL
/RestoreL
functions to save/access settings
should change to using the new repository access class. Some candidates are:
Implementations of CBaseMtm::SaveMessageL()
and LoadMessageL
,
Implementations of CBaseMtmUi::CreateL()
,
EditL
, ViewL
, and DeleteServiceL
.
Any code that handles global settings, such as the default service. Details of this are given below.
Three new functions are added to CBaseMtm
to
support default services:
|
The base class implementations assume that the MTM only supports one service, and so does not store any setting to identify the default service. If this assumption is wrong for your MTM, you should override the default implementations to store such a setting. The recommended method is to use a "default service" key in the MTM's repository, whose value is the entry ID of the default service:
In the class used to access the repository, define member functions to manipulate the default service setting. For example, to get the default service setting:
EXPORT_C TMsvId CBarSettings::DefaultServiceL() const
{
// Get the default service ID from CenRep, key is KDefaultServiceId
TInt temp = 0;
User::LeaveIfError(iRepository->Get(KDefaultServiceId, temp));
return static_cast<TMsvId>(temp);
}
In the client MTM, simply call these functions. For example for
DefaultServiceL
:
TMsvId CBarClientMtm::DefaultServiceL() const
{
return iSettings->DefaultServiceL();
}
The SendAs API classes CSendAs
and
MSendAsObserver
provided in previous releases of the OS are
deprecated in v9.1, and a new API is introduced to which clients should
migrate.
The new API has all the functionality of the old API, plus support for:
Sending a message. Sending a message can require security capabilities (for network access etc.) that an application may not have. The message can still be sent if an application does not have the required capabilities, but only after SendAs has got confirmation from the UI MTM, which typically queries the user to confirm that the send should proceed.
Launching an editor for a message
The new API uses the client/server framework, and has two main classes:
RSendAs
: used to establish a session with the
Send-As server, and to find the available message types and services
RSendAsMessage
: used to create, set, and send
messages.
Unlike the previous API, the new API does not expose the message server
APIs such as CBaseMtm
.
To use the new API, the client should include the header
sendas2.h
and link against the library sendas2.lib
.
The rest of this section describes the following:
In the old API, the first task was typically to get a list of MTMs
available to send the message, by specifying the features that the MTMs must
have using AddMtmCapabilityL()
; for example:
iSendAs->ResetMtmCapabilitiesL();
iSendAs->AddMtmCapabilityL(KUidMtmQuerySupportAttachments,EFalse);
iSendAs->AddMtmCapabilityL(KUidMtmQueryMaxTotalMsgSize, ETrue); // calls back CapabilityOK()
Similar functionality is available on RSendAs
,
using the FilterAgainstCapability()
member function:
// reset filter
User::LeaveIfError(iSendAsServer.ResetMessageFilter());
// set filter for presence of capability
User::LeaveIfError(iSendAsServer.FilterAgainstCapability(KUidMtmQuerySupportAttachments));
// set filter to test that KUidMtmQueryMaxBodySize >= bodySize
User::LeaveIfError(iSendAsServer.FilterAgainstCapability(KUidMtmQueryMaxBodySize,
bodySize, ESendAsGreaterThan));
The chief difference here is that AddMtmCapabilityL()
can
call back a client implementation of the
MSendAsObserver::CapabilityOK()
interface to do a further
test on a returned capability value. FilterAgainstCapability
doesn't need this callback, as the overload:
FilterAgainstCapability(TUid aMessageCapability, TInt aValue, TSendAsConditionType aConditionType)
allows you to specify a value and a condition type (e.g. greater than) with which to test the capability.
Once a filter has been set, the available MTMs can be retrieved. The
replacement for CSendAs::AvailableMtms()
is
RSendAs::FilteredMessageTypes()
, which populates a
CSendAsMessageTypes
object:
// get message types
CSendAsMessageTypes* iMessageTypeInfo = CSendAsMessageTypes::NewL();
User::LeaveIfError(iSendAsServer.FilteredMessageTypes(*iMessageTypeInfo));
// get array of names of available types
const MDesCArray& mtms = iMessageTypeInfo->AvailableMessageTypes();
In the old SendAs
, once an MTM had been chosen, the
available services could be retrieved using
CSendAs::AvailableServices()
. The new API allows a list of
available services to be obtained using
RSendAs::AvailableAccountsL()
, which populates a
CSendAsAccounts
object. The MTM for which to get the
services is specified by the message type UID, which can be obtained from the
CSendAsMessageTypes
object:
// get message type UID of first MTM in the list of those available
TUid mtmuid = iMessageTypeInfo->MessageTypeUid(0);
// get a list of available services
CSendAsAccounts* accounts = CSendAsAccounts::NewL();
CleanupStack::PushL(accounts);
iSendAsServer.AvailableAccountsL(mtmuid, *accounts);
// get the names of the services, e.g. for sub-menu text
const MDesCArray& accountNames = accounts->AccountNames();
Once an account has been selected, the ID of the service can be obtained (for later use when creating a message):
// get ID of first available service
TSendAsAccount serviceId = accounts->Account(0);
Creating a message and setting its contents is now done through
RSendAsMessage
.
To create a message, use one of:
void CreateL(RSendAs& aSendAs, TSendAsAccount aAccount);
void CreateL(RSendAs& aSendAs, TUid aMessageType);
specifying either the service ID or message type obtained from
CSendAsMessageTypes
or
CSendAsAccounts
.
The contents of the message can then be set.
Note: There is no direct equivalent for CSendAs::QueryMessageCapability() for testing if an MTM supports a particular feature at this stage. Instead, you should be prepared to handle a returned error code that indicates that the setting cannot be made.
The rest of this section describes:
RSendAsMessage
offers the following member
functions to set the message's body text, subject, and BIO type.
void SetBodyTextL(const CRichText& aBody);
void SetBodyTextL(const TDesC& aBody);
void SetSubjectL(const TDesC& aSubject);
void SetBioTypeL(TUid aBioType);
These are very similar to the corresponding member functions on
CSendAs
.
RSendAsMessage
has similar member functions to
CSendAs
for setting recipients:
void AddRecipientL(const TDesC& aAddress, TSendAsRecipientType aRecipientType);
void AddRecipientL(const TDesC& aAddress, const TDesC& aAlias, TSendAsRecipientType aRecipientType);
Note, however, that compared to CSendAs
these member
functions have an extra TSendAsRecipientType
parameter to specify
whether the recipient is of a 'To' , 'Cc' or 'Bcc' type. If the message type
does not support 'Cc' recipients, the recipient is instead treated as a 'To'
recipient. If the 'Bcc' field is not supported, the member functions return
KErrNotSupported
.
There is no equivalent to
CSendAs::RemoveRecipient()
.
CSendAs
had a single
CreateAttachmentL()
member function with which to add an
attachment to a message. RSendAsMessage
has a collection
of member functions as follows:
IMPORT_C void AddAttachment(const TDesC& aFilePath, TRequestStatus& aStatus);
IMPORT_C void AddAttachment(const TDesC& aFilePath, const TDesC8& aMimeType, TRequestStatus& aStatus);
IMPORT_C void AddAttachment(RFile& aFile, const TDesC8& aMimeType, TRequestStatus& aStatus);
IMPORT_C void AddAttachment(RFile& aFile, TRequestStatus& aStatus);
IMPORT_C void AddLinkedAttachment(const TDesC& aFilePath, const TDesC8& aMimeType, TRequestStatus& aStatus);
IMPORT_C void AddLinkedAttachment(const TDesC& aFilePath, TRequestStatus& aStatus);
IMPORT_C void CreateAttachmentL(TDes& aFileName, RFile& aAttachmentFile);
IMPORT_C void CreateAttachmentL(TDes& aFileName, RFile& aAttachmentFile, const TDesC8& aMimeType);
The first AddAttachment
member function is the closest
equivalent to CSendAs
::CreateAttachmentL()
.
The other member functions add some extra functionality, which might better
suit some applications:
The AddLinkedAttachment()
member functions do not
make a copy of the specified attachment, but simply keep a reference to its
path. Linked attachments must be located in a public area of the file system,
so that they can be accessed by the message server when it is sending the
message.
The CreateAttachmentL()
member functions return an
open file handle for a read/write attachment file in the message store. The
client application can adopt this file handle and use it to stream the
attachment data into the file. The client application is responsible for
closing the file handle.
Each attach member function has an overload that specifies a MIME-type for the attachment, which the sending MTM can use if appropriate to the message type.
There is no equivalent to
CSendAs::DeleteAttachmentL()
.
Sending a message is done using the following member functions:
IMPORT_C void SendMessage(TRequestStatus& aStatus);
IMPORT_C void SendMessageAndCloseL();
IMPORT_C void SendMessageConfirmed(TRequestStatus& aStatus);
IMPORT_C void SendMessageConfirmedAndCloseL();
IMPORT_C void ProgressL(TSendAsProgress& aProgress);
The client application can request to send the created message in two ways – unconfirmed and confirmed.
For a confirmed send request, the Send-As server uses the UI MTM of
the message type to confirm the sending of the message. Typically the UI MTM
will query the user, who can accept or refuse the send. If the send is refused
by the user, the send request completes with the error
KErrPermissionDenied
. The message remains in the Drafts folder,
and can still be accessed through the Send-As API.
For an unconfirmed send, the client must have the security capabilities (e.g. NetworkServices for SMS, or email) required by the MTM to send messages. The call will leave if the client does not have the required capabilities.
For an unconfirmed send, or a confirmed send that has been accepted by the user, the message is copied to the Outbox and then the MTM for the message type is used to send the message. The message is now no longer accessible through the Send-As APIs, and the client application cannot modify or delete the message.
The outcome of a successful or unsuccessful send is dependent on the MTMs for the message type. For instance, a successfully sent message may be moved to the Sent folder (e.g. SMS) or deleted (e.g. OBEX), while an unsuccessfully sent message may remain in the Outbox and can be re-scheduled depending on the send error (e.g. SMS).
The synchronous member functions, SendMessageAndCloseL()
and SendMessageConfirmedAndCloseL()
send the message in the
background and close the RSendAsMessage
handle.
For the asynchronous member functions, SendMessage()
and
SendMessageConfirmed()
:
Any send errors are reported through the
TRequestStatus
object.
The send can be cancelled using the Cancel member function.
Progress information can be obtained using
RSendAsMessage::ProgressL()
. This populates a progress
information object TSendAsProgress
. The client can use
this to e.g. display a progress bar while sending is taking place.
Once the send request has completed, the client application must
close the RSendAsMessage
object to release server-side
resources.
The following member function allows a client application to launch the
editor (as provided by UI MTM) for the created message. The handle to the
message is closed, so it can no longer be accessed through
RSendAsMessage
.
IMPORT_C void LaunchEditorAndCloseL();
The message can also be saved to the message store (if this supported by the MTM) without being sent using the member function:
IMPORT_C void SaveMessageAndCloseL();
From v9.1, the BIO-message parsers are:
relocated to the system's new location for executables
identified by file name rather than by UID
loaded client-side rather than server-side
If you have an existing BIO parser, you need to make the following changes:
1. Change the parser to derive from the new
CBaseScriptParser2
class rather than
CBaseScriptParser
. The significant change is that the parser
receives the message to parse as an CMsvEntry
rather than
a CMsvServerEntry
. The CMsvEntry
still provides access to all of the BIO message data.
2. Build the binary to the default binaries directory rather than to
\system\parsers\
. The build tools ignore the mmp
file
targetpath
statement in v9.1, so this does not need to be
explicitly configured.
3. In the resource file BIO_INFO_FILE
structure, replace the
message_parser_uid
member with a member
message_parser_name
that specifies the parser's filename. For
example:
#ifdef __MESSAGING_API_V2__
#ifdef __MESSAGING_API_V2__
message_parser_name="cbcp.dll";
#else
message_parser_uid=0x1000526B;
#endif
The resource file should include biftool2.rh
rather than
biftool.rh
: i.e. use:
#ifdef __MESSAGING_API_V2__
#include <biftool2.rh>
#else
#include <biftool.rh>
#endif // __MESSAGING_API_V2__
4. Export or build BIF
files (built from .rss
files) and mbm
files to \resource\messaging\bif\
rather than \system\bif\
. For example:
START RESOURCE ..\cbcpbif\cbcp.rss
#ifdef __MESSAGING_API_V2__
TARGETPATH resource\messaging\Bif
#else
TARGETPATH System\Bif
#endif
LANG SC
END
START BITMAP cbcp.mbm
#ifdef __MESSAGING_API_V2__
TARGETPATH resource\messaging\Bif
#else
TARGETPATH System\Bif
#endif
5. If the parser is built into a ROM, amend .iby
files
accordingly for steps 2 and 4.