1/***************************************************************************
2 * Copyright (C) 2010 by Volker Krause <vkrause@kde.org> *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU Library General Public License as *
6 * published by the Free Software Foundation; either version 2 of the *
7 * License, or (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU Library General Public *
15 * License along with this program; if not, write to the *
16 * Free Software Foundation, Inc., *
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
18 ***************************************************************************/
19
20#include "bridgeconnection.h"
21
22#include <shared/akstandarddirs.h>
23
24#include <QtCore/QDebug>
25#include <QtCore/QMetaObject>
26#include <QtCore/QRegExp>
27#include <QtCore/QSettings>
28#include <QtNetwork/QLocalSocket>
29#include <QtNetwork/QTcpSocket>
30
31#ifdef Q_OS_UNIX
32#include <sys/socket.h>
33#include <sys/un.h>
34#endif
35
36BridgeConnection::BridgeConnection(QTcpSocket *remoteSocket, QObject *parent)
37 : QObject(parent)
38 , m_localSocket(0)
39 , m_remoteSocket(remoteSocket)
40{
41 // wait for the vtable to be complete
42 QMetaObject::invokeMethod(this, "doConnects", Qt::QueuedConnection);
43 QMetaObject::invokeMethod(this, "connectLocal", Qt::QueuedConnection);
44}
45
46BridgeConnection::~BridgeConnection()
47{
48 delete m_remoteSocket;
49}
50
51void BridgeConnection::slotDataAvailable()
52{
53 if (m_localSocket->bytesAvailable() > 0) {
54 m_remoteSocket->write(m_localSocket->read(m_localSocket->bytesAvailable()));
55 }
56 if (m_remoteSocket->bytesAvailable() > 0) {
57 m_localSocket->write(m_remoteSocket->read(m_remoteSocket->bytesAvailable()));
58 }
59}
60
61AkonadiBridgeConnection::AkonadiBridgeConnection(QTcpSocket *remoteSocket, QObject *parent)
62 : BridgeConnection(remoteSocket, parent)
63{
64 m_localSocket = new QLocalSocket(this);
65}
66
67void AkonadiBridgeConnection::connectLocal()
68{
69 const QSettings connectionSettings(AkStandardDirs::connectionConfigFile(), QSettings::IniFormat);
70#ifdef Q_OS_WIN //krazy:exclude=cpp
71 const QString namedPipe = connectionSettings.value(QLatin1String("Data/NamedPipe"), QLatin1String("Akonadi")).toString();
72 (static_cast<QLocalSocket *>(m_localSocket))->connectToServer(namedPipe);
73#else
74 const QString defaultSocketDir = AkStandardDirs::saveDir("data");
75 const QString path = connectionSettings.value(QLatin1String("Data/UnixPath"), QString(defaultSocketDir + QLatin1String("/akonadiserver.socket"))).toString();
76 (static_cast<QLocalSocket *>(m_localSocket))->connectToServer(path);
77#endif
78}
79
80DBusBridgeConnection::DBusBridgeConnection(QTcpSocket *remoteSocket, QObject *parent)
81 : BridgeConnection(remoteSocket, parent)
82{
83 m_localSocket = new QLocalSocket(this);
84}
85
86void DBusBridgeConnection::connectLocal()
87{
88 // TODO: support for !Linux
89#ifdef Q_OS_UNIX
90 const QByteArray sessionBusAddress = qgetenv("DBUS_SESSION_BUS_ADDRESS");
91 QRegExp rx(QLatin1String("=(.*)[,$]"));
92 if (rx.indexIn(QString::fromLatin1(sessionBusAddress)) >= 0) {
93 const QString dbusPath = rx.cap(1);
94 qDebug() << dbusPath;
95 if (sessionBusAddress.contains("abstract")) {
96 const int fd = socket(PF_UNIX, SOCK_STREAM, 0);
97 Q_ASSERT(fd >= 0);
98 struct sockaddr_un dbus_socket_addr;
99 dbus_socket_addr.sun_family = PF_UNIX;
100 dbus_socket_addr.sun_path[0] = '\0'; // this marks an abstract unix socket on linux, something QLocalSocket doesn't support
101 memcpy(dbus_socket_addr.sun_path + 1, dbusPath.toLatin1().data(), dbusPath.toLatin1().size() + 1);
102 /*sizeof(dbus_socket_addr) gives me a too large value for some reason, although that's what QLocalSocket uses*/
103 const int result = ::connect(fd, (struct sockaddr *) &dbus_socket_addr, sizeof (dbus_socket_addr.sun_family) + dbusPath.size() + 1 /* for the leading \0 */);
104 Q_ASSERT(result != -1);
105 Q_UNUSED(result); // in release mode
106 (static_cast<QLocalSocket *>(m_localSocket))->setSocketDescriptor(fd, QLocalSocket::ConnectedState, QLocalSocket::ReadWrite);
107 } else {
108 (static_cast<QLocalSocket *>(m_localSocket))->connectToServer(dbusPath);
109 }
110 }
111#endif
112}
113
114void BridgeConnection::doConnects()
115{
116 connect(m_localSocket, SIGNAL(disconnected()), SLOT(deleteLater()));
117 connect(m_remoteSocket, SIGNAL(disconnected()), SLOT(deleteLater()));
118 connect(m_localSocket, SIGNAL(readyRead()), SLOT(slotDataAvailable()));
119 connect(m_remoteSocket, SIGNAL(readyRead()), SLOT(slotDataAvailable()));
120 connect(m_localSocket, SIGNAL(connected()), SLOT(slotDataAvailable()));
121}
122