|
1 // Copyright (c) 1999-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 // Compact Business Card Parser for the BIO Messaging project. |
|
15 // Still in a rudimentary shape, pending specifications and design from Symbian. |
|
16 // When ParseL is called, the parser parses the data into an array. This array is saved to a store. |
|
17 // The message is converted to vCard format and then saved as an attachment file. |
|
18 // Finally, the message body is converted to an informative message for the user. |
|
19 // Possibles: May have to implement a ProcessL fn to either save the file in a different directory |
|
20 // or launch an application after the user presses the accept button in the viewer. |
|
21 // N.B. The Compact Business Card specification defines the delimiter to be <line-feed>. |
|
22 // However, it will often be the case that the <line-feed> is preceded by a <carriage-return>. |
|
23 // The <carriage-return> characters must be stripped out. |
|
24 // |
|
25 // |
|
26 |
|
27 #include <msvids.h> |
|
28 #include <msvuids.h> |
|
29 #include <msventry.h> |
|
30 |
|
31 #include <bsp.h> |
|
32 #include "CBCP.H" |
|
33 #include "CBCPDEF.H" |
|
34 #ifdef SYMBIAN_ENABLE_SPLIT_HEADERS |
|
35 #include "tmsvbioinfo.h" |
|
36 #endif |
|
37 |
|
38 // Factory methods |
|
39 EXPORT_C CBusinessCardParser* CBusinessCardParser::NewL(CRegisteredParserDll& aRegisteredParserDll, CMsvEntry& aEntry, RFs& aFs) |
|
40 { |
|
41 CBusinessCardParser* self = new (ELeave) CBusinessCardParser(aRegisteredParserDll, aEntry, aFs); |
|
42 CleanupStack::PushL(self); |
|
43 self->ConstructL(); |
|
44 CleanupStack::Pop(); |
|
45 return self; |
|
46 } |
|
47 // end CBusinessCardParser::NewL() |
|
48 |
|
49 |
|
50 void CBusinessCardParser::ConstructL() |
|
51 { |
|
52 iParsedFieldArray = new (ELeave) CArrayPtrSeg<CParsedField>(16); |
|
53 CActiveScheduler::Add(this); |
|
54 } |
|
55 // end CBusinessCardParser::ConstructL() |
|
56 |
|
57 |
|
58 void CBusinessCardParser::ParseL(TRequestStatus& aStatus, const TDesC& aSms) |
|
59 // Doesn't actually do any parsing (see ParseMessageL) but kicks off the parsing process. |
|
60 { |
|
61 TMsvEntry entry = iEntry.Entry(); // Get the generic stuff. |
|
62 iEntryId = entry.Id(); // Store the TMsvId. |
|
63 |
|
64 __ASSERT_DEBUG((entry.MtmData3() == 0 || entry.MtmData3() == 1), |
|
65 User::Panic(_L("CBCP-DLL"),KErrGeneral)); |
|
66 // Already parsed.... |
|
67 if(entry.MtmData3() == 1) |
|
68 { |
|
69 iReport = &aStatus; |
|
70 User::RequestComplete(iReport, KErrNone); |
|
71 } |
|
72 // Not parsed.... |
|
73 else if(entry.MtmData3() == 0) |
|
74 { |
|
75 if (iSmsBuf != NULL) |
|
76 { |
|
77 delete iSmsBuf; |
|
78 iSmsBuf = NULL; |
|
79 } |
|
80 iSmsBuf = aSms.AllocL(); // Allocate new HBufC object. |
|
81 ChangeStateL(EUnfoldMessage); // Unfold message and set thread active. |
|
82 aStatus = KRequestPending; |
|
83 iReport = &aStatus; |
|
84 } |
|
85 else |
|
86 { |
|
87 User::Leave(KErrNotSupported); |
|
88 } |
|
89 } |
|
90 // end CBusinessCardParser::ParseL(TRequestStatus&, const TDesC&) |
|
91 |
|
92 |
|
93 // ProcessL() -- Business Card parser doesn't use this function at present. |
|
94 void CBusinessCardParser::ProcessL(TRequestStatus& aStatus) |
|
95 { |
|
96 iReport = &aStatus; |
|
97 User::RequestComplete(iReport, KErrNotSupported); |
|
98 } |
|
99 // end CBusinessCardParser::CommitL(TRequestStatus&) |
|
100 |
|
101 |
|
102 void CBusinessCardParser::DoCancel() // Must be provided. |
|
103 { |
|
104 User::RequestComplete(iReport,KErrCancel); |
|
105 } |
|
106 // end CBusinessCardParser::DoCancel() |
|
107 |
|
108 |
|
109 void CBusinessCardParser::RunL() // Must be provided since this is derived from a CActive object. |
|
110 { |
|
111 iCompleted = iStatus.Int(); |
|
112 if (iCompleted != KErrNone) |
|
113 { |
|
114 User::RequestComplete(iReport,iCompleted); |
|
115 return; |
|
116 } |
|
117 |
|
118 switch (iState) |
|
119 { |
|
120 case EUnfoldMessage: // Message unfolded so parse it. |
|
121 TRAPD(err, ChangeStateL(EParseMessage)); |
|
122 if (err != KErrNone) |
|
123 User::RequestComplete(iReport, err); |
|
124 break; |
|
125 |
|
126 case EParseMessage: // Message parsed so update message. |
|
127 TRAP(err, ChangeStateL(ECompleteMessage)); |
|
128 if(err != KErrNone) |
|
129 { |
|
130 User::RequestComplete(iReport, err); |
|
131 } |
|
132 break; |
|
133 |
|
134 case ECompleteMessage: // CompleteMessage done. We're finished here. |
|
135 User::RequestComplete(iReport, KErrNone); |
|
136 break; |
|
137 |
|
138 default: |
|
139 break; |
|
140 } |
|
141 } |
|
142 // end CBusinessCardParser::RunL() |
|
143 |
|
144 |
|
145 void CBusinessCardParser::ChangeStateL(TParseSession aState) |
|
146 { |
|
147 iState = aState; // Increments iState. |
|
148 switch (iState) |
|
149 { |
|
150 case EUnfoldMessage: |
|
151 UnfoldMessageL(); // Perform MIME unfolding of SMS message. |
|
152 break; |
|
153 |
|
154 case EParseMessage: |
|
155 ParseMessageL(); // Parse message in Tlex object into array. |
|
156 break; |
|
157 |
|
158 case ECompleteMessage: |
|
159 CompleteMessageL(); // Copy message data to child and write new message body. |
|
160 break; |
|
161 |
|
162 default: |
|
163 break; |
|
164 } |
|
165 RequestComplete(iStatus, KErrNone); // Go back to ready state. |
|
166 SetActive(); |
|
167 } |
|
168 // end CBusinessCardParser::ChangeStateL(TParseSession) |
|
169 |
|
170 |
|
171 void CBusinessCardParser::ParseMessageL() |
|
172 // Parses Tlex object iSms into array. |
|
173 { |
|
174 StripCarriageReturnsL(); // Strip carriage returns from message. |
|
175 TPtrC fieldName; |
|
176 TPtrC fieldValue; |
|
177 TInt i; |
|
178 |
|
179 // First line of a CBC is "Business Card". This keyword may not exist if the card is |
|
180 // received over NBS (port 5501 decimal, 157D hex). |
|
181 // Need to hunt for keyword. If it does not exist then we assume that it is a valid |
|
182 // CBC received over NBS. |
|
183 |
|
184 // reset parsedfield array |
|
185 |
|
186 if (iParsedFieldArray->Count() > 0) |
|
187 iParsedFieldArray->ResetAndDestroy(); |
|
188 |
|
189 TLexMark startMark; |
|
190 iSms.Mark(startMark); |
|
191 iSms.SkipSpaceAndMark(); |
|
192 TBool isCompactBusinessCard = EFalse; |
|
193 do |
|
194 { |
|
195 while ( (iSms.Peek() != 'B') && (!iSms.Eos()) ) iSms.Inc(); |
|
196 if (iSms.Peek() == 'B') // If the next character is a B then... |
|
197 { |
|
198 iSms.Mark(); |
|
199 iSms.SkipCharacters(); // Skip over non-white space (hopefully "Business"). |
|
200 if (!iSms.Eos()) iSms.Inc(); // Skip over a single white space. |
|
201 if (!iSms.Eos()) iSms.SkipCharacters(); // Skip over non-white space (hopefully "Card"). |
|
202 // N.B. '/n' is a white space character. |
|
203 |
|
204 // Extract text from between mark and current position and check that it is as we hope. |
|
205 if (iSms.MarkedToken() != KBusinessCardHeader) // Not keyword so keep looking. |
|
206 { |
|
207 iSms.UnGetToMark(); |
|
208 iSms.Inc(); |
|
209 iSms.Mark(); |
|
210 } |
|
211 else |
|
212 isCompactBusinessCard = ETrue; |
|
213 } |
|
214 else // No keyword so received over NBS. |
|
215 { |
|
216 isCompactBusinessCard = ETrue; |
|
217 iSms.UnGetToMark(startMark); |
|
218 } |
|
219 } |
|
220 while (!isCompactBusinessCard); |
|
221 // Move on to next line: |
|
222 while (iSms.Peek() != KCharLineFeed && !iSms.Eos()) iSms.Inc(); |
|
223 if (iSms.Eos()) |
|
224 User::Leave(KBspInvalidMessage); // Leave. |
|
225 else |
|
226 iSms.SkipAndMark(1); |
|
227 |
|
228 // Parse the first three compulsory fields: |
|
229 AddRequiredFieldL(KHeaderName); |
|
230 AddRequiredFieldL(KHeaderCompany); |
|
231 AddRequiredFieldL(KHeaderTitle); |
|
232 |
|
233 for (i=0; i<3; i++) |
|
234 { |
|
235 while (iSms.Peek() != KCharLineFeed && !iSms.Eos()) // Skip to next delimiter. |
|
236 iSms.Inc(); |
|
237 fieldName.Set(iParsedFieldArray->At(i)->FieldName()); // Store (pointer to) field name. |
|
238 fieldValue.Set(iSms.MarkedToken()); // Store (pointer to) field value. |
|
239 AddParsedFieldL(fieldName, fieldValue, ETrue); // All fields are mandatory. |
|
240 if (!iSms.Eos()) |
|
241 iSms.SkipAndMark(1); // Move on to next line. |
|
242 else |
|
243 User::Leave(KBspInvalidMessage); // Leave - not long enough for valid CBC. |
|
244 } |
|
245 iNumberOfCbcFields = i; |
|
246 |
|
247 // Now parse the fax and telephone fields: |
|
248 // The first telephone field must be the fourth line of the compact-card-body. It must |
|
249 // either be empty or start with "tel". Subsequent telephone lines must also start with |
|
250 // "tel", otherwise we move on to the fax line(s). |
|
251 iNumberOfTel = 0; |
|
252 AddRequiredFieldL(KHeaderPhone); |
|
253 if (iSms.Peek() != KCharLineFeed) // We have a potential phone number. |
|
254 { |
|
255 if ( iSms.Peek() != 't' || iSms.Remainder().Length() < 4 ) |
|
256 User::Leave(KBspInvalidMessage); // No valid phone number line. |
|
257 do { |
|
258 iSms.Inc(3); |
|
259 if (iSms.MarkedToken().Compare(_L("tel")) != 0 && iNumberOfTel == 0) |
|
260 User::Leave(KBspInvalidMessage); // No valid phone number line. |
|
261 else if (iSms.MarkedToken().Compare(_L("tel")) != 0) |
|
262 { // Not a valid phone number line. |
|
263 iSms.UnGetToMark(); // Go back to start of line. |
|
264 break; // Exit; go on to fax number lines |
|
265 } |
|
266 else if (iSms.MarkedToken().Compare(_L("tel")) == 0 && iNumberOfTel > 0) |
|
267 { // Additional phone number. |
|
268 TBuf<8> aPhoneHeader; |
|
269 aPhoneHeader.Append(KHeaderPhone); |
|
270 TBuf<3> aNumber; |
|
271 aNumber.NumFixedWidth(++iNumberOfTel,EDecimal,3); |
|
272 aPhoneHeader.Append(aNumber); |
|
273 AddRequiredFieldL(aPhoneHeader); |
|
274 } |
|
275 else |
|
276 iNumberOfTel = 1; // First phone number |
|
277 for (;;) |
|
278 { |
|
279 if (IsValidTelephoneCharacter()) |
|
280 { |
|
281 iSms.Mark(); |
|
282 while (iSms.Peek() != KCharLineFeed && !iSms.Eos()) iSms.Inc(); |
|
283 i = iNumberOfCbcFields + iNumberOfTel - 1; |
|
284 fieldName.Set(iParsedFieldArray->At(i)->FieldName());// Store (pointer to) field name. |
|
285 fieldValue.Set(iSms.MarkedToken()); // Store (pointer to) field value. |
|
286 AddParsedFieldL(fieldName, fieldValue, ETrue); // All fields are mandatory. |
|
287 iSms.SkipAndMark(1); // Move on to next line. |
|
288 break; |
|
289 } |
|
290 else if (iSms.Peek() == KCharLineFeed) |
|
291 { |
|
292 iSms.SkipAndMark(1); // Move on to next line. |
|
293 break; |
|
294 } |
|
295 else if (iSms.Eos()) |
|
296 User::Leave(KBspInvalidMessage);// Leave - not long enough for valid CBC. |
|
297 else |
|
298 iSms.Inc(); // Skip to next digit. |
|
299 } |
|
300 } |
|
301 while (iSms.Peek() == 't' && iSms.Remainder().Length() >= 3); |
|
302 } |
|
303 else |
|
304 { |
|
305 iSms.SkipAndMark(1); // No phone number - move on to next line. |
|
306 iNumberOfTel = 1; // One (empty) phone number field. |
|
307 } |
|
308 |
|
309 // The first fax field must be the next line of the compact-card-body. It must either |
|
310 // be empty or start with "fax". Subsequent fax number lines must also start with "fax". |
|
311 AddRequiredFieldL(KHeaderFax); |
|
312 iNumberOfFax = 0; |
|
313 if (iSms.Peek() != KCharLineFeed) // We have a potential fax number. |
|
314 { |
|
315 if ( iSms.Peek() != 'f' || iSms.Remainder().Length() < 4 ) |
|
316 User::Leave(KBspInvalidMessage); // No valid fax number line. |
|
317 do { |
|
318 iSms.Inc(3); |
|
319 if (iSms.MarkedToken().Compare(_L("fax")) != 0 && iNumberOfFax == 0) |
|
320 User::Leave(KBspInvalidMessage); // No valid fax number line. |
|
321 else if (iSms.MarkedToken().Compare(_L("fax")) != 0) |
|
322 { // Not a valid fax number line. |
|
323 iSms.UnGetToMark(); // Go back to start of line. |
|
324 break; // Exit; go on to email line |
|
325 } |
|
326 else if (iSms.MarkedToken().Compare(_L("fax")) == 0 && iNumberOfFax > 0) |
|
327 { // Additional fax number. |
|
328 TBuf<6> aFaxHeader; |
|
329 aFaxHeader.Append(KHeaderFax); |
|
330 TBuf<3> aNumber; |
|
331 aNumber.NumFixedWidth(++iNumberOfFax,EDecimal,3); |
|
332 aFaxHeader.Append(aNumber); |
|
333 AddRequiredFieldL(aFaxHeader); |
|
334 } |
|
335 else |
|
336 iNumberOfFax = 1; // First fax number |
|
337 for (;;) // Could use a switch. |
|
338 { |
|
339 if (IsValidTelephoneCharacter()) |
|
340 { |
|
341 iSms.Mark(); |
|
342 while (iSms.Peek() != KCharLineFeed && !iSms.Eos()) iSms.Inc(); |
|
343 i = iNumberOfCbcFields + iNumberOfTel + iNumberOfFax - 1; |
|
344 fieldName.Set(iParsedFieldArray->At(i)->FieldName());// Store (pointer to) field name. |
|
345 fieldValue.Set(iSms.MarkedToken()); // Store (pointer to) field value. |
|
346 AddParsedFieldL(fieldName, fieldValue, ETrue); // All fields are mandatory. |
|
347 iSms.SkipAndMark(1); // Move on to next line. |
|
348 break; |
|
349 } |
|
350 else if (iSms.Peek() == KCharLineFeed) |
|
351 { |
|
352 iSms.SkipAndMark(1); // Move on to next line. |
|
353 break; |
|
354 } |
|
355 else if (iSms.Eos()) |
|
356 User::Leave(KBspInvalidMessage);// Leave - not long enough for valid CBC. |
|
357 else |
|
358 iSms.Inc(); // Skip to next digit. |
|
359 } |
|
360 } |
|
361 while (iSms.Peek() == 'f' && iSms.Remainder().Length() >= 3); |
|
362 } |
|
363 else |
|
364 { |
|
365 iSms.SkipAndMark(1); // No fax number - move on to next line. |
|
366 iNumberOfFax = 1; // One (empty) fax number field. |
|
367 } |
|
368 |
|
369 // Now parse the last six compulsory fields: |
|
370 iNumberOfCbcFields += (iNumberOfFax + iNumberOfTel); |
|
371 AddRequiredFieldL(KHeaderEmail); |
|
372 AddRequiredFieldL(KHeaderStreet1); |
|
373 AddRequiredFieldL(KHeaderStreet2); |
|
374 AddRequiredFieldL(KHeaderStreet3); |
|
375 AddRequiredFieldL(KHeaderStreet4); |
|
376 AddRequiredFieldL(KHeaderStreet5); |
|
377 for (i=iNumberOfCbcFields; i<iNumberOfCbcFields+6; i++) |
|
378 { |
|
379 while (!iSms.Eos() && iSms.Peek() != KCharLineFeed) iSms.Inc(); // Skip to next delimiter. |
|
380 fieldName.Set(iParsedFieldArray->At(i)->FieldName()); // Store (pointer to) field name. |
|
381 fieldValue.Set(iSms.MarkedToken()); // Store (pointer to) field value. |
|
382 AddParsedFieldL(fieldName, fieldValue, ETrue); // All fields are mandatory. |
|
383 if (!iSms.Eos()) |
|
384 { |
|
385 iSms.SkipAndMark(1); // Move on to next line. |
|
386 } |
|
387 else |
|
388 i=iNumberOfCbcFields+6; // Exit FOR loop. |
|
389 } |
|
390 iNumberOfCbcFields = i; |
|
391 |
|
392 // Throw any extra lines into the note field: |
|
393 if (!iSms.Eos()) |
|
394 { |
|
395 AddRequiredFieldL(KHeaderExtra); |
|
396 iNumberOfCbcFields++; |
|
397 while (!iSms.Eos()) iSms.Inc(); // Include remainder of text. |
|
398 TInt notesLength = iSms.TokenLength(); |
|
399 iSms.UnGetToMark(); |
|
400 delete iNotesBuffer; |
|
401 iNotesBuffer = NULL; |
|
402 iNotesBuffer=HBufC::NewLC(notesLength); // Buffer large enough for remainder of text. |
|
403 TPtr notesPtr = iNotesBuffer->Des(); |
|
404 |
|
405 iSms.SkipSpaceAndMark(); |
|
406 // Need to strip out line feeds: |
|
407 while (!iSms.Eos()) |
|
408 { |
|
409 while (!iSms.Eos() && iSms.Peek() != KCharLineFeed) iSms.Inc(); |
|
410 notesPtr.Append(iSms.MarkedToken()); |
|
411 notesPtr.Append(KCharComma); // Delimit data with commas. |
|
412 if (!iSms.Eos()) iSms.SkipSpaceAndMark(); |
|
413 } |
|
414 |
|
415 notesLength = notesPtr.Length(); // Reduce size of buffer to minimum. |
|
416 iNotesBuffer = iNotesBuffer->ReAllocL(notesLength); |
|
417 |
|
418 fieldValue.Set(iNotesBuffer->Des()); // Store (pointer to) field value |
|
419 fieldName.Set(KHeaderExtra); // Store (pointer to) field name |
|
420 AddParsedFieldL(fieldName, fieldValue, EFalse); // This field is optional. |
|
421 CleanupStack::Pop(); // iNotesBuffer (deleted in destructor). |
|
422 } |
|
423 } |
|
424 // end CBusinessCardParser::ParseMessageL |
|
425 |
|
426 |
|
427 void CBusinessCardParser::StripCarriageReturnsL() |
|
428 { |
|
429 // Strips out the carriage returns; they shouldn't be there anyway! |
|
430 TPtr smsPtr = iSmsBuf->Des(); |
|
431 for (TInt pos = 0; pos < (smsPtr.Length() - 1); pos++) |
|
432 if (smsPtr[pos] == KCharCarriageReturn) |
|
433 smsPtr.Delete(pos, 1); |
|
434 iSmsBuf = iSmsBuf->ReAllocL(smsPtr.Length()); // Reallocate iSmsBuf with new size. |
|
435 iSms = iSmsBuf->Des(); // Initialise Tlex object. |
|
436 } |
|
437 // end CBusinessCardParser::StripCarriageReturnsL |
|
438 |
|
439 |
|
440 void CBusinessCardParser::CompleteMessageL() |
|
441 // Streams the contents of iParsedFieldsArray as a child entry of the original message. |
|
442 // Converts data to vCard format and saves to a file. |
|
443 // If this returns OK sets the iMtmData3 flag to 1 (parsed) and writes a new message body into the SmartMessage. |
|
444 { |
|
445 // Create new stream (containing parsed data) within store associated with message entry: |
|
446 iEntry.SetEntryL(iEntryId); // Changes the entry used as the Message Server context. |
|
447 CMsvStore* store=iEntry.EditStoreL(); // Returns the message store for the current context with write access. |
|
448 // 'store' is the 'active object' responsible for the request. |
|
449 CleanupStack::PushL(store); |
|
450 StoreL(*store); // Store the parsed fields into a message stream. |
|
451 CleanupStack::PopAndDestroy(); |
|
452 |
|
453 // Change Entry Body text to vCard and save to a file: |
|
454 iEntry.SetEntryL(iEntryId); // Changes the entry used as the Message Server context. |
|
455 |
|
456 CreateDataL(); |
|
457 |
|
458 TBuf<64> tempBuf; |
|
459 tempBuf.Format(_L("%x"), iEntry.Entry().Id()); |
|
460 tempBuf.Append(KVCardExt); |
|
461 StoreL(TFileName(tempBuf)); // Pass the filename to base class method - creates a new folder |
|
462 // linked to message entry and stores body as an 8 bit attachment file. |
|
463 |
|
464 TMsvEntry entry= iEntry.Entry(); // 'entry' is the 'active object' responsible for the request. |
|
465 |
|
466 entry.SetMtmData3(1); // Indicates that we've parsed it. |
|
467 // |
|
468 iEntry.ChangeL(entry); // Changes the current context. |
|
469 } |
|
470 // end CBusinessCardParser::CompleteMessageL() |
|
471 |
|
472 void CBusinessCardParser::AddRequiredFieldL(const TDesC& aFieldName) |
|
473 { |
|
474 // Create new CParsedField object on heap: |
|
475 CParsedField* parsedField = new (ELeave) CParsedField; |
|
476 CleanupStack::PushL(parsedField); |
|
477 |
|
478 // Initialise field name: |
|
479 parsedField->SetFieldNameL(aFieldName); |
|
480 parsedField->SetFieldValueL(KInitialFieldValue); |
|
481 parsedField->SetMandatoryField(EFalse); |
|
482 |
|
483 // Add pointer to array: |
|
484 iParsedFieldArray->AppendL(parsedField); |
|
485 CleanupStack::Pop(parsedField); // No need to delete the CParsedField object, since it's now owned by the array. |
|
486 } |
|
487 // end CBusinessCardParser::AddRequiredFieldL(const TDesC&) |
|
488 |
|
489 |
|
490 void CBusinessCardParser::CreateDataL() |
|
491 { |
|
492 delete iSettings; |
|
493 iSettings = HBufC::NewL(512); |
|
494 |
|
495 // Write vCard to iSettings: |
|
496 AppendItemL( KVCardHeader); // Header. |
|
497 AppendItemL( KVCardVersion); // Version of vCard spec. |
|
498 AppendItemL( KVCardFormattedName); // Formatted name. |
|
499 AppendItemL( iParsedFieldArray->At(0)->FieldValue()); |
|
500 |
|
501 // Parse out name into vCard semicolon delimited fields: |
|
502 // The Nokia Smart Messaging Specification, Revision 2.0.0, Section 3.3.1 suggests that the name |
|
503 // should be in the format "last-name first-name". The following code assumes that this convention |
|
504 // is used. A single name is assumed to be a last name. If there are more than two words then the |
|
505 // remaining text is assumed to be additional names. |
|
506 AppendItemL( KVCardName); // Name, semicolon delimited. |
|
507 TLex iField = iParsedFieldArray->At(0)->FieldValue(); // Put name into a TLex object |
|
508 iField.SkipSpace(); // Last name. |
|
509 if (!iField.Eos()) |
|
510 { |
|
511 iField.Mark(); |
|
512 iField.SkipCharacters(); |
|
513 AppendItemL( iField.MarkedToken()); |
|
514 } |
|
515 AppendItemL( KCharSemiColon ); |
|
516 iField.SkipSpace(); // First name. |
|
517 if (!iField.Eos()) |
|
518 { |
|
519 iField.Mark(); |
|
520 iField.SkipCharacters(); |
|
521 AppendItemL( iField.MarkedToken()); |
|
522 } |
|
523 AppendItemL( KCharSemiColon); |
|
524 iField.SkipSpace(); |
|
525 AppendItemL( iField.Remainder()); // Additional names. |
|
526 AppendItemL( KCharSemiColon); // Honourific prefices. |
|
527 AppendItemL( KCharSemiColon); // Honourific suffices. |
|
528 |
|
529 AppendItemL( KVCardAddress); // Address, semicolon delimited. |
|
530 TInt addressOffset = iNumberOfFax + iNumberOfTel + KTelOffset; // Offset of address lines from start of cbc. |
|
531 TInt i; |
|
532 for (i=0; i<KNumberOfAddressLines; i++) |
|
533 { |
|
534 AppendItemL( KCharSemiColon); |
|
535 AppendItemL( iParsedFieldArray->At(addressOffset+i)->FieldValue()); |
|
536 } |
|
537 |
|
538 // note info is optional - so append if it exists |
|
539 |
|
540 if (addressOffset+KNumberOfAddressLines < iParsedFieldArray->Count()) |
|
541 { |
|
542 // Extra gubbins tacked to end of notes field, after address: |
|
543 AppendItemL( KVCardNote); |
|
544 AppendItemL( |
|
545 iParsedFieldArray->At(addressOffset+KNumberOfAddressLines)->FieldValue()); |
|
546 } |
|
547 |
|
548 // Telephone numbers: |
|
549 for (i=KTelOffset-1; i<iNumberOfTel+KTelOffset-1; i++) |
|
550 { |
|
551 AppendTelItemL(iParsedFieldArray->At(i)->FieldValue(), KVCardTel, KVCardTelCell); |
|
552 } |
|
553 |
|
554 // Fax numbers: |
|
555 for (; i<iNumberOfFax+iNumberOfTel+KTelOffset-1; i++) |
|
556 { |
|
557 AppendTelItemL(iParsedFieldArray->At(i)->FieldValue(), KVCardFax, KVCardFaxCell); |
|
558 } |
|
559 |
|
560 // Other stuff: |
|
561 AppendItemL( KVCardEmail); // Email address. |
|
562 AppendItemL( |
|
563 iParsedFieldArray->At(iNumberOfFax+iNumberOfTel+KTelOffset-1)->FieldValue()); |
|
564 AppendItemL( KVCardTitle); // Title (job description). |
|
565 AppendItemL( iParsedFieldArray->At(2)->FieldValue()); |
|
566 AppendItemL( KVCardOrg); // Organisation: company. |
|
567 AppendItemL( iParsedFieldArray->At(1)->FieldValue()); |
|
568 AppendItemL( KVCardFooter); // End of vCard. |
|
569 } |
|
570 |
|
571 void CBusinessCardParser::AppendTelItemL(const TDesC& aTel, const TDesC& aDefaultLabel, const TDesC& aCellLabel) |
|
572 { |
|
573 // We must check for the prefix (GSM) to see if the number should |
|
574 // be stored in the cellphone field instead |
|
575 |
|
576 // Store the field for the first number and check for the (GSM) prefix |
|
577 |
|
578 TLex telLex(aTel); |
|
579 const TPtrC prefixCell(KVPrefixCell); |
|
580 const TInt prefixCellLen = prefixCell.Length(); |
|
581 |
|
582 TPtrC label(aDefaultLabel); |
|
583 TPtrC value(aTel); |
|
584 |
|
585 if (aTel.Length() > prefixCellLen && telLex.Peek() == TChar(*prefixCell.Ptr())) |
|
586 { |
|
587 telLex.Inc(prefixCellLen); |
|
588 if(telLex.MarkedToken().CompareF(prefixCell) == 0) // If there is a GSM prefix create as cellphone number |
|
589 { |
|
590 telLex.SkipSpaceAndMark(); |
|
591 label.Set(aCellLabel); |
|
592 value.Set(telLex.RemainderFromMark()); |
|
593 } |
|
594 } |
|
595 |
|
596 AppendItemL(label); |
|
597 AppendItemL(value); |
|
598 } |
|
599 |
|
600 void CBusinessCardParser::AppendItemL(const TDesC& aItem) |
|
601 { |
|
602 TInt newLength = iSettings->Des().Length() + aItem.Length(); |
|
603 if(iSettings->Des().MaxLength() < newLength) |
|
604 { |
|
605 iSettings = iSettings->ReAllocL(newLength); |
|
606 } |
|
607 TPtr des = iSettings->Des(); |
|
608 des.Append(aItem); |
|
609 } |
|
610 |
|
611 void CBusinessCardParser::AddParsedFieldL(const TDesC& aFieldName, |
|
612 const TDesC& aFieldValue, |
|
613 TBool aMandatory) |
|
614 { |
|
615 // This method is responsible for adding field values found by the parser to the array of parsed fields. |
|
616 // It enforces the "each field once only" rule (see Nokia Smart Messaging spec, 2.0.0pre, 3-34). |
|
617 for (TInt i = 0; i < iParsedFieldArray->Count(); i++) |
|
618 { |
|
619 // Use CompareF() to perform case-insensitive match: |
|
620 if (aFieldName.CompareF(iParsedFieldArray->At(i)->FieldName()) == 0) |
|
621 { |
|
622 // Field name exists, so insert a value: |
|
623 iParsedFieldArray->At(i)->SetFieldValueL(aFieldValue); |
|
624 iParsedFieldArray->At(i)->SetMandatoryField(aMandatory); |
|
625 return; |
|
626 } |
|
627 } |
|
628 } |
|
629 // end CBusinessCardParser::AddParsedField(const TDesC&, const TDesC&, TBool) |
|
630 |
|
631 |
|
632 void CBusinessCardParser::RequestComplete(TRequestStatus& aStatus, TInt aError) |
|
633 { |
|
634 TRequestStatus* p = &aStatus; |
|
635 User::RequestComplete(p, aError); |
|
636 } |
|
637 // end CBusinessCardParser::RequestComplete(TRequestStatus&, TInt) |
|
638 |
|
639 TBool CBusinessCardParser::IsValidTelephoneCharacter() const |
|
640 { |
|
641 const TChar ch = iSms.Peek(); |
|
642 |
|
643 if (ch.IsDigit() || |
|
644 ch == '(' || |
|
645 ch == '-' || |
|
646 ch == '*' || |
|
647 ch == '#' || |
|
648 ch == 'w' || |
|
649 ch == 'W' || |
|
650 ch == 'p' || |
|
651 ch == 'P' || |
|
652 ch =='+') |
|
653 return ETrue; |
|
654 else |
|
655 return EFalse; |
|
656 } |
|
657 |
|
658 // Constructor |
|
659 CBusinessCardParser::CBusinessCardParser(CRegisteredParserDll& aRegisteredParserDll, CMsvEntry& aEntry, RFs& aFs) |
|
660 : CBaseScriptParser2(aRegisteredParserDll, aEntry, aFs) |
|
661 { |
|
662 } |
|
663 // end CBusinessCardParser::CBusinessCardParser() |
|
664 |
|
665 |
|
666 CBusinessCardParser::~CBusinessCardParser() |
|
667 { |
|
668 if (iSmsBuf != NULL) |
|
669 { |
|
670 delete iSmsBuf; |
|
671 } |
|
672 if (iParsedFieldArray != NULL) |
|
673 { |
|
674 iParsedFieldArray->ResetAndDestroy(); |
|
675 delete iParsedFieldArray; |
|
676 delete iNotesBuffer; |
|
677 } |
|
678 } |
|
679 // end CBusinessCardParser::~CBusinessCardParser() |