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