summaryrefslogtreecommitdiffstats
path: root/lex.cgi
diff options
context:
space:
mode:
Diffstat (limited to 'lex.cgi')
-rwxr-xr-xlex.cgi75
1 files changed, 75 insertions, 0 deletions
diff --git a/lex.cgi b/lex.cgi
new file mode 100755
index 0000000..8ba7d37
--- /dev/null
+++ b/lex.cgi
@@ -0,0 +1,75 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+use File::Path qw(make_path);
+use Time::HiRes qw(time);
+use OpenBSD::Pledge;
+use OpenBSD::Unveil;
+
+unveil("/tmp", "rwc") or die "unveil /tmp failed: $!";
+unveil() or die "unveil lock failed: $!";
+
+pledge('stdio rpath wpath cpath') or die "pledge failed: $!";
+
+my $content_type = $ENV{'CONTENT_TYPE'} || '';
+my $content_length = $ENV{'CONTENT_LENGTH'} // 0;
+
+if ($content_length > 0) {
+ binmode(STDIN);
+
+ my $raw_data = '';
+ read(STDIN, $raw_data, $content_length);
+
+ # Extract boundary string from CONTENT_TYPE or raw payload
+ my $boundary;
+ if ($content_type =~ /boundary="?([^";\s]+)"?/i) {
+ $boundary = $1;
+ } elsif ($raw_data =~ /^--([^\r\n]+)/) {
+ $boundary = $1;
+ }
+
+ my %params;
+ if ($boundary) {
+ my @parts = split(/--\Q$boundary\E(?:--)?\r?\n/, $raw_data);
+
+ for my $part (@parts) {
+ next unless $part =~ /\S/;
+
+ my ($header_block, $body_block) = split(/\r?\n\r?\n/, $part, 2);
+ next unless defined $header_block && defined $body_block;
+
+ $body_block =~ s/\r?\n$//;
+
+ if ($header_block =~ /Content-Disposition:[^\n]*?\bname="([^"]+)"/i) {
+ my $name = $1;
+ $params{$name} //= $body_block;
+ }
+ }
+ }
+
+ my $mail_body = $params{'stripped-text'} // $params{'body-plain'} // '';
+
+ if ($mail_body ne '') {
+ my $dir = "/tmp/lex";
+ unless (-d $dir) {
+ make_path($dir);
+ }
+
+ my $msg_id = sprintf("msg_%.6f_$$", time());
+ my $filename = "${dir}/${msg_id}.txt";
+
+ if (open(my $fh, '>', $filename)) {
+ print $fh $mail_body;
+ close($fh);
+ } else {
+ warn "Failed to write $filename: $!";
+ }
+ }
+}
+
+print "Status: 200 OK\r\n";
+print "Content-Type: text/plain; charset=utf-8\r\n\r\n";
+print "OK\n";
+exit 0;
+