diff -r 43e37759235e -r 51a74ef9ed63 Symbian3/SDK/Source/GUID-E180D222-CC4F-5007-93FC-C339BBE708BC.dita --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Symbian3/SDK/Source/GUID-E180D222-CC4F-5007-93FC-C339BBE708BC.dita Wed Mar 31 11:11:55 2010 +0100 @@ -0,0 +1,384 @@ + + + + + +Client +MTM +

Client MTMs provide a client-side API to functionality provided by the +Server MTM, mainly for message manipulation and transport. It acts as the +interface between the internal representation of a message’s data and the +User Interface (UI) MTM. This architecture provides certain advantages; for +example, a UI MTM can offer a user interface to enter message addresses without +knowing the address storage format. Message client applications that do not +require a user interface can use these client-side functions directly for +automated message handling.

+

The Message Server entry with which Client MTMs currently work is referred +to as the context. UI MTMs always operate on the contexts set through Client +MTMs.

+

Client MTMs offer some or all of the following capabilities:

+ +
Client MTM +base class

The base class for Client MTMs is CBaseMtm which +provides a high-level interface for accessing and manipulating a Message Server +entry

The following are some significant functions in CBaseMtm. +Some functions are implemented by the base class, and others must be implemented +in a derived class:

    +
  • Context functions

    The CBaseMtm::SetCurrentEntryL (CMsvEntry *) and CBaseMtm::SwitchCurrentEntryL (TMsvId) functions +change the Message Server entry (the context) on which later actions are performed. +After creating a new Client MTM object, a message client application must +set an initial context before using other functions.

  • +
  • Store and restore +entry data functions

    The changes that a message client application +makes to a message context through Client MTM functions, such as altering +the body text obtained through CBaseMtm::Body(), are, for +efficiency, cached in memory by a Client MTM. The message store (SaveMessageL())and +restore (LoadMessageL()), functions are concerned with +transferring data between that cache and committed storage.

    Note: Unlike +message contexts, message client applications are not expected to manipulate +directly contexts for message services. Instead, the corresponding User Interface +MTM provides a dialog to allow the user to alter service settings, and calls +Client MTM functions to handle their retrieval and storage.

  • +
  • Store and restore +body text functions

    The base class maintains a private CRichText object +cache to store the body text for the current context. This can be accessed +for reading and writing by message client applications through CBaseMtm::Body(). +The CBaseMtm::StoreBodyL() (CMsvStore &) and CBaseMtm::RestoreBodyL() (CMsvStore +&) functions encapsulate the retrieval and storage of this CRichText object +to a CMsvStore.

  • +
  • Address list functions

    The +format and storage of message addresses is MTM-specific. The CBaseMtm::AddresseeList() const, CBaseMtm::AddAddresseeL (const TDesC &), and CBaseMtm::RemoveAddressee (TInt) allow +clients to access address information in a generic way without having MTM-specific +knowledge.

  • +
  • MTM-specific client +functions

    MTM components can offer protocol-specific functionality +not provided by base class interface functions. MTM components define IDs +that correspond to each protocol-specific operation offered, and implement +the CBaseMtm::InvokeSyncFunctionL() and CBaseMtm::InvokeAsyncFunctionL() functions +to allow clients to access these operations by passing in the appropriate +ID. These functions are provided to allow the MTM component to offer both +synchronous and asynchronous functionality. Message client applications can +dynamically add user-interface features for these operations using CBaseMtmUiData::MtmSpecificFunctions().

  • +
  • Query function

    The +Client MTM QueryCapability() function is used to inquire +whether an MTM supports a given feature. The first argument is a UID defined +to correspond to a particular capability. The function returns a system error +code and the response (whether the MTM supports the queried capability) is +passed back through the second (by-reference)aResponse parameter. +This value can be an integer or a bit set, depending on the capability.

    The +UIDs for the different types of query are as follows:

    + + + +UID +Capability + + + + +

    KUidMsvMtmQueryMaxBodySize

    +

    Maximum message body size

    +
    + +

    KUidMtmQueryMaxTotalMsgSize

    +

    Maximum total size of message.

    +
    + +

    KUidMtmQuerySupportedBody

    +

    Character widths supported by message type. The returned value is +the sum of the appropriate values. The return type is either of KMtm7BitBody, +KMtm8BitBody, KMtm16BitBody, and KMtmBinaryBody)

    +
    + +

    KUidMtmQuerySupportAttachments

    +

    To check if the attachments are supported

    +
    + +

    KUidMtmQuerySupportSubject

    +

    Does the MTM message type have a subject field

    +
    + +

    KUidMtmQuerySupportsFolder

    +

    Does the MTM support folders

    +
    + +

    KUidMtmQueryOffLineAllowed

    +

    Off-line operation allowed

    +
    + +

    KUidMtmQueryCanSendMsg

    +

    Can send the message

    +
    + +

    KUidMtmQueryCanReceiveMsg

    +

    Can receive the message

    +
    + +

    KUidMtmQueryMaxRecipientCount

    +

    Maximum number of recipients (-1 indicates unlimited numbers).

    +
    + +

    KUidMtmQuerySendAsRequiresRenderedImage

    +

    When using the MTM in Send As, does a rendered image have to be +prepared.

    +
    + +

    KUidMtmQuerySendAsRenderingUid

    +

    Printer driver UID for rendering the fax image.

    +
    + +

    KUidMsvMtmQueryEditorUid

    +

    UID of default message editor.

    +
    + +

    KUidMsvQuerySupportsBioMsg

    +

    Does the MTM support BIO messages

    +
    + +

    KUidMsvQuerySupportsScheduling

    +

    Does the MTM support scheduled sending.

    +
    + +

    KUidMtmQuerySupportsRecipientType

    +

    Does the MTM support the use of recipient type.

    +
    + +

    KUidMtmQuerySendAsMessageSendSupport

    +

    Support for Sending messages using SendAs.

    If this is supported, +then the MTM supports sending messages created through the SendAs API.

    +
    + + +

    The following example is a snapshot of the Text MTM example. For +more implementation details, see Messaging +Text MTM example code.

    TInt CTextMtmClient::QueryCapability(TUid aCapability, TInt& aResponse) + { + TInt error = KErrNone; + switch (aCapability.iUid) + { + case KUidMtmQueryMaxBodySizeValue: + case KUidMtmQueryMaxTotalMsgSizeValue: + aResponse = KMaxTextMessageSize; + break; + case KUidMtmQuerySupportedBodyValue: + aResponse = KMtm8BitBody + KMtm7BitBody; + break; + case KUidMtmQueryOffLineAllowedValue: + case KUidMtmQueryCanReceiveMsgValue: + aResponse = ETrue; + break; + case KUidMtmQuerySupportAttachmentsValue: + default: + return KErrNotSupported; + } + return error; + } +
  • +

The CBaseMtm class provides the virtual functions +for overriding in derived classes.

+
Client-side +operations

Many Messaging tasks can take a long time to complete. +For example, sending all items from the Outbox or downloading a large number +of items from a POP3 server. In these situations, the use of active objects +to wait for the completion of the task is inadequate, since applications also +require to obtain progress information while the task is running (for example, +to update a progress dialog). To solve this problem, most asynchronous functions +in Messaging create a CMsvOperation object and return a +pointer to it, as well as taking a TRequestStatus& parameter. +The CMsvOperation class is derived from CActive and +is used to obtain progress information about a long-running task.

The +base class for all client-side Messaging operations is CMsvOperation. +The asynchronous methods in the CBaseMtm interface all +return a pointer to a CMsvOperation object. When you implement +an MTM, you will have to provide your own custom operations, derived from CMsvOperation, +and return those polymorphically from your implementations of the asynchronous +APIs.

Example

The forward operation of the Text MTM +is explained in the following example.

The forward operation is an +active object state machine that runs a series of asynchronous tasks one after +another and waits for each to complete before moving on to the next. After +the operation has been completed, an active object is notified through its TRequestStatus passed +into the operation at construction.

The forward operation is constructed +using standard two-phase construction. The NewL() function +takes two arguments of a TMsvId (source message and destination +folder) type, a CMsvSession reference, and the observer’s TRequestStatus, +which is notified on completion. The active object is constructed and added +to the scheduler, and then ConstructL() is called:

void CTxtMtmForwardOperation::ConstructL() + { + iObserverRequestStatus = KRequestPending; + SetActive(); + TRequestStatus* stat = &iStatus; + User::RequestComplete(stat, KErrNone); + } +

This has the effect of marking this stage of the operation +as complete and means that RunL() is called at the next +opportunity. This simplifies the state machine because it means that all states +and tasks are started in RunL() and not in ConstructL().

The RunL() function +starts each task and receives a notification when it completes. The current +task being executed is stored in iProgress and iState, +as are the errors and the ID of the new forwarded message, once complete. +The default state for iState on construction is EInit.

void CTxtMtmForwardOperation::RunL() + { + User::LeaveIfError(iStatus.Int()); + switch(iProgress.iState) + { + case TTxtMtmForwardOpProgress::EInit: + iProgress.iState = + TTxtMtmForwardOpProgress::ECreateMessage; + CreateMessageL(); + break; + + case TTxtMtmForwardOpProgress::ECreateMessage: + iProgress.iState = + TTxtMtmForwardOpProgress::EFormatBodyText; + FormatBodyTextL(); + break; + + case TTxtMtmForwardOpProgress::EFormatBodyText: + iProgress.iState = + TTxtMtmForwardOpProgress::EFinished; + + default: + break; + } + if(!IsActive()) + { + TRequestStatus* stat = &iObserverRequestStatus; + User::RequestComplete(stat, KErrNone); + } + } +

If the state is EInit, the RunL() changes +state to ECreateMessage and then calls CreateMessageL() to +start the process of creating a message asynchronously.

void CTxtMtmForwardOperation::CreateMessageL() + { +

The function constructs a CMsvEntry for +the source entry and then retrieves its index entry.

delete iMsvEntry; + iMsvEntry = NULL; + iMsvEntry = iMsvSession.GetEntryL(iSourceMessage); + + // Get the entry to be forwarded + TMsvEntry forwardEntry = iMsvEntry->Entry(); +

The context of iMsvEntry is changed to +the destination folder and an entry is created.

// Set the context to the destination folder + iMsvEntry->SetEntryL(iDestinationFolder); +

The index entry’s date is updated to reflect the current date.

// Create the forwarded index entry + forwardEntry.iDate.HomeTime(); + iMsvEntry->CreateL(forwardEntry); +

The iFinalMsgId member of the progress +is updated to reflect the newly created entry.

iProgress.iFinalMsgId = forwardEntry.Id(); + + // schedules the active object to complete so that this + // class's RunL method + // will be called by the active scheduler + SetActive(); +

The operation’s TRequestStatus is then flagged +to cause RunL().

TRequestStatus* stat = &iStatus; + User::RequestComplete(stat, KErrNone); + } +

When this happens, iProgress.iState is set +to ECreateMessage, so the following code is executed:

case TTxtMtmForwardOpProgress::ECreateMessage: + iProgress.iState = TTxtMtmForwardOpProgress::EFormatBodyText; + FormatBodyTextL(); + break;

The state is set to EFormatBodyText and +the FormatBodyTextL() function is called.

+void CTxtMtmForwardOperation::FormatBodyTextL() + { +

The function constructs a CParaFormatLayer, +a CCharFormatLayer, and a CRichText object. +These objects are required to store the body text of the forwarded message.

CParaFormatLayer* paraLayer = CParaFormatLayer::NewL(); + CleanupStack::PushL(paraLayer); + CCharFormatLayer* charLayer = CCharFormatLayer::NewL(); + CleanupStack::PushL(charLayer); + CRichText* body = CRichText::NewL(paraLayer, charLayer); + CleanupStack::PushL(body); +

Then the context of iMsvEntry is changed +to point at the source message and a read-only CMsvStore is +opened for that entry.

// Get the message store from the source entry + iMsvEntry->SetEntryL(iSourceMessage); + CMsvStore* readStore = iMsvEntry->ReadStoreL(); + CleanupStack::PushL(readStore);

The context of the iMsvEntry object +is changed to point at the newly created entry and a CMsvStore is +opened for that entry.

// Get the message store from the newly created destination + // entry + iMsvEntry->SetEntryL(iProgress.iFinalMsgId); + CMsvStore* writeStore = iMsvEntry->EditStoreL(); + CleanupStack::PushL(writeStore); + + // Get the body text from the source entry and write it + // to the destination entry, prepending the forward + // prefix + readStore->RestoreBodyTextL(*body); + body->InsertL(0, KTxtMtmFwdPrefix); + + // this method performs a commit for us + writeStore->StoreBodyTextL(*body); + + CleanupStack::PopAndDestroy(5, paraLayer); + + // schedules the active object to complete so that this + // class's RunL method + // will be called by the active scheduler + SetActive(); + TRequestStatus* stat = &iStatus; + User::RequestComplete(stat, KErrNone); + } +

The iProgress.iState is set to EFinished, +and because the object has not been activated the following conditional statement +evaluates true:

if(!IsActive()) + { + TRequestStatus* stat = &iObserverRequestStatus; + User::RequestComplete(stat, KErrNone); + } +

The observer active object’s TRequestStatus is +flagged to let it know that the operation is complete.

To return progress +from the operation, implement the ProgressL() and FinalProgress() functions. ProgressL() must +be used to return progress information on the operation during processing, +and FinalProgress() is guaranteed to return the status +of a completed operation. ProgressL() must be implemented +to leave with KErrNotReady if the operation is not in progress, +and FinalProgress() must panic if the operation is not +complete.

const TDesC8& CTxtMtmForwardOperation::ProgressL() + { + if (!IsActive()) + { + User::Leave(KErrNotReady); + } + iProgressBuf() = iProgress; + return iProgressBuf; + } + +const TDesC8& CTxtMtmForwardOperation::FinalProgress() + { + __ASSERT_ALWAYS(!IsActive(), User::Panic(KTxtCPanic, + ETxtcOperationIsActive)); + iProgressBuf() = iProgress; + return iProgressBuf; + }

The RunError() function must also be +implemented to get any leaves in RunL().

TInt CTxtMtmForwardOperation::RunError(TInt aError) + { + iProgress.iError = aError; + TRequestStatus* stat = &iObserverRequestStatus; + User::RequestComplete(stat, aError); + return KErrNone; + }
+
+MTM overview + +MTM Capabilities + +Writing a +Client MTM +
\ No newline at end of file