Beta merge 2
[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 <calllog.h>
30 #include <contacts-svc.h>
31
32 #include "CallHistoryFilter.h"
33 #include <app.h>
34
35 using namespace TizenApis::Api::Tizen;
36 using namespace TizenApis::Api::Call;
37 using namespace WrtDeviceApis;
38 using namespace WrtDeviceApis::Commons;
39 using namespace DPL;
40
41 namespace TizenApis {
42 namespace Platform {
43 namespace Call {
44
45 std::vector<CallHistory::WatcherPtr> CallHistory::m_watchers;
46
47 CallHistory::CallHistory()
48 {
49         _db_init();
50
51         if (calllog_connect() == CALLLOG_ERROR_NONE) {
52                 LogDebug("Successful to connect Call history DB ");
53         } else {
54                 LogDebug("Failed to connect Call history DB ");
55         }
56 }
57
58 CallHistory::~CallHistory()
59 {
60         _db_finish();
61         
62         if (calllog_disconnect() == CALLLOG_ERROR_NONE) {
63                 LogDebug("Successful to disconnect Call history DB ");
64         } else {
65                 LogDebug("Failed to disconnect Call history DB ");
66         }
67
68         std::vector<CallHistory::WatcherPtr>::iterator it = CallHistory::m_watchers.begin();
69
70         if (m_watchers.size() > 0) {
71                 for (;it < CallHistory::m_watchers.end();) {
72                         contacts_svc_unsubscribe_change(CTS_SUBSCRIBE_PLOG_CHANGE, addedListenerCB);
73                         contacts_svc_unsubscribe_change(CTS_SUBSCRIBE_MISSED_CALL_CHANGE, changedListenerCB);
74                         it = CallHistory::m_watchers.erase(it);
75                         ++it;
76                 }
77                 LogDebug("CallHistory Watcher is removed. (" << CallHistory::m_watchers.size() << ")");
78         }
79 }
80
81 bool CallHistory::convertCallHistory(callhistory_query_s *query_log, CallHistoryEntryListPtr &callEntries)
82 {
83         if (query_log == NULL || callEntries == NULL)
84                 return false;
85
86         CallHistoryEntryPropertiesPtr callHistoryItem(new CallHistoryEntryProperties());
87         StringArrayPtr stringArray(new StringArray());
88         RemotePartyPtr remoteParty(new RemoteParty());
89         RemotePartyListPtr remotePartyList(new RemotePartyList());
90
91         std::string callType("");
92         std::string tags("");
93         std::string direction("");
94         std::string number("");
95         
96         if (query_log->phone_number != NULL) {
97                 number.append(query_log->phone_number);
98         }
99
100         switch(query_log->calllog_type) {
101         case CALLLOG_TYPE_VOICE_ANSWERED:
102                 callType.append(STR_TIZEN_TEL);
103                 tags.append(STR_CALL_VOICE);
104                 direction.append(STR_RECEIVED);
105                 break;
106         case CALLLOG_TYPE_VOICE_OUTGOING:
107                 callType.append(STR_TIZEN_TEL);
108                 tags.append(STR_CALL_VOICE);
109                 direction.append(STR_DIALED);
110                 break;
111         case CALLLOG_TYPE_VOICE_MISSED_CHECKED:
112                 callType.append(STR_TIZEN_TEL);
113                 tags.append(STR_CALL_VOICE);
114                 direction.append(STR_MISSED);
115                 break;
116         case CALLLOG_TYPE_VOICE_MISSED_UNCHECKED:
117                 callType.append(STR_TIZEN_TEL);
118                 tags.append(STR_CALL_VOICE);
119                 direction.append(STR_MISSED_NEW);
120                 break;
121         case CALLLOG_TYPE_VOICE_REJECTED:
122                 callType.append(STR_TIZEN_TEL);
123                 tags.append(STR_CALL_VOICE);
124                 direction.append(STR_REJECTED);
125                 break;
126         case CALLLOG_TYPE_VOICE_BLOCKED:
127                 callType.append(STR_TIZEN_TEL);
128                 tags.append(STR_CALL_VOICE);
129                 direction.append(STR_BLOCKED);
130                 break;
131         case CALLLOG_TYPE_VIDEO_ANSWERED:
132                 callType.append(STR_TIZEN_TEL);
133                 tags.append(STR_CALL_VIDEO);
134                 direction.append(STR_RECEIVED);
135                 break;
136         case CALLLOG_TYPE_VIDEO_OUTGOING:
137                 callType.append(STR_TIZEN_TEL);
138                 tags.append(STR_CALL_VIDEO);
139                 direction.append(STR_DIALED);
140                 break;
141         case CALLLOG_TYPE_VIDEO_MISSED_CHECKED:
142                 callType.append(STR_TIZEN_TEL);
143                 tags.append(STR_CALL_VIDEO);
144                 direction.append(STR_MISSED);
145                 break;
146         case CALLLOG_TYPE_VIDEO_MISSED_UNCHECKED:
147                 callType.append(STR_TIZEN_TEL);
148                 tags.append(STR_CALL_VIDEO);
149                 direction.append(STR_MISSED_NEW);
150                 break;
151         case CALLLOG_TYPE_VIDEO_REJECTED:
152                 callType.append(STR_TIZEN_TEL);
153                 tags.append(STR_CALL_VIDEO);
154                 direction.append(STR_REJECTED);
155                 break;
156         case CALLLOG_TYPE_VIDEO_BLOCKED:
157                 callType.append(STR_TIZEN_TEL);
158                 tags.append(STR_CALL_VIDEO);
159                 direction.append(STR_BLOCKED);
160                 break;
161         default:
162                 return false;
163         }
164
165         std::stringstream contactId;
166         contactId << query_log->contact_db_id;
167
168         callHistoryItem->setEntryId(query_log->calllog_db_id);
169         callHistoryItem->setCallType(callType);
170         stringArray->push_back(tags);
171         callHistoryItem->setTags(stringArray);
172
173         remoteParty->setRemoteParty(number);
174         remoteParty->setContactId(contactId.str());
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 log_time DESC LIMIT 1");
228                         executeQuery(query, callHistoryListPtr);
229
230                         if (callHistoryListPtr->size() > 0) {
231                                 watcher->setCurrentLogTime((*callHistoryListPtr)[0]->getStartTime());
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         query.append(" WHERE  log_type <= 12 AND log_time > ");
269
270         std::stringstream currentLogTime;
271         currentLogTime << static_cast<int>(((CallHistory::Watcher*)user_data)->getCurrentLogTime());
272         query.append(currentLogTime.str());
273
274         query.append(" ORDER BY log_time DESC");
275         ((CallHistory::Watcher*)user_data)->executeQuery(query, callHistoryListPtr);
276
277         if (callHistoryListPtr->size() > 0) {
278                 ((CallHistory::Watcher*)user_data)->addMissedCall(callHistoryListPtr);
279                 ((CallHistory::Watcher*)user_data)->setCurrentLogTime((*callHistoryListPtr)[callHistoryListPtr->size() - 1]->getStartTime());
280                 ((CallHistory::Watcher*)user_data)->stateHasChanged(callHistoryListPtr, EventCallHistoryListener::ADDED);
281         }
282 }
283
284 void CallHistory::changedListenerCB(void *user_data)
285 {
286         MissedCallListPtr missedCallListPtr(((CallHistory::Watcher*)user_data)->getMissedCallList());
287         CallHistoryEntryListPtr callHistoryListPtr(new CallHistoryEntryList());
288         if (missedCallListPtr->size() > 0) {
289                 std::string query(STR_BASE_QUERY);
290                 query.append(" WHERE log_type <= 12 AND (");
291
292                 MissedCallList::iterator itM = missedCallListPtr->begin();
293                 std::stringstream id;
294
295                 do {
296                         if (itM != missedCallListPtr->begin()) {
297                                 query.append(" OR ");
298                         }
299                         query.append(" id = ");
300                         id << static_cast<unsigned long>(*itM);
301                         query.append(id.str());
302                         id.str("");
303                         itM++;
304                 } while(itM < missedCallListPtr->end());
305
306                 query.append(")");
307
308                 ((CallHistory::Watcher*)user_data)->executeQuery(query, callHistoryListPtr);
309
310                 CallHistoryEntryList::iterator itC = callHistoryListPtr->begin();
311
312                 for (;itC != callHistoryListPtr->end();) {
313                         if ((*itC)->getDirection().compare(STR_MISSED) != 0) {
314                                 itC = callHistoryListPtr->erase(itC);
315                                 continue;
316                         }
317                         ++itC;
318                 }
319
320                 if (callHistoryListPtr->size() > 0) {
321                         ((CallHistory::Watcher*)user_data)->updateCurrentMissedCall();
322                         ((CallHistory::Watcher*)user_data)->stateHasChanged(callHistoryListPtr, EventCallHistoryListener::CHANGED);
323                 }
324         }
325
326 }
327 bool CallHistory::executeQuery(std::string &query, CallHistoryEntryListPtr &callEntries)
328 {
329         callhistory_query_s query_data;
330
331         stmt hstmt = NULL;
332         int ret = 0;
333
334         hstmt = _query_prepare((char *)(query.c_str()));
335
336         do {
337                 ret = _query_step(hstmt);
338                 if (ret == SQLITE_ROW) {
339                         query_data.calllog_db_id = (unsigned long)_query_column_int64(hstmt, 0);
340                         query_data.calllog_type = (calllog_type_e)_query_column_int(hstmt, 1);
341                         query_data.contact_db_id = _query_column_int(hstmt, 2);
342                         query_data.phone_number = _query_column_text(hstmt, 3);
343                         query_data.timestamp = (time_t)_query_column_int(hstmt, 4);
344                         query_data.duration_sec = _query_column_int(hstmt, 5);
345                         
346                         convertCallHistory(&query_data, callEntries);
347                 } else if (ret == SQLITE_DONE) {
348                         break;
349                 } else {
350                         break;
351                 }
352         } while (1);
353
354         _query_finalize(hstmt);
355         return true;
356 }
357
358 std::string CallHistory::convertAttrName(std::string &name)
359 {
360         std::string attrName("");
361         if (name.compare("remoteParty") == 0) {
362                 return attrName.append("number");
363         } else if (name.compare("startTime") == 0) {
364                 return attrName.append("log_time");
365         } else if (name.compare("duration") == 0) {
366                 return attrName.append("data1");
367         } else if (name.compare("direction") == 0) {
368                 return attrName.append("log_type");
369         } else {
370                 return attrName;
371         }
372 }
373
374 std::string CallHistory::makeQuerySortMode(SortModePtr attr)
375 {
376         std::string query("");
377         std::string attriName;
378
379         attriName = attr->getAttributeName();
380         attriName = convertAttrName(attriName);
381         if (attriName.compare("") != 0) { 
382                 query.append(" ORDER BY ");
383                 query.append(attriName);
384
385                 if (attr->getOrder() == Api::Tizen::ASCENDING_SORT_ORDER) {
386                         query.append(" ASC");
387                 } else {
388                         query.append(" DESC");
389                 }
390         }
391
392         return query;
393 }
394
395 MissedCallListPtr CallHistory::updateCurrentMissedCall()
396 {
397         CallHistoryEntryListPtr callHistoryListPtr(new CallHistoryEntryList());
398         std::string query(STR_BASE_QUERY);
399         query.append(" WHERE log_type = 5 OR log_type = 7 ORDER BY log_time DESC");
400         executeQuery(query, callHistoryListPtr);
401         LogDebug("result counter [" << callHistoryListPtr->size() << "]");
402
403         CallHistoryEntryList::iterator it = callHistoryListPtr->begin();
404         MissedCallListPtr missedCallList(new MissedCallList());
405
406         for (;it != callHistoryListPtr->end(); ++it) {
407                 missedCallList->push_back((*it)->getEntryId());
408         }
409         LogDebug("missed Call size (" << missedCallList->size() << ")");
410
411         return missedCallList;
412 }
413
414 void CallHistory::OnRequestReceived(const EventFindCallHistoryPtr& event)
415 {
416         try {
417                 CallHistoryEntryListPtr callHistoryListPtr(new CallHistoryEntryList());
418
419                 std::string query(STR_BASE_QUERY);
420
421                 CallHistoryFilterPtr filtering(new CallHistoryFilter());
422                 IFilterVisitorPtr filterTraversal = DPL::StaticPointerCast<IFilterVisitor>(filtering);
423
424                 if (event->getFilterIsSet()) {
425                         FilterPtr filter = event->getFilter();
426                         filter->travel(filterTraversal, 0);
427                         query.append(filtering->getResult());
428                         query.append(" AND log_type <= 12");
429                 } else {
430                         query.append(" WHERE log_type <= 12");
431                 }
432
433                 if (event->getSortModesIsSet()) {
434                         query.append(makeQuerySortMode(event->getSortMode()));
435                 } else {
436                         query.append(" ORDER BY log_time DESC");
437                 }
438
439                 if (event->getLimitIsSet()) {
440                         query.append(" LIMIT ");
441                         std::stringstream limitStream;
442                         limitStream << event->getLimit();
443                         query.append(limitStream.str());
444                         if (event->getOffsetIsSet()) {
445                                 query.append(" OFFSET ");
446                                 std::stringstream offsetStream;
447                                 offsetStream << event->getOffset();
448                                 query.append(offsetStream.str());
449                         }
450                 }
451
452                 LogDebug("execute query [" << query << "]");
453
454                 executeQuery(query, callHistoryListPtr);
455                 event->setResult(callHistoryListPtr);
456
457         } catch (const Commons::PlatformException& ex) {
458                 LogError("Exception: " << ex.GetMessage());
459                 event->setExceptionCode(Commons::ExceptionCodes::PlatformException);
460         }
461 }
462
463 void CallHistory::OnRequestReceived(const EventRemoveBatchPtr& event)
464 {
465         try {
466                 std::vector<unsigned long> entryIds = event->getEntryIds();
467                 unsigned int cnt = 0;
468                 int ret = CALLLOG_ERROR_NONE;
469                 for (cnt = 0; cnt < entryIds.size(); cnt++) {
470                         ret = calllog_delete_from_db(static_cast<int>(entryIds[cnt]));
471                         if (ret != CALLLOG_ERROR_NONE) {
472                                 event->setExceptionCode(Commons::ExceptionCodes::PlatformException);
473                         }
474                 }
475         } catch (const Commons::PlatformException& ex) {
476                 LogError("Exception: " << ex.GetMessage());
477                 event->setExceptionCode(Commons::ExceptionCodes::PlatformException);
478         }
479 }
480
481 void CallHistory::OnRequestReceived(const EventRemoveAllPtr& event)
482 {
483         try {
484                 int ret = CALLLOG_ERROR_NONE;
485                 ret = calllog_delete_all_from_db();
486                 if (ret != CALLLOG_ERROR_NONE) {
487                         event->setExceptionCode(Commons::ExceptionCodes::PlatformException);
488                 }
489         } catch (const Commons::PlatformException& ex) {
490                 LogError("Exception: " << ex.GetMessage());
491                 event->setExceptionCode(Commons::ExceptionCodes::PlatformException);
492         }
493 }
494
495 CallHistory::Watcher::Watcher(int handle, const Api::Call::EventCallHistoryListenerEmitterPtr& emitter) :
496                         m_handle(handle),
497                         m_emitter(emitter),
498                         m_currentLogTime(0)
499 {
500         m_missedCallList = MissedCallListPtr(new MissedCallList());
501         _db_init();
502 }
503
504 CallHistory::Watcher::~Watcher()
505 {
506         _db_finish();
507 }
508
509 void CallHistory::Watcher::stateHasChanged(CallHistoryEntryListPtr &entryList, EventCallHistoryListener::ResultStates state)
510 {
511         if (entryList == NULL)
512                 return;
513
514         EventCallHistoryListenerPtr event(new EventCallHistoryListener());
515         event->setResultState(state);
516         event->setResult(entryList);
517         m_emitter->emit(event);
518 }
519
520 bool CallHistory::Watcher::executeQuery(std::string &query, CallHistoryEntryListPtr &entryList)
521 {
522         CallHistory* callHistory = (CallHistory *) this;
523         if (callHistory != NULL) {
524                 callHistory->executeQuery(query, entryList);
525                 return true;
526         }
527         return false;
528 }
529
530 bool CallHistory::Watcher::addMissedCall(CallHistoryEntryListPtr &entryList)
531 {
532         if (entryList != NULL) {
533                 CallHistoryEntryList::iterator it = entryList->begin();
534                 for (; it != entryList->end(); it++) {
535                         if ((*it)->getDirection().compare(STR_MISSED_NEW) == 0) {
536                                 m_missedCallList->push_back((*it)->getEntryId());
537                         }
538                 }
539                 return true;
540         }
541         return false;
542 }
543
544 bool CallHistory::Watcher::updateCurrentMissedCall()
545 {
546         CallHistory* callHistory = (CallHistory *) this;
547         if (callHistory != NULL) {
548                 setMissedCallList(callHistory->updateCurrentMissedCall());
549                 return true;
550         }
551         return false;
552 }
553
554 }
555 }
556 }
557