|
1 <?xml version="1.0" encoding="utf-8"?> |
|
2 <!-- Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved. --> |
|
3 <!-- This component and the accompanying materials are made available under the terms of the License |
|
4 "Eclipse Public License v1.0" which accompanies this distribution, |
|
5 and is available at the URL "http://www.eclipse.org/legal/epl-v10.html". --> |
|
6 <!-- Initial Contributors: |
|
7 Nokia Corporation - initial contribution. |
|
8 Contributors: |
|
9 --> |
|
10 <!DOCTYPE concept |
|
11 PUBLIC "-//OASIS//DTD DITA Concept//EN" "concept.dtd"> |
|
12 <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 |
|
13 { |
|
14 public: |
|
15 static CContentViewer* NewL(); |
|
16 static CContentViewer* NewLC(); |
|
17 |
|
18 // Display given content. |
|
19 void DisplayContent(const TDesC& aUri, TRequestStatus& aStatus) |
|
20 { |
|
21 TRAPD(err, DisplayContentL(aUri)); |
|
22 User::RequestComplete(aStatus, err); |
|
23 } |
|
24 |
|
25 private: |
|
26 CContentViewer() : CBase() {} |
|
27 ~CContentViewer() {} |
|
28 |
|
29 void DisplayContentL(const TDesC& aUri) |
|
30 { |
|
31 TInt size = 0; |
|
32 TInt I = 0; |
|
33 |
|
34 // Create a CContent object |
|
35 // CAF figures out the appropriate agent |
|
36 CContent *content = CContent::NewLC(aUri); |
|
37 |
|
38 // Create a CData object to read the content |
|
39 // Tell the agent we are planning to display the content |
|
40 CData *data = content->OpenContentLC(EDisplay); |
|
41 |
|
42 // Don't need content object any more |
|
43 CleanupStack::PopAndDestroy(content); |
|
44 |
|
45 // get the size of the plaintext content |
|
46 data->DataSizeL(size); |
|
47 |
|
48 // Execute the intent, tell the agent that we plan to display the content |
|
49 // It is at this point that any stateful rights is decremented |
|
50 data->ExecuteIntentL(EDisplay); |
|
51 |
|
52 // read and display the file until we reach the end of the file |
|
53 TBuf <128> buffer; |
|
54 while(I < size) |
|
55 { |
|
56 // read from the file |
|
57 User::LeaveIfError(data->Read(buffer)); |
|
58 I += buffer.Length(); |
|
59 |
|
60 // display on screen |
|
61 printf(buffer); |
|
62 } |
|
63 |
|
64 // finished with Data object |
|
65 CleanupStack::PopAndDestroy(data); |
|
66 } |
|
67 }; |
|
68 |
|
69 </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 |
|
70 { |
|
71 public: |
|
72 static CContentViewer* NewL(); |
|
73 static CContentViewer* NewLC(); |
|
74 |
|
75 // Display given content. |
|
76 void DisplayContent(const TDesC& aUri, TRequestStatus& aStatus) |
|
77 { |
|
78 iUri = aUri; |
|
79 iClientStatus = &aStatus; |
|
80 *iClientStatus = KRequestPending; |
|
81 iCurrentState = EOpenFile; |
|
82 // trigger our RunL |
|
83 iStatus = KRequestPending; |
|
84 SetActive(); |
|
85 User::RequestComplete(iStatus, KErrNone); |
|
86 } |
|
87 |
|
88 void RunL() |
|
89 { |
|
90 TInt err = iStatus.Int(); |
|
91 |
|
92 switch (iCurrentState) |
|
93 { |
|
94 case EOpenFile: |
|
95 iContent = CContent::NewL(aUri); |
|
96 TRAP(err, iData = iContent->OpenContentL(EDisplay)); |
|
97 iCurrentState = EReadAndDisplay; // follow through... |
|
98 case EReadAndDisplay: |
|
99 if(err == KErrNone) |
|
100 { |
|
101 TRAP(err, DisplayFile()); |
|
102 iCurrentState = EFinished; |
|
103 // tell client iStatus that we have finished |
|
104 User::RequestComplete(*iClientStatus, err); |
|
105 return; |
|
106 } |
|
107 else if(err == KErrCANoRights) |
|
108 { |
|
109 // we don't have rights so we need to wait for them |
|
110 iCurrentState = EWaitingForRights; |
|
111 // ask CAF to initiate download of rights |
|
112 iContent->RequestRights(iStatus); |
|
113 } |
|
114 else if(err == KErrCAPendingRights) |
|
115 { |
|
116 // waiting for rights to arrive, expected any minute now |
|
117 iCurrentState = EWaitingForRights; |
|
118 // ask CAF to notify us when they arrive |
|
119 iContent->NotifyStatusChange(ERightsAvailable , iStatus); |
|
120 } |
|
121 // wait for CAF to complete our request |
|
122 iLastError = err; |
|
123 iStatus = KRequestPending; |
|
124 SetActive(); |
|
125 break; |
|
126 case EWaitingForRights: |
|
127 if(ret == KErrNone) |
|
128 { |
|
129 // change the state to try and display content again |
|
130 iCurrentState = EReadAndDisplay; |
|
131 // trigger our RunL |
|
132 iLastError = err; |
|
133 iStatus = KRequestPending; |
|
134 SetActive(); |
|
135 User::RequestComplete(iStatus, KErrNone); |
|
136 } |
|
137 else |
|
138 { |
|
139 // couldn't get rights, tell parent active object we're finished |
|
140 User::RequestComplete(iClientStatus, err); |
|
141 return; |
|
142 } |
|
143 break; |
|
144 } |
|
145 } |
|
146 |
|
147 protected: |
|
148 void DoCancel() |
|
149 { |
|
150 if (iLastError == KErrCAPendingRights) |
|
151 iContent->CancelNotifyStatusChange(iStatus); |
|
152 else if (iLastError == KErrCANoRights) |
|
153 iContent->CancelRequestRights(iStatus); |
|
154 } |
|
155 |
|
156 private: |
|
157 CContentViewer() : CActive(EPriorityStandard) |
|
158 { |
|
159 CActiveScheduler::Add(this); |
|
160 } |
|
161 ~CContentViewer() |
|
162 { |
|
163 Cancel(); |
|
164 if (iData) delete iData; |
|
165 if (iContent) delete iContent; |
|
166 } |
|
167 |
|
168 // Display the content, if any error occurs then leave |
|
169 void DisplayContentL(); |
|
170 { |
|
171 TInt size = 0; |
|
172 TInt I = 0; |
|
173 TBuf <128> buffer; |
|
174 |
|
175 // Execute the intent, tell the agent that we plan to display the content |
|
176 // It is at this point that any stateful rights is decremented |
|
177 iData->ExecuteIntentL(EDisplay); |
|
178 |
|
179 // get the size of the plaintext content |
|
180 iData->DataSizeL(size); |
|
181 |
|
182 // read and display the file until we reach the end of the file |
|
183 while(I < size) |
|
184 { |
|
185 // read from the file |
|
186 User::LeaveIfError(iData->Read(buffer)); |
|
187 I += buffer.Length(); |
|
188 |
|
189 // Display on screen |
|
190 printf(buffer); |
|
191 } |
|
192 } |
|
193 |
|
194 private: |
|
195 enum TState |
|
196 { |
|
197 EOpenFile = 0, |
|
198 EReadAndDisplay, |
|
199 EWaitingForRights, |
|
200 EFinished |
|
201 }; |
|
202 |
|
203 CContent* iContent; |
|
204 CData* iData; |
|
205 TDesC iUri; |
|
206 |
|
207 TState iCurrentState; |
|
208 TInt iLastError; |
|
209 TRequestStatus* iClientStatus; |
|
210 }; </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 |
|
211 CData *data = content->OpenContentL(EUnknown); |
|
212 |
|
213 // Execute the intent, tell the agent that we have no idea what the content is used for |
|
214 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) |
|
215 { |
|
216 TInt size = 0; |
|
217 TInt I = 0; |
|
218 |
|
219 TBuf <128> buffer; |
|
220 |
|
221 // Create a CContent object |
|
222 // CAF figures out the appropriate agent |
|
223 CContent *content = CContent::NewLC(aUri); |
|
224 |
|
225 // Find the objects in the file with MIME type image/jpeg |
|
226 RStreamablePtrArray<CEmbeddedObject> myArray; |
|
227 CleanupClosePushL(myArray); |
|
228 |
|
229 User::LeaveIfError(content->Search(myArray, _L("image/jpeg"), EFalse)); |
|
230 |
|
231 // Get the virtual path of the first image/jpeg we find |
|
232 TVirtualPathPtr picture = *myArray[0]; |
|
233 |
|
234 // Tell the agent to open the object with the given UniqueId |
|
235 CData *data = content->OpenContentLC(EDisplay, picture.UniqueId()); |
|
236 |
|
237 // Don't need content object or array any more |
|
238 CleanupStack::PopAndDestroy(2); // content, myArray |
|
239 |
|
240 // get the size of the plaintext content |
|
241 data->DataSizeL(size); |
|
242 |
|
243 // Execute the intent, tell the agent that we plan to display the content |
|
244 // It is at this point that any stateful rights is decremented |
|
245 data->ExecuteIntentL(EDisplay); |
|
246 |
|
247 // read and display the file until we reach the end of the file |
|
248 while(I < size) |
|
249 { |
|
250 // read from the file |
|
251 User::LeaveIfError(data->Read(buffer)); |
|
252 I += buffer.Length(); |
|
253 |
|
254 // display on screen |
|
255 printf(buffer); |
|
256 } |
|
257 |
|
258 // finished with Data object |
|
259 CleanupStack::PopAndDestroy(data); |
|
260 } |
|
261 |
|
262 </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) |
|
263 { |
|
264 // Create supplier object |
|
265 CSupplier* supplier = CSupplier::NewLC(); |
|
266 |
|
267 // Tell the agent where we would like the output files to be written |
|
268 supplier->SetOutputDirectoryL(_L("C:\\files")); |
|
269 |
|
270 // Check if CAF can import this attachment we just received |
|
271 if(supplier->IsImportSupported(aContentType)) |
|
272 { |
|
273 ProcessAttachmentL(supplier, aContentType, aMessageAttachment); |
|
274 } |
|
275 else |
|
276 { |
|
277 // just save the message to a file in its current form |
|
278 RFile theFile; |
|
279 theFile.Open(iFs, "myFile"); |
|
280 theFile.Write(aMessageAttachment); |
|
281 theFile.Close(); |
|
282 |
|
283 // Add the file to the list of attachments |
|
284 AddAttachment("myFile"); |
|
285 } |
|
286 } |
|
287 |
|
288 |
|
289 void CMyApp::ProcessAttachmentL(CSupplier* aSupplier, const TDesC8& aContentType, const TDesC8& aMessageAttachment) |
|
290 { |
|
291 TInt err = KErrNone; |
|
292 TBuf <128> buf; |
|
293 |
|
294 // Create meta-data array |
|
295 CMetaDataArray* metaDataArray = new (ELeave) CMetaDataArray(); |
|
296 CleanupStack::PushL(metaDataArray); |
|
297 |
|
298 // Add any useful information we can think of.... |
|
299 // Obviously these would not be hardcoded this way in a real import |
|
300 metaDataArray->AddL(_L("Content Type"), _L("application/vnd.oma.drm.dm")); |
|
301 metaDataArray->AddL(_L("Content Length"), _L("1201")); |
|
302 metaDataArray->AddL(_L("X-Oma-Drm-Separate-Delivery"), _L("6")); |
|
303 |
|
304 // Create the import object |
|
305 CImportFile* import = aSupplier->ImportFileL(aContentType, *metaDataArray, _L("myfile")); |
|
306 CleanupStack::PushL(import); |
|
307 |
|
308 // import the attachment |
|
309 err = import->WriteData(aMessageText); |
|
310 |
|
311 // tell CAF (and hence the agent) it's now got the entire file |
|
312 if (err == KErrNone) |
|
313 { |
|
314 err = import->WriteDataComplete(); |
|
315 if (err == KErrNone) |
|
316 { |
|
317 // Look at the output of the import operation |
|
318 for(TInt I = 0; I < import->OutputFileCountL(); I++) |
|
319 { |
|
320 // for this example only add content output files |
|
321 // (absorb any rights in the original attachment 'silently') |
|
322 if(import->OutputFilesL(I).OutputType == EContent) |
|
323 { |
|
324 // Add file to list of attachments for this message |
|
325 AddAttachment(import->OutputFilesL(I).FileName()); |
|
326 } |
|
327 } |
|
328 } |
|
329 } |
|
330 |
|
331 // Error handling |
|
332 if (err != KErrNone) |
|
333 { |
|
334 if (err == KErrNotReady) |
|
335 { |
|
336 DisplayErrorMsg("Agent not ready for import"); |
|
337 } |
|
338 else if (err == KErrCACorruptContent) |
|
339 { |
|
340 DisplayErrorMsg("Content data is corrupt"); |
|
341 } |
|
342 else |
|
343 { |
|
344 DisplayErrorMsg("Unexpected error: %d", err); |
|
345 } |
|
346 } |
|
347 |
|
348 // Finished |
|
349 CleanupStack::PopAndDestroy(2); // metaDataArray, import |
|
350 }</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) |
|
351 { |
|
352 // Create supplier object |
|
353 CSupplier* supplier = CSupplier::NewLC(); |
|
354 |
|
355 // Check if CAF can import this attachment we just received |
|
356 if(supplier->IsImportSupported(aContentType)) |
|
357 { |
|
358 ProcessAttachmentL(supplier, aContentType, aMessageAttachment); |
|
359 } |
|
360 else |
|
361 { |
|
362 // just save the message to a file in its current form |
|
363 RFile theFile; |
|
364 theFile.Open(iFs, "myFile"); |
|
365 theFile.Write(aMessageAttachment); |
|
366 theFile.Close(); |
|
367 |
|
368 // Add the file to the list of attachments |
|
369 AddAttachment("myFile"); |
|
370 } |
|
371 } |
|
372 |
|
373 |
|
374 void CMyApp::ProcessAttachmentL(CSupplier* aSupplier, const TDesC8& aContentType, const TDesC8& aMessageAttachment) |
|
375 { |
|
376 TInt err = KErrNone; |
|
377 TBuf <128> buf; |
|
378 TBuf <4> fileExtension; |
|
379 |
|
380 _LIT(KOutputFileName, "\\private\\12345678\\outputfile."); |
|
381 TFileName fileName(KOutputFileExtension); |
|
382 |
|
383 RFile file; |
|
384 |
|
385 // Create meta-data array |
|
386 CMetaDataArray* metaDataArray = CMetaDataArray::NewLC(); |
|
387 |
|
388 // Add any useful information we can think of.... |
|
389 // Obviously these would not be hardcoded this way in a real import |
|
390 metaDataArray->AddL(_L("Content Type"), _L("application/vnd.oma.drm.dm")); |
|
391 metaDataArray->AddL(_L("Content Length"), _L("1201")); |
|
392 metaDataArray->AddL(_L("X-Oma-Drm-Separate-Delivery"), _L("6")); |
|
393 |
|
394 // Create the import object, no suggested file name implies the application supplies output files |
|
395 CImportFile* import = aSupplier->ImportFileL(aContentType, *metaDataArray); |
|
396 CleanupStack::PushL(import); |
|
397 |
|
398 // Start importing the attachment |
|
399 // (if the agent needs one or more output files, continue looping until |
|
400 // the agent finishes the previous) |
|
401 TInt err = import->WriteData(aMessageText); |
|
402 while(err == KErrCANewFileHandleRequired) |
|
403 { |
|
404 import->GetSuggestedOutputFileExtension(fileExtension); |
|
405 filName.Append(fileExtension); |
|
406 |
|
407 User::LeaveIfError(file.Open(iFs, fileName)); |
|
408 err = import->ContinueWithNewOutputFile(file); |
|
409 file.Close(); |
|
410 } |
|
411 |
|
412 if (err == KErrNone) |
|
413 { |
|
414 // Complete the import process |
|
415 err = import->WriteDataComplete(); |
|
416 while(err == KErrCANewFileHandleRequired) |
|
417 { |
|
418 import->GetSuggestedOutputFileExtension(fileExtension); |
|
419 filName.Append(fileExtension); |
|
420 |
|
421 User::LeaveIfError(file.Open(iFs, fileName)); |
|
422 err = import->ContinueWithNewOutputFile(file); |
|
423 file.Close(); |
|
424 } |
|
425 |
|
426 if (err == KErrNone) |
|
427 { |
|
428 // Look at the output of the import operation |
|
429 for(TInt I = 0; I < import->OutputFileCountL(); I++) |
|
430 { |
|
431 // for this example only add content output files |
|
432 // (absorb any rights in the original attachment 'silently') |
|
433 if(import->OutputFilesL(I).OutputType == EContent) |
|
434 { |
|
435 // Add file to list of attachments for this message |
|
436 AddAttachment(import->OutputFilesL(I).FileName()); |
|
437 } |
|
438 } |
|
439 } |
|
440 } |
|
441 |
|
442 // Error handling |
|
443 if (err != KErrNone) |
|
444 { |
|
445 if (err == KErrNotReady) |
|
446 { |
|
447 DisplayErrorMsg("Agent not ready for import"); |
|
448 } |
|
449 else if (err == KErrCACorruptContent) |
|
450 { |
|
451 DisplayErrorMsg("Content data is corrupt"); |
|
452 } |
|
453 else |
|
454 { |
|
455 DisplayErrorMsg("Unexpected error: %d", err); |
|
456 } |
|
457 } |
|
458 |
|
459 // Finshed |
|
460 CleanupStack::PopAndDestroy(2); // metaDataArray, import |
|
461 }</codeblock> </section> </conbody></concept> |