summaryrefslogtreecommitdiff
path: root/lib/JWebmail/Model/ReadMails
diff options
context:
space:
mode:
Diffstat (limited to 'lib/JWebmail/Model/ReadMails')
-rw-r--r--lib/JWebmail/Model/ReadMails/MockJSON.pm7
-rw-r--r--lib/JWebmail/Model/ReadMails/MockMaildir.pm34
-rw-r--r--lib/JWebmail/Model/ReadMails/QMailAuthuser.pm76
-rw-r--r--lib/JWebmail/Model/ReadMails/Role.pm1
4 files changed, 76 insertions, 42 deletions
diff --git a/lib/JWebmail/Model/ReadMails/MockJSON.pm b/lib/JWebmail/Model/ReadMails/MockJSON.pm
index 6b3b6d2..e429d53 100644
--- a/lib/JWebmail/Model/ReadMails/MockJSON.pm
+++ b/lib/JWebmail/Model/ReadMails/MockJSON.pm
@@ -109,6 +109,13 @@ sub show {
sub folders { ['', qw(cur test devel debug)] }
+sub raw {
+ my $self = shift;
+ my ($auth, $folder, $mid, $path) = @_;
+
+ ...
+}
+
sub search { ... }
sub move { ... }
diff --git a/lib/JWebmail/Model/ReadMails/MockMaildir.pm b/lib/JWebmail/Model/ReadMails/MockMaildir.pm
index 9b1bb29..de5c745 100644
--- a/lib/JWebmail/Model/ReadMails/MockMaildir.pm
+++ b/lib/JWebmail/Model/ReadMails/MockMaildir.pm
@@ -14,12 +14,12 @@ use constant {
has user => sub { $ENV{USER} };
has maildir => 't/';
-has extractor => 'perl';
+has extractor => 'python';
our %EXTRACTORS = (
- perl => 'perl script/qmauth.pl',
- python => 'python script/qmauth.py',
- rust => 'extract/target/debug/jwebmail-extract',
+ perl => 'script/qmauth.pl',
+ python => 'script/qmauth.py',
+ rust => 'bin/jwebmail-extract',
);
@@ -51,33 +51,17 @@ sub verify_user {
}
}
-sub build_and_run {
+sub start_qmauth {
my $self = shift;
my ($auth, $mode, $args) = @_;
my $mail_user = 'maildir';
- my $exec = $EXTRACTORS{$self->extractor} . ' ' . join(' ', map { my $x = s/(['\\])/\\$1/gr; "'$x'" } ($self->maildir, $self->user, $mail_user, $mode, @$args));
+ my @exec = ($EXTRACTORS{$self->extractor}, $self->maildir, $self->user, $mail_user, $mode, @$args);
- my $pid = open(my $reader, '-|', $exec)
- or die 'failed to create subprocess';
+ my $pid = open(my $reader, '-|', @exec)
+ or die "failed to create subprocess: $!";
- my $input = <$reader>;
-
- waitpid($pid, 0);
- my $rc = $? >> 8;
-
- my $resp;
- if ($rc == 3 || $rc == 0) {
- eval { $resp = decode_json $input; };
- if (my $err = $@) { $resp = {error => "decoding error '$err'"}; $rc ||= 1; };
- }
- elsif ($rc) {
- $resp = {error => "qmauth returned code: $rc"};
- }
-
- local $" = ', ';
- die "error @{[%$resp]}" if $rc;
- return $resp;
+ return $pid, $reader;
}
diff --git a/lib/JWebmail/Model/ReadMails/QMailAuthuser.pm b/lib/JWebmail/Model/ReadMails/QMailAuthuser.pm
index a61cf01..e16e2f2 100644
--- a/lib/JWebmail/Model/ReadMails/QMailAuthuser.pm
+++ b/lib/JWebmail/Model/ReadMails/QMailAuthuser.pm
@@ -36,7 +36,7 @@ package JWebmail::Model::ReadMails::QMailAuthuser::Error {
sub to_string {
my $self = shift;
- my $verbose = shift;
+ my $verbose = 1; #shift;
if ($verbose && defined $self->{data}) {
my $errstr = Data::Dumper->new([$self->{data}])->Terse(1)->Indent(0)->Quotekeys(0)->Dump;
@@ -139,6 +139,13 @@ sub show {
return $self->build_and_run($auth, 'read', [$folder, $mid]);
}
+sub raw {
+ my $self = shift;
+ my ($auth, $folder, $mid, $path) = @_;
+
+ return $self->build_and_run($auth, 'raw', [$folder, $mid, $path//'']);
+}
+
sub search {
my $self = shift;
my ($auth, $pattern, $folder) = @_;
@@ -175,34 +182,69 @@ sub build_arg {
return $self->{qmail_dir}.'/bin/qmail-authuser'
. $self->{prefix} . ' '
- . join(' ', map { my $x = s/(['\\])/\\$1/gr; "'$x'" } ($self->{prog}, $self->{maildir}, $self->{user}, $user_name, $mode, @{$args || []}))
+ . join(' ', map { my $x = s/(['\\])/\\$1/gr; "'$x'" } ($self->{prog}, $self->{maildir}, $self->{user}, $user_name, $mode, @$args))
. ' 3<&0'
. ' 2>>'.$self->{logfile};
}
-sub execute {
- my $_self = shift;
- my ($auth, $exec) = @_;
+sub start_qmauth {
+ my $self = shift;
+ my ($auth, $mode, $args) = @_;
+
+ my $exec = $self->build_arg($auth->{user}, $mode, $args);
my $pid = open2(my $reader, my $writer, $exec)
- or die 'failed to create subprocess';
+ or die "failed to create subprocess: $!";
my $challenge = $auth->{challenge} || '';
$writer->print("$auth->{user}\0$auth->{password}\0$challenge\0")
- or die 'pipe wite failed';
+ or die "pipe wite failed: $!";
close $writer
- or die 'closing write pipe failed';
+ or die "closing write pipe failed: $!";
+
+ return $pid, $reader;
+}
+
+sub read_qmauth {
+ my $_self = shift;
+ my ($pid, $reader) = @_;
- #binmode $reader, ':encoding(UTF-8)';
my $input = <$reader>;
- close $reader
- or die 'closing read pipe failed';
- waitpid $pid, 0;
- my $rc = $? >> 8;
+ my $rc;
+ if (eof $reader) {
+ # for regular open
+ close $reader
+ or warn "closing read pipe failed: $!";
+ $rc = $? >> 8;
+
+ # for IPC::Open2
+ if (waitpid($pid, 0) == $pid) {
+ $rc = $? >> 8;
+ }
+ }
my $resp;
- if ($rc == 3 || $rc == 0) {
+ if (!defined $rc) {
+ my ($r, $e);
+ eval { $r = decode_json $input; 1 }
+ or do {
+ $rc = 6;
+ $e = "$@";
+ };
+ $reader->read(my $buf, 4 * 1024**2);
+ if (!eof $reader) {
+ die 'mailpart too large (>4MB)'
+ }
+ close $reader;
+ $resp = {
+ head => $r,
+ body => $buf,
+ rc => $rc,
+ e => $e,
+ };
+ }
+ elsif ($rc == 3 || $rc == 0) {
eval { $resp = decode_json $input if $input; 1 }
or do {
$resp = {
@@ -214,7 +256,7 @@ sub execute {
$rc = 3;
};
}
- elsif ($rc) {
+ else {
$resp = {
info => "got unsuccessful return code by qmail-authuser",
return_code => $rc,
@@ -229,8 +271,8 @@ sub build_and_run {
my $self = shift;
my ($auth, $mode, $args) = @_;
- my $exec = $self->build_arg($auth->{user}, $mode, $args);
- my ($resp, $rc) = $self->execute($auth, $exec);
+ my @exec = $self->start_qmauth($auth, $mode, $args||[]);
+ my ($resp, $rc) = $self->read_qmauth(@exec);
if ($rc) {
JWebmail::Model::ReadMails::QMailAuthuser::Error->throw(
diff --git a/lib/JWebmail/Model/ReadMails/Role.pm b/lib/JWebmail/Model/ReadMails/Role.pm
index d6fa1e5..ae113de 100644
--- a/lib/JWebmail/Model/ReadMails/Role.pm
+++ b/lib/JWebmail/Model/ReadMails/Role.pm
@@ -46,6 +46,7 @@ my @methods = (
'read_headers_for', # auth:Auth, *folder='', *start=0, *end=24, *sort='date' -> ^ :hashref
'search', # auth:Auth, pattern, folder -> ^ :hashref
'show', # auth:Auth, mid -> ^ :hashref
+ 'raw',
);
requires(@methods);