Initial Import
[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         qCritical() << QString("Failed to connect to %1 for call %2:\n\t%3")
79             .arg(staticInterfaceName())
80             .arg(callPath)
81             .arg(lastError().message());
82     } else {
83         QDBusPendingReply<QVariantMap> reply;
84         QDBusPendingCallWatcher *watcher;
85
86         reply = GetProperties();
87         watcher = new QDBusPendingCallWatcher(reply);
88
89         // Force this to be sync to ensure we have initial properties
90         watcher->waitForFinished();
91         getPropertiesFinished(watcher);
92
93         if (isValid()) {
94             connect(this,
95                     SIGNAL(PropertyChanged(const QString&,const QDBusVariant&)),
96                     SLOT(propertyChanged(const QString&,const QDBusVariant&)));
97             connect(this, SIGNAL(DisconnectReason(const QString&)),
98                     SLOT(disconnectReason(const QString&)));
99         } else {
100             qCritical() << QString("Invalid CallProxy instance: state == %1")
101                 .arg(m_state);
102         }
103     }
104 }
105
106 CallProxy::~CallProxy()
107 {
108     TRACE;
109     // FIXME: Do something here!!!
110 }
111
112 bool CallProxy::isValid()
113 {
114     TRACE;
115     return (org::ofono::VoiceCall::isValid() &&
116             m_connected &&
117             (m_state != "disconnected"));
118 }
119
120 QString CallProxy::lineID() const
121 {
122     TRACE;
123     return m_lineid;
124 }
125
126 QString CallProxy::name() const
127 {
128     TRACE;
129     return m_name;
130 }
131
132 QString CallProxy::state() const
133 {
134     TRACE;
135     return m_state;
136 }
137
138 QDateTime CallProxy::startTime() const
139 {
140     TRACE;
141     return m_startTime;
142 }
143
144 int CallProxy::duration() const
145 {
146     TRACE;
147     if (m_startTime.isValid())
148         return m_startTime.secsTo(QDateTime::currentDateTime());
149     else
150         return 0;
151 }
152
153 QString CallProxy::reason() const
154 {
155     TRACE;
156     return m_reason;
157 }
158
159 bool CallProxy::multiparty() const
160 {
161     TRACE;
162     return m_multiparty;
163 }
164
165 void CallProxy::answer()
166 {
167     TRACE;
168     proceedCallAnswer();
169 }
170
171 void CallProxy::proceedCallAnswer()
172 {
173     TRACE;
174
175     QDBusPendingReply<QDBusObjectPath> reply;
176     QDBusPendingCallWatcher *watcher;
177
178     reply = Answer();
179     watcher = new QDBusPendingCallWatcher(reply);
180
181     connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
182             SLOT(answerFinished(QDBusPendingCallWatcher*)));
183 }
184
185 void CallProxy::deniedCallAnswer()
186 {
187     TRACE;
188
189     // Hang up the incoming call, if resources to accept it are inavailabe
190     hangup();
191
192     emit ManagerProxy::instance()->callManager()->deniedCallAnswer();
193 }
194
195 void CallProxy::deflect(const QString toNumber)
196 {
197     TRACE;
198
199     QDBusPendingReply<QDBusObjectPath> reply;
200     QDBusPendingCallWatcher *watcher;
201
202     reply = Deflect(toNumber);
203     watcher = new QDBusPendingCallWatcher(reply);
204
205     connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
206             SLOT(deflectFinished(QDBusPendingCallWatcher*)));
207 }
208
209 void CallProxy::hangup()
210 {
211     TRACE;
212
213     QDBusPendingReply<> reply;
214     QDBusPendingCallWatcher *watcher;
215
216     reply = Hangup();
217     watcher = new QDBusPendingCallWatcher(reply);
218
219     connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
220             SLOT(hangupFinished(QDBusPendingCallWatcher*)));
221 }
222
223 void CallProxy::getPropertiesFinished(QDBusPendingCallWatcher *watcher)
224 {
225     TRACE;
226
227     QDBusPendingReply<QVariantMap> reply = *watcher;
228
229     if (reply.isError()) {
230         qCritical() << QString("Failed to connect to %1 for call %2:\n\t%3")
231             .arg(staticInterfaceName())
232             .arg(path())
233             .arg(lastError().message());
234         return;
235     }
236
237     QVariantMap props = reply.value();
238
239     QString l_start;
240
241     m_lineid = qdbus_cast<QString>(props["LineIdentification"]);
242     m_name   = qdbus_cast<QString>(props["Name"]);
243     m_state  = qdbus_cast<QString>(props["State"]);
244     l_start  = qdbus_cast<QString>(props["StartTime"]);
245     m_multiparty  = qdbus_cast<bool>(props["Multiparty"]);
246
247     setStartTimeFromString(l_start);
248
249     // Indicate for this instance, that we've actually performed at least
250     // one round trip call to this VoiceCall and we are in sync with it
251     m_connected = true;
252 }
253
254 void CallProxy::answerFinished(QDBusPendingCallWatcher *watcher)
255 {
256     TRACE;
257     QDBusPendingReply<QDBusObjectPath> reply = *watcher;
258     if (reply.isError())
259         qCritical() << QString("Answer() Failed: %1 - %2")
260             .arg(reply.error().name())
261             .arg(reply.error().message());
262 }
263
264 void CallProxy::deflectFinished(QDBusPendingCallWatcher *watcher)
265 {
266     TRACE;
267     QDBusPendingReply<QDBusObjectPath> reply = *watcher;
268     if (reply.isError())
269         qCritical() << QString("Deflect() Failed: %1 - %2")
270             .arg(reply.error().name())
271             .arg(reply.error().message());
272 }
273
274 void CallProxy::hangupFinished(QDBusPendingCallWatcher *watcher)
275 {
276     TRACE;
277     QDBusPendingReply<> reply = *watcher;
278     if (reply.isError())
279         qCritical() << QString("Hangup() Failed: %1 - %2")
280             .arg(reply.error().name())
281             .arg(reply.error().message());
282 }
283
284 void CallProxy::propertyChanged(const QString &in0, const QDBusVariant &in1)
285 {
286     TRACE;
287
288     if (in0 == "LineIdentification") {
289         m_lineid = qdbus_cast<QString>(in1.variant());
290         emit dataChanged();
291     } else if (in0 == "State") {
292         m_state  = qdbus_cast<QString>(in1.variant());
293         emit stateChanged();
294     } else if (in0 == "StartTime") {
295         setStartTimeFromString(qdbus_cast<QString>(in1.variant()));
296     } else if (in0 == "Multiparty") {
297         m_multiparty = qdbus_cast<bool>(in1.variant());
298         emit multipartyChanged();
299     } else {
300         qDebug() << QString("Unexpected property \"%1\" changed...").arg(in0);
301     }
302 }
303
304 void CallProxy::disconnectReason(const QString &in0)
305 {
306     TRACE;
307     m_reason = in0;
308     emit callDisconnected(in0);
309 }
310
311 void CallProxy::setStartTimeFromString(const QString &val)
312 {
313     TRACE;
314     if (val.isEmpty())
315         return;
316
317     m_startTime = qDateTimeFromOfono(val);
318
319     if (!m_startTime.isValid())
320         m_startTime = QDateTime::QDateTime::currentDateTime();
321 }
322
323 /* Local Variables:      */
324 /* mode:c++              */
325 /* c-basic-offset:4      */
326 /* indent-tabs-mode: nil */
327 /* End:                  */