summaryrefslogtreecommitdiffstats
path: root/src/postqueue/showq_compat.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/postqueue/showq_compat.c')
-rw-r--r--src/postqueue/showq_compat.c222
1 files changed, 222 insertions, 0 deletions
diff --git a/src/postqueue/showq_compat.c b/src/postqueue/showq_compat.c
new file mode 100644
index 0000000..f5ca059
--- /dev/null
+++ b/src/postqueue/showq_compat.c
@@ -0,0 +1,222 @@
+/*++
+/* NAME
+/* showq_compat 8
+/* SUMMARY
+/* Sendmail mailq compatibility adapter
+/* SYNOPSIS
+/* void showq_compat(
+/* VSTREAM *showq)
+/* DESCRIPTION
+/* This function converts a record stream from the showq(8)
+/* daemon to of an approximation of Sendmail mailq command
+/* output.
+/* DIAGNOSTICS
+/* Fatal errors: out of memory, malformed showq(8) daemon output.
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <time.h>
+#include <string.h>
+#include <sysexits.h>
+#include <errno.h>
+
+/* Utility library. */
+
+#include <vstring.h>
+#include <vstream.h>
+#include <stringops.h>
+#include <mymalloc.h>
+#include <msg.h>
+
+/* Global library. */
+
+#include <mail_proto.h>
+#include <mail_queue.h>
+#include <mail_date.h>
+#include <mail_params.h>
+
+/* Application-specific. */
+
+#include <postqueue.h>
+
+ /*
+ * The enable_long_queue_ids parameter determines the output format.
+ *
+ * The historical output format for short queue IDs (inode number and time in
+ * microseconds modulo 1) is not suitable for large inode numbers, but we
+ * won't change it to avoid breaking compatibility with programs that parse
+ * this output.
+ */
+#define S_STRING_FORMAT "%-11s %7s %-20s %s\n"
+#define S_SENDER_FORMAT "%-11s %7ld %20.20s %s\n"
+#define S_HEADINGS "-Queue ID-", "--Size--", \
+ "----Arrival Time----", "-Sender/Recipient-------"
+
+#define L_STRING_FORMAT "%-17s %8s %-19s %s\n"
+#define L_SENDER_FORMAT "%-17s %8ld %19.19s %s\n"
+#define L_HEADINGS "----Queue ID-----", "--Size--", \
+ "---Arrival Time----", "--Sender/Recipient------"
+
+#define STR(x) vstring_str(x)
+
+/* showq_message - report status for one message */
+
+static unsigned long showq_message(VSTREAM *showq_stream)
+{
+ static VSTRING *queue_name = 0;
+ static VSTRING *queue_id = 0;
+ static VSTRING *id_status = 0;
+ static VSTRING *addr = 0;
+ static VSTRING *why = 0;
+ long arrival_time;
+ long message_size;
+ char *saved_reason = mystrdup("");
+ const char *show_reason;
+ int padding;
+ int showq_status;
+ time_t time_t_arrival_time;
+ int forced_expire;
+
+ /*
+ * One-time initialization.
+ */
+ if (queue_name == 0) {
+ queue_name = vstring_alloc(100);
+ queue_id = vstring_alloc(100);
+ id_status = vstring_alloc(100);
+ addr = vstring_alloc(100);
+ why = vstring_alloc(100);
+ }
+
+ /*
+ * Read the message properties and sender address.
+ */
+ if (attr_scan(showq_stream, ATTR_FLAG_MORE | ATTR_FLAG_STRICT
+ | ATTR_FLAG_PRINTABLE,
+ RECV_ATTR_STR(MAIL_ATTR_QUEUE, queue_name),
+ RECV_ATTR_STR(MAIL_ATTR_QUEUEID, queue_id),
+ RECV_ATTR_LONG(MAIL_ATTR_TIME, &arrival_time),
+ RECV_ATTR_LONG(MAIL_ATTR_SIZE, &message_size),
+ RECV_ATTR_INT(MAIL_ATTR_FORCED_EXPIRE, &forced_expire),
+ RECV_ATTR_STR(MAIL_ATTR_SENDER, addr),
+ ATTR_TYPE_END) != 6)
+ msg_fatal_status(EX_SOFTWARE, "malformed showq server response");
+
+ /*
+ * Decorate queue file names in specific states, then print the result
+ * left-aligned, followed by other status info and the sender address
+ * which is already in externalized RFC 5321 form.
+ */
+ vstring_strcpy(id_status, STR(queue_id));
+ if (strcmp(STR(queue_name), MAIL_QUEUE_ACTIVE) == 0)
+ vstring_strcat(id_status, "*");
+ else if (strcmp(STR(queue_name), MAIL_QUEUE_HOLD) == 0)
+ vstring_strcat(id_status, "!");
+ if (forced_expire)
+ vstring_strcat(id_status, "#");
+ time_t_arrival_time = arrival_time;
+ vstream_printf(var_long_queue_ids ?
+ L_SENDER_FORMAT : S_SENDER_FORMAT, STR(id_status),
+ message_size, asctime(localtime(&time_t_arrival_time)),
+ STR(addr));
+
+ /*
+ * Read zero or more (recipient, reason) pair(s) until attr_scan_more()
+ * consumes a terminator. If the showq daemon messes up, don't try to
+ * resynchronize.
+ */
+ while ((showq_status = attr_scan_more(showq_stream)) > 0) {
+ if (attr_scan(showq_stream, ATTR_FLAG_MORE | ATTR_FLAG_STRICT
+ | ATTR_FLAG_PRINTABLE,
+ RECV_ATTR_STR(MAIL_ATTR_RECIP, addr),
+ RECV_ATTR_STR(MAIL_ATTR_WHY, why),
+ ATTR_TYPE_END) != 2)
+ msg_fatal_status(EX_SOFTWARE, "malformed showq server response");
+
+ /*
+ * Don't output a "(reason)" line when no recipient has a reason, or
+ * when the previous recipient has the same (non)reason as the
+ * current recipient. Do output a "(reason unavailable)" when the
+ * previous recipient has a reason, and the current recipient has
+ * none.
+ */
+ if (strcmp(saved_reason, STR(why)) != 0) {
+ myfree(saved_reason);
+ saved_reason = mystrdup(STR(why));
+ show_reason = *saved_reason ? saved_reason : "reason unavailable";
+ if ((padding = 76 - (int) strlen(show_reason)) < 0)
+ padding = 0;
+ vstream_printf("%*s(%s)\n", padding, "", show_reason);
+ }
+ vstream_printf(var_long_queue_ids ?
+ L_STRING_FORMAT : S_STRING_FORMAT,
+ "", "", "", STR(addr));
+ }
+ if (showq_status < 0)
+ msg_fatal_status(EX_SOFTWARE, "malformed showq server response");
+ myfree(saved_reason);
+ return (message_size);
+}
+
+/* showq_compat - legacy mailq-style output adapter */
+
+void showq_compat(VSTREAM *showq_stream)
+{
+ unsigned long file_count = 0;
+ unsigned long queue_size = 0;
+ int showq_status;
+
+ /*
+ * Process zero or more queue file objects until attr_scan_more()
+ * consumes a terminator.
+ */
+ while ((showq_status = attr_scan_more(showq_stream)) > 0) {
+ if (file_count > 0) {
+ vstream_printf("\n");
+ } else if (var_long_queue_ids) {
+ vstream_printf(L_STRING_FORMAT, L_HEADINGS);
+ } else {
+ vstream_printf(S_STRING_FORMAT, S_HEADINGS);
+ }
+ queue_size += showq_message(showq_stream);
+ file_count++;
+ if (vstream_fflush(VSTREAM_OUT)) {
+ if (errno != EPIPE)
+ msg_fatal_status(EX_IOERR, "output write error: %m");
+ return;
+ }
+ }
+ if (showq_status < 0)
+ msg_fatal_status(EX_SOFTWARE, "malformed showq server response");
+
+ /*
+ * Print the queue summary.
+ */
+ if (file_count == 0)
+ vstream_printf("Mail queue is empty\n");
+ else {
+ vstream_printf("\n-- %lu Kbytes in %lu Request%s.\n",
+ queue_size / 1024, file_count,
+ file_count == 1 ? "" : "s");
+ }
+ if (vstream_fflush(VSTREAM_OUT) && errno != EPIPE)
+ msg_fatal_status(EX_IOERR, "output write error: %m");
+}