58bbe92a13eba79eae72b9e3f6bfc03e330194fc
[vicar] / src / vicar-telepathy / cpp / connection.cpp
1 /*
2 @version: 0.6
3 @author: Sudheer K. <scifi1947 at gmail.com>
4 @license: GNU General Public License
5
6 Based on Telepathy-SNOM with copyright notice below.
7 */
8
9 /*
10  * Telepathy SNOM VoIP phone connection manager
11  * Copyright (C) 2006 by basyskom GmbH
12  *  @author Tobias Hunger <info@basyskom.de>
13  *
14  * This library is free software; you can redisQObject::tribute it and/or
15  * modify it under the terms of the GNU Lesser General Public
16  * License version 2.1 as published by the Free Software Foundation.
17  *
18  * This library is disQObject::tributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21  * Lesser General Public License for more details.
22  *
23  * You should have received a copy of the GNU Lesser General Public
24  * License along with this library; if not, write to the
25  * Free Software Foundation, Inc.,
26  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
27  */
28
29 #include "connection.h"
30 #include "connectionadaptor.h"
31 #include "connectioninterfacerequestsadaptor.h"
32 #include "connectioninterfacerequeststypes.h"
33 #include "connectioninterfacecapabilitiesadaptor.h"
34 #include "connectioninterfacecapabilitiestypes.h"
35 #include "names.h"
36 #include "vicarcallrouterproxy.h"
37 #include <logutility.h>
38
39 #include <QtCore/QDebug>
40 #include <QtCore/QCoreApplication>
41 #include <QtCore/QVariantMap>
42 #include <QDBusMessage>
43 #include <QDBusReply>
44
45
46 namespace
47 {
48 static const QString protocol_vicar("tel");
49
50 static const QString connection_service_name_prefix("org.freedesktop.Telepathy.Connection.vicar." + protocol_vicar + '.');
51 static const QString connection_object_path_prefix("/org/freedesktop/Telepathy/Connection/vicar/" + protocol_vicar + '/');
52 static const QString requests_interface("org.freedesktop.Telepathy.Connection.Interface.Requests");
53 }
54
55 using namespace org::maemo;
56
57
58 class ConnectionPrivate
59 {
60 public:
61     ConnectionPrivate(Connection * p,
62                       const QString & acc) :
63         account(acc),
64         connection_status(Connection::Disconnected),
65         adaptor(new ConnectionAdaptor(p)),
66         connIfaceReqsAdaptor(new ConnectionInterfaceRequestsAdaptor(p)),
67         logUtility(new LogUtility("/var/log/vicar/vicar.log",p)),
68         parent(p)
69     {
70         Q_ASSERT(0 != adaptor);
71     }
72
73     ~ConnectionPrivate()
74     {
75         qDebug() << "VICaR Connection: Connection Destructing";
76     }
77
78     const QString account;
79
80     Connection::Status connection_status;
81     ConnectionAdaptor * adaptor;
82     ConnectionInterfaceRequestsAdaptor * connIfaceReqsAdaptor;
83     LogUtility * const logUtility;
84     Connection * const parent;
85 };
86
87 // ---------------------------------------------------------------------------
88
89 Connection::Connection(const QString & account,
90                         QObject * parent) :
91     QObject(parent),
92     d(new ConnectionPrivate(this, account))
93 {
94
95     QString strMessage;
96     strMessage = "DEBUG: In Connection Constructor";
97     qDebug() << strMessage;
98     d->logUtility->logMessage(strMessage);
99
100     Q_ASSERT(0 != d);
101     Q_ASSERT(!account.isEmpty());
102
103     /*  -- Set the Dynamic property "Interfaces" ---
104
105         Apparently it is not sufficient to implement an additional interface like Conn.I.Requests.
106         We have to assign the list of additional interfaces to the DBus Property Interfaces.
107
108         The actual DBus property "Interfaces" is declared in ConnectionAdaptor class,
109          which is our Connection Interface implementation.
110      */
111
112     QStringList interfaces = QStringList(requests_interface);
113     this->setProperty("Interfaces",interfaces);
114
115     // Set the Dynamic property "HasImmortalHandles" to true as per telepathy Connection spec 0.21.6
116     //The handles for vicar connection are expected to last throughout the lifetime of the connection
117     this->setProperty("HasImmortalHandles",true);
118
119     this->setProperty("Status",org::freedesktop::Telepathy::CONNECTION_STATUS_CONNECTED);
120     this->setProperty("SelfHandle",org::freedesktop::Telepathy::HANDLE_TYPE_CONTACT);
121
122     //Set the property RequestableChannelClasses
123     org::freedesktop::Telepathy::RequestableChannelClassList requestableChannelClasses;
124
125     uint targetHandleType(1);
126
127     org::freedesktop::Telepathy::RequestableChannelClass requestableChannelClass1;
128     requestableChannelClass1.fixedProperties.insert("org.freedesktop.Telepathy.Channel.TargetHandleType",targetHandleType);
129     requestableChannelClass1.fixedProperties.insert("org.freedesktop.Telepathy.Channel.ChannelType","org.freedesktop.Telepathy.Channel.Type.StreamedMedia");
130
131     requestableChannelClass1.allowedProperties.append("org.freedesktop.Telepathy.Channel.TargetHandle");
132     requestableChannelClass1.allowedProperties.append("org.freedesktop.Telepathy.Channel.Type.StreamedMedia.InitialAudio");
133
134     requestableChannelClasses.append(requestableChannelClass1);
135
136     org::freedesktop::Telepathy::RequestableChannelClass requestableChannelClass2;
137     requestableChannelClass2.fixedProperties.insert("org.freedesktop.Telepathy.Channel.TargetHandleType",targetHandleType);
138     requestableChannelClass2.fixedProperties.insert("org.freedesktop.Telepathy.Channel.ChannelType","org.freedesktop.Telepathy.Channel.Type.StreamedMedia");
139
140     requestableChannelClass2.allowedProperties.append("com.nokia.Telepathy.Channel.Interface.Conference.InitialMembers");
141     requestableChannelClass2.allowedProperties.append("org.freedesktop.Telepathy.Channel.TargetHandleType");
142     requestableChannelClass2.allowedProperties.append("org.freedesktop.Telepathy.Channel.Type.StreamedMedia.InitialAudio");
143
144     requestableChannelClasses.append(requestableChannelClass2);
145
146
147     this->setProperty("RequestableChannelClasses",QVariant::fromValue(requestableChannelClasses));
148
149     //Set the property Channels
150     org::freedesktop::Telepathy::ChannelDetailsList channelDetails;
151     this->setProperty("Channels",QVariant::fromValue(channelDetails));
152
153     //Set the connection status to Connected (default for Vicar)
154     d->connection_status = Connection::Connected;
155
156
157     strMessage = "VICaR Connection: Connection set up.";
158
159     qDebug() << strMessage;
160     d->logUtility->logMessage(strMessage);
161 }
162
163 Connection::~Connection()
164 {
165     qDebug() << "VICaR Connection: Connection closed.";
166     delete(d);
167 }
168
169 bool Connection::registerObject()
170 {
171     QString strMessage;
172
173     if (!QDBusConnection::sessionBus().interface()->isServiceRegistered(serviceName())){
174         if (!QDBusConnection::sessionBus().registerService(serviceName()))
175         {
176             strMessage = "VICaR Connection: Problem registering connection service:" + serviceName();
177             qDebug() << strMessage;
178             d->logUtility->logMessage(strMessage);
179             return false;
180         }
181
182         if (!QDBusConnection::sessionBus().registerObject(objectPath().path(),
183                                                           this))
184         {
185             strMessage = "VICaR Connection: Problem registering object path:" + objectPath().path();
186             qDebug() << strMessage;
187             d->logUtility->logMessage(strMessage);
188             return false;
189         }
190     }
191     else{
192         strMessage = "VICaR Connection: " + serviceName()+" is already registered on DBus";
193         qDebug() << strMessage;
194         d->logUtility->logMessage(strMessage);
195     }
196     return true;
197 }
198
199 void Connection::unregisterObject()
200 {
201     QString strMessage = "VICaR Connection: Unregistering Connection object from DBus";
202     qDebug() << strMessage;
203     d->logUtility->logMessage(strMessage);
204     QDBusConnection::sessionBus().unregisterObject(objectPath().path());
205     QDBusConnection::sessionBus().unregisterService(serviceName());
206 }
207
208 QString Connection::name() const
209 {    
210     return QString("vicar");
211 }
212
213
214 QString Connection::serviceName() const
215 { return connection_service_name_prefix + name(); }
216
217 QDBusObjectPath Connection::objectPath() const
218 { return QDBusObjectPath(connection_object_path_prefix + name()); }
219
220
221 //org.freedesktop.Telepathy.Connection
222 void Connection::Connect()
223 {
224     /*
225        Since this is not a "real" Telepathy Connection to a SIP, Chat server,
226        I am not connecting to anything.
227      */
228     QString strMessage = "VICaR Connection: Changing status to Connected...";
229     qDebug() << strMessage;
230     d->logUtility->logMessage(strMessage);
231     d->connection_status = Connection::Connected;
232
233     //Let all the Telepathy clients know that connection status has changed
234     strMessage = "VICaR Connection: Emitting StatusChanged.";
235     qDebug() << strMessage;
236     d->logUtility->logMessage(strMessage);
237     emit StatusChanged(d->connection_status, ReasonRequested);
238 }
239
240 void Connection::Disconnect()
241 {
242     QString strMessage = "VICaR Connection: Changing status to Disconnected...";
243     qDebug() << strMessage;
244     d->logUtility->logMessage(strMessage);
245     //We don't have any Handles to release here. So just change the status to Disconnected
246     d->connection_status = Connection::Disconnected;
247
248     strMessage = "VICaR Connection: Emitting StatusChanged";
249     qDebug() << strMessage;
250     d->logUtility->logMessage(strMessage);
251     emit StatusChanged(d->connection_status, ReasonRequested);
252
253     //As per Telepathy specfication, on disconnect we need to unregister from Dbus and destroy the object.
254     unregisterObject();
255     deleteLater();
256 }
257
258 QStringList Connection::GetInterfaces()
259 {
260     QStringList result;
261     if (d->connection_status != Connected)
262     {
263         sendErrorReply("org.freedesktop.Telepathy.Error.Disconnected",
264                        "VICaR - Unable to get Interfaces List. The connection is no longer available.");
265         return result;
266     }    
267     result <<requests_interface;
268     return result;
269 }
270
271 QString Connection::GetProtocol()
272 { return protocol_vicar; }
273
274 uint Connection::GetStatus()
275 { return static_cast<uint>(d->connection_status); }
276
277 uint Connection::GetSelfHandle()
278 {
279     QString strMessage = "VICaR Connection: GetSelfHandle";
280     qDebug() << strMessage;
281     d->logUtility->logMessage(strMessage);
282     if (d->connection_status != Connected)
283     {
284         sendErrorReply("org.freedesktop.Telepathy.Error.Disconnected",
285                        "VICaR - Unable to get Self Handle. The connection is no longer available.");
286         strMessage = "VICaR Connection: NOT CONNECTED when requesting selfhandle!";
287         qDebug() << strMessage;
288         d->logUtility->logMessage(strMessage);
289         return 0;
290     }
291
292     //WARNING: Incomplete implemenation
293     uint handle = 0;
294     strMessage = "VICaR Connection: Returning Handle " + QString(handle) + "as self handle.";
295     qDebug() << strMessage;
296     d->logUtility->logMessage(strMessage);
297     return handle;
298 }
299
300 QList<uint> Connection::RequestHandles(uint handle_type,
301                                        const QStringList & names)
302 {
303     Q_UNUSED(names);
304     QList<uint> result;
305
306     // check input:
307     if (d->connection_status != Connected)
308     {
309         sendErrorReply("org.freedesktop.Telepathy.Error.Disconnected",
310                        "VICaR - Unable to process handle request. The connection is no longer available.");
311         return result;
312     }
313     if (handle_type != HandleContact)
314     {
315         sendErrorReply("org.freedesktop.Telepathy.Error.InvalidArgument",
316                        "VICaR - Supports handles of type Contact only.");
317         return result;
318     }
319
320     //WARNING: Incomplete implementation. Create a handle and return the value here.
321     return result;
322 }
323
324 void Connection::HoldHandles(const uint handle_type, const QList<uint> &handles)
325 {
326     Q_UNUSED(handles);
327     QString strMessage = "VICaR Connection: HoldHandles.";
328     qDebug() << strMessage;
329     d->logUtility->logMessage(strMessage);
330     if (d->connection_status != Connected)
331     {
332
333         strMessage = "VICaR Connection: HoldHandles - Not Connected.";
334         qDebug() << strMessage;
335         d->logUtility->logMessage(strMessage);
336
337         sendErrorReply("org.freedesktop.Telepathy.Error.Disconnected",
338                        "VICaR - Unable to process handle request. The connection is no longer available.");
339         return;
340     }
341     if (handle_type != HandleContact)
342     {
343
344         strMessage = "VICaR Connection: HoldHandles - Invalid Handle Type.";
345         qDebug() << strMessage;
346         d->logUtility->logMessage(strMessage);
347
348         sendErrorReply("org.freedesktop.Telepathy.Error.InvalidArgument",
349                        "VICaR - Supports handles of type Contact only.");
350         return;
351     }
352
353     //WARNING: Incomplete implementation
354 }
355
356 QStringList Connection::InspectHandles(const uint handle_type,
357                                        const QList<uint> &handles)
358 {
359     Q_UNUSED(handles);
360     QStringList handlesList;
361
362     QString strMessage = "VICaR Connection: InspectHandles.";
363     qDebug() << strMessage;
364     d->logUtility->logMessage(strMessage);
365
366         // check input:
367     if (d->connection_status != Connected)
368     {
369         sendErrorReply("org.freedesktop.Telepathy.Error.Disconnected",
370                        "VICaR - Unable to process handle request. The connection is no longer available.");
371         return handlesList;
372     }
373     if (handle_type != HandleContact)
374     {
375         sendErrorReply("org.freedesktop.Telepathy.Error.InvalidArgument",
376                        "VICaR - Supports handles of type Contact only.");
377         return handlesList;
378     }
379
380     uint handle = 0;
381     for (int i = 0 ; i < handles.length(); i++) {
382         handle = handles.at(i);
383         strMessage = "VICaR Connection: Inspecting handle "+QString(handle);
384         qDebug() << strMessage;
385         d->logUtility->logMessage(strMessage);
386         handlesList.append(QString(handle));
387     }
388
389     //WARNING: Incomplete implementation
390     return handlesList;
391 }
392
393 void Connection::ReleaseHandles(const uint handle_type, const QList<uint> &handles)
394 {
395     Q_UNUSED(handles);
396     QString strMessage;
397     if (d->connection_status != Connected)
398     {
399         sendErrorReply("org.freedesktop.Telepathy.Error.Disconnected",
400                        "VICaR - Unable to release handle. The connection is no longer available.");
401         strMessage = "VICaR Connection: Releasing Handle while connection is no longer connected.";
402         qDebug() << strMessage;
403         d->logUtility->logMessage(strMessage);
404         return;
405     }
406     if (handle_type != HandleContact)
407     {
408         sendErrorReply("org.freedesktop.Telepathy.Error.InvalidArgument",
409                        "VICaR - Supports handles of type Contact only.");
410         strMessage =  "VICaR Connection: Trying to release a Handle that is not a contact.";
411         qDebug() << strMessage;
412         d->logUtility->logMessage(strMessage);
413         return;
414     }
415
416     //WARNING: Incomplete implementation
417 }
418
419 org::freedesktop::Telepathy::ChannelInfoList Connection::ListChannels()
420 {
421     org::freedesktop::Telepathy::ChannelInfoList result;
422     if (d->connection_status != Connected)
423     {
424         sendErrorReply("org.freedesktop.Telepathy.Error.Disconnected",
425                        "VICaR - Unable to list channels. The connection is no longer available.");
426         return result;
427     }
428
429     //WARNING: Incomplete implementation
430     //Btw - We never have any channels :)
431
432     return result;
433 }
434
435 QDBusObjectPath Connection::RequestChannel(const QString &type,
436                                            uint handle_type, uint handle,
437                                            bool suppress_handler)
438 {
439     Q_UNUSED(handle);
440     Q_UNUSED(suppress_handler);
441     //This method is deprecated and no longer used as per latest Telepathy spec
442
443     if (type != QString("org.freedesktop.Telepathy.Channel.Type.StreamedMedia"))
444     {
445         sendErrorReply("org.freedesktop.Telepathy.Error.NotImplemented",
446                        "VICaR Connection: Failed to create channel: Channel type not implemented.");
447         return QDBusObjectPath();
448     }
449
450     if (handle_type != HandleContact )
451     {
452         sendErrorReply("org.freedesktop.Telepathy.Error.InvalidHandle",
453                        "VICaR Connection: Failed to create channel: Handle type not supported.");
454         return QDBusObjectPath();
455     }
456
457     if (d->connection_status != Connected)
458     {
459         sendErrorReply("org.freedesktop.Telepathy.Error.Disconnected",
460                        "VICaR Connection: Failed to create channel: Connection is Disconnected.");
461         return QDBusObjectPath();
462     }
463
464     //WARNING: Incomplete implementation, we are not creating any channels here at all.
465     QDBusObjectPath channel_path;
466     return channel_path;
467 }
468
469 //org.freedesktop.Telepathy.Connection.Interface.Requests
470 QDBusObjectPath Connection::CreateChannel(const QVariantMap &request,
471                                                            QVariantMap &channel_properties)
472 {
473     Q_UNUSED(channel_properties);
474     Q_ASSERT(!request.isEmpty());
475     QString strMessage;
476     strMessage = "VICaR Connection: CreateChannel";
477     qDebug() << strMessage;
478     d->logUtility->logMessage(strMessage);
479     qDebug() << " Request details are: "<< request;
480
481      //Ideally we need to emit NewChannels signal here, but since we are not creating any channels we ignore it
482
483     //WARNING: VICaR - Specific implementation
484     return processChannel(request);
485
486 }
487
488 bool Connection::EnsureChannel(const QVariantMap &request,
489                                                 QDBusObjectPath &channel_object,
490                                                 QVariantMap &channel_properties)
491 {
492     Q_UNUSED(channel_object);
493     Q_UNUSED(channel_properties);
494     Q_ASSERT(!request.isEmpty());
495     QString strMessage = "VICaR Connection: EnsureChannel";
496     qDebug() << strMessage;
497     d->logUtility->logMessage(strMessage);
498     qDebug() << " Request details are: "<< request;
499
500     //WARNING: Incomplete implementation
501     processChannel(request);
502
503     return true;
504 }
505
506 QDBusObjectPath Connection::processChannel(const QVariantMap &request){
507
508     QString strMessage = "VICaR Connection: ProcessChannel";
509     qDebug() << strMessage;
510     d->logUtility->logMessage(strMessage);
511
512     QDBusObjectPath channel_path;
513
514     if (!request.contains("org.freedesktop.Telepathy.Channel.TargetID")){
515         sendErrorReply("org.freedesktop.Telepathy.Error.InvalidArgument",
516                        "VICaR - Invalid request. TargetID (Phone Number) not included.");
517         return channel_path;
518     }
519
520     QVariant vNumber = request.value("org.freedesktop.Telepathy.Channel.TargetID");
521     if (!vNumber.isValid()){
522         sendErrorReply("org.freedesktop.Telepathy.Error.InvalidArgument",
523                        "VICaR - Invalid request. Phone Number is not valid.");
524         return channel_path;
525     }
526     QString strNumber = vNumber.toString();
527     if (strNumber.isEmpty()){
528         sendErrorReply("org.freedesktop.Telepathy.Error.InvalidArgument",
529                        "VICaR - Invalid request. Phone Number is empty.");
530         return channel_path;
531     }
532     else if (strNumber == "publish" || strNumber == "subscribe"){
533     //Deny the persistent Mission control requests to publish and subscribe
534         QString strError = "VICaR - Invalid request. " + strNumber + " is not supported.";
535         sendErrorReply("org.freedesktop.Telepathy.Error.InvalidArgument",
536                        strError);
537         return channel_path;
538
539     }
540
541     //Only allow requests with handle type as contact
542     QVariant vTargetHandleType = request.value("org.freedesktop.Telepathy.Channel.TargetHandleType");
543     uint intTargetHandleType = vTargetHandleType.toUInt();
544     if (intTargetHandleType != HandleContact)
545     {
546         strMessage = "VICaR - Supports handles of type Contact only. Recieved handle type ";
547         strMessage.append(vTargetHandleType.toString());
548
549         sendErrorReply("org.freedesktop.Telepathy.Error.InvalidArgument",
550                        strMessage);
551         return channel_path;
552     }
553
554
555     /*
556         Send an error reply to Tp Client (Mission Control) to force it to close the active channel.
557         Once it recieves the reply, the client does not bother what we return.
558
559      */
560
561     sendErrorReply("org.freedesktop.Telepathy.Error.NotAvailable",
562                    "VICaR - Creating a new channel to "+strNumber+" via Ring.");
563
564
565     //Initiate a new call to CC/Google Out/Skype-out number by requesting a new channel with Ring CM.
566
567     VicarCallRouterProxy *callRouter = new VicarCallRouterProxy(APPLICATION_DBUS_SERVICE,APPLICATION_DBUS_PATH,QDBusConnection::sessionBus(),this);
568
569     callRouter->callInternationalNumber(strNumber);
570
571     strMessage = "VICaR Connection: Call is processed.";
572
573     qDebug() << strMessage;
574     d->logUtility->logMessage(strMessage);
575
576     return channel_path;
577 }
578
579
580 void Connection::AddClientInterest(const QStringList &tokens){
581     //WARNING: Incomplete implementation
582     Q_UNUSED(tokens);    
583     QString strMessage;
584
585     strMessage = "VICaR Connection: AddClientInterest";
586     qDebug() << strMessage;
587     d->logUtility->logMessage(strMessage);
588 }
589
590 void Connection::RemoveClientInterest(const QStringList &tokens){
591     //WARNING: Incomplete implementation
592     Q_UNUSED(tokens);    
593     QString strMessage;
594
595     strMessage = "VICaR Connection: RemoveClientInterest";
596     qDebug() << strMessage;
597     d->logUtility->logMessage(strMessage);
598 }
599
600 //org.freedesktop.Telepathy.Connection.Interface.Capabilities
601 org::freedesktop::Telepathy::ContactCapabilitiesList Connection::GetCapabilities(const QList<uint> &Handles){
602     Q_UNUSED(Handles);
603     org::freedesktop::Telepathy::ContactCapabilitiesList capabilities;
604     return capabilities;
605
606 }
607
608
609 org::freedesktop::Telepathy::CapabilityPairList Connection::AdvertiseCapabilities(org::freedesktop::Telepathy::CapabilityPairList Add, const QStringList &Remove){
610     Q_UNUSED(Add);
611     Q_UNUSED(Remove);
612     org::freedesktop::Telepathy::CapabilityPairList capabilities;
613     return capabilities;
614 }