Added the ability to edit the PID number using the number pad.
[profile/ivi/hfdialer.git] / src / callproxy.cpp
1 /*
2  * hfdialer - Hands Free Voice Call Manager
3  * Copyright (c) 2012, Intel Corporation.
4  *
5  * This program is licensed under the terms and conditions of the
6  * Apache License, version 2.0.  The full text of the Apache License is at
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  */
10
11 #include <QDateTime>
12 #include "common.h"
13 #include "callproxy.h"
14 #include "managerproxy.h"
15
16 // Returns a valid QDateTime if parsable as such, otherwise the result
17 // will be !isValid()
18 static QDateTime qDateTimeFromOfono(const QString &val)
19 {
20     TRACE
21     QDateTime result;
22
23     if (val.isEmpty())
24         return result;
25
26     // NOTE: Ofono formats time to string with the following format spec:
27     //       %Y-%m-%dT%H:%M:%S%z (for example: "2001-10-19T10:32:30-05:00")
28
29     // Start by trying to parse this as an ISODate "YYYY-MM-DDTHH:MM:SSTZD"
30     result = QDateTime::fromString(val,Qt::ISODate);
31 #ifdef VERBOSE
32     qDebug() << QString("Converted %1 with Qt::ISODate: %2")
33                        .arg(val)
34                        .arg(result.toString());
35 #endif
36
37     if (!result.isValid()) {
38     // ISODate conversion has failed, fallback to manual method
39     // NOTE: QDateTime::fromString(val, Qt::ISODate) Fails since the date
40     //       format from Ofono is in RFC 822 form, but QDateTime can't parse it
41         struct tm time_tm;
42         QByteArray  bytes = val.toAscii();
43         const char *str = bytes.constData();
44         if (strptime(str, "%Y-%m-%dT%H:%M:%S%z", &time_tm) != NULL) {
45             time_t t = mktime(&time_tm);
46             if (t >= (time_t)(0)) {
47                 result.setTime_t(t);
48 #ifdef VERBOSE 
49                 qDebug() << QString("Converted %1 with strptime: %2")
50                                    .arg(val)
51                                    .arg(result.toString());
52 #endif
53             }
54         }
55
56         if (!result.isValid())
57             qCritical() << QString("Format error, unknown date/time: %1")
58                                   .arg(str);
59     }
60
61     return result;
62 }
63
64 CallProxy::CallProxy(const QString &callPath)
65     : org::ofono::VoiceCall(OFONO_SERVICE,
66                             callPath,
67                             QDBusConnection::systemBus()),
68       m_lineid(QString()),
69       m_state(QString()),
70       m_startTime(QDateTime()),
71       m_reason(QString()),
72       m_connected(false),
73       m_multiparty(false)
74 {
75     TRACE
76
77     if (!org::ofono::VoiceCall::isValid())
78     {
79             qCritical() << QString("Failed to connect to %1 for call %2:\n\t%3")
80                        .arg(staticInterfaceName())
81                        .arg(callPath)
82                        .arg(lastError().message());
83         }
84     else {
85         QDBusPendingReply<QVariantMap> reply;
86         QDBusPendingCallWatcher *watcher;
87
88         reply = GetProperties();
89         watcher = new QDBusPendingCallWatcher(reply);
90
91 /*
92         connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
93                          SLOT(getPropertiesFinished(QDBusPendingCallWatcher*)));
94 */
95
96         // Force this to be sync to ensure we have initial properties
97         watcher->waitForFinished();
98         getPropertiesFinished(watcher);
99
100         if (isValid()) {
101             connect(this,
102                     SIGNAL(PropertyChanged(const QString&,const QDBusVariant&)),
103                     SLOT(propertyChanged(const QString&,const QDBusVariant&)));
104             connect(this, SIGNAL(DisconnectReason(const QString&)),
105                           SLOT(disconnectReason(const QString&)));
106         } else
107             qCritical() << QString("Invalid CallProxy instance: state == %1")
108                            .arg(m_state);
109     }
110 }
111
112 CallProxy::~CallProxy()
113 {
114     TRACE
115     // FIXME: Do something here!!!
116 }
117
118 bool CallProxy::isValid()
119 {
120     TRACE
121     return (org::ofono::VoiceCall::isValid() &&
122             m_connected &&
123             (m_state != "disconnected"));
124 }
125
126 QString CallProxy::lineID() const
127 {
128     TRACE
129     return m_lineid;
130 }
131
132 QString CallProxy::name() const
133 {
134     TRACE
135     return m_name;
136 }
137
138 QString CallProxy::state() const
139 {
140     TRACE
141     return m_state;
142 }
143
144 QDateTime CallProxy::startTime() const
145 {
146     TRACE
147     return m_startTime;
148 }
149
150 int CallProxy::duration() const
151 {
152     TRACE
153     if (m_startTime.isValid())
154         return m_startTime.secsTo(QDateTime::currentDateTime());
155     else
156         return 0;
157 }
158
159 QString CallProxy::reason() const
160 {
161     TRACE
162     return m_reason;
163 }
164
165 bool CallProxy::multiparty() const
166 {
167     TRACE
168     return m_multiparty;
169 }
170
171 void CallProxy::answer()
172 {
173     TRACE
174
175 //    ResourceProxy *resource = ResourceProxy::instance();
176
177 //    connect(resource, SIGNAL(answerResourceAcquired()), SLOT(proceedCallAnswer()));
178 //    connect(resource, SIGNAL(answerResourceDenied()), SLOT(deniedCallAnswer()));
179
180 //    resource->acquireAnswerResource();
181
182 proceedCallAnswer();
183 }
184
185 void CallProxy::proceedCallAnswer()
186 {
187     TRACE
188
189 //    ResourceProxy *resource = ResourceProxy::instance();
190     QDBusPendingReply<QDBusObjectPath> reply;
191     QDBusPendingCallWatcher *watcher;
192
193  //   disconnect(resource, SIGNAL(answerResourceAcquired()));
194  //   disconnect(resource, SIGNAL(answerResourceDenied()));
195
196     reply = Answer();
197     watcher = new QDBusPendingCallWatcher(reply);
198
199     connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
200                      SLOT(answerFinished(QDBusPendingCallWatcher*)));
201 }
202
203 void CallProxy::deniedCallAnswer()
204 {
205     TRACE
206
207 //    ResourceProxy *resource = ResourceProxy::instance();
208
209 //    disconnect(resource, SIGNAL(answerResourceAcquired()));
210 //    disconnect(resource, SIGNAL(answerResourceDenied()));
211
212     // Hang up the incoming call, if resources to accept it are inavailabe
213     hangup();
214
215     emit ManagerProxy::instance()->callManager()->deniedCallAnswer();
216 }
217
218 void CallProxy::deflect(const QString toNumber)
219 {
220     TRACE
221
222     QDBusPendingReply<QDBusObjectPath> reply;
223     QDBusPendingCallWatcher *watcher;
224
225     reply = Deflect(toNumber);
226     watcher = new QDBusPendingCallWatcher(reply);
227
228     connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
229                      SLOT(deflectFinished(QDBusPendingCallWatcher*)));
230 }
231
232 void CallProxy::hangup()
233 {
234     TRACE
235
236     QDBusPendingReply<> reply;
237     QDBusPendingCallWatcher *watcher;
238
239     reply = Hangup();
240     watcher = new QDBusPendingCallWatcher(reply);
241
242     connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
243                      SLOT(hangupFinished(QDBusPendingCallWatcher*)));
244 }
245
246 void CallProxy::getPropertiesFinished(QDBusPendingCallWatcher *watcher)
247 {
248     TRACE
249
250     QDBusPendingReply<QVariantMap> reply = *watcher;
251
252     if (reply.isError()) {
253         qCritical() << QString("Failed to connect to %1 for call %2:\n\t%3")
254                        .arg(staticInterfaceName())
255                        .arg(path())
256                        .arg(lastError().message());
257         return;
258     }
259
260     QVariantMap props = reply.value();
261
262     QString l_start;
263
264     m_lineid = qdbus_cast<QString>(props["LineIdentification"]);
265     m_name   = qdbus_cast<QString>(props["Name"]);
266     m_state  = qdbus_cast<QString>(props["State"]);
267     l_start  = qdbus_cast<QString>(props["StartTime"]);
268     m_multiparty  = qdbus_cast<bool>(props["Multiparty"]);
269
270     setStartTimeFromString(l_start);
271
272     // Indicate for this instance, that we've actually performed at least
273     // one round trip call to this VoiceCall and we are in sync with it
274     m_connected = true;
275 }
276
277 void CallProxy::answerFinished(QDBusPendingCallWatcher *watcher)
278 {
279     TRACE
280     QDBusPendingReply<QDBusObjectPath> reply = *watcher;
281     if (reply.isError())
282         qCritical() << QString("Answer() Failed: %1 - %2")
283                        .arg(reply.error().name())
284                        .arg(reply.error().message());
285 }
286
287 void CallProxy::deflectFinished(QDBusPendingCallWatcher *watcher)
288 {
289     TRACE
290     QDBusPendingReply<QDBusObjectPath> reply = *watcher;
291     if (reply.isError())
292         qCritical() << QString("Deflect() Failed: %1 - %2")
293                        .arg(reply.error().name())
294                        .arg(reply.error().message());
295 }
296
297 void CallProxy::hangupFinished(QDBusPendingCallWatcher *watcher)
298 {
299     TRACE
300     QDBusPendingReply<> reply = *watcher;
301     if (reply.isError())
302         qCritical() << QString("Hangup() Failed: %1 - %2")
303                        .arg(reply.error().name())
304                        .arg(reply.error().message());
305 }
306
307 void CallProxy::propertyChanged(const QString &in0, const QDBusVariant &in1)
308 {
309     TRACE
310
311     if (in0 == "LineIdentification") {
312         m_lineid = qdbus_cast<QString>(in1.variant());
313         emit dataChanged();
314     } else if (in0 == "State") {
315         m_state  = qdbus_cast<QString>(in1.variant());
316         emit stateChanged();
317     } else if (in0 == "StartTime") {
318         setStartTimeFromString(qdbus_cast<QString>(in1.variant()));
319     } else if (in0 == "Multiparty") {
320         m_multiparty = qdbus_cast<bool>(in1.variant());
321         emit multipartyChanged();
322     } else {
323         qDebug() << QString("Unexpected property \"%1\" changed...").arg(in0);
324     }
325 }
326
327 void CallProxy::disconnectReason(const QString &in0)
328 {
329     TRACE
330     m_reason = in0;
331     emit callDisconnected(in0);
332 }
333
334 void CallProxy::setStartTimeFromString(const QString &val)
335 {
336     TRACE
337     if (val.isEmpty())
338         return;
339
340     m_startTime = qDateTimeFromOfono(val);
341
342     if (!m_startTime.isValid())
343         m_startTime = QDateTime::QDateTime::currentDateTime();
344 }
345