changeset 21894:cb05b557fd74

lib-imap: Add imap_write_args_for_human()
author Timo Sirainen <timo.sirainen@dovecot.fi>
date Tue, 04 Apr 2017 15:58:15 +0300
parents 5511ffac2ca4
children 76327526ee5c
files src/lib-imap/imap-util.c src/lib-imap/imap-util.h
diffstat 2 files changed, 72 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-imap/imap-util.c	Tue Apr 04 15:38:00 2017 +0300
+++ b/src/lib-imap/imap-util.c	Tue Apr 04 15:58:15 2017 +0300
@@ -4,6 +4,7 @@
 #include "array.h"
 #include "str.h"
 #include "strescape.h"
+#include "unichar.h"
 #include "mail-types.h"
 #include "imap-parser.h"
 #include "imap-util.h"
@@ -119,6 +120,73 @@
 	}
 }
 
+static void imap_human_args_fix_control_chars(char *str)
+{
+	size_t i;
+
+	for (i = 0; str[i] != '\0'; i++) {
+		if (str[i] < 0x20 || str[i] == 0x7f)
+			str[i] = '?';
+	}
+}
+
+void imap_write_args_for_human(string_t *dest, const struct imap_arg *args)
+{
+	bool first = TRUE;
+
+	for (; !IMAP_ARG_IS_EOL(args); args++) {
+		if (first)
+			first = FALSE;
+		else
+			str_append_c(dest, ' ');
+
+		switch (args->type) {
+		case IMAP_ARG_NIL:
+			str_append(dest, "NIL");
+			break;
+		case IMAP_ARG_ATOM:
+			/* atom has only printable us-ascii chars */
+			str_append(dest, imap_arg_as_astring(args));
+			break;
+		case IMAP_ARG_STRING:
+		case IMAP_ARG_LITERAL: {
+			const char *strarg = imap_arg_as_astring(args);
+
+			if (strpbrk(strarg, "\r\n") != NULL) {
+				str_printfa(dest, "<%"PRIuSIZE_T" byte multi-line literal>",
+					    strlen(strarg));
+				break;
+			}
+			strarg = str_escape(strarg);
+
+			str_append_c(dest, '"');
+			size_t start_pos = str_len(dest);
+			/* append only valid UTF-8 chars */
+			if (uni_utf8_get_valid_data((const unsigned char *)strarg,
+						    strlen(strarg), dest))
+				str_append(dest, strarg);
+			/* replace all control chars */
+			imap_human_args_fix_control_chars(
+				str_c_modifiable(dest) + start_pos);
+			str_append_c(dest, '"');
+			break;
+		}
+		case IMAP_ARG_LIST:
+			str_append_c(dest, '(');
+			imap_write_args_for_human(dest, imap_arg_as_list(args));
+			str_append_c(dest, ')');
+			break;
+		case IMAP_ARG_LITERAL_SIZE:
+		case IMAP_ARG_LITERAL_SIZE_NONSYNC:
+			str_printfa(dest, "<%"PRIuUOFF_T" byte literal>",
+				    imap_arg_as_literal_size(args));
+			break;
+		case IMAP_ARG_EOL:
+			i_unreached();
+		}
+	}
+}
+
 const char *imap_args_to_str(const struct imap_arg *args)
 {
 	string_t *str;
--- a/src/lib-imap/imap-util.h	Tue Apr 04 15:38:00 2017 +0300
+++ b/src/lib-imap/imap-util.h	Tue Apr 04 15:58:15 2017 +0300
@@ -16,6 +16,10 @@
 void imap_write_seq_range(string_t *dest, const ARRAY_TYPE(seq_range) *array);
 /* Write IMAP args to given string. The string is mainly useful for humans. */
 void imap_write_args(string_t *dest, const struct imap_arg *args);
+/* Write IMAP args in a human-readable format to given string (e.g. for
+   logging). The output is a single valid UTF-8 line without control
+   characters. Multi-line literals are replaced with a generic placeholder. */
+void imap_write_args_for_human(string_t *dest, const struct imap_arg *args);
 /* Like imap_write_args(), but return the string allocated from data stack. */
 const char *imap_args_to_str(const struct imap_arg *args);