File indexing completed on 2024-05-19 05:06:55
0001 /* 0002 SPDX-FileCopyrightText: 2017 Thomas Baumgart <tbaumgart@kde.org> 0003 SPDX-License-Identifier: GPL-2.0-or-later 0004 */ 0005 0006 #include "webconnect.h" 0007 0008 #include <QLocalSocket> 0009 #include <QLocalServer> 0010 #include <QStandardPaths> 0011 #include <QDataStream> 0012 #include <QUrl> 0013 0014 Q_LOGGING_CATEGORY(WebConnectLog, "WebConnect") 0015 0016 class WebConnect::Private 0017 { 0018 Q_DISABLE_COPY_MOVE(Private) 0019 0020 public: 0021 explicit Private(WebConnect* parent) 0022 : q(parent) 0023 , clientSocket(new QLocalSocket(parent)) 0024 , serverSocket(0) 0025 , server(new QLocalServer(parent)) 0026 , serverFail(false) 0027 , blockSize(0) 0028 { 0029 } 0030 0031 WebConnect* q; 0032 0033 QString socketName; 0034 QLocalSocket* clientSocket; 0035 QLocalSocket* serverSocket; 0036 QLocalServer* server; 0037 bool serverFail; 0038 quint32 blockSize; 0039 0040 void startup() 0041 { 0042 // create a per user socket name 0043 socketName = QString("%1/KMyMoney-WebConnect").arg(QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation)); 0044 // try to find a server 0045 if (!connectToServer()) { 0046 // no other instance seems to be running, so we start the server 0047 if (!server->listen(socketName)) { 0048 qCInfo(WebConnectLog) << "Starting server failed. Try to remove stale socket."; 0049 server->removeServer(socketName); 0050 if(!server->listen(socketName)) { 0051 qCWarning(WebConnectLog) << "Starting server failed again. WebConnect not available."; 0052 serverFail = true; 0053 } 0054 } 0055 if (!serverFail) { 0056 qCInfo(WebConnectLog) << "Running in server mode"; 0057 } else { 0058 qCWarning(WebConnectLog) << "Unable to start server mode"; 0059 } 0060 } else { 0061 qCInfo(WebConnectLog) << "Running in client mode"; 0062 clientSocket->disconnectFromServer(); 0063 } 0064 } 0065 0066 bool connectToServer() 0067 { 0068 // try to find a server 0069 qCDebug(WebConnectLog) << "Try to connect to WebConnect server"; 0070 clientSocket->setServerName(socketName); 0071 clientSocket->connectToServer(); 0072 bool rc = clientSocket->waitForConnected(200); 0073 qCDebug(WebConnectLog) << "Connect to server" << (rc ? "is ok" : "failed"); 0074 return rc; 0075 } 0076 }; 0077 0078 WebConnect::WebConnect(QObject* parent) 0079 : QObject(parent) 0080 , d(new Private(this)) 0081 { 0082 connect(d->clientSocket, &QLocalSocket::connected, this, &WebConnect::serverConnected); 0083 connect(d->clientSocket, &QLocalSocket::disconnected, this, &WebConnect::serverDisconnected); 0084 connect(d->server, &QLocalServer::newConnection, this, &WebConnect::clientConnected); 0085 0086 d->startup(); 0087 } 0088 0089 WebConnect::~WebConnect() 0090 { 0091 if (d->server->isListening()) { 0092 d->server->close(); 0093 } 0094 delete d; 0095 } 0096 0097 void WebConnect::clientConnected() 0098 { 0099 qCDebug(WebConnectLog) << "Client connected"; 0100 disconnect(d->server, &QLocalServer::newConnection, this, &WebConnect::clientConnected); 0101 if (!d->serverSocket) { 0102 qCDebug(WebConnectLog) << "Get next pending connection"; 0103 // Reset to beginning of stream 0104 d->blockSize = 0; 0105 d->serverSocket = d->server->nextPendingConnection(); 0106 connect(d->serverSocket, &QLocalSocket::disconnected, this, &WebConnect::clientDisconnected); 0107 connect(d->serverSocket, &QLocalSocket::readyRead, this, &WebConnect::dataAvailable); 0108 } 0109 } 0110 0111 void WebConnect::clientDisconnected() 0112 { 0113 qCDebug(WebConnectLog) << "Client disconnected"; 0114 d->serverSocket->deleteLater(); 0115 d->serverSocket = 0; 0116 if (d->server->hasPendingConnections()) { 0117 qCDebug(WebConnectLog) << "Processing next pending connection"; 0118 clientConnected(); 0119 } else { 0120 qCDebug(WebConnectLog) << "Wait for next client"; 0121 connect(d->server, &QLocalServer::newConnection, this, &WebConnect::clientConnected); 0122 } 0123 } 0124 0125 void WebConnect::serverConnected() 0126 { 0127 qCDebug(WebConnectLog) << "Server connected"; 0128 } 0129 0130 void WebConnect::serverDisconnected() 0131 { 0132 qCDebug(WebConnectLog) << "Server disconnected"; 0133 } 0134 0135 void WebConnect::dataAvailable() 0136 { 0137 QDataStream in(d->serverSocket); 0138 in.setVersion(QDataStream::Qt_4_0); 0139 0140 if (d->blockSize == 0) { 0141 // Relies on the fact that we put the length into the QDataStream 0142 if (d->serverSocket->bytesAvailable() < (int)sizeof(quint32)) { 0143 return; 0144 } 0145 in >> d->blockSize; 0146 } 0147 0148 if (d->serverSocket->bytesAvailable() < (int)sizeof(quint32) || d->serverSocket->atEnd()) { 0149 return; 0150 } 0151 QUrl url; 0152 in >> url; 0153 qCDebug(WebConnectLog) << "Processing" << url; 0154 Q_EMIT gotUrl(url); 0155 } 0156 0157 void WebConnect::loadFile(const QUrl& url) 0158 { 0159 if (d->connectToServer()) { 0160 qCDebug(WebConnectLog) << "Pass to server" << url; 0161 // transfer filename 0162 QByteArray block; 0163 QDataStream stream(&block, QIODevice::WriteOnly); 0164 stream.setVersion(QDataStream::Qt_4_0); 0165 stream << (quint32) 0; 0166 stream << url; 0167 stream.device()->seek(0); 0168 stream << (quint32)(block.size() - sizeof(quint32)); 0169 d->clientSocket->write(block); 0170 d->clientSocket->flush(); 0171 d->clientSocket->disconnectFromServer(); 0172 } else { 0173 qCWarning(WebConnectLog) << "Webconnect loadfile connection failed on client side"; 0174 } 0175 } 0176 0177 bool WebConnect::isClient() const 0178 { 0179 return !d->server->isListening() && !d->serverFail; 0180 }