From 4650d9945ada92bbdd5fd3fd3b29a7fd568b2883 Mon Sep 17 00:00:00 2001 From: Dominik Meyer Date: Fri, 7 Feb 2025 11:00:38 +0100 Subject: [PATCH] feat: provide queue information for local recipient --- federationhq_rcpt | 75 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 72 insertions(+), 3 deletions(-) diff --git a/federationhq_rcpt b/federationhq_rcpt index d82919a..d0716fd 100644 --- a/federationhq_rcpt +++ b/federationhq_rcpt @@ -27,7 +27,10 @@ sub createStatements $self->{rcpt_sth} = $self->{dbh}->prepare("select username from email_address where alias=? and domain=?"); - $self->{fetch_all_sth} = $self->{dbh}->prepare("select username from email_address where domain=? and isFetchAll=1"); + $self->{fetch_all_sth} = $self->{dbh}->prepare("select username,dovecot_server from email_address where domain=? and isFetchAll=1"); + + $self->{fetch_dovecot_details_sth} = $self->{dbh}->prepare("select hostname, port from dovecot_server where name=?"); + } sub connect @@ -45,6 +48,13 @@ sub connect } +sub disconnect +{ + my $self = shift; + + $self->{dbh}->disconnect() if ($self->{dbh}); +} + sub createDSN { my $self = shift; @@ -63,6 +73,47 @@ sub createDSN $self->log(LOGDEBUG, "created DSN " . $self->{dsn}); } +sub updateTransactionWithRecipientInfo +{ + my $self = shift; + my $transaction = shift + my $sth = shift; + + return unless $sth->rows == 1; + + my $row = $th->fetchrow_hashref; + my $dovecot_server = $row->{dovecot_server}; + my $username = $row->{username}; + + my $result = $self->{fetch_dovecot_details_sth}->execute($dovecot_server); + if (!$result) + { + $self->log(LOGERROR, "Failed to fetch dovecot server information for user " . $username . " and dovecot server " . $dovecot_server ); + return 0; + } + + if ($self->{fetch_dovecot_details_sth}->rows == 0) + { + $self->log(LOGERROR, "no dovecot server information found for user " . $username . " and dovecot server " . $dovecot_server ); + return 0; + } + + my $row = $self->{fetch_dovecot_details_sth}->fetchrow_hashref(); + + my $hostname = $row->{hostname}; + my $port = $row->{port}; + + $transaction->notes("queue", "lmtp://$hostname:$port"); + $self->log(LOGNOTICE, "Setting LMTP server to dovecot on $hostname:$port for user: $username"); + + return 1; +} + +sub hook_quit { + my ($self, $transaction) = @_; + + $self->disconnect(); +} sub hook_rcpt { my ($self, $transaction, $recipient) = @_; @@ -75,12 +126,30 @@ sub hook_rcpt { $self->createStatements(); my $result = $self->{rcpt_sth}->execute($recipient->user, $recipient->host); - - if ($self->{rcpt_sth}->rows > 0) + if (!$result) + { + $self->log(LOGERROR, "Failed to fetch recipient information from the database"); return DECLINED; + } + + + if ($self->{rcpt_sth}->rows == 1) { $self->log(LOGDEBUG, " found recipient in database"); + my $ret = $self->updateTransactionWithRecipientInfo($transaction, $self->{rcpt_sth}); + + if (!$ret) + { + $self->log(LOGERROR, "Failed to update transaction with recipient information"); + return DENYSOFT; + } + return OK; } + elsif ($self->{rcpt_sth}->rows > 1) + { + $self->log(LOGERROR,"found multiple users for same recipient in database. Something wrong with database? (" . $recipient->user . '@' . $recipient->host . ")" ); + return DENYSOFT; + } $result = $self->{fetch_all_sth}->execute($recipient->host);