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