Addition of the PDK content and example code for Documentation_content according to Feature bug 1607 and bug 1608
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved. -->
<!-- This component and the accompanying materials are made available under the terms of the License
"Eclipse Public License v1.0" which accompanies this distribution,
and is available at the URL "http://www.eclipse.org/legal/epl-v10.html". -->
<!-- Initial Contributors:
Nokia Corporation - initial contribution.
Contributors:
-->
<!DOCTYPE concept
PUBLIC "-//OASIS//DTD DITA Concept//EN" "concept.dtd">
<concept xml:lang="en" id="GUID-AC2903B2-0C3A-5104-B2A2-866DDAAAE2A9"><title>Example Code</title><prolog><metadata><keywords/></metadata></prolog><conbody><p>The example code demonstrates how to implement the CAF functions. Some of these examples listed here do not include complete error checking. The examples are written this way to simplify the understanding of the basic steps involved. All errors must be handled appropriately in production code. </p> <section><title>Reading from a file without checking errors </title> <p>This example function takes the URI of a file and displays the plaintext version of that content on screen. If anything goes wrong, for instance the file does not exist or there are no valid rights that allows the file to be displayed, the function leaves. </p> <p>It is important to notice the call to <xref href="GUID-B54C8391-FE69-324C-AC0A-1E88C2555F00.dita#GUID-B54C8391-FE69-324C-AC0A-1E88C2555F00/GUID-3E5B2A86-A06B-3710-99C9-FA205E99088F"><apiname>ContentAccess::CData::ExecuteIntent()</apiname></xref>. This must always be called, even if you think it is unlikely to open DRM content. </p> <codeblock id="GUID-5BC1FDCA-0E8A-5118-AE09-19B9896C2C3E" xml:space="preserve">class CContentViewer : public CBase
{
public:
static CContentViewer* NewL();
static CContentViewer* NewLC();
// Display given content.
void DisplayContent(const TDesC& aUri, TRequestStatus& aStatus)
{
TRAPD(err, DisplayContentL(aUri));
User::RequestComplete(aStatus, err);
}
private:
CContentViewer() : CBase() {}
~CContentViewer() {}
void DisplayContentL(const TDesC& aUri)
{
TInt size = 0;
TInt I = 0;
// Create a CContent object
// CAF figures out the appropriate agent
CContent *content = CContent::NewLC(aUri);
// Create a CData object to read the content
// Tell the agent we are planning to display the content
CData *data = content->OpenContentLC(EDisplay);
// Don't need content object any more
CleanupStack::PopAndDestroy(content);
// get the size of the plaintext content
data->DataSizeL(size);
// Execute the intent, tell the agent that we plan to display the content
// It is at this point that any stateful rights is decremented
data->ExecuteIntentL(EDisplay);
// read and display the file until we reach the end of the file
TBuf <128> buffer;
while(I < size)
{
// read from the file
User::LeaveIfError(data->Read(buffer));
I += buffer.Length();
// display on screen
printf(buffer);
}
// finished with Data object
CleanupStack::PopAndDestroy(data);
}
};
</codeblock> </section> <section><title>Reading from a file, with error checking</title> <p>This example is the same as before except it attempts to obtain or wait for rights to become available rather than just leaving if access to the content is restricted. </p> <codeblock id="GUID-C197103B-57E1-506D-9E63-F37A8CAB31E7" xml:space="preserve">class CContentViewer : public CActive
{
public:
static CContentViewer* NewL();
static CContentViewer* NewLC();
// Display given content.
void DisplayContent(const TDesC& aUri, TRequestStatus& aStatus)
{
iUri = aUri;
iClientStatus = &aStatus;
*iClientStatus = KRequestPending;
iCurrentState = EOpenFile;
// trigger our RunL
iStatus = KRequestPending;
SetActive();
User::RequestComplete(iStatus, KErrNone);
}
void RunL()
{
TInt err = iStatus.Int();
switch (iCurrentState)
{
case EOpenFile:
iContent = CContent::NewL(aUri);
TRAP(err, iData = iContent->OpenContentL(EDisplay));
iCurrentState = EReadAndDisplay; // follow through...
case EReadAndDisplay:
if(err == KErrNone)
{
TRAP(err, DisplayFile());
iCurrentState = EFinished;
// tell client iStatus that we have finished
User::RequestComplete(*iClientStatus, err);
return;
}
else if(err == KErrCANoRights)
{
// we don't have rights so we need to wait for them
iCurrentState = EWaitingForRights;
// ask CAF to initiate download of rights
iContent->RequestRights(iStatus);
}
else if(err == KErrCAPendingRights)
{
// waiting for rights to arrive, expected any minute now
iCurrentState = EWaitingForRights;
// ask CAF to notify us when they arrive
iContent->NotifyStatusChange(ERightsAvailable , iStatus);
}
// wait for CAF to complete our request
iLastError = err;
iStatus = KRequestPending;
SetActive();
break;
case EWaitingForRights:
if(ret == KErrNone)
{
// change the state to try and display content again
iCurrentState = EReadAndDisplay;
// trigger our RunL
iLastError = err;
iStatus = KRequestPending;
SetActive();
User::RequestComplete(iStatus, KErrNone);
}
else
{
// couldn't get rights, tell parent active object we're finished
User::RequestComplete(iClientStatus, err);
return;
}
break;
}
}
protected:
void DoCancel()
{
if (iLastError == KErrCAPendingRights)
iContent->CancelNotifyStatusChange(iStatus);
else if (iLastError == KErrCANoRights)
iContent->CancelRequestRights(iStatus);
}
private:
CContentViewer() : CActive(EPriorityStandard)
{
CActiveScheduler::Add(this);
}
~CContentViewer()
{
Cancel();
if (iData) delete iData;
if (iContent) delete iContent;
}
// Display the content, if any error occurs then leave
void DisplayContentL();
{
TInt size = 0;
TInt I = 0;
TBuf <128> buffer;
// Execute the intent, tell the agent that we plan to display the content
// It is at this point that any stateful rights is decremented
iData->ExecuteIntentL(EDisplay);
// get the size of the plaintext content
iData->DataSizeL(size);
// read and display the file until we reach the end of the file
while(I < size)
{
// read from the file
User::LeaveIfError(iData->Read(buffer));
I += buffer.Length();
// Display on screen
printf(buffer);
}
}
private:
enum TState
{
EOpenFile = 0,
EReadAndDisplay,
EWaitingForRights,
EFinished
};
CContent* iContent;
CData* iData;
TDesC iUri;
TState iCurrentState;
TInt iLastError;
TRequestStatus* iClientStatus;
}; </codeblock> </section> <section><title>Preventing access to DRM content</title> <p>Some servers may wish to prevent access to DRM content by untrusted clients, even if the server itself has DRM capability. </p> <p>To achieve this, the server must use the <xref href="GUID-EC31A59B-B7BB-3064-B327-4FAE7E702E6C.dita#GUID-EC31A59B-B7BB-3064-B327-4FAE7E702E6C/GUID-828A8D23-ADF3-333E-B8F0-C62519D3A511"><apiname>ContentAccess::TIntent::EUnknown</apiname></xref> intent when accessing content. Content files that are not DRM protected still work normally, but access to DRM protected content is blocked. </p> <codeblock id="GUID-9A600CE9-BFEF-5474-9977-CBFAEA77979C" xml:space="preserve">// Tell the agent we have no idea what the application plans to do
CData *data = content->OpenContentL(EUnknown);
// Execute the intent, tell the agent that we have no idea what the content is used for
data->ExecuteIntentL(EUnknown);</codeblock> </section> <section><title>File containing several content objects</title> <p>When reading from a particular content object within a file, the application must supply the <codeph>UniqueId</codeph> of the object when calling <xref href="GUID-FC40011B-32D3-328B-BB59-35BEF46A215A.dita#GUID-FC40011B-32D3-328B-BB59-35BEF46A215A/GUID-32BA0116-1D7F-31B1-B80E-32E1F55803C3"><apiname>ContentAccess::CContent::OpenContentL()</apiname></xref>. </p> <codeblock id="GUID-65AF3C9B-23DE-547B-BADA-553161E69564" xml:space="preserve">void DisplayTextFileL(const TDesC& aUri)
{
TInt size = 0;
TInt I = 0;
TBuf <128> buffer;
// Create a CContent object
// CAF figures out the appropriate agent
CContent *content = CContent::NewLC(aUri);
// Find the objects in the file with MIME type image/jpeg
RStreamablePtrArray<CEmbeddedObject> myArray;
CleanupClosePushL(myArray);
User::LeaveIfError(content->Search(myArray, _L("image/jpeg"), EFalse));
// Get the virtual path of the first image/jpeg we find
TVirtualPathPtr picture = *myArray[0];
// Tell the agent to open the object with the given UniqueId
CData *data = content->OpenContentLC(EDisplay, picture.UniqueId());
// Don't need content object or array any more
CleanupStack::PopAndDestroy(2); // content, myArray
// get the size of the plaintext content
data->DataSizeL(size);
// Execute the intent, tell the agent that we plan to display the content
// It is at this point that any stateful rights is decremented
data->ExecuteIntentL(EDisplay);
// read and display the file until we reach the end of the file
while(I < size)
{
// read from the file
User::LeaveIfError(data->Read(buffer));
I += buffer.Length();
// display on screen
printf(buffer);
}
// finished with Data object
CleanupStack::PopAndDestroy(data);
}
</codeblock> </section> <section><title>Importing a content file, agent provides output files</title> <p>This example shows how a messaging application that has just received a message attachment from a mail server can offer the attachment to CAF for processing. The output files is saved in <filepath>C:\files\</filepath>. </p> <codeblock id="GUID-EA47147D-FF97-5C4B-A75F-1E86CFB5E210" xml:space="preserve">void CMyApp::ReceiveMessageAttachment(const TDesC8& aContentType, const TDesC8& aMessageAttachment)
{
// Create supplier object
CSupplier* supplier = CSupplier::NewLC();
// Tell the agent where we would like the output files to be written
supplier->SetOutputDirectoryL(_L("C:\\files"));
// Check if CAF can import this attachment we just received
if(supplier->IsImportSupported(aContentType))
{
ProcessAttachmentL(supplier, aContentType, aMessageAttachment);
}
else
{
// just save the message to a file in its current form
RFile theFile;
theFile.Open(iFs, "myFile");
theFile.Write(aMessageAttachment);
theFile.Close();
// Add the file to the list of attachments
AddAttachment("myFile");
}
}
void CMyApp::ProcessAttachmentL(CSupplier* aSupplier, const TDesC8& aContentType, const TDesC8& aMessageAttachment)
{
TInt err = KErrNone;
TBuf <128> buf;
// Create meta-data array
CMetaDataArray* metaDataArray = new (ELeave) CMetaDataArray();
CleanupStack::PushL(metaDataArray);
// Add any useful information we can think of....
// Obviously these would not be hardcoded this way in a real import
metaDataArray->AddL(_L("Content Type"), _L("application/vnd.oma.drm.dm"));
metaDataArray->AddL(_L("Content Length"), _L("1201"));
metaDataArray->AddL(_L("X-Oma-Drm-Separate-Delivery"), _L("6"));
// Create the import object
CImportFile* import = aSupplier->ImportFileL(aContentType, *metaDataArray, _L("myfile"));
CleanupStack::PushL(import);
// import the attachment
err = import->WriteData(aMessageText);
// tell CAF (and hence the agent) it's now got the entire file
if (err == KErrNone)
{
err = import->WriteDataComplete();
if (err == KErrNone)
{
// Look at the output of the import operation
for(TInt I = 0; I < import->OutputFileCountL(); I++)
{
// for this example only add content output files
// (absorb any rights in the original attachment 'silently')
if(import->OutputFilesL(I).OutputType == EContent)
{
// Add file to list of attachments for this message
AddAttachment(import->OutputFilesL(I).FileName());
}
}
}
}
// Error handling
if (err != KErrNone)
{
if (err == KErrNotReady)
{
DisplayErrorMsg("Agent not ready for import");
}
else if (err == KErrCACorruptContent)
{
DisplayErrorMsg("Content data is corrupt");
}
else
{
DisplayErrorMsg("Unexpected error: %d", err);
}
}
// Finished
CleanupStack::PopAndDestroy(2); // metaDataArray, import
}</codeblock> </section> <section><title>Importing a content file (application provides output files)</title> <p>This example shows how a messaging application that has just received a message attachment from a mail server can offer the attachment to CAF for processing and store the file in its own private directory. </p> <codeblock id="GUID-D7E16FC9-B524-5C09-B575-3A09B87004B9" xml:space="preserve">void CMyApp::ReceiveMessageAttachment(const TDesC8& aContentType, const TDesC8& aMessageAttachment)
{
// Create supplier object
CSupplier* supplier = CSupplier::NewLC();
// Check if CAF can import this attachment we just received
if(supplier->IsImportSupported(aContentType))
{
ProcessAttachmentL(supplier, aContentType, aMessageAttachment);
}
else
{
// just save the message to a file in its current form
RFile theFile;
theFile.Open(iFs, "myFile");
theFile.Write(aMessageAttachment);
theFile.Close();
// Add the file to the list of attachments
AddAttachment("myFile");
}
}
void CMyApp::ProcessAttachmentL(CSupplier* aSupplier, const TDesC8& aContentType, const TDesC8& aMessageAttachment)
{
TInt err = KErrNone;
TBuf <128> buf;
TBuf <4> fileExtension;
_LIT(KOutputFileName, "\\private\\12345678\\outputfile.");
TFileName fileName(KOutputFileExtension);
RFile file;
// Create meta-data array
CMetaDataArray* metaDataArray = CMetaDataArray::NewLC();
// Add any useful information we can think of....
// Obviously these would not be hardcoded this way in a real import
metaDataArray->AddL(_L("Content Type"), _L("application/vnd.oma.drm.dm"));
metaDataArray->AddL(_L("Content Length"), _L("1201"));
metaDataArray->AddL(_L("X-Oma-Drm-Separate-Delivery"), _L("6"));
// Create the import object, no suggested file name implies the application supplies output files
CImportFile* import = aSupplier->ImportFileL(aContentType, *metaDataArray);
CleanupStack::PushL(import);
// Start importing the attachment
// (if the agent needs one or more output files, continue looping until
// the agent finishes the previous)
TInt err = import->WriteData(aMessageText);
while(err == KErrCANewFileHandleRequired)
{
import->GetSuggestedOutputFileExtension(fileExtension);
filName.Append(fileExtension);
User::LeaveIfError(file.Open(iFs, fileName));
err = import->ContinueWithNewOutputFile(file);
file.Close();
}
if (err == KErrNone)
{
// Complete the import process
err = import->WriteDataComplete();
while(err == KErrCANewFileHandleRequired)
{
import->GetSuggestedOutputFileExtension(fileExtension);
filName.Append(fileExtension);
User::LeaveIfError(file.Open(iFs, fileName));
err = import->ContinueWithNewOutputFile(file);
file.Close();
}
if (err == KErrNone)
{
// Look at the output of the import operation
for(TInt I = 0; I < import->OutputFileCountL(); I++)
{
// for this example only add content output files
// (absorb any rights in the original attachment 'silently')
if(import->OutputFilesL(I).OutputType == EContent)
{
// Add file to list of attachments for this message
AddAttachment(import->OutputFilesL(I).FileName());
}
}
}
}
// Error handling
if (err != KErrNone)
{
if (err == KErrNotReady)
{
DisplayErrorMsg("Agent not ready for import");
}
else if (err == KErrCACorruptContent)
{
DisplayErrorMsg("Content data is corrupt");
}
else
{
DisplayErrorMsg("Unexpected error: %d", err);
}
}
// Finshed
CleanupStack::PopAndDestroy(2); // metaDataArray, import
}</codeblock> </section> </conbody></concept>