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