1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039 |
- #include "httpserver.h"
- #include "ircclient.h"
- #include "connectiondata.h"
- #include "global.h"
- #include "version.h"
- #include <QRegularExpression>
- #include <QDirIterator>
- #include <QDateTime>
- #include <QHostAddress>
- #include <QTcpSocket>
- #include <QDebug>
- #include <QFile>
- #include <QDir>
- constexpr int MAX_MESSAGE_LENGTH_WITHOUT_WBR = 30;
- constexpr int MAX_NICKNAME_LENGTH_WITHOUT_WBR = 20;
- constexpr int BUFFER_SIZE = 2048;
- HttpServer::HttpServer(const QString &address, quint16 port, const QString& logFolder,
- const QString& mainChannel, QObject *parent) :
- QObject(parent),
- m_TcpServer(new QTcpServer),
- m_mainChannel(mainChannel),
- m_logFolder(logFolder)
- {
- if (not m_TcpServer->listen(QHostAddress(address), port)) {
- throw std::runtime_error("HttpServer not binded at " +
- address.toStdString() + " : " + QString::number(port).toStdString());
- }
- else {
- consoleLog(address + " : " + QString::number(port));
- }
- connect (m_TcpServer, &QTcpServer::newConnection, this, &HttpServer::acceptor);
- }
- HttpServer::~HttpServer()
- {
- m_TcpServer->close();
- m_TcpServer->deleteLater();
- }
- QString HttpServer::convertToClickableLink(const QString &httpLine)
- {
- QString result;
- if (not httpLine.contains(QRegularExpression("http.?://"))) return result;
- QString displayedName {httpLine};
- displayedName.remove(QRegularExpression("http.?://(www\\.)?"));
- displayedName.remove(QRegularExpression("/$"));
- result = "<a href=\"" + httpLine + "\"> " + displayedName + " </a>";
- return result;
- }
- std::pair<QString, QString> HttpServer::splitUserNameAndMessage(const QString &rawLine)
- {
- std::pair<QString, QString> result;
- QString nick {rawLine};
- nick.remove(QRegularExpression("\\]\\s.*$"));
- nick.remove(QRegularExpression("^\\["));
- if (nick.isEmpty()) {
- return result;
- }
- QString text {rawLine};
- text.remove(QRegularExpression("^\\[[^\\s]*\\]\\s"));
- if (text.isEmpty()) {
- return result;
- }
- nick = nick.toHtmlEscaped();
- // long nicks
- if (nick.size() > MAX_NICKNAME_LENGTH_WITHOUT_WBR) {
- int lastWbr = 0;
- for (int i = 0; i < nick.size(); i++) {
- if (i-lastWbr > MAX_NICKNAME_LENGTH_WITHOUT_WBR) {
- nick.insert(i, "<wbr>");
- lastWbr = i;
- }
- }
- }
- text = text.toHtmlEscaped();
- // http links
- while (QRegularExpression("(^|\\s)http.?://").match(text).hasMatch()) {
- int pos = text.indexOf(QRegularExpression("(^|\\s)http.?://"));
- if (pos == -1) {
- consoleLog("Bug! HttpServer.cpp while (QRegularExpression(\"(^|\\s)http.?://\").match(text).hasMatch())");
- break;
- }
- QString rawLink {text};
- rawLink.remove(0, pos);
- if (rawLink.startsWith(' ')) {
- rawLink.remove(0,1);
- }
- int space = rawLink.indexOf(' ');
- if (space > 0) {
- rawLink.remove(space, rawLink.size()-space);
- }
- text.replace(rawLink, convertToClickableLink(rawLink));
- }
- // long lines
- int space = 0;
- bool nbTag = false; // For safe HTML tags like a ⁢ via <wbr>!
- bool isHref = false;
- for (int i = 0; i < text.size(); i++) {
- if (text[i] == ' ') {
- space = i;
- if (isHref) {
- isHref = false;
- }
- else {
- if (text.indexOf("href=\"http", i+1) == i+1) {
- isHref = true;
- }
- }
- }
- if (nbTag and text[i-1] == ';') {
- nbTag = false;
- }
- if (text.indexOf(QRegularExpression("(\\&|\\<|\\>|\\").*"), i) == i) {
- nbTag = true;
- }
- if (not isHref and i-space > MAX_MESSAGE_LENGTH_WITHOUT_WBR and not nbTag) {
- text.insert(i, "<wbr>");
- space = i;
- }
- }
- result.first = nick;
- result.second = text;
- return result;
- }
- void HttpServer::consoleLog(const QString &message)
- {
- qInfo().noquote() << "[WEBINTERFACE]" << message;
- }
- void HttpServer::debugLog(const QString &req)
- {
- QFile log(m_logFolder + "httprequests.log");
- if (log.open(QIODevice::WriteOnly | QIODevice::Append)) {
- log.write(QDateTime::currentDateTime().toString().toUtf8() + ":\n" + req.toUtf8() + "\n");
- log.close();
- }
- }
- void HttpServer::acceptor()
- {
- QTcpSocket* socket = m_TcpServer->nextPendingConnection();
- connect(socket, &QTcpSocket::readyRead, this, &HttpServer::reader);
- connect(socket, &QTcpSocket::disconnected, socket, &QTcpSocket::deleteLater);
- }
- void HttpServer::reader()
- {
- QTcpSocket* socket = static_cast<QTcpSocket*>(sender());
- QString request = socket->read(BUFFER_SIZE);
- if (not request.startsWith("GET") and not request.startsWith("HEAD")) {
- if (socket->isOpen()) {
- socket->write("Your request has been rejected!\n");
- socket->disconnectFromHost();
- }
- return;
- }
- bool isHeadRequest = false;
- if (request.startsWith("HEAD ")) {
- isHeadRequest = true;
- }
- QString urlPath = getRequestPath(request);
- // static files
- if (urlPath == "/favicon.ico") {
- QString eTag = global::getValue(request, "If-None-Match", global::eHttpHeader);
- if (eTag == HTTP_ACTUAL_ETAG) {
- if (socket->isOpen()) socket->write(HEADER_304.toUtf8());
- }
- else {
- QFile icon("://html/favicon.ico");
- if (icon.open(QIODevice::ReadOnly)) {
- QByteArray file = icon.readAll();
- icon.close();
- QString header = HEADER_ICO;
- replaceTag(header, "SIZE", QString::number(file.size()));
- if (socket->isOpen()) {
- socket->write(header.toUtf8());
- if (not isHeadRequest) socket->write(file);
- }
- }
- }
- }
- else if (urlPath == "/style.css") {
- QString eTag = global::getValue(request, "If-None-Match", global::eHttpHeader);
- if (eTag == HTTP_ACTUAL_ETAG) {
- if (socket->isOpen()) socket->write(HEADER_304.toUtf8());
- }
- else {
- QFile css("://html/style.css");
- if (css.open(QIODevice::ReadOnly)) {
- QByteArray file = css.readAll();
- css.close();
- QString header = HEADER_CSS;
- replaceTag(header, "SIZE", QString::number(file.size()));
- if (socket->isOpen()) {
- socket->write(header.toUtf8());
- if (not isHeadRequest) socket->write(file);
- }
- }
- }
- }
- else if (urlPath.endsWith(".svg")) {
- QString eTag = global::getValue(request, "If-None-Match", global::eHttpHeader);
- if (eTag == HTTP_ACTUAL_ETAG) {
- if (socket->isOpen()) socket->write(HEADER_304.toUtf8());
- }
- else {
- QFile svg("://html"+urlPath);
- if (svg.open(QIODevice::ReadOnly)) {
- QByteArray file = svg.readAll();
- svg.close();
- QString header = HEADER_SVG;
- replaceTag(header, "SIZE", QString::number(file.size()));
- if (socket->isOpen()) {
- socket->write(header.toUtf8());
- if (not isHeadRequest) socket->write(file);
- }
- }
- else {
- if (socket->isOpen()) {
- socket->write(HEADER_404.toUtf8());
- if (not isHeadRequest) socket->write("<center><h1>NOT FOUND</H1></center>");
- }
- }
- }
- }
- // dynamic page
- else {
- writeMainPage(socket, urlPath, isHeadRequest);
- }
- socket->disconnectFromHost();
- }
- void HttpServer::ircBotFirstInfo(QString server, QStringList channels)
- {
- for (const auto &c: channels) {
- m_onlineUsers[server][c] = QStringList();
- }
- }
- void HttpServer::ircUsersOnline(QString server, QString channel, QStringList users)
- {
- if (server.isEmpty()) return;
- QStringList sortedNicknames;
- QStringList ownersNicks;
- QStringList operNicks;
- QStringList halfopNicks;
- QStringList adminNicks;
- QStringList voicedNicks;
- QStringList plainNicks;
- for (const auto& rawOneNick: users) {
- if (rawOneNick.startsWith('~')) {
- ownersNicks.push_back(rawOneNick);
- }
- else if (rawOneNick.startsWith('@')) {
- operNicks.push_back(rawOneNick);
- }
- else if (rawOneNick.startsWith('%')) {
- halfopNicks.push_back(rawOneNick);
- }
- else if (rawOneNick.startsWith('&')) {
- adminNicks.push_back(rawOneNick);
- }
- else if (rawOneNick.startsWith('+')) {
- voicedNicks.push_back(rawOneNick);
- }
- else {
- plainNicks.push_back(rawOneNick);
- }
- }
- if (not ownersNicks.isEmpty()) {
- std::sort(ownersNicks.begin(), ownersNicks.end());
- sortedNicknames += ownersNicks;
- }
- if (not operNicks.isEmpty()) {
- std::sort(operNicks.begin(), operNicks.end());
- sortedNicknames += operNicks;
- }
- if (not halfopNicks.isEmpty()) {
- std::sort(halfopNicks.begin(), halfopNicks.end());
- sortedNicknames += halfopNicks;
- }
- if (not adminNicks.isEmpty()) {
- std::sort(adminNicks.begin(), adminNicks.end());
- sortedNicknames += adminNicks;
- }
- if (not voicedNicks.isEmpty()) {
- std::sort(voicedNicks.begin(), voicedNicks.end());
- sortedNicknames += voicedNicks;
- }
- if (not plainNicks.isEmpty()) {
- std::sort(plainNicks.begin(), plainNicks.end());
- sortedNicknames += plainNicks;
- }
- sortedNicknames.removeAll("");
- m_onlineUsers[server][channel] = sortedNicknames;
- }
- void HttpServer::ircChannelTopic(QString server, QString channel, QString topic)
- {
- m_channelsTopic[server][channel] = topic;
- }
- void HttpServer::ircServerOnline(QString server, quint8 status)
- {
- if (server.isEmpty()) return;
- bool online = status;
- m_serversOnline[server] = online;
- }
- void HttpServer::ircBotNick(QString server, QString nickname)
- {
- m_botsNick[server] = nickname;
- }
- QString HttpServer::getRequestPath(const QString &req)
- {
- if (req.isEmpty()) return QString();
- QString result(req);
- int begin = result.indexOf(' ');
- if (begin == -1) return QString();
- result.remove(0, begin+1);
- int space = result.indexOf(' ');
- int size = result.size();
- result.remove(space, size-space);
- result = QByteArray::fromPercentEncoding(result.toUtf8());
- return result;
- }
- QString HttpServer::getWordFromPath(const QString &path)
- {
- QString result {path};
- result.remove(QRegularExpression("\\?.*$")); // any actions like a ?toSearch=
- if (result.startsWith('/')) {
- result.remove(QRegularExpression("^/"));
- }
- result.remove(QRegularExpression("/.*$"));
- return result;
- }
- void HttpServer::writeErrorPage(QTcpSocket *socket)
- {
- if (socket->isOpen()) {
- socket->write(HEADER_404.toUtf8());
- socket->write("<title>404</title><center><h1>NOT FOUND</H1></center>");
- }
- }
- void HttpServer::removeBrakelineSymbols(QString &line)
- {
- line.remove('\r');
- line.remove('\n');
- line.remove('\t');
- }
- void HttpServer::replaceTag(QString &page, const QString &tag, const QString &payload)
- {
- page.replace("{{"+tag+"}}", payload);
- }
- void HttpServer::writeMainPage(QTcpSocket *socket, QString &urlPath, bool isHeadRequest)
- {
- QString searchRequest;
- bool isRegexp {false};
- int specSymbol = urlPath.indexOf('?'); // any actions like a ?toSearch=
- if (specSymbol != -1) {
- searchRequest = global::getValue(urlPath, "toSearch", global::eForWeb);
- isRegexp = global::getValue(urlPath, "isRegexp", global::eForWeb) == "on";
- urlPath.remove(specSymbol, urlPath.size()-specSymbol);
- }
- if (urlPath == "/") {
- urlPath += m_mainChannel;
- }
- QFile main("://html/main.html");
- QString page;
- if (main.open(QIODevice::ReadOnly)) {
- page = main.readAll();
- main.close();
- }
- else {
- if (socket->isOpen()) {
- socket->write(HEADER_404.toUtf8());
- if (not isHeadRequest) socket->write("<title>Critical error</title><center><h1>NOT FOUND</H1><p>Maybe it's compile time error</p></center>");
- }
- }
- if (isRegexp) {
- page.replace("<input id=\"main_header__search_checkbox__button\" type=\"checkbox\" name=\"isRegexp\">",
- "<input id=\"main_header__search_checkbox__button\" type=\"checkbox\" name=\"isRegexp\" checked>");
- }
- QString server = getWordFromPath(urlPath);
- QDir fsPath(m_logFolder+server);
- if (not fsPath.exists()) {
- if (isHeadRequest) {
- if (socket->isOpen()) socket->write(HEADER_404.toUtf8());
- } else {
- writeErrorPage(socket);
- }
- return;
- }
- urlPath.remove(QRegularExpression("^.*/"+server));
- QString channel = getWordFromPath(urlPath);
- channel.remove(QRegularExpression("\\?.*$"));
- if (channel.isEmpty()){
- // First channel is main if not passed directly
- QDirIterator it(fsPath.path());
- while (it.hasNext()) {
- channel = it.next();
- if (channel.endsWith(".") or channel.endsWith("..")) continue; // QDir::NoDotAndNoDotDot not works!
- while(channel.contains('/')) {
- channel.remove(QRegularExpression("^.*/"));
- }
- break;
- }
- }
- if (not fsPath.cd(channel)) {
- if (isHeadRequest) {
- if (socket->isOpen()) socket->write(HEADER_404.toUtf8());
- } else {
- writeErrorPage(socket);
- }
- return;
- }
- QString originalServerName;
- for (const auto &s: m_onlineUsers) {
- if (global::toLowerAndNoSpaces(s.first) == server) {
- originalServerName = s.first;
- }
- }
- QString originalChannelName;
- for (const auto &server: m_onlineUsers) {
- for (const auto &channel_users: server.second) {
- if (global::toLowerAndNoSpaces(channel_users.first) == "#"+channel) {
- originalChannelName = global::toLowerAndNoSpaces(channel_users.first);
- }
- }
- }
- urlPath.remove(QRegularExpression("^.*/"+channel));
- QString year = getWordFromPath(urlPath);
- year.remove(QRegularExpression("\\?.*$"));
- QString month;
- QString day;
- if (not year.isEmpty() and fsPath.cd(year)) {
- urlPath.remove(QRegularExpression("^.*/"+year));
- month = getWordFromPath(urlPath);
- month.remove(QRegularExpression("\\?.*$"));
- if (not month.isEmpty() and fsPath.cd(month)) {
- if (urlPath.startsWith("/"+month+"/")) {
- urlPath.remove(0,1);
- int pos = urlPath.indexOf('/');
- if (pos != -1) {
- urlPath.remove(0,pos);
- day = getWordFromPath(urlPath);
- if (urlPath.endsWith(".txt")) {
- QFile plain(fsPath.path()+global::slash+day);
- if (plain.open(QIODevice::ReadOnly)) {
- QString header = HEADER_TEXT;
- QByteArray file = plain.readAll();
- plain.close();
- replaceTag(header, "SIZE", QString::number(file.size()));
- if (socket->isOpen()) {
- socket->write(header.toUtf8());
- if (not isHeadRequest) socket->write(file);
- }
- }
- else {
- if (isHeadRequest) {
- if (socket->isOpen()) socket->write(HEADER_404.toUtf8());
- } else {
- writeErrorPage(socket);
- }
- }
- return;
- }
- else {
- if (not QFile::exists(fsPath.path()+global::slash+day+".txt")) {
- day.clear();
- }
- }
- }
- }
- }
- else { month.clear(); }
- }
- else { year.clear(); }
- //// Left menu compilation
- QString htmlServersSectionS;
- for (const auto &s: m_onlineUsers) {
- if (s.first.isEmpty()) continue; // empty server name?
- QString htmlServersSection = HTML_SERVER_SECTION;
- replaceTag(htmlServersSection, "SERVER_NAME", s.first);
- QString htmlChannelLineS;
- for (const auto &c: s.second) {
- QString htmlChannelLine;
- if (originalServerName == s.first and originalChannelName == c.first) {
- htmlChannelLine = HTML_SERVER_SECTION_CHANNEL_SELECTED;
- } else {
- htmlChannelLine = HTML_SERVER_SECTION_CHANNEL;
- }
- replaceTag(htmlChannelLine, "CHANNEL_NAME", c.first);
- QString channelNameForUrl {c.first};
- channelNameForUrl.remove('#');
- QString channelLink = "/" + global::toLowerAndNoSpaces(s.first) + "/" + channelNameForUrl;
- if (not year.isEmpty()) {
- channelLink += "/" + year;
- if (not month.isEmpty()) {
- channelLink += "/" + month;
- if (not day.isEmpty()) {
- channelLink += "/" + day;
- }
- }
- }
- replaceTag(htmlChannelLine, "CHANNEL_LINK", channelLink);
- htmlChannelLineS += htmlChannelLine;
- }
- replaceTag(htmlServersSection, "CHANNELS", htmlChannelLineS);
- bool online {false};
- for (const auto &srv: m_serversOnline) {
- if (srv.first == s.first) {
- online = srv.second;
- break;
- }
- }
- if (online) {
- replaceTag(htmlServersSection, "ONLINE_STATUS", HTML_SERVER_ONLINE_MARKER);
- } else {
- replaceTag(htmlServersSection, "ONLINE_STATUS", HTML_SERVER_OFFLINE_MARKER);
- }
- htmlServersSectionS += htmlServersSection;
- }
- replaceTag(page, "SERVERS_SECTION", htmlServersSectionS);
- //// Main section header compilation
- if (m_onlineUsers.size() > 1) {
- replaceTag(page, "PAGE_TITLE", originalChannelName + " ("+originalServerName+") | IRCaBot");
- } else {
- replaceTag(page, "PAGE_TITLE", originalChannelName + " | IRCaBot");
- }
- replaceTag(page, "MAIN_HEADER", originalChannelName);
- if (not m_channelsTopic[originalServerName][originalChannelName].isEmpty()) {
- m_channelsTopic[originalServerName][originalChannelName].replace('\"', """);
- page.replace("<div class=\"main_header__title\">",
- "<div class=\"main_header__title\" title=\"" + m_channelsTopic[originalServerName][originalChannelName] + "\">");
- }
- QString middlePath = "<a style=\"text-decoration: none\" href=\"/"+server+"/"+channel+"\">" + "/" + "</a>";
- if (not year.isEmpty()) {
- middlePath += "<a style=\"text-decoration: none\" href=\"/"+server+"/"+channel+"/"+year+"\">" + year + "</a>";
- if (not month.isEmpty()) {
- middlePath += "/<a style=\"text-decoration: none\" href=\"/"+server+"/"+channel+"/"+year+"/"+month+"\">" + month + "</a>";
- if (not day.isEmpty()) {
- middlePath += "/" + day;
- }
- }
- }
- int currentOnline = 0;
- QString onlineUserS;
- for (const auto &user: m_onlineUsers[originalServerName][originalChannelName]) {
- if (QRegularExpression("^(@|\\&|\\+|~)?"+m_botsNick[originalServerName]+"$").match(user).hasMatch()) {
- continue;
- }
- QString onlineUser = HTML_ONLINE_POINT;
- replaceTag(onlineUser, "NICKNAME", user);
- onlineUserS += onlineUser;
- currentOnline++;
- }
- replaceTag(page, "ONLINE", QString::number(currentOnline));
- replaceTag(page, "ONLINE_LIST", onlineUserS);
- if (not searchRequest.isEmpty()) {
- page.replace("<input class=\"main_header__search_input\" type=\"search\" name=\"toSearch\" placeholder=\"{{SEARCH_PLACEHOLDER}}\">",
- "<input class=\"main_header__search_input\" type=\"search\" name=\"toSearch\" value=\"" + searchRequest + "\">");
- } else if (middlePath == "/") {
- replaceTag(page, "SEARCH_PLACEHOLDER", originalChannelName);
- } else if (month.isEmpty()) {
- replaceTag(page, "SEARCH_PLACEHOLDER", originalChannelName + "/" + year);
- } else {
- replaceTag(page, "SEARCH_PLACEHOLDER", originalChannelName + "/" + year + "/" + month);
- }
- //// Main section body compilation
- QString payloadBlock;
- // Search request
- if (not searchRequest.isEmpty()) {
- uint counter = 0;
- QRegularExpression userRgx(searchRequest, QRegularExpression::CaseInsensitiveOption);
- bool rgxIsValid = false;
- if (isRegexp and userRgx.isValid()) {
- rgxIsValid = true;
- }
- consoleLog("Search request (" + server + "): " + searchRequest);
- if (not day.isEmpty()) {
- middlePath.remove(QRegularExpression("/[0-9]{2}$"));
- }
- QStringList paths;
- QDirIterator it(fsPath.path());
- while (it.hasNext()) {
- QString currentPath = it.next();
- if (currentPath.endsWith(".") or currentPath.endsWith("..")) continue;
- QString logFolder = m_logFolder;
- #ifdef WIN32
- logFolder.replace('\\', '/');
- #endif
- QString server {currentPath}; // Folder wich is not server folder is ignored
- server.remove(QRegularExpression("^"+logFolder));
- server.remove(QRegularExpression("/.*$"));
- bool serverIsOk = false;
- for (const auto &srv: m_onlineUsers) {
- if (global::toLowerAndNoSpaces(srv.first) == server) {
- serverIsOk = true;
- break;
- }
- }
- if (not serverIsOk) continue;
- QString currentChannel {currentPath}; // Folder wich is not channel folder is ignored
- currentChannel.remove(QRegularExpression("^"+logFolder+"[^/]*/"));
- currentChannel.remove(QRegularExpression("/.*$"));
- bool channelIsOk = false; // Канал явно указан в конфиге
- for (const auto &ch: m_onlineUsers[originalServerName]) {
- QString searchChan {ch.first};
- searchChan.remove('#');
- if (searchChan == currentChannel) {
- channelIsOk = true;
- break;
- }
- }
- if (not channelIsOk) continue;
- paths.push_back(currentPath);
- }
- if (paths.isEmpty()) {
- payloadBlock = HTML_PAYLOAD_ERROR;
- replaceTag(payloadBlock, "ERROR_TITLE", "Not found");
- replaceTag(payloadBlock, "ERROR_TEXT", "");
- }
- else {
- std::map<QString, QStringList> matchedPathsAndMessages;
- if (not month.isEmpty()) {
- for (const auto& path: paths) {
- if (not QRegularExpression("^.*[0-9]{2}\\.txt$").match(path).hasMatch()) continue;
- QFile file(path);
- if (not file.open(QIODevice::ReadOnly)) {
- consoleLog("Error! I can't open log file " + fsPath.path());
- continue;
- }
- QString buffer {file.readLine()};
- while (not buffer.isEmpty()) {
- removeBrakelineSymbols(buffer);
- bool finded = false;
- if (rgxIsValid) {
- if (QRegularExpression(searchRequest, QRegularExpression::CaseInsensitiveOption).match(buffer).hasMatch()) {
- finded = true;
- }
- } else {
- if (buffer.contains(searchRequest, Qt::CaseInsensitive)) {
- finded = true;
- }
- }
- if (finded) {
- std::pair<QString, QString> rawMessage = splitUserNameAndMessage(buffer);
- if (rawMessage.first.isEmpty() or rawMessage.second.isEmpty()) {
- buffer = file.readLine();
- continue;
- }
- counter++;
- QString message = HTML_PAYLOAD_LIST_CHAT_MESSAGE;
- for (const auto &user: m_onlineUsers[originalServerName][originalChannelName]) {
- if (QRegularExpression("^.?"+rawMessage.first+"$").match(user).hasMatch()) {
- message.replace("<div class=\"main_payload__chat_username\">",
- "<div class=\"main_payload__chat_username\" style=\"color: green\">");
- break;
- }
- }
- replaceTag(message, "USERNAME", rawMessage.first);
- replaceTag(message, "MESSAGE_TEXT", rawMessage.second);
- matchedPathsAndMessages[path].push_back(message);
- }
- buffer = file.readLine();
- }
- file.close();
- }
- }
- else if (month.isEmpty() and not year.isEmpty()){
- for (const auto &p: paths) {
- QStringList slavePaths;
- QDirIterator it(p);
- while (it.hasNext()) {
- QString fileName = it.next();
- if (fileName.endsWith(".") or fileName.endsWith("..")) continue;
- if (not QRegularExpression("\\.txt$").match(fileName).hasMatch()) continue;
- slavePaths.push_back(fileName);
- }
- for (const auto &path: slavePaths) {
- if (not QRegularExpression("^.*[0-9]{2}\\.txt$").match(path).hasMatch()) continue;
- QFile file(path);
- if (not file.open(QIODevice::ReadOnly)) {
- consoleLog("Error! I can't open log file " + fsPath.path());
- continue;
- }
- QString buffer {file.readLine()};
- while (not buffer.isEmpty()) {
- removeBrakelineSymbols(buffer);
- bool finded = false;
- if (rgxIsValid) {
- if (QRegularExpression(searchRequest, QRegularExpression::CaseInsensitiveOption).match(buffer).hasMatch()) {
- finded = true;
- }
- } else {
- if (buffer.contains(searchRequest, Qt::CaseInsensitive)) {
- finded = true;
- }
- }
- if (finded) {
- std::pair<QString, QString> rawMessage = splitUserNameAndMessage(buffer);
- if (rawMessage.first.isEmpty() or rawMessage.second.isEmpty()) {
- buffer = file.readLine();
- continue;
- }
- counter++;
- QString message = HTML_PAYLOAD_LIST_CHAT_MESSAGE;
- for (const auto &user: m_onlineUsers[originalServerName][originalChannelName]) {
- if (QRegularExpression("^.?"+rawMessage.first+"$").match(user).hasMatch()) {
- message.replace("<div class=\"main_payload__chat_username\">",
- "<div class=\"main_payload__chat_username\" style=\"color: green\">");
- break;
- }
- }
- replaceTag(message, "USERNAME", rawMessage.first);
- replaceTag(message, "MESSAGE_TEXT", rawMessage.second);
- matchedPathsAndMessages[path].push_back(message);
- }
- buffer = file.readLine();
- }
- file.close();
- }
- }
- }
- else { // root directory
- QStringList yearPaths;
- for (const auto& p: paths) {
- if (not QRegularExpression("/2[0-9]{3}$").match(p).hasMatch()) continue;
- yearPaths.push_back(p);
- }
- /* If you are reading this code, maybe you are crying now.
- * Sorry me, man (woman/fagot/etc). Maybe I'll refactor this hell in the future.
- * acetone.
- */
- QStringList fileNameS;
- for (const auto& p: yearPaths) {
- QStringList slavePaths;
- QDirIterator it(p);
- while (it.hasNext()) {
- QString folderName = it.next();
- if (folderName.endsWith(".") or folderName.endsWith("..")) continue;
- if (not QRegularExpression("/[0-9]{2}$").match(folderName).hasMatch()) continue;
- slavePaths.push_back(folderName);
- }
- for (const auto &path: slavePaths) {
- QDirIterator itMonth(path);
- while (itMonth.hasNext()) {
- QString fileName = itMonth.next();
- if (fileName.endsWith(".") or fileName.endsWith("..")) continue;
- if (not QRegularExpression("^.*[0-9]{2}\\.txt$").match(fileName).hasMatch()) continue;
- fileNameS.push_back(fileName);
- }
- }
- }
- for (const auto& path: fileNameS) {
- QFile file(path);
- if (not file.open(QIODevice::ReadOnly)) {
- consoleLog("Error! I can't open log file " + fsPath.path());
- continue;
- }
- QString buffer {file.readLine()};
- while (not buffer.isEmpty()) {
- removeBrakelineSymbols(buffer);
- bool finded = false;
- if (rgxIsValid) {
- if (QRegularExpression(searchRequest, QRegularExpression::CaseInsensitiveOption).match(buffer).hasMatch()) {
- finded = true;
- }
- } else {
- if (buffer.contains(searchRequest, Qt::CaseInsensitive)) {
- finded = true;
- }
- }
- if (finded) {
- std::pair<QString, QString> rawMessage = splitUserNameAndMessage(buffer);
- if (rawMessage.first.isEmpty() or rawMessage.second.isEmpty()) {
- buffer = file.readLine();
- continue;
- }
- counter++;
- QString message = HTML_PAYLOAD_LIST_CHAT_MESSAGE;
- for (const auto &user: m_onlineUsers[originalServerName][originalChannelName]) {
- if (QRegularExpression("^.?"+rawMessage.first+"$").match(user).hasMatch()) {
- message.replace("<div class=\"main_payload__chat_username\">",
- "<div class=\"main_payload__chat_username\" style=\"color: green\">");
- break;
- }
- }
- replaceTag(message, "USERNAME", rawMessage.first);
- replaceTag(message, "MESSAGE_TEXT", rawMessage.second);
- matchedPathsAndMessages[path].push_back(message);
- }
- buffer = file.readLine();
- }
- file.close();
- }
- }
- if (matchedPathsAndMessages.empty()) {
- payloadBlock = HTML_PAYLOAD_ERROR;
- replaceTag(payloadBlock, "ERROR_TITLE", "Not found");
- replaceTag(payloadBlock, "ERROR_TEXT", "");
- }
- else {
- QStringList findedPaths;
- for (const auto& fp: matchedPathsAndMessages) {
- findedPaths << fp.first;
- }
- std::sort(findedPaths.begin(), findedPaths.end());
- for (auto& link: findedPaths) {
- QString logFolder {m_logFolder};
- logFolder.remove(QRegularExpression(".$"));
- QStringList& messages = matchedPathsAndMessages[link];
- link.remove(logFolder);
- link.remove(QRegularExpression("\\.txt$"));
- QString finded = HTML_PAYLOAD_LIST_POINT_MESSAGE;
- finded.replace("class=\"main_payload__block\"", "class=\"main_payload__block\" style=\"background: #b6c7d6\"");
- replaceTag(finded, "POINT_LINK", link);
- link.remove(QRegularExpression("^.*"+channel));
- replaceTag(finded, "POINT_CONTENT", link);
- payloadBlock += finded;
- for(const auto& m: messages) {
- payloadBlock += m;
- }
- payloadBlock += " \n";
- }
- }
- }
- middlePath += " " + searchRequest + " ";
- if (rgxIsValid) middlePath += "rgx";
- middlePath += "(" + QString::number(counter) + ")";
- }
- // Plain log explorer
- else {
- if (year.isEmpty()) { // /
- QStringList folderNameS;
- QDirIterator it(fsPath.path());
- while (it.hasNext()) {
- QString folderName = it.next();
- if (folderName.endsWith(".") or folderName.endsWith("..")) continue;
- while(folderName.contains('/')) {
- folderName.remove(QRegularExpression("^.*/"));
- }
- folderName.remove(QRegularExpression("\\.txt$"));
- folderNameS << folderName;
- }
- if (not folderNameS.isEmpty()) {
- std::sort(folderNameS.begin(), folderNameS.end());
- for (const auto &f: folderNameS) {
- QString onePoint = HTML_PAYLOAD_LIST_POINT_FOLDER;
- replaceTag(onePoint, "POINT_CONTENT", f);
- replaceTag(onePoint, "POINT_LINK", "/"+server+"/"+channel+"/"+f);
- payloadBlock += onePoint;
- }
- }
- }
- else if (not year.isEmpty() and month.isEmpty()) { // /YYYY
- QStringList folderNameS;
- QDirIterator it(fsPath.path());
- while (it.hasNext()) {
- QString folderName = it.next();
- if (folderName.endsWith(".") or folderName.endsWith("..")) continue;
- while(folderName.contains('/')) {
- folderName.remove(QRegularExpression("^.*/"));
- }
- folderName.remove(QRegularExpression("\\.txt$"));
- folderNameS << folderName;
- }
- if (not folderNameS.isEmpty()) {
- std::sort(folderNameS.begin(), folderNameS.end());
- for (const auto &f: folderNameS) {
- QString onePoint = HTML_PAYLOAD_LIST_POINT_FOLDER;
- replaceTag(onePoint, "POINT_CONTENT", f);
- replaceTag(onePoint, "POINT_LINK", "/"+server+"/"+channel+"/"+year+"/"+f);
- payloadBlock += onePoint;
- }
- }
- }
- else if (not month.isEmpty() and day.isEmpty()) { // /YYYY/MM
- QStringList fileNameS;
- QDirIterator it(fsPath.path());
- while (it.hasNext()) {
- QString fileName = it.next();
- if (fileName.endsWith(".") or fileName.endsWith("..")) continue; // QDir::NoDotAndNoDotDot not works!
- while(fileName.contains('/')) {
- fileName.remove(QRegularExpression("^.*/"));
- }
- fileName.remove(QRegularExpression("\\.txt$"));
- fileNameS << fileName;
- }
- if (not fileNameS.isEmpty()) {
- std::sort(fileNameS.begin(), fileNameS.end());
- for (const auto &a: fileNameS) {
- QString onePoint = HTML_PAYLOAD_LIST_POINT_MESSAGE;
- replaceTag(onePoint, "POINT_CONTENT", a);
- replaceTag(onePoint, "POINT_LINK", "/"+server+"/"+channel+"/"+year+"/"+month+"/"+a);
- payloadBlock += onePoint;
- }
- }
- }
- else if (not day.isEmpty()) { // /YYYY/MM/dd
- QFile file(fsPath.path()+global::slash+day+".txt");
- if (not file.open(QIODevice::ReadOnly)) {
- consoleLog("Error! I can't open log file " + fsPath.path());
- payloadBlock = HTML_PAYLOAD_ERROR;
- replaceTag(payloadBlock, "ERROR_TITLE", "Internal error");
- replaceTag(payloadBlock, "ERROR_TEXT", "Requested log file openning failed");
- }
- else {
- QString buffer = file.readLine();
- while (not buffer.isEmpty()) {
- removeBrakelineSymbols(buffer);
- std::pair<QString, QString> rawMessage = splitUserNameAndMessage(buffer);
- if (rawMessage.first.isEmpty() or rawMessage.second.isEmpty()) {
- buffer = file.readLine();
- continue;
- }
- QString message = HTML_PAYLOAD_LIST_CHAT_MESSAGE;
- for (const auto &user: m_onlineUsers[originalServerName][originalChannelName]) {
- if (QRegularExpression("^.?"+rawMessage.first+"$").match(user).hasMatch()) {
- message.replace("<div class=\"main_payload__chat_username\">",
- "<div class=\"main_payload__chat_username\" style=\"color: green\">");
- break;
- }
- }
- replaceTag(message, "USERNAME", rawMessage.first);
- replaceTag(message, "MESSAGE_TEXT", rawMessage.second);
- payloadBlock += message;
- buffer = file.readLine();
- }
- file.close();
- }
- }
- if (payloadBlock.isEmpty()) {
- payloadBlock = HTML_PAYLOAD_ERROR;
- replaceTag(payloadBlock, "ERROR_TITLE", "Empty");
- replaceTag(payloadBlock, "ERROR_TEXT", "No logs found for this channel");
- }
- }
- replaceTag(page, "MIDDLE_PATH", middlePath);
- replaceTag(page, "PAYLOAD_BLOCK", payloadBlock);
- //// Footer
- replaceTag(page, "VERSION", IRCABOT_VERSION);
- replaceTag(page, "COPYRIGHT_YEAR", COPYRIGHT_YEAR);
- QString mainHeader = HEADER_HTML;
- replaceTag(mainHeader, "SIZE", QString::number(QByteArray(page.toUtf8()).size()));
- if (socket->isOpen()) {
- socket->write(mainHeader.toUtf8());
- if (not isHeadRequest) socket->write(page.toUtf8());
- }
- }
|