File indexing completed on 2024-12-15 04:51:47
0001 /******************************************************************* 0002 KNotes -- Notes for the KDE project 0003 0004 SPDX-FileCopyrightText: 2003 Daniel Martin <daniel.martin@pirack.com> 0005 SPDX-FileCopyrightText: 2004, 2006 Michael Brade <brade@kde.org> 0006 SPDX-FileCopyrightText: 2013-2024 Laurent Montel <montel.org> 0007 0008 SPDX-License-Identifier: GPL-2.0-or-later 0009 *******************************************************************/ 0010 0011 #include "notesnetworkreceiver.h" 0012 0013 #include "noteshared_debug.h" 0014 #include "noteutils.h" 0015 #include <QDateTime> 0016 #include <QHostAddress> 0017 #include <QLocale> 0018 #include <QStringDecoder> 0019 #include <QTcpSocket> 0020 #include <QTimer> 0021 0022 // Maximum note size in chars we are going to accept, 0023 // to prevent "note floods". 0024 #define MAXBUFFER 4096 0025 0026 // Maximum time we are going to wait between data receptions, 0027 // to prevent memory and connection floods. In milliseconds. 0028 #define MAXTIME 10000 0029 0030 // Small buffer's size 0031 #define SBSIZE 512 0032 using namespace NoteShared; 0033 0034 class NoteShared::NotesNetworkReceiverPrivate 0035 { 0036 public: 0037 NotesNetworkReceiverPrivate(QTcpSocket *s) 0038 : m_buffer(new QByteArray()) 0039 , m_sock(s) 0040 { 0041 } 0042 0043 ~NotesNetworkReceiverPrivate() 0044 { 0045 delete m_buffer; 0046 delete m_sock; 0047 } 0048 0049 QTimer *m_timer = nullptr; // to avoid memory and connection floods 0050 0051 QByteArray *const m_buffer; 0052 QTcpSocket *const m_sock; 0053 0054 QString m_titleAddon; 0055 }; 0056 0057 NotesNetworkReceiver::NotesNetworkReceiver(QTcpSocket *s) 0058 : QObject() 0059 , d(new NoteShared::NotesNetworkReceiverPrivate(s)) 0060 { 0061 const QString date = QLocale().toString(QDateTime::currentDateTime(), QLocale::ShortFormat); 0062 0063 // Add the remote IP or hostname and the date to the title, to help the 0064 // user guess who wrote it. 0065 d->m_titleAddon = QStringLiteral(" [%1, %2]").arg(d->m_sock->peerAddress().toString(), date); 0066 0067 // Setup the communications 0068 connect(d->m_sock, &QTcpSocket::readyRead, this, &NotesNetworkReceiver::slotDataAvailable); 0069 connect(d->m_sock, &QTcpSocket::disconnected, this, &NotesNetworkReceiver::slotConnectionClosed); 0070 connect(d->m_sock, qOverload<QAbstractSocket::SocketError>(&QTcpSocket::errorOccurred), this, &NotesNetworkReceiver::slotError); 0071 // Setup the timer 0072 d->m_timer = new QTimer(this); 0073 d->m_timer->setSingleShot(true); 0074 connect(d->m_timer, &QTimer::timeout, this, &NotesNetworkReceiver::slotReceptionTimeout); 0075 d->m_timer->start(MAXTIME); 0076 } 0077 0078 NotesNetworkReceiver::~NotesNetworkReceiver() = default; 0079 0080 void NotesNetworkReceiver::slotDataAvailable() 0081 { 0082 char smallBuffer[SBSIZE]; 0083 int smallBufferLen; 0084 0085 do { 0086 // Append to "big buffer" only if we have some space left. 0087 int curLen = d->m_buffer->size(); 0088 0089 smallBufferLen = d->m_sock->read(smallBuffer, SBSIZE); 0090 0091 // Limit max transfer over buffer, to avoid overflow. 0092 smallBufferLen = qMin(smallBufferLen, MAXBUFFER - curLen); 0093 0094 if (smallBufferLen > 0) { 0095 d->m_buffer->resize(curLen + smallBufferLen); 0096 memcpy(d->m_buffer->data() + curLen, smallBuffer, smallBufferLen); 0097 } 0098 } while (smallBufferLen == SBSIZE); 0099 0100 // If we are overflowing, close connection. 0101 if (d->m_buffer->size() == MAXBUFFER) { 0102 d->m_sock->close(); 0103 } else { 0104 d->m_timer->start(MAXTIME); 0105 } 0106 } 0107 0108 void NotesNetworkReceiver::slotReceptionTimeout() 0109 { 0110 d->m_sock->close(); 0111 } 0112 0113 void NotesNetworkReceiver::slotConnectionClosed() 0114 { 0115 QStringDecoder codec(QStringDecoder::System); 0116 0117 if (d->m_timer->isActive()) { 0118 const QString noteText = QString(codec.decode(*d->m_buffer)).trimmed(); 0119 NoteUtils utils; 0120 const NoteUtils::NoteText result = utils.extractNoteText(noteText, d->m_titleAddon); 0121 if (!result.noteText.isEmpty()) { 0122 Q_EMIT sigNoteReceived(result.noteTitle, result.noteText); 0123 } 0124 } 0125 0126 deleteLater(); 0127 } 0128 0129 void NotesNetworkReceiver::slotError(QAbstractSocket::SocketError error) 0130 { 0131 qCWarning(NOTESHARED_LOG) << "error type :" << static_cast<int>(error) << " error string : " << d->m_sock->errorString(); 0132 } 0133 0134 #include "moc_notesnetworkreceiver.cpp"