summaryrefslogtreecommitdiffstats
path: root/src/lib-imap/imap-util.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/lib-imap/imap-util.c202
1 files changed, 202 insertions, 0 deletions
diff --git a/src/lib-imap/imap-util.c b/src/lib-imap/imap-util.c
new file mode 100644
index 0000000..dc1ae24
--- /dev/null
+++ b/src/lib-imap/imap-util.c
@@ -0,0 +1,202 @@
+/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "array.h"
+#include "str.h"
+#include "strescape.h"
+#include "unichar.h"
+#include "mail-types.h"
+#include "imap-parser.h"
+#include "imap-util.h"
+
+void imap_write_flags(string_t *dest, enum mail_flags flags,
+ const char *const *keywords)
+{
+ size_t size;
+
+ size = str_len(dest);
+ if ((flags & MAIL_ANSWERED) != 0)
+ str_append(dest, "\\Answered ");
+ if ((flags & MAIL_FLAGGED) != 0)
+ str_append(dest, "\\Flagged ");
+ if ((flags & MAIL_DELETED) != 0)
+ str_append(dest, "\\Deleted ");
+ if ((flags & MAIL_SEEN) != 0)
+ str_append(dest, "\\Seen ");
+ if ((flags & MAIL_DRAFT) != 0)
+ str_append(dest, "\\Draft ");
+ if ((flags & MAIL_RECENT) != 0)
+ str_append(dest, "\\Recent ");
+
+ if (keywords != NULL) {
+ /* we have keywords too */
+ while (*keywords != NULL) {
+ str_append(dest, *keywords);
+ str_append_c(dest, ' ');
+ keywords++;
+ }
+ }
+
+ if (str_len(dest) != size)
+ str_truncate(dest, str_len(dest)-1);
+}
+
+enum mail_flags imap_parse_system_flag(const char *str)
+{
+ if (strcasecmp(str, "\\Answered") == 0)
+ return MAIL_ANSWERED;
+ else if (strcasecmp(str, "\\Flagged") == 0)
+ return MAIL_FLAGGED;
+ else if (strcasecmp(str, "\\Deleted") == 0)
+ return MAIL_DELETED;
+ else if (strcasecmp(str, "\\Seen") == 0)
+ return MAIL_SEEN;
+ else if (strcasecmp(str, "\\Draft") == 0)
+ return MAIL_DRAFT;
+ else if (strcasecmp(str, "\\Recent") == 0)
+ return MAIL_RECENT;
+ else
+ return 0;
+}
+
+void imap_write_seq_range(string_t *dest, const ARRAY_TYPE(seq_range) *array)
+{
+ const struct seq_range *range;
+ unsigned int i, count;
+
+ range = array_get(array, &count);
+ for (i = 0; i < count; i++) {
+ if (i > 0)
+ str_append_c(dest, ',');
+ str_printfa(dest, "%u", range[i].seq1);
+ if (range[i].seq1 != range[i].seq2)
+ str_printfa(dest, ":%u", range[i].seq2);
+ }
+}
+
+void imap_write_arg(string_t *dest, const struct imap_arg *arg)
+{
+ switch (arg->type) {
+ case IMAP_ARG_NIL:
+ str_append(dest, "NIL");
+ break;
+ case IMAP_ARG_ATOM:
+ str_append(dest, imap_arg_as_astring(arg));
+ break;
+ case IMAP_ARG_STRING: {
+ const char *strarg = imap_arg_as_astring(arg);
+ str_append_c(dest, '"');
+ str_append_escaped(dest, strarg, strlen(strarg));
+ str_append_c(dest, '"');
+ break;
+ }
+ case IMAP_ARG_LITERAL: {
+ const char *strarg = imap_arg_as_astring(arg);
+ str_printfa(dest, "{%zu}\r\n",
+ strlen(strarg));
+ str_append(dest, strarg);
+ break;
+ }
+ case IMAP_ARG_LIST:
+ str_append_c(dest, '(');
+ imap_write_args(dest, imap_arg_as_list(arg));
+ 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(arg));
+ break;
+ case IMAP_ARG_EOL:
+ i_unreached();
+ }
+}
+
+void imap_write_args(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, ' ');
+ imap_write_arg(dest, 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, "<%zu 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;
+
+ str = t_str_new(128);
+ imap_write_args(str, args);
+ return str_c(str);
+}