|
1 // Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // This class contains the parsing and processing of BIO messages. |
|
15 // This functionality was originally carried out in the BIO Server MTM but |
|
16 // has been moved to the Client MTM for reasons of capability. Potentially, |
|
17 // BIO parsers may need additional capabilities for their processing and it would |
|
18 // be difficult to ensure that the Message Server (and all other server MTMs) had |
|
19 // the same capabilities. By moving the processing to the Client MTM it is only |
|
20 // the client UI app that needs the additional capabilities. |
|
21 // Parsing and processing of a message is initiated by calling StartCommandL(). |
|
22 // The command function can be one of the following: |
|
23 // KBiosMtmParse - just parse the message |
|
24 // KBiosMtmParseThenProcess - parse the message and then process it |
|
25 // KBiosMtmProcess - just process the mesage (must have been parsed previously) |
|
26 // Parsing a message involves finding the relevant BIO parser, loading it and then calling |
|
27 // ParseL() on the parser. |
|
28 // Processing a message involves finding the relevant BIO parser, loading it and then |
|
29 // calling ProcessL() on the parser. |
|
30 // To avoid unresponsiveness, a parse-then-process command is carried out in two steps. |
|
31 // The parsing is carried out first and then the AO is set up so the processing is |
|
32 // carried out in a separate RunL(). |
|
33 // Both the parser ParseL() and parser ProcessL() are asynchronous methods. |
|
34 // |
|
35 // |
|
36 |
|
37 #include <e32uid.h> |
|
38 #include <msvstd.h> |
|
39 #include <biodb.h> // bio database |
|
40 #include <biouids.h> // contains panic codes |
|
41 #include <txtrich.h> |
|
42 #include <txtfmlyr.h> |
|
43 |
|
44 #include "BIOSCMDS.H" |
|
45 #include "regpsdll.h" // Parser Registry - used to load the parser |
|
46 #include "bsp.h" // CBaseScriptParser, CBaseScriptParser2 |
|
47 #include "BIOOP.H" |
|
48 #ifdef SYMBIAN_ENABLE_SPLIT_HEADERS |
|
49 #include <biomessageuids.h> |
|
50 #include "tmsvbioinfo.h" |
|
51 #endif |
|
52 |
|
53 // panic text |
|
54 _LIT(KBioOpPanic, "BIOO"); |
|
55 |
|
56 CBIOOperation* CBIOOperation::NewL(RFs aRFs, CMsvSession& aSession, CBIODatabase* aBDB, TRequestStatus& aCompletionStatus) |
|
57 { |
|
58 CBIOOperation* self=new(ELeave) CBIOOperation(aRFs, aSession, aBDB, aCompletionStatus); |
|
59 CleanupStack::PushL(self); |
|
60 self->ConstructL(); |
|
61 CleanupStack::Pop(self); |
|
62 return self; |
|
63 } |
|
64 |
|
65 |
|
66 CBIOOperation::CBIOOperation(RFs aRFs, CMsvSession& aSession, CBIODatabase* aBDB, TRequestStatus& aCompletionStatus) |
|
67 : CMsvOperation(aSession, EPriorityStandard, aCompletionStatus), |
|
68 iFs(aRFs), iBioDatabase(aBDB), iInOperation(EFalse) |
|
69 { |
|
70 } |
|
71 |
|
72 |
|
73 void CBIOOperation::ConstructL() |
|
74 // |
|
75 // 2nd phase construction |
|
76 // |
|
77 { |
|
78 // initiallise progress |
|
79 iProgress.iBioState = TBioProgress::EBiosWaiting; |
|
80 |
|
81 // create msv entry |
|
82 iCurrentEntry = CMsvEntry::NewL(iMsvSession, KMsvRootIndexEntryIdValue, TMsvSelectionOrdering()); |
|
83 |
|
84 // add active object |
|
85 CActiveScheduler::Add(this); |
|
86 } |
|
87 |
|
88 |
|
89 CBIOOperation::~CBIOOperation() |
|
90 { |
|
91 Cancel(); |
|
92 delete iParser; |
|
93 delete iCurrentEntry; |
|
94 delete iRegisteredParserDll; |
|
95 delete iMessageBody; |
|
96 } |
|
97 |
|
98 |
|
99 void CBIOOperation::StartCommand(const CMsvEntrySelection& aSelection, TInt aCommand, TRequestStatus& aStatus) |
|
100 // |
|
101 // BIOServer specific commands |
|
102 // |
|
103 { |
|
104 __ASSERT_DEBUG(iBioOperationState == EBiooWaiting, User::Panic(KBioOpPanic, KBIOMessageOperationNotInactive)); |
|
105 __ASSERT_ALWAYS(aSelection.Count() >= 1, User::Panic(KBioOpPanic, KBIOMessageNotFound)); |
|
106 |
|
107 // to notify caller on completion |
|
108 iReportStatus = &aStatus; |
|
109 aStatus = KRequestPending; |
|
110 |
|
111 TMsvId service; |
|
112 TMsvEntry entry; |
|
113 |
|
114 TInt error = iMsvSession.GetEntry(aSelection.At(0), service, entry); |
|
115 |
|
116 iMtm = entry.iMtm; |
|
117 iService = entry.iServiceId; |
|
118 |
|
119 // perform the command, no need to go on if we already got an error |
|
120 if (error == KErrNone) |
|
121 { |
|
122 switch (aCommand) |
|
123 { |
|
124 case KBiosMtmParse: |
|
125 TRAP(error, ParseL(aSelection, EFalse)); |
|
126 break; |
|
127 case KBiosMtmParseThenProcess: |
|
128 TRAP(error, ParseL(aSelection, ETrue)); |
|
129 break; |
|
130 case KBiosMtmProcess: |
|
131 TRAP(error, ProcessL(aSelection)); |
|
132 break; |
|
133 default: |
|
134 error = KErrNotSupported; |
|
135 break; |
|
136 } |
|
137 }; |
|
138 |
|
139 // check for errors |
|
140 if (error != KErrNone) |
|
141 { |
|
142 // complete |
|
143 iStatus = KRequestPending; |
|
144 TRequestStatus* stat = &iStatus; |
|
145 SetActive(); |
|
146 User::RequestComplete(stat, error); |
|
147 } |
|
148 } |
|
149 |
|
150 |
|
151 void CBIOOperation::DoCancel() |
|
152 // |
|
153 // Cancel |
|
154 // |
|
155 { |
|
156 if (iParser) |
|
157 iParser->Cancel(); |
|
158 iInOperation = EFalse; |
|
159 User::RequestComplete(iReportStatus, KErrCancel); |
|
160 } |
|
161 |
|
162 |
|
163 void CBIOOperation::RunL() |
|
164 // |
|
165 // Active object RunL |
|
166 // |
|
167 { |
|
168 TInt error = iStatus.Int(); |
|
169 if (error == KErrNone) |
|
170 { |
|
171 switch (iBioOperationState) |
|
172 { |
|
173 case EBiooParsing: |
|
174 { |
|
175 iCurrentEntry->SetEntryL(iCurrentMsvId); |
|
176 |
|
177 if (iBioOperationOperation == EBioParseAndProcess) |
|
178 { |
|
179 iBioOperationState = EBiooWaiting; |
|
180 ProcessL(); |
|
181 } |
|
182 else |
|
183 { |
|
184 iBioOperationState = EBiooComplete; |
|
185 } |
|
186 break; |
|
187 } |
|
188 case EBiooProcessing: |
|
189 iBioOperationState = EBiooComplete; |
|
190 case EBiooCreating: |
|
191 case EBiooWaiting: |
|
192 default: |
|
193 break; |
|
194 } |
|
195 } |
|
196 |
|
197 if (iBioOperationState == EBiooComplete || error != KErrNone) |
|
198 { |
|
199 RunError(error); |
|
200 } |
|
201 } |
|
202 |
|
203 |
|
204 TInt CBIOOperation::RunError(TInt aError) |
|
205 { |
|
206 // also called with aError == KErrNone |
|
207 TMsvEntry entry = iCurrentEntry->Entry(); |
|
208 entry.SetReadOnly(ETrue); |
|
209 TInt error = KErrNone; |
|
210 TRAP(error,iCurrentEntry->ChangeL(entry)); |
|
211 |
|
212 iBioOperationState = EBiooWaiting; |
|
213 iInOperation = EFalse; |
|
214 iProgress.iErrorCode = aError; |
|
215 |
|
216 User::RequestComplete(iReportStatus, aError); |
|
217 |
|
218 return error; |
|
219 } |
|
220 |
|
221 |
|
222 void CBIOOperation::ParseL(const CMsvEntrySelection& aSelection, TBool aCommit) |
|
223 { |
|
224 // parse and process? |
|
225 iBioOperationOperation = aCommit ? EBioParseAndProcess : EBioParseOnly; |
|
226 |
|
227 // set context |
|
228 iCurrentMsvId = aSelection[0]; |
|
229 iCurrentEntry->SetEntryL(iCurrentMsvId); |
|
230 |
|
231 // check if it's alreadly parsed |
|
232 // iMtmData3 == 0 => not yet parsed |
|
233 // iMtmData3 == 1 => parsed |
|
234 // iMtmData3 == 2 => processed |
|
235 if (iCurrentEntry->Entry().MtmData3()==EBioMsgNotParsed) |
|
236 { |
|
237 // put in check that it's a valid SMS/smart message |
|
238 StartParserL(); |
|
239 } |
|
240 else if (iCurrentEntry->Entry().MtmData3()==EBioMsgParsed || |
|
241 iCurrentEntry->Entry().MtmData3()==EBioMsgProcessed) |
|
242 { |
|
243 iStatus = KRequestPending; |
|
244 TRequestStatus* ps = &iStatus; |
|
245 SetActive(); |
|
246 User::RequestComplete(ps, KErrNone); |
|
247 iProgress.iBioState = TBioProgress::EBiosCreating; |
|
248 |
|
249 if (iBioOperationOperation == EBioParseAndProcess) |
|
250 { |
|
251 iBioOperationState = EBiooParsing; |
|
252 CreateParserL(); |
|
253 } |
|
254 else |
|
255 { |
|
256 iBioOperationState = EBiooComplete; |
|
257 } |
|
258 } |
|
259 else |
|
260 { |
|
261 User::Leave(KErrCorrupt); |
|
262 } |
|
263 iInOperation = ETrue; |
|
264 } |
|
265 |
|
266 |
|
267 void CBIOOperation::CreateParserL() |
|
268 { |
|
269 |
|
270 // get bio type uid from message |
|
271 TUid parserUid; |
|
272 parserUid.iUid = iCurrentEntry->Entry().iBioType; |
|
273 |
|
274 // check if we already have a parser and if it's the correct one |
|
275 if ((iParser != NULL) && (parserUid != iParser->ParserUid())) |
|
276 { |
|
277 // first delete the old parser before creating the new one |
|
278 delete iParser; |
|
279 iParser = NULL; |
|
280 } |
|
281 |
|
282 if (iParser == NULL) |
|
283 { |
|
284 // create the local variables |
|
285 if (parserUid.iUid == 0) |
|
286 User::Leave(KBspSmartMessageNoParserDefined); |
|
287 |
|
288 // get parser filename for loading |
|
289 TFileName parserDllName(iBioDatabase->GetBioParserNameL(parserUid)); |
|
290 |
|
291 // create dll registry |
|
292 delete iRegisteredParserDll; |
|
293 iRegisteredParserDll = NULL; |
|
294 iRegisteredParserDll = CRegisteredParserDll::NewL(parserDllName); |
|
295 |
|
296 // get handle to dll |
|
297 RLibrary parserlibrary; |
|
298 User::LeaveIfError(iRegisteredParserDll->GetLibrary(iFs, parserlibrary)); |
|
299 |
|
300 // create a typedef so that we can make a call to the dll to create a parser. |
|
301 typedef CBaseScriptParser2* (*NewParserL)(CRegisteredParserDll& registeredparserdll, CMsvEntry& aEntry, RFs& aFs); |
|
302 |
|
303 // entry point for NewL function found at ordinal 1 |
|
304 TLibraryFunction libFunc = parserlibrary.Lookup(1); |
|
305 |
|
306 // check that we found the entry point |
|
307 if (libFunc == NULL) |
|
308 User::Leave(KErrBadLibraryEntryPoint) ; |
|
309 |
|
310 // create a function pointer to NewL |
|
311 NewParserL pFunc = (NewParserL)libFunc; |
|
312 CBaseScriptParser2* parser(NULL); |
|
313 |
|
314 TInt refcount = iRegisteredParserDll->DllRefCount(); |
|
315 TRAPD(ret, parser = ((*pFunc)(*iRegisteredParserDll, *iCurrentEntry, iFs))); |
|
316 |
|
317 // unload the library if allocation failed and refcount == 1 |
|
318 if ((ret != KErrNone) && (iRegisteredParserDll->DllRefCount() == refcount)) |
|
319 iRegisteredParserDll->ReleaseLibrary(); |
|
320 |
|
321 // leave if error |
|
322 User::LeaveIfError(ret); |
|
323 iParser = parser; |
|
324 } |
|
325 } |
|
326 |
|
327 |
|
328 void CBIOOperation::StartParserL() |
|
329 // |
|
330 // We have a parser parse the message (fire up the parser) |
|
331 // |
|
332 { |
|
333 __ASSERT_DEBUG(iBioOperationState == EBiooWaiting, User::Panic(KBioOpPanic, KBIOMessageOperationNotInactive)); |
|
334 |
|
335 // get the msg body |
|
336 ExtractMessageBodyL(); |
|
337 |
|
338 // create parser |
|
339 CreateParserL(); |
|
340 |
|
341 // set the entry and start the parser (parser takes ownership of entry) |
|
342 // make sure it points to the message |
|
343 iCurrentEntry->SetEntryL(iCurrentMsvId); |
|
344 |
|
345 // make the entry editable |
|
346 TMsvEntry entry(iCurrentEntry->Entry()); |
|
347 entry.SetReadOnly(EFalse); |
|
348 iCurrentEntry->ChangeL(entry); |
|
349 |
|
350 // parse |
|
351 iParser->ParseL(iStatus, *iMessageBody); |
|
352 SetActive(); |
|
353 |
|
354 iBioOperationState = EBiooParsing; |
|
355 iProgress.iBioState = TBioProgress::EBiosParsing; |
|
356 } |
|
357 |
|
358 |
|
359 void CBIOOperation::ExtractMessageBodyL() |
|
360 // |
|
361 // Get the message body |
|
362 // |
|
363 { |
|
364 // build a CRichText object to read in message body |
|
365 CParaFormatLayer* paraFormatLayer = CParaFormatLayer::NewL(); |
|
366 CleanupStack::PushL(paraFormatLayer); |
|
367 CCharFormatLayer* charFormatLayer = CCharFormatLayer::NewL(); |
|
368 CleanupStack::PushL(charFormatLayer); |
|
369 CRichText* richText = CRichText::NewL(paraFormatLayer, charFormatLayer); |
|
370 CleanupStack::PushL(richText); |
|
371 |
|
372 // get store holding message body |
|
373 CMsvStore* store = iCurrentEntry->ReadStoreL(); |
|
374 CleanupStack::PushL(store); |
|
375 |
|
376 // check for message body |
|
377 if (!store->HasBodyTextL()) |
|
378 User::Leave(KErrNotFound); |
|
379 |
|
380 // extract the body text |
|
381 store->RestoreBodyTextL(*richText); |
|
382 |
|
383 // create buffer to hold body text |
|
384 TInt messageLength = richText->DocumentLength(); |
|
385 if (iMessageBody) |
|
386 { |
|
387 delete iMessageBody; |
|
388 iMessageBody = NULL; |
|
389 } |
|
390 iMessageBody = HBufC::NewL(messageLength); |
|
391 |
|
392 // read in message body |
|
393 TPtr messDes = iMessageBody->Des(); |
|
394 TInt length = messDes.Length(); |
|
395 while (length < messageLength) |
|
396 { |
|
397 TPtrC desc = richText->Read(length, messageLength-length); |
|
398 messDes.Append(desc); |
|
399 length+=desc.Length(); |
|
400 } |
|
401 CleanupStack::PopAndDestroy(4, paraFormatLayer); // store, text, charFormatLayer, paraFormatLayer |
|
402 } |
|
403 |
|
404 |
|
405 void CBIOOperation::ProcessL(const CMsvEntrySelection& aSelection) |
|
406 // |
|
407 // successfully parsed the message - do the settings |
|
408 // |
|
409 { |
|
410 // set operation |
|
411 iBioOperationOperation = EBioProcess; |
|
412 |
|
413 // get the id of the bio message |
|
414 iCurrentMsvId = aSelection[0]; |
|
415 iCurrentEntry->SetEntryL(iCurrentMsvId); |
|
416 |
|
417 CreateParserL(); |
|
418 |
|
419 iInOperation = ETrue; |
|
420 ProcessL(); |
|
421 } |
|
422 |
|
423 |
|
424 void CBIOOperation::ProcessL() |
|
425 // |
|
426 // successfully parsed the message - do the settings |
|
427 // |
|
428 { |
|
429 __ASSERT_DEBUG(iBioOperationState == EBiooWaiting, User::Panic(KBioOpPanic, KBIOMessageOperationNotInactive)); |
|
430 |
|
431 if (iInOperation == EFalse) |
|
432 User::Leave(KErrDisconnected); |
|
433 |
|
434 __ASSERT_ALWAYS(iParser != NULL, User::Panic(KBioOpPanic, KBIOMessageNoParserCreated)); |
|
435 iProgress.iBioState = TBioProgress::EBiosProcessing; |
|
436 |
|
437 // make entry readable so we can change things |
|
438 TMsvEntry entry = iCurrentEntry->Entry(); |
|
439 if (entry.ReadOnly()) |
|
440 { |
|
441 entry.SetReadOnly(EFalse); |
|
442 iCurrentEntry->ChangeL(entry); |
|
443 } |
|
444 |
|
445 // start to process message |
|
446 iParser->ProcessL(iStatus); |
|
447 SetActive(); |
|
448 |
|
449 iBioOperationState = EBiooProcessing; |
|
450 } |
|
451 |
|
452 |
|
453 const TDesC8& CBIOOperation::ProgressL() |
|
454 // |
|
455 // get progress information |
|
456 // |
|
457 { |
|
458 iProgressBuf = TBioProgressBuf(iProgress); |
|
459 return iProgressBuf; |
|
460 } |