|
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 // |
|
15 |
|
16 #include <s32file.h> |
|
17 #include <logcntmodel.h> |
|
18 #include <logengevents.h> |
|
19 #include "LOGADD.H" |
|
20 #include "logservpanic.h" |
|
21 #include "LOGDUP.H" |
|
22 #include "LOGQUERY.H" |
|
23 #include "LogServRecentList.h" |
|
24 #include "LogServDatabaseTransactionInterface.h" |
|
25 #include "LogServResourceInterpreter.h" |
|
26 #include "LogServCacheConfig.h" |
|
27 #include "LogServDatabaseChangeInterface.h" |
|
28 #include <logserv.rsg> |
|
29 #include <centralrepository.h> |
|
30 #include "LogServCacheStrings.h" |
|
31 #include "LogServCacheTypes.h" |
|
32 #include "LOGREPDEFS.H" |
|
33 |
|
34 const TInt KMinimumNumberOfDigitsToMatch = 3; |
|
35 |
|
36 //////////////////////////////////////////////////////////////////////////////////////////// |
|
37 // Local functions |
|
38 |
|
39 #ifdef SYSLIBS_TEST |
|
40 |
|
41 #pragma BullseyeCoverage off |
|
42 |
|
43 static void LogStore32IntL(RFs& aFs, const TDesC& aFilePath, TInt aVal) |
|
44 { |
|
45 RFile file; |
|
46 User::LeaveIfError(file.Replace(aFs, aFilePath, EFileWrite)); |
|
47 TPtrC8 p((const TUint8*)&aVal, sizeof(aVal)); |
|
48 TInt err = file.Write(p); |
|
49 if(err == KErrNone) |
|
50 { |
|
51 err = file.Flush(); |
|
52 } |
|
53 file.Close(); |
|
54 User::LeaveIfError(err); |
|
55 } |
|
56 |
|
57 static void LogStoreContactMatchCountAndNameFormatL(TInt aContactMatchCount, TLogContactNameFormat aContactNameFormat) |
|
58 { |
|
59 RFs fs; |
|
60 CleanupClosePushL(fs); |
|
61 User::LeaveIfError(fs.Connect()); |
|
62 |
|
63 _LIT(KTestDir, "c:\\test\\"); |
|
64 TInt err = fs.MkDir(KTestDir); |
|
65 if(err != KErrNone && err != KErrAlreadyExists) |
|
66 { |
|
67 User::Leave(err); |
|
68 } |
|
69 |
|
70 _LIT(KLogengTestFileNameCount, "c:\\test\\test_logengconfig_count.ini"); |
|
71 LogStore32IntL(fs, KLogengTestFileNameCount, aContactMatchCount); |
|
72 |
|
73 _LIT(KLogengTestFileNameFormat, "c:\\test\\test_logengconfig_format.ini"); |
|
74 LogStore32IntL(fs, KLogengTestFileNameFormat, (TInt)aContactNameFormat); |
|
75 |
|
76 CleanupStack::PopAndDestroy(&fs); |
|
77 } |
|
78 |
|
79 #pragma BullseyeCoverage on |
|
80 |
|
81 #endif //SYSLIBS_TEST |
|
82 |
|
83 //This function reads logeng repository file and returns the integer value of the given key. |
|
84 static TInt LogGetRepositoryValueL(CRepository& aRepository, TInt aKey) |
|
85 { |
|
86 TInt val = -1; |
|
87 User::LeaveIfError(aRepository.Get(aKey, val)); |
|
88 return val; |
|
89 } |
|
90 |
|
91 //This function reads logeng resource file and returns the integer value of the given resource id. |
|
92 static TInt LogGetResourceValueL(CLogServResourceInterpreter& aResourceInterpreter, TInt aResourceId) |
|
93 { |
|
94 TResourceReader reader; |
|
95 aResourceInterpreter.CreateResourceReaderLC(reader, aResourceId, CLogServResourceInterpreter::ELogServer); |
|
96 TInt val = reader.ReadInt16(); |
|
97 CleanupStack::PopAndDestroy(); |
|
98 return val; |
|
99 } |
|
100 |
|
101 static void LogGetContactmatchCountAndNameFormatL(CLogServResourceInterpreter& aResourceInterpreter, TInt& aContactMatchCount, TLogContactNameFormat& aContactNameFormat) |
|
102 { |
|
103 CRepository* repository = NULL; |
|
104 TRAPD(err, repository = CRepository::NewL(KUidLogengRepository)); |
|
105 if(err == KErrCorrupt) |
|
106 { |
|
107 __ASSERT_DEBUG(!repository, User::Invariant()); |
|
108 User::Leave(err); |
|
109 } |
|
110 else if(err == KErrNone) |
|
111 { |
|
112 CleanupStack::PushL(repository); |
|
113 aContactMatchCount = LogGetRepositoryValueL(*repository, KContactMatchCountRepKey); |
|
114 aContactNameFormat = static_cast <TLogContactNameFormat> (LogGetRepositoryValueL(*repository, KContactNameFormatRepKey)); |
|
115 CleanupStack::PopAndDestroy(repository); |
|
116 } |
|
117 else |
|
118 { |
|
119 __ASSERT_DEBUG(!repository, User::Invariant()); |
|
120 aContactMatchCount = LogGetResourceValueL(aResourceInterpreter, R_LOG_CONTACT_MATCH_COUNT); |
|
121 aContactNameFormat = static_cast <TLogContactNameFormat> (LogGetResourceValueL(aResourceInterpreter, R_LOG_CONTACT_NAME_FORMAT)); |
|
122 } |
|
123 #ifdef SYSLIBS_TEST |
|
124 LogStoreContactMatchCountAndNameFormatL(aContactMatchCount, aContactNameFormat); |
|
125 #endif |
|
126 } |
|
127 |
|
128 //////////////////////////////////////////////////////////////////////////////////////////// |
|
129 // CLogAddEvent class |
|
130 |
|
131 CLogAddEvent::CLogAddEvent(MLogServDatabaseTransactionInterface& aDatabase, TInt aPriority) : |
|
132 CLogActive(aPriority), |
|
133 iDatabase(aDatabase) |
|
134 { |
|
135 } |
|
136 |
|
137 CLogAddEvent::~CLogAddEvent() |
|
138 { |
|
139 Cancel(); |
|
140 |
|
141 CloseContactsPlugin(); |
|
142 |
|
143 delete iDuplicate; |
|
144 delete iDuplicateFilter; |
|
145 } |
|
146 |
|
147 CLogAddEvent* CLogAddEvent::NewL(MLogServDatabaseTransactionInterface& aDatabase, TInt aPriority) |
|
148 { |
|
149 CLogAddEvent* self = new(ELeave) CLogAddEvent(aDatabase, aPriority); |
|
150 CleanupStack::PushL(self); |
|
151 self->ConstructL(); |
|
152 CleanupStack::Pop(self); |
|
153 return self; |
|
154 } |
|
155 |
|
156 void CLogAddEvent::ConstructL() |
|
157 { |
|
158 iDuplicate = CLogDuplicate::NewL(iDatabase, Priority()); |
|
159 iDuplicateFilter = CLogFilter::NewL(); |
|
160 ::LogGetContactmatchCountAndNameFormatL(iDatabase.DTIResourceInterface(), iContactMatchCount, iContactNameFormat); |
|
161 } |
|
162 |
|
163 //This method will open contacts database (if not opened yet), only if the value of |
|
164 //r_log_contact_match_count resource in logserv.rsg resource file is not 0. |
|
165 //Se how iContactMatchCount data member is initialised. |
|
166 TBool CLogAddEvent::PerformContactMatchL() |
|
167 { |
|
168 if (iContactMatchCount <= 0 || iEvent->Contact() != KLogNullContactId) |
|
169 return EFalse; |
|
170 |
|
171 if (iContactPlugin) |
|
172 return ETrue; |
|
173 |
|
174 // Attempt to load plugin |
|
175 TRAPD( err, iContactPlugin=CLogCntModel::NewL()); |
|
176 |
|
177 // If plugin doesn't exist this is equivalent to matching being disabled so we don't leave |
|
178 // for KErrNotFound |
|
179 if(err==KEComErrNoInterfaceIdentified) |
|
180 { |
|
181 // Disable contacts matching so that we don't keep attempting to match |
|
182 iContactMatchCount = 0; |
|
183 // Plugin doesn't exist |
|
184 return EFalse; |
|
185 } |
|
186 |
|
187 User::LeaveIfError(err); |
|
188 |
|
189 // Open the DB |
|
190 OpenContactsL(); |
|
191 |
|
192 return ETrue; |
|
193 } |
|
194 |
|
195 void CLogAddEvent::StartL(CLogEvent& aEvent, const CLogServRecentList* aRecentList, TRequestStatus& aStatus, const RMessage2& aMessage) |
|
196 { |
|
197 __ASSERT_ALWAYS(!IsActive(), Panic(ELogAlreadyActive1)); |
|
198 |
|
199 LOGTEXT("CLogAddEvent::StartL()"); |
|
200 |
|
201 // Store event details which were obtained from the client side |
|
202 iEvent = &aEvent; |
|
203 iState = ELogAddEvent; |
|
204 |
|
205 if (!iDatabase.DTIIsAllowed(EWriteOp, aMessage, iEvent->EventType())) |
|
206 { |
|
207 User::Leave(KErrPermissionDenied); |
|
208 } |
|
209 |
|
210 if (PerformContactMatchL()) |
|
211 iState = ELogSetContactAndRemoteParty; // Go look for a matching contact |
|
212 |
|
213 iRecentList = aRecentList; |
|
214 iEventAdded = EFalse; |
|
215 |
|
216 // Setup the event's time (UTC) |
|
217 TTime time; |
|
218 time.UniversalTime(); |
|
219 iEvent->SetTime(time); |
|
220 |
|
221 // Save the observer's request status and set it to KRequestPending |
|
222 Queue(aStatus); |
|
223 |
|
224 // Start this objects RunL chain |
|
225 TRequestStatus* status = &iStatus; |
|
226 User::RequestComplete(status, KErrNone); |
|
227 SetActive(); |
|
228 } |
|
229 |
|
230 void CLogAddEvent::SetEventContact() |
|
231 { |
|
232 // Start by converting the phone number text into a number |
|
233 // check we've got a long enough number to be worth checking |
|
234 if(iEvent->Number().Length() >= KMinimumNumberOfDigitsToMatch) |
|
235 { |
|
236 // now search for a contact by looking up the phone number |
|
237 TLogContactItemId contactId = KLogNullContactId; |
|
238 TRAPD(err, contactId = iContactPlugin->MatchPhoneNumberL(iEvent->Number(), iContactMatchCount)); |
|
239 |
|
240 if(err == KErrNone) |
|
241 { |
|
242 // we have at least one match |
|
243 if(contactId != KLogNullContactId) |
|
244 { |
|
245 // we have a match so set the contact id |
|
246 iEvent->SetContact(contactId); |
|
247 } |
|
248 } |
|
249 } |
|
250 iEvent->SetFlags(KLogEventContactSearched); |
|
251 } |
|
252 |
|
253 void CLogAddEvent::SetRemoteParty() |
|
254 { |
|
255 // Get the contact id |
|
256 TLogContactItemId contactId = iEvent->Contact(); |
|
257 if((contactId != KLogNullContactId) && (iEvent->RemoteParty().Length() == 0)) |
|
258 { |
|
259 // Look it up and get the remote party info |
|
260 // Setup buffer to contain concatenated result |
|
261 TBuf<128> buf; |
|
262 // Go get the info |
|
263 TRAPD(err, iContactPlugin->ReadContactNameL(contactId, buf, iContactNameFormat)); |
|
264 |
|
265 if(err == KErrNotFound) |
|
266 { |
|
267 // Couldn't find the contact with that id so set it to NULL |
|
268 iEvent->SetContact(KLogNullContactId); |
|
269 } |
|
270 else |
|
271 { |
|
272 // Found it so fill in remote party |
|
273 iEvent->SetRemoteParty(buf); |
|
274 } |
|
275 } |
|
276 } |
|
277 |
|
278 void CLogAddEvent::GetConfigL() |
|
279 { |
|
280 iConfig = iDatabase.DTICacheConfig().Config(); |
|
281 if(iConfig.iMaxLogSize == 0) |
|
282 { |
|
283 LOGTEXT("CLogAddEvent::DoRunL() - logging disabled"); |
|
284 User::Leave(KErrNotSupported); |
|
285 } |
|
286 } |
|
287 |
|
288 TLogTypeId CLogAddEvent::SetDescriptionL() |
|
289 { |
|
290 const TLogServCacheTypeEntry& entry = iDatabase.DTICacheTypes().FindByUid(iEvent->EventType()); |
|
291 if(entry.iEventTypeId == KLogNullTypeId) |
|
292 { |
|
293 LOGTEXT("CLogAddEvent::DoRunL() - type not found"); |
|
294 User::Leave(KErrNotFound); |
|
295 } |
|
296 if(!entry.iEventType->LoggingEnabled()) |
|
297 { |
|
298 LOGTEXT("CLogAddEvent::DoRunL() - type not enabled"); |
|
299 User::Leave(KErrNotSupported); |
|
300 } |
|
301 iEvent->SetDescription(entry.iEventType->Description()); |
|
302 return entry.iEventTypeId; |
|
303 } |
|
304 |
|
305 TBool CLogAddEvent::DetectDuplicateEventsL() |
|
306 { |
|
307 TBool rc = EFalse; |
|
308 if(iRecentList) |
|
309 { |
|
310 iRecentList->GetFilter(*iEvent, *iDuplicateFilter); |
|
311 rc = iDuplicate->StartL(iEvent->Id(), iRecentList->Id(), *iDuplicateFilter, iStatus); |
|
312 } |
|
313 return rc; |
|
314 } |
|
315 |
|
316 void CLogAddEvent::DoRunL() |
|
317 { |
|
318 LOGTEXT3("CLogAddEvent::DoRunL(%d), state = %d", iStatus.Int(), iState); |
|
319 |
|
320 switch (iState) |
|
321 { |
|
322 case ELogSetContactAndRemoteParty: |
|
323 { |
|
324 SetEventContact(); |
|
325 SetRemoteParty(); |
|
326 TRequestStatus* status = &iStatus; |
|
327 User::RequestComplete(status, KErrNone); |
|
328 iState = ELogAddEvent; |
|
329 SetActive(); |
|
330 break; |
|
331 } |
|
332 case ELogAddEvent: |
|
333 { |
|
334 GetConfigL(); |
|
335 TLogTypeId typeId = SetDescriptionL(); |
|
336 RLogEventDbTable tbl; |
|
337 tbl.OpenLC(iDatabase.DTIDatabase()); |
|
338 ::LogPurgeMainL(iDatabase, tbl, iConfig.iMaxLogSize, 1); |
|
339 DoAddEventL(tbl, typeId, iDatabase.DTICacheStrings().GetIdL(iEvent->Direction()), iDatabase.DTICacheStrings().GetIdL(iEvent->Status())); |
|
340 CleanupStack::PopAndDestroy();//tbl |
|
341 iEventAdded = ETrue; |
|
342 if(DetectDuplicateEventsL()) |
|
343 { |
|
344 iState = ELogPurgeRecent; |
|
345 SetActive(); |
|
346 break; |
|
347 } |
|
348 iState = ELogPurgeRecent; |
|
349 TRequestStatus* status = &iStatus; |
|
350 User::RequestComplete(status, KErrNone); |
|
351 SetActive(); |
|
352 break; |
|
353 } |
|
354 case ELogPurgeRecent: |
|
355 { |
|
356 // Delete old recent events |
|
357 if (iRecentList) |
|
358 { |
|
359 RArray<TLogId> logIds; |
|
360 ::LogGetRecentEventsLC(iDatabase, iRecentList->Id(), iConfig.iMaxRecentLogSize, logIds); |
|
361 ::LogPurgeRecentEventsL(iDatabase, logIds); |
|
362 CleanupStack::PopAndDestroy(&logIds); |
|
363 } |
|
364 } |
|
365 break; |
|
366 default: |
|
367 __ASSERT_DEBUG(ETrue, Panic(ELogBadState1)); |
|
368 break; |
|
369 } |
|
370 |
|
371 LOGTEXT("CLogAddEvent::DoRunL() - end"); |
|
372 } |
|
373 |
|
374 void CLogAddEvent::DoCancel() |
|
375 { |
|
376 iDuplicate->Cancel(); |
|
377 CLogActive::DoCancel(); |
|
378 } |
|
379 |
|
380 void CLogAddEvent::DoAddEventL(RLogEventDbTable& aTbl, TLogTypeId aTypeId, TLogStringId aDirectionId, TLogStringId aStatusId) |
|
381 { |
|
382 LOGTEXT("CLogAddEvent::DoAddEventL()"); |
|
383 |
|
384 // Insert a new record |
|
385 aTbl.InsertL(); |
|
386 |
|
387 aTbl.SetColL(RLogEventDbTable::iTypeColNo, (TUint32)aTypeId); |
|
388 |
|
389 if (iEvent->RemoteParty().Length() > 0) |
|
390 aTbl.SetColL(RLogEventDbTable::iRemotePartyColNo, iEvent->RemoteParty()); |
|
391 |
|
392 if (iEvent->Direction().Length() > 0) |
|
393 aTbl.SetColL(RLogEventDbTable::iDirectionColNo, (TUint32)aDirectionId); |
|
394 |
|
395 aTbl.SetColL(RLogEventDbTable::iTimeColNo, iEvent->Time()); |
|
396 aTbl.SetColL(RLogEventDbTable::iDurationTypeColNo, (TInt32)iEvent->DurationType()); |
|
397 |
|
398 if (iEvent->DurationType() != KLogNullDurationType) |
|
399 aTbl.SetColL(RLogEventDbTable::iDurationColNo, iEvent->Duration()); |
|
400 |
|
401 if (iEvent->Status().Length() > 0) |
|
402 aTbl.SetColL(RLogEventDbTable::iStatusColNo, (TUint32)aStatusId); |
|
403 |
|
404 if (iEvent->Subject().Length() > 0) |
|
405 aTbl.SetColL(RLogEventDbTable::iSubjectColNo, iEvent->Subject()); |
|
406 |
|
407 if (iEvent->Number().Length() > 0) |
|
408 aTbl.SetColL(RLogEventDbTable::iNumberColNo, iEvent->Number()); |
|
409 |
|
410 if (iEvent->Contact() != KLogNullContactId) |
|
411 aTbl.SetColL(RLogEventDbTable::iContactColNo, iEvent->Contact()); |
|
412 |
|
413 if (iEvent->Link() != KLogNullLink) |
|
414 aTbl.SetColL(RLogEventDbTable::iLinkColNo, iEvent->Link()); |
|
415 |
|
416 if (iEvent->Data().Length() > 0) |
|
417 aTbl.SetColL(RLogEventDbTable::iDataColNo, iEvent->Data()); |
|
418 |
|
419 // Set the flags |
|
420 TInt bit = KLogFlagsCount; |
|
421 while(bit--) |
|
422 { |
|
423 aTbl.SetColL(RLogEventDbTable::iFlagColNo[bit], (TUint32)((iEvent->Flags() & 0x1 << bit) ? 1 : 0)); |
|
424 } |
|
425 |
|
426 if (iRecentList) |
|
427 { |
|
428 __ASSERT_DEBUG(iRecentList->Id() != KLogNullRecentList, Panic(ELogNullRecentList)); |
|
429 aTbl.SetColL(RLogEventDbTable::iRecentColNo, (TInt32)iRecentList->Id()); |
|
430 } |
|
431 |
|
432 #ifdef SYMBIAN_ENABLE_EVENTLOGGER_DUALSIM |
|
433 if(iEvent->SimId() != KLogNullSimId) |
|
434 { |
|
435 aTbl.SetColL(RLogEventDbTable::iSimIdColNo, iEvent->SimId()); |
|
436 } |
|
437 else |
|
438 { |
|
439 aTbl.SetColNullL(RLogEventDbTable::iSimIdColNo); |
|
440 } |
|
441 #endif |
|
442 |
|
443 // Assign event id and end the rowset operation |
|
444 const TLogId newId = aTbl.ColInt32(RLogEventDbTable::iIdColNo); |
|
445 iEvent->SetId(newId); |
|
446 aTbl.PutL(); |
|
447 |
|
448 // Tell change interface about the addition |
|
449 iDatabase.DTIChangeInterface().DCISubmitChangedEventContextL(ELogChangeTypeEventAdded, newId); |
|
450 |
|
451 LOGTEXT("CLogAddEvent::DoAddEventL() - end"); |
|
452 } |
|
453 |
|
454 void CLogAddEvent::DoComplete(TInt& aStatus) |
|
455 { |
|
456 LOGTEXT2("CLogAddEvent::DoComplete(%d)", aStatus); |
|
457 |
|
458 if (iDatabase.DTIInTransaction()) |
|
459 { |
|
460 LOGTEXT2("CLogAddEvent::DoComplete() - in transaction: %d", aStatus); |
|
461 if (aStatus == KErrNone) |
|
462 aStatus = iDatabase.DTICommitAndEnd(); |
|
463 |
|
464 LOGTEXT2("CLogAddEvent::DoComplete() - checking for need to rollback: %d", aStatus); |
|
465 if (aStatus < KErrNone) |
|
466 iDatabase.DTIRollBack(); |
|
467 } |
|
468 else |
|
469 { |
|
470 if (iEventAdded) |
|
471 aStatus = KErrNone; |
|
472 } |
|
473 |
|
474 LOGTEXT2("CLogAddEvent::DoComplete() - final status value is: %d", aStatus); |
|
475 } |
|
476 |
|
477 //Opens the default contacts database. |
|
478 void CLogAddEvent::OpenContactsL() |
|
479 { |
|
480 //Sometimes, after a sequence of OpenContactsL()/CloseContacts() calls the Contacts server crashes |
|
481 //and OpenContactsL() leaves with error -15. In order to avoid that the following delay has been added. |
|
482 //(something related to Contacts server state machine) |
|
483 User::After(100); |
|
484 // Attempt to open DB |
|
485 TRAPD(err,iContactPlugin->OpenContactsL()); |
|
486 if(KErrNone!=err) |
|
487 { |
|
488 // If DB doesn't open delete plugin |
|
489 delete iContactPlugin; |
|
490 iContactPlugin = NULL; |
|
491 User::Leave(err); |
|
492 } |
|
493 } |
|
494 |
|
495 //Closes the default contacts database and deletes the plugin. |
|
496 void CLogAddEvent::CloseContactsPlugin() |
|
497 { |
|
498 if(iContactPlugin) |
|
499 { |
|
500 iContactPlugin->CloseContacts(); |
|
501 delete iContactPlugin; |
|
502 iContactPlugin = NULL; |
|
503 //REComSession::FinalClose() call moved here from logcntmodel.cpp. |
|
504 //The in-source documentation of REComSession::FinalClose() notes that: |
|
505 //"It must never be called from within a plug-in implementations class |
|
506 //destructor, especially following a DestroyImplementation() ". |
|
507 //That was the case before the function call was moved here. |
|
508 REComSession::FinalClose(); |
|
509 } |
|
510 } |