00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "connection-manager.h"
00024 #include "debug.h"
00025 #include "libsignoncommon.h"
00026 #include "signond/signoncommon.h"
00027
00028 #include <QDBusConnectionInterface>
00029 #include <QDBusError>
00030 #include <QDBusPendingCallWatcher>
00031 #include <QPointer>
00032 #include <QProcessEnvironment>
00033 #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
00034 #include <QStandardPaths>
00035 #endif
00036
00037 using namespace SignOn;
00038
00039 static QPointer<ConnectionManager> connectionInstance = 0;
00040
00041 ConnectionManager::ConnectionManager(QObject *parent):
00042 QObject(parent),
00043 m_connection(QLatin1String("libsignon-qt-invalid")),
00044 m_serviceStatus(ServiceStatusUnknown)
00045 {
00046 if (connectionInstance == 0) {
00047 init();
00048 connectionInstance = this;
00049 } else {
00050 BLAME() << "SignOn::ConnectionManager instantiated more than once!";
00051 }
00052 }
00053
00054 ConnectionManager::~ConnectionManager()
00055 {
00056 }
00057
00058 ConnectionManager *ConnectionManager::instance()
00059 {
00060 if (connectionInstance == 0) {
00061 connectionInstance = new ConnectionManager;
00062 }
00063 return connectionInstance;
00064 }
00065
00066 void ConnectionManager::connect()
00067 {
00068 if (m_connection.isConnected()) {
00069 Q_EMIT connected(m_connection);
00070 } else {
00071 init();
00072 }
00073 }
00074
00075 bool ConnectionManager::hasConnection() const
00076 {
00077 return m_connection.isConnected();
00078 }
00079
00080 ConnectionManager::SocketConnectionStatus
00081 ConnectionManager::setupSocketConnection()
00082 {
00083 QProcessEnvironment environment = QProcessEnvironment::systemEnvironment();
00084 QLatin1String one("1");
00085 if (environment.value(QLatin1String("SSO_USE_PEER_BUS"), one) != one) {
00086 return SocketConnectionUnavailable;
00087 }
00088
00089 #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
00090 QString runtimeDir =
00091 QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation);
00092 #else
00093 QString runtimeDir = environment.value(QLatin1String("XDG_RUNTIME_DIR"));
00094 #endif
00095 if (runtimeDir.isEmpty()) return SocketConnectionUnavailable;
00096
00097 QString socketFileName =
00098 QString::fromLatin1("unix:path=%1/" SIGNOND_SOCKET_FILENAME).arg(runtimeDir);
00099 static int count = 0;
00100
00101 QDBusConnection connection =
00102 QDBusConnection::connectToPeer(socketFileName,
00103 QString(QLatin1String("libsignon-qt%1")).arg(count++));
00104 if (!connection.isConnected()) {
00105 QDBusError error = connection.lastError();
00106 QString name = error.name();
00107 TRACE() << "p2p error:" << error << error.type();
00108 if (name == QLatin1String("org.freedesktop.DBus.Error.FileNotFound") &&
00109 m_serviceStatus != ServiceActivated) {
00110 return SocketConnectionNoService;
00111 } else {
00112 return SocketConnectionUnavailable;
00113 }
00114 }
00115
00116 m_connection = connection;
00117 m_connection.connect(QString(),
00118 QLatin1String("/org/freedesktop/DBus/Local"),
00119 QLatin1String("org.freedesktop.DBus.Local"),
00120 QLatin1String("Disconnected"),
00121 this, SLOT(onDisconnected()));
00122
00123 return SocketConnectionOk;
00124 }
00125
00126 void ConnectionManager::init()
00127 {
00128 if (m_serviceStatus == ServiceActivating) return;
00129
00130 SocketConnectionStatus status = setupSocketConnection();
00131
00132 if (status == SocketConnectionNoService) {
00133 TRACE() << "Peer connection unavailable, activating service";
00134 QDBusConnectionInterface *interface =
00135 QDBusConnection::sessionBus().interface();
00136 QDBusPendingCall call =
00137 interface->asyncCall(QLatin1String("StartServiceByName"),
00138 SIGNOND_SERVICE, uint(0));
00139 m_serviceStatus = ServiceActivating;
00140 QDBusPendingCallWatcher *watcher =
00141 new QDBusPendingCallWatcher(call, this);
00142 QObject::connect(watcher,
00143 SIGNAL(finished(QDBusPendingCallWatcher*)),
00144 this,
00145 SLOT(onActivationDone(QDBusPendingCallWatcher*)));
00146 } else if (status == SocketConnectionUnavailable) {
00147 m_connection = SIGNOND_BUS;
00148 }
00149
00150 if (m_connection.isConnected()) {
00151 TRACE() << "Connected to" << m_connection.name();
00152 Q_EMIT connected(m_connection);
00153 }
00154 }
00155
00156 void ConnectionManager::onActivationDone(QDBusPendingCallWatcher *watcher)
00157 {
00158 QDBusPendingReply<> reply(*watcher);
00159 watcher->deleteLater();
00160
00161 if (!reply.isError()) {
00162 m_serviceStatus = ServiceActivated;
00163
00164 init();
00165 } else {
00166 BLAME() << reply.error();
00167 }
00168 }
00169
00170 void ConnectionManager::onDisconnected()
00171 {
00172 TRACE() << "Disconnected from daemon";
00173 m_serviceStatus = ServiceStatusUnknown;
00174 Q_EMIT disconnected();
00175 }