From 81e7c2a04bb26334680d7e30401491e79658e379 Mon Sep 17 00:00:00 2001 From: Ludovic Cartier Date: Fri, 2 Jan 2026 16:02:55 +0100 Subject: [PATCH] add pfq (custom queue TUI) --- files/pfq | 78 +++++++++++++++++++++++++++++++++++++++++++++ tasks/configure.yml | 7 ++++ tasks/install.yml | 1 + 3 files changed, 86 insertions(+) create mode 100755 files/pfq diff --git a/files/pfq b/files/pfq new file mode 100755 index 0000000..1c5d690 --- /dev/null +++ b/files/pfq @@ -0,0 +1,78 @@ +#!/bin/bash + +# 1. Root privileges check +if [ "$EUID" -ne 0 ]; then + echo "Error: This script must be run as root." + exit 1 +fi + +# Binary paths +POSTSUPER="/usr/sbin/postsuper" +POSTQUEUE="/usr/sbin/postqueue" +POSTCAT="/usr/sbin/postcat" + +# 2. Column width definitions +W_ID=12 +W_SIZE=8 +W_DATE=16 +W_SENDER=30 + +# 3. Enhanced functions +# Function to list mails (one line per mail) +list_mails() { + $POSTQUEUE -p | awk -v w_id="$W_ID" -v w_size="$W_SIZE" -v w_date="$W_DATE" -v w_send="$W_SENDER" ' + BEGIN { RS = "" } + $1 ~ /^[0-9A-Fa-f]+[*!]?$/ { + id = $1; sub(/[*!]/, "", id); + size = $2; + date = $4" "$5" "$6; + sender = $7; + reason = "N/A"; + if (match($0, /\(.*\)/)) { + reason = substr($0, RSTART+1, RLENGTH-2); + gsub(/\n/, " ", reason); # Truncate newlines for the list + } + printf " %-*s | %*s | %-*s | %-*s | %s\n", w_id, id, w_size, size, w_date, date, w_send, sender, reason + }' +} + +# Function to show full reason + mail content in preview +show_detail() { + local id=$1 + echo -e "\033[1;33m--- FULL DELIVERY FAILURE REASON ---\033[0m" + $POSTQUEUE -p | awk -v id="$id" 'BEGIN {RS=""} $1 ~ id {print $0}' | grep -v "^$id" | sed 's/^[[:space:]]*//' + echo "" + echo -e "\033[1;34m--- MAIL CONTENT ---\033[0m" + $POSTCAT -q "$id" +} + +export -f list_mails show_detail +export POSTSUPER POSTQUEUE POSTCAT + +# Internal calls for fzf +if [ "$1" == "--list" ]; then list_mails; exit 0; fi +if [ "$1" == "--detail" ]; then show_detail "$2"; exit 0; fi + +# 4. Interface Configuration +HEADER=$(printf " %-*s | %-*s | %-*s | %-*s | %s" $W_ID "ID" $W_SIZE "SIZE" $W_DATE "DATE" $W_SENDER "SENDER" "REASON") +LEGEND=" [ENTER] View Full Reason & Mail | [SPACE/TAB] Select | [CTRL-D] Delete | [CTRL-H] Hold | [CTRL-R] Requeue | [CTRL-F] Flush | [CTRL-Q] Quit " + +# 5. Launch fzf +list_mails | fzf --ansi --multi \ + --header "$HEADER" \ + --layout=reverse --height=100% --no-height \ + --prompt="Search : " \ + --pointer=">" --marker="X" \ + --color="marker:green,pointer:red,header:blue" \ + --border --border-label="$LEGEND" --border-label-pos=bottom \ + --preview "$0 --detail {1}" \ + --preview-window="bottom:75%:hidden:border-top" \ + --bind "enter:show-preview" \ + --bind "esc:hide-preview" \ + --bind "ctrl-q:abort" \ + --bind "space:toggle" \ + --bind "tab:toggle" \ + --bind "ctrl-d:execute-silent(echo {+1} | xargs -n1 $POSTSUPER -d)+reload($0 --list)" \ + --bind "ctrl-h:execute-silent(echo {+1} | xargs -n1 $POSTSUPER -h)+reload($0 --list)" \ + --bind "ctrl-r:execute-silent(echo {+1} | xargs -n1 $POSTSUPER -r)+reload($0 --list)" \ + --bind "ctrl-f:execute-silent(echo {+1} | xargs -n1 $POSTQUEUE -i)+reload($0 --list)" \ No newline at end of file diff --git a/tasks/configure.yml b/tasks/configure.yml index 1db9334..63f345b 100644 --- a/tasks/configure.yml +++ b/tasks/configure.yml @@ -61,3 +61,10 @@ - restart postfix when: postfix_sasl_password_map is defined +- name: postfix | copy pfq script + file: + src: pfq + dest: /usr/local/bin/pfq + owner: root + group: root + mode: 0755 diff --git a/tasks/install.yml b/tasks/install.yml index a258ea4..ff864ed 100644 --- a/tasks/install.yml +++ b/tasks/install.yml @@ -4,6 +4,7 @@ - postfix - libsasl2-modules - libsasl2-modules-db + - zfz state: present tags: ['postfix']