diff --git a/frontend.pl b/frontend.pm
similarity index 66%
rename from frontend.pl
rename to frontend.pm
index 3e8b3b4..36a9b50 100644
--- a/frontend.pl
+++ b/frontend.pm
@@ -14,9 +14,12 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
+package frontend;
+
use IO::Socket;
use File::Spec;
use Time::Piece;
+use DBI;
use lib ".";
use configuration;
@@ -50,6 +53,59 @@ sub stringToHTTPMethod {
}
}
+use constant {
+ PPATH_URL => 0,
+ PPATH_GET_KEY => 1,
+ PPATH_GET_VALUE => 2
+};
+sub parsePath {
+ my $aPath = $_[0];
+
+ my $pathLength = length($aPath);
+ my $state = PPATH_URL;
+ my $currentString = "";
+ my $currentString2 = "";
+ my %output;
+ foreach my $i (0..$pathLength-1) {
+ my $char = substr($aPath, $i, 1);
+ given($state) {
+ when(PPATH_URL) {
+ if($char eq "?") {
+ $output{"url"} = $currentString;
+ $currentString = "";
+ $state = PPATH_GET_KEY;
+ next;
+ }
+ $currentString.=$char;
+ if($i==$pathLength-1) {
+ $output{"url"} = $currentString;
+ }
+ }
+ when(PPATH_GET_KEY) {
+ if($char eq "=") {
+ $state = PPATH_GET_VALUE;
+ next;
+ }
+ $currentString.=$char;
+ }
+ when(PPATH_GET_VALUE) {
+ if($char eq "&") {
+ $state = PPATH_GET_KEY;
+ $output{"parameters"}{$currentString} = $currentString2;
+ $currentString = "";
+ $currentString2 = "";
+ next;
+ }
+ $currentString2.=$char;
+ if($i==$pathLength-1) {
+ $output{"parameters"}{$currentString} = $currentString2;
+ }
+ }
+ }
+ }
+ return %output;
+}
+
use constant {
PHTTP_METHOD => 0,
PHTTP_PATH => 1,
@@ -80,7 +136,7 @@ sub parseHTTPRequest {
}
when(PHTTP_PATH) {
if($char eq " ") {
- $output{"path"} = $currentString;
+ $output{"path"} = { parsePath($currentString) };
$currentString = "";
$state = PHTTP_VERSION;
next;
@@ -153,6 +209,18 @@ sub sendNotFound {
$aClient->send($response);
}
+sub sendBadRequest {
+ my $aClient = $_[0];
+ my $aMessage = $_[1];
+
+ my $content = "
400 Bad Request
irclogger_web
Error: $aMessage";
+ my $response = getBaseResponse(400, "Bad Request");
+ $response.="Content-Type: text/html, charset=utf-8\r\n";
+ $response.="Content-Length: ".length($content)."\r\n\r\n";
+ $response.=$content;
+ $aClient->send($response);
+}
+
use constant {
PREPROCESSOR_STATE_TEXT => 0,
PREPROCESSOR_STATE_VAR => 1,
@@ -208,7 +276,7 @@ sub preprocessHTML {
if($nextChar eq "]") {
$index++;
if(open(my $file, "<", $currentString)) {
- $output.=readFullFile($file);
+ $output.=preprocessHTML(readFullFile($file), $aVariables);
close($file);
}
else {
@@ -242,6 +310,7 @@ sub sendTemplate {
my $response = getBaseResponse(200, "OK");
$response.="Content-Length: $length\r\n\r\n";
$response.=$content;
+ print("$response\n");
$aClient->send($response);
}
@@ -249,10 +318,54 @@ sub handlePath {
my $aClient = $_[0];
my $aPath = $_[1];
my $aRequest = $_[2];
+ my $aConnection = $_[3];
given($aPath) {
when("/") {
- sendTemplate("templates/index.html", $aClient, {"var"=>"value"});
+ my $query = $aConnection->prepare(qq(select channels.id, channels.name, servers.name from channels inner join servers on channels.server_id=servers.id where channels.public=1;));
+ $query->execute();
+ my $table = "";
+ while(my @row = $query->fetchrow_array()) {
+ my $channelID = $row[0];
+ my $channelName = $row[1];
+ my $serverName = $row[2];
+
+ $table.="$channelName | $serverName |
";
+ }
+ sendTemplate("templates/index.html", $aClient, {"publicChannels"=>$table});
+ return 1;
+ }
+ when("/view_logs") {
+ my $channelID = $aRequest->{"path"}{"parameters"}{"channel"};
+ if(!defined($channelID)) {
+ sendBadRequest($aClient, "view_log requires channel URL parameter");
+ return 1;
+ }
+
+ my $query = $aConnection->prepare(qq(select channels.name, servers.name from channels inner join servers on channels.server_id=servers.id where channels.id=?;));
+ $query->execute($channelID);
+ my @row = $query->fetchrow_array();
+ if(scalar(@row)==0) {
+ sendBadRequest($aClient, "Unknown channel with ID $channelID");
+ return 1;
+ }
+ my $channelName = $row[0];
+ my $serverName = $row[1];
+ my $logsPath = "logs/".$serverName."/".$channelName;
+
+ my $result = opendir(my $folder, $logsPath);
+ if(!$result) {
+ sendBadRequest($aClient, "Channel $channelName on $serverName doesn't have any logs");
+ return 1;
+ }
+ my @entries = grep(!/^\.\.?$/, readdir($folder));
+
+ my $table = "";
+ foreach my $entry (@entries) {
+ $table.="$entry |
";
+ }
+
+ sendTemplate("templates/view_logs.html", $aClient, {"channel"=>$channelName, "server"=>$serverName, "logs"=>$table});
return 1;
}
}
@@ -262,6 +375,7 @@ sub handlePath {
sub sendResponse {
my $aClient = $_[0];
my $aRequest = $_[1];
+ my $aConnection = $_[2];
if($aRequest->{"version"} ne "HTTP/1.1") {
sendNotImplemented($aClient);
@@ -270,11 +384,11 @@ sub sendResponse {
given($aRequest->{"method"}) {
when(HTTP_METHOD_GET) {
- my $path = File::Spec->canonpath($aRequest->{"path"});
+ my $path = File::Spec->canonpath($aRequest->{"path"}{"url"});
if($path eq "/index.html" || $path eq "/index.htm") {
$path = "/";
}
- if(handlePath($aClient, $path, $aRequest)) {
+ if(handlePath($aClient, $path, $aRequest, $aConnection)) {
return;
}
my $filePath = "static".$path;
@@ -300,6 +414,7 @@ sub sendResponse {
}
sub httpServerWorker {
+ my $db = DBI->connect("DBI:SQLite:dbname=$configuration::database", "", "", {RaiseError=>1});
my $server = new IO::Socket::INET(LocalHost=>"localhost", LocalPort=>$configuration::httpServerPort, Proto=>"tcp", Listen=>1, Reuse=>1);
if(!$server) {
print("Failed to open HTTP server on port $configuration::httpServerPort\n");
@@ -314,9 +429,9 @@ sub httpServerWorker {
next;
}
my %request = parseHTTPRequest($buffer);
- sendResponse($client, \%request);
+ sendResponse($client, \%request, $db);
close($client);
}
}
-httpServerWorker();
+1;
diff --git a/logger.pl b/logger.pl
index d552db7..a36b5ea 100644
--- a/logger.pl
+++ b/logger.pl
@@ -18,7 +18,6 @@ use IO::Socket;
use List::Util;
use Time::Piece;
use File::Path;
-use DBI;
use threads;
use lib ".";
diff --git a/main.pl b/main.pl
new file mode 100644
index 0000000..4f618a9
--- /dev/null
+++ b/main.pl
@@ -0,0 +1,26 @@
+# irclogger_web
+# Copyright (C) 2023 mrkubax10
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+use lib ".";
+use frontend;
+
+use threads;
+
+use strict;
+use warnings;
+
+my $frontendThread = threads->create("frontend::httpServerWorker");
+$frontendThread->join();
diff --git a/templates/index.html b/templates/index.html
index b12ef73..54b535b 100644
--- a/templates/index.html
+++ b/templates/index.html
@@ -1 +1,13 @@
-{{var}}
+
+
+
+ irclogger_web
+
+
+ Channel list
+
+ Channel | Network |
+ {{publicChannels}}
+
+
+
diff --git a/templates/view_logs.html b/templates/view_logs.html
new file mode 100644
index 0000000..b2556a9
--- /dev/null
+++ b/templates/view_logs.html
@@ -0,0 +1,12 @@
+
+
+
+ Logs for {{channel}} at {{server}}
+
+
+
+
+