upload tizen1.0 source
[profile/ivi/wrt-plugins-tizen.git] / src / platform / Tizen / Call / CallHistory.cpp
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License. 
15  */
16
17
18 #include "CallHistory.h"
19
20 #include <vector>
21 #include <string>
22 #include <sstream>
23 #include <cassert>
24 #include <Commons/Exception.h>
25 #include <dpl/shared_ptr.h>
26 #include <dpl/log/log.h>
27 #include <API/Filter/IFilter.h>
28 #include <API/Filter/IFilterVisitor.h>
29 #include <API/Call/CallDefine.h>
30 #include <calllog.h>
31 #include <contacts-svc.h>
32
33 #include "CallHistoryFilter.h"
34 #include <app.h>
35
36 using namespace TizenApis::Api::Tizen;
37 using namespace TizenApis::Api::Call;
38 using namespace WrtDeviceApis;
39 using namespace WrtDeviceApis::Commons;
40 using namespace DPL;
41
42 namespace TizenApis {
43 namespace Platform {
44 namespace Call {
45
46 std::vector<CallHistory::WatcherPtr> CallHistory::m_watchers;
47
48 CallHistory::CallHistory()
49 {
50         _db_init();
51
52         if (calllog_connect() == CALLLOG_ERROR_NONE) {
53                 LogDebug("Successful to connect Call history DB ");
54         } else {
55                 LogDebug("Failed to connect Call history DB ");
56         }
57 }
58
59 CallHistory::~CallHistory()
60 {
61         _db_finish();
62         
63         if (calllog_disconnect() == CALLLOG_ERROR_NONE) {
64                 LogDebug("Successful to disconnect Call history DB ");
65         } else {
66                 LogDebug("Failed to disconnect Call history DB ");
67         }
68
69         std::vector<CallHistory::WatcherPtr>::iterator it = CallHistory::m_watchers.begin();
70
71         if (m_watchers.size() > 0) {
72                 for (;it < CallHistory::m_watchers.end();) {
73                         contacts_svc_unsubscribe_change(CTS_SUBSCRIBE_PLOG_CHANGE, addedListenerCB);
74                         contacts_svc_unsubscribe_change(CTS_SUBSCRIBE_MISSED_CALL_CHANGE, changedListenerCB);
75                         it = CallHistory::m_watchers.erase(it);
76                         ++it;
77                 }
78                 LogDebug("CallHistory Watcher is removed. (" << CallHistory::m_watchers.size() << ")");
79         }
80 }
81
82 bool CallHistory::convertCallHistory(callhistory_query_s *query_log, CallHistoryEntryListPtr &callEntries)
83 {
84         if (query_log == NULL || callEntries == NULL)
85                 return false;
86
87         CallHistoryEntryPropertiesPtr callHistoryItem(new CallHistoryEntryProperties());
88         StringArrayPtr stringArray(new StringArray());
89         RemotePartyPtr remoteParty(new RemoteParty());
90         RemotePartyListPtr remotePartyList(new RemotePartyList());
91         Api::Contact::ContactRefPtr contactRef(new Api::Contact::ContactRef());
92
93         std::string callType("");
94         std::string tags("");
95         std::string direction("");
96         std::string number("");
97         
98         if (query_log->phone_number != NULL) {
99                 number.append(query_log->phone_number);
100         }
101
102         switch(query_log->calllog_type) {
103         case CALLLOG_TYPE_VOICE_ANSWERED:
104                 callType.append(STR_TIZEN_TEL);
105                 tags.append(STR_CALL_VOICE);
106                 direction.append(STR_RECEIVED);
107                 break;
108         case CALLLOG_TYPE_VOICE_OUTGOING:
109                 callType.append(STR_TIZEN_TEL);
110                 tags.append(STR_CALL_VOICE);
111                 direction.append(STR_DIALED);
112                 break;
113         case CALLLOG_TYPE_VOICE_MISSED_CHECKED:
114                 callType.append(STR_TIZEN_TEL);
115                 tags.append(STR_CALL_VOICE);
116                 direction.append(STR_MISSED);
117                 break;
118         case CALLLOG_TYPE_VOICE_MISSED_UNCHECKED:
119                 callType.append(STR_TIZEN_TEL);
120                 tags.append(STR_CALL_VOICE);
121                 direction.append(STR_MISSED_NEW);
122                 break;
123         case CALLLOG_TYPE_VOICE_REJECTED:
124                 callType.append(STR_TIZEN_TEL);
125                 tags.append(STR_CALL_VOICE);
126                 direction.append(STR_REJECTED);
127                 break;
128         case CALLLOG_TYPE_VOICE_BLOCKED:
129                 callType.append(STR_TIZEN_TEL);
130                 tags.append(STR_CALL_VOICE);
131                 direction.append(STR_BLOCKED);
132                 break;
133         case CALLLOG_TYPE_VIDEO_ANSWERED:
134                 callType.append(STR_TIZEN_TEL);
135                 tags.append(STR_CALL_VIDEO);
136                 direction.append(STR_RECEIVED);
137                 break;
138         case CALLLOG_TYPE_VIDEO_OUTGOING:
139                 callType.append(STR_TIZEN_TEL);
140                 tags.append(STR_CALL_VIDEO);
141                 direction.append(STR_DIALED);
142                 break;
143         case CALLLOG_TYPE_VIDEO_MISSED_CHECKED:
144                 callType.append(STR_TIZEN_TEL);
145                 tags.append(STR_CALL_VIDEO);
146                 direction.append(STR_MISSED);
147                 break;
148         case CALLLOG_TYPE_VIDEO_MISSED_UNCHECKED:
149                 callType.append(STR_TIZEN_TEL);
150                 tags.append(STR_CALL_VIDEO);
151                 direction.append(STR_MISSED_NEW);
152                 break;
153         case CALLLOG_TYPE_VIDEO_REJECTED:
154                 callType.append(STR_TIZEN_TEL);
155                 tags.append(STR_CALL_VIDEO);
156                 direction.append(STR_REJECTED);
157                 break;
158         case CALLLOG_TYPE_VIDEO_BLOCKED:
159                 callType.append(STR_TIZEN_TEL);
160                 tags.append(STR_CALL_VIDEO);
161                 direction.append(STR_BLOCKED);
162                 break;
163         default:
164                 return false;
165         }
166
167         callHistoryItem->setEntryId(query_log->calllog_db_id);
168         callHistoryItem->setCallType(callType);
169         stringArray->push_back(tags);
170         callHistoryItem->setTags(stringArray);
171
172         remoteParty->setRemoteParty(number);
173         contactRef->setContactId(query_log->contact_db_id);
174         remoteParty->setContactRef(contactRef);
175         remotePartyList->push_back(remoteParty);
176         callHistoryItem->setRemoteParties(remotePartyList);
177
178         callHistoryItem->setStartTime(query_log->timestamp);
179         callHistoryItem->setDuration((unsigned long)(query_log->duration_sec));
180         callHistoryItem->setDirection(direction);
181
182         callEntries->insert(callEntries->end(), callHistoryItem);
183
184         return true;
185 }
186
187 void CallHistory::find(const EventFindCallHistoryPtr& event)
188 {
189         EventRequestReceiver<EventFindCallHistory>::PostRequest(event);
190 }
191
192 bool CallHistory::remove(const unsigned long entryId)
193 {
194         try {
195                 int ret = calllog_delete_from_db(entryId);
196
197                 if (ret == CALLLOG_ERROR_NONE) {
198                         return true;
199                 } else {
200                         return false;
201                 }
202         } catch (const Commons::PlatformException& ex) {
203                 ThrowMsg(Commons::PlatformException, ex.GetMessage());
204         }
205 }
206
207 void CallHistory::removeBatch(const EventRemoveBatchPtr& event)
208 {
209         EventRequestReceiver<EventRemoveBatch>::PostRequest(event);
210 }
211
212 void CallHistory::removeAll(const EventRemoveAllPtr& event)
213 {
214         EventRequestReceiver<EventRemoveAll>::PostRequest(event);
215 }
216
217 long CallHistory::addListener(const EventCallHistoryListenerEmitterPtr& emitter)
218 {
219         int ret =0;
220         if (CallHistory::m_watchers.size() == 0) {
221                 WatcherPtr watcher(new Watcher(0, emitter));
222                 ret = contacts_svc_subscribe_change(CTS_SUBSCRIBE_PLOG_CHANGE, addedListenerCB, watcher.Get());
223
224                 if (ret == CTS_SUCCESS) {
225                         CallHistoryEntryListPtr callHistoryListPtr(new CallHistoryEntryList());
226                         std::string query(STR_BASE_QUERY);
227                         query.append(" WHERE log_type <= 12 ORDER BY id DESC LIMIT 1");
228                         executeQuery(query, callHistoryListPtr);
229
230                         if (callHistoryListPtr->size() > 0) {
231                                 watcher->setCurrentLogId((*callHistoryListPtr)[0]->getEntryId());
232                         }
233                 }
234
235                 ret = contacts_svc_subscribe_change(CTS_SUBSCRIBE_MISSED_CALL_CHANGE, changedListenerCB, watcher.Get());
236
237                 if (ret == CTS_SUCCESS) {
238                         MissedCallListPtr missedCallList(updateCurrentMissedCall());
239                         watcher->setMissedCallList(missedCallList);
240                 }
241
242                 CallHistory::m_watchers.push_back(watcher);
243                 return static_cast<long>(emitter->getId());
244         } else {
245                 return 0;
246         }
247 }
248
249 void CallHistory::removeListener(EventCallHistoryListenerEmitter::IdType id)
250 {
251         std::vector<CallHistory::WatcherPtr>::iterator it = CallHistory::m_watchers.begin();
252         
253         for (;it < CallHistory::m_watchers.end();) {
254                 if (id == (*it)->getEmitter()->getId()) {
255                         contacts_svc_unsubscribe_change(CTS_SUBSCRIBE_PLOG_CHANGE, addedListenerCB);
256                         contacts_svc_unsubscribe_change(CTS_SUBSCRIBE_MISSED_CALL_CHANGE, changedListenerCB);
257                         it = CallHistory::m_watchers.erase(it);
258                         continue;
259                 }
260                 ++it;
261         }
262 }
263
264 void CallHistory::addedListenerCB(void *user_data)
265 {
266         CallHistoryEntryListPtr callHistoryListPtr(new CallHistoryEntryList());
267         std::string query(STR_BASE_QUERY);
268
269         query.append(" WHERE  log_type <= 12 AND id > ");
270
271         std::stringstream currentLogId;
272         currentLogId << static_cast<int>(((CallHistory::Watcher*)user_data)->getCurrentLogId());
273         query.append(currentLogId.str());
274         query.append(" ORDER BY id DESC");
275
276         ((CallHistory::Watcher*)user_data)->executeQuery(query, callHistoryListPtr);
277
278         if (callHistoryListPtr->size() > 0) {
279                 ((CallHistory::Watcher*)user_data)->setCurrentLogId((*callHistoryListPtr)[0]->getEntryId());
280                 ((CallHistory::Watcher*)user_data)->stateHasChanged(callHistoryListPtr, EventCallHistoryListener::ADDED);
281                 ((CallHistory::Watcher*)user_data)->addMissedCall(callHistoryListPtr);
282         }
283 }
284
285 void CallHistory::changedListenerCB(void *user_data)
286 {
287         MissedCallListPtr missedCallListPtr(((CallHistory::Watcher*)user_data)->getMissedCallList());
288         CallHistoryEntryListPtr callHistoryListPtr(new CallHistoryEntryList());
289         if (missedCallListPtr->size() > 0) {
290                 std::string query(STR_BASE_QUERY);
291                 query.append(" WHERE log_type <= 12 AND (");
292
293                 MissedCallList::iterator itM = missedCallListPtr->begin();
294                 std::stringstream id;
295
296                 do {
297                         if (itM != missedCallListPtr->begin()) {
298                                 query.append(" OR ");
299                         }
300                         query.append(" id = ");
301                         id << static_cast<unsigned long>(*itM);
302                         query.append(id.str());
303                         id.str("");
304                         itM++;
305                 } while(itM < missedCallListPtr->end());
306
307                 query.append(")");
308
309                 ((CallHistory::Watcher*)user_data)->executeQuery(query, callHistoryListPtr);
310
311                 CallHistoryEntryList::iterator itC = callHistoryListPtr->begin();
312
313                 for (;itC != callHistoryListPtr->end();) {
314                         if ((*itC)->getDirection().compare(STR_MISSED) != 0) {
315                                 itC = callHistoryListPtr->erase(itC);
316                                 continue;
317                         }
318                         ++itC;
319                 }
320
321                 if (callHistoryListPtr->size() > 0) {
322                         ((CallHistory::Watcher*)user_data)->updateCurrentMissedCall();
323                         ((CallHistory::Watcher*)user_data)->stateHasChanged(callHistoryListPtr, EventCallHistoryListener::CHANGED);
324                 }
325         }
326
327 }
328 bool CallHistory::executeQuery(std::string &query, CallHistoryEntryListPtr &callEntries)
329 {
330         callhistory_query_s query_data;
331
332         stmt hstmt = NULL;
333         int ret = 0;
334
335         hstmt = _query_prepare((char *)(query.c_str()));
336
337         do {
338                 ret = _query_step(hstmt);
339                 if (ret == SQLITE_ROW) {
340                         query_data.calllog_db_id = (unsigned long)_query_column_int64(hstmt, 0);
341                         query_data.calllog_type = (calllog_type_e)_query_column_int(hstmt, 1);
342                         query_data.contact_db_id = _query_column_int(hstmt, 2);
343                         query_data.phone_number = _query_column_text(hstmt, 3);
344                         query_data.timestamp = (time_t)_query_column_int(hstmt, 4);
345                         query_data.duration_sec = _query_column_int(hstmt, 5);
346                         
347                         convertCallHistory(&query_data, callEntries);
348                 } else if (ret == SQLITE_DONE) {
349                         break;
350                 } else {
351                         break;
352                 }
353         } while (1);
354
355         _query_finalize(hstmt);
356         return true;
357 }
358
359 std::string CallHistory::convertAttrName(std::string &name)
360 {
361         std::string attrName("");
362         if (name.compare(STR_RP_REMOTEPARTY) == 0) {
363                 return attrName.append(STR_NUMBER);
364         } else if (name.compare(STR_START_TIME) == 0) {
365                 return attrName.append(STR_LOG_TIME);
366         } else if (name.compare(STR_DURATION) == 0) {
367                 return attrName.append(STR_DATA1);
368         } else if (name.compare(STR_DIRECTION) == 0) {
369                 return attrName.append(STR_LOG_TYPE);
370         } else {
371                 return attrName;
372         }
373 }
374
375 std::string CallHistory::makeQuerySortMode(SortModePtr attr)
376 {
377         std::string query("");
378         std::string attriName;
379
380         attriName = attr->getAttributeName();
381         attriName = convertAttrName(attriName);
382         if (attriName.compare("") != 0) { 
383                 query.append(" ORDER BY ");
384                 query.append(attriName);
385
386                 if (attr->getOrder() == Api::Tizen::ASCENDING_SORT_ORDER) {
387                         query.append(" ASC");
388                 } else {
389                         query.append(" DESC");
390                 }
391         }
392
393         return query;
394 }
395
396 MissedCallListPtr CallHistory::updateCurrentMissedCall()
397 {
398         CallHistoryEntryListPtr callHistoryListPtr(new CallHistoryEntryList());
399         std::string query(STR_BASE_QUERY);
400         query.append(" WHERE log_type = 5 OR log_type = 7 ORDER BY log_time DESC");
401         executeQuery(query, callHistoryListPtr);
402         LogDebug("result counter [" << callHistoryListPtr->size() << "]");
403
404         CallHistoryEntryList::iterator it = callHistoryListPtr->begin();
405         MissedCallListPtr missedCallList(new MissedCallList());
406
407         for (;it != callHistoryListPtr->end(); ++it) {
408                 missedCallList->push_back((*it)->getEntryId());
409         }
410         LogDebug("missed Call size (" << missedCallList->size() << ")");
411
412         return missedCallList;
413 }
414
415 void CallHistory::OnRequestReceived(const EventFindCallHistoryPtr& event)
416 {
417         try {
418                 CallHistoryEntryListPtr callHistoryListPtr(new CallHistoryEntryList());
419
420                 std::string query(STR_BASE_QUERY);
421
422                 CallHistoryFilterPtr filtering(new CallHistoryFilter());
423                 IFilterVisitorPtr filterTraversal = DPL::StaticPointerCast<IFilterVisitor>(filtering);
424
425                 if (event->getFilterIsSet()) {
426                         FilterPtr filter = event->getFilter();
427                         filter->travel(filterTraversal, 0);
428                         query.append(filtering->getResult());
429                         query.append(" AND log_type <= 12");
430                 } else {
431                         query.append(" WHERE log_type <= 12");
432                 }
433
434                 if (event->getSortModesIsSet()) {
435                         query.append(makeQuerySortMode(event->getSortMode()));
436                 } else {
437                         query.append(" ORDER BY log_time DESC");
438                 }
439
440                 if (event->getLimitIsSet()) {
441                         query.append(" LIMIT ");
442                         std::stringstream limitStream;
443                         limitStream << event->getLimit();
444                         query.append(limitStream.str());
445                         if (event->getOffsetIsSet()) {
446                                 query.append(" OFFSET ");
447                                 std::stringstream offsetStream;
448                                 offsetStream << event->getOffset();
449                                 query.append(offsetStream.str());
450                         }
451                 }
452
453                 LogDebug("execute query [" << query << "]");
454
455                 executeQuery(query, callHistoryListPtr);
456                 event->setResult(callHistoryListPtr);
457
458         } catch (const Commons::PlatformException& ex) {
459                 LogError("Exception: " << ex.GetMessage());
460                 event->setExceptionCode(Commons::ExceptionCodes::PlatformException);
461         }
462 }
463
464 void CallHistory::OnRequestReceived(const EventRemoveBatchPtr& event)
465 {
466         try {
467                 std::vector<unsigned long> entryIds = event->getEntryIds();
468                 unsigned int cnt = 0;
469                 int ret = CALLLOG_ERROR_NONE;
470                 for (cnt = 0; cnt < entryIds.size(); cnt++) {
471                         ret = calllog_delete_from_db(static_cast<int>(entryIds[cnt]));
472                         if (ret != CALLLOG_ERROR_NONE) {
473                                 event->setExceptionCode(Commons::ExceptionCodes::PlatformException);
474                                 break;
475                         }
476                 }
477         } catch (const Commons::PlatformException& ex) {
478                 LogError("Exception: " << ex.GetMessage());
479                 event->setExceptionCode(Commons::ExceptionCodes::PlatformException);
480         }
481 }
482
483 void CallHistory::OnRequestReceived(const EventRemoveAllPtr& event)
484 {
485         try {
486                 int ret = CALLLOG_ERROR_NONE;
487                 ret = calllog_delete_all_from_db();
488                 if (ret != CALLLOG_ERROR_NONE) {
489                         event->setExceptionCode(Commons::ExceptionCodes::PlatformException);
490                 }
491         } catch (const Commons::PlatformException& ex) {
492                 LogError("Exception: " << ex.GetMessage());
493                 event->setExceptionCode(Commons::ExceptionCodes::PlatformException);
494         }
495 }
496
497 CallHistory::Watcher::Watcher(int handle, const Api::Call::EventCallHistoryListenerEmitterPtr& emitter) :
498                         m_handle(handle),
499                         m_emitter(emitter),
500                         m_currentLogId(0)
501 {
502         m_missedCallList = MissedCallListPtr(new MissedCallList());
503         _db_init();
504 }
505
506 CallHistory::Watcher::~Watcher()
507 {
508         _db_finish();
509 }
510
511 void CallHistory::Watcher::stateHasChanged(CallHistoryEntryListPtr &entryList, EventCallHistoryListener::ResultStates state)
512 {
513         if (entryList == NULL)
514                 return;
515
516         EventCallHistoryListenerPtr event(new EventCallHistoryListener());
517         event->setResultState(state);
518         event->setResult(entryList);
519         m_emitter->emit(event);
520 }
521
522 bool CallHistory::Watcher::executeQuery(std::string &query, CallHistoryEntryListPtr &entryList)
523 {
524         CallHistory* callHistory = (CallHistory *) this;
525         if (callHistory != NULL) {
526                 callHistory->executeQuery(query, entryList);
527                 return true;
528         }
529         return false;
530 }
531
532 bool CallHistory::Watcher::addMissedCall(CallHistoryEntryListPtr &entryList)
533 {
534         if (entryList != NULL) {
535                 CallHistoryEntryList::iterator it = entryList->begin();
536                 for (; it != entryList->end(); it++) {
537                         if ((*it)->getDirection().compare(STR_MISSED_NEW) == 0) {
538                                 m_missedCallList->push_back((*it)->getEntryId());
539                         }
540                 }
541                 return true;
542         }
543         return false;
544 }
545
546 bool CallHistory::Watcher::updateCurrentMissedCall()
547 {
548         CallHistory* callHistory = (CallHistory *) this;
549         if (callHistory != NULL) {
550                 setMissedCallList(callHistory->updateCurrentMissedCall());
551                 return true;
552         }
553         return false;
554 }
555
556 }
557 }
558 }
559