From: Timo Sirainen Date: Tue, 4 Apr 2017 12:58:15 +0000 (+0300) Subject: lib-imap: Add imap_write_args_for_human() X-Git-Tag: 2.2.29.rc1~14 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=6abef1aaac8233e13ab28f062978f0b174df015a;p=thirdparty%2Fdovecot%2Fcore.git lib-imap: Add imap_write_args_for_human() --- diff --git a/src/lib-imap/imap-util.c b/src/lib-imap/imap-util.c index f4bd9dae1f..3e38d10180 100644 --- a/src/lib-imap/imap-util.c +++ b/src/lib-imap/imap-util.c @@ -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 @@ void imap_write_args(string_t *dest, const struct imap_arg *args) } } +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; diff --git a/src/lib-imap/imap-util.h b/src/lib-imap/imap-util.h index 2813dbce93..07f8af3903 100644 --- a/src/lib-imap/imap-util.h +++ b/src/lib-imap/imap-util.h @@ -16,6 +16,10 @@ enum mail_flags imap_parse_system_flag(const char *str); 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);