summaryrefslogtreecommitdiffstats
path: root/src/lib-imap/imap-envelope.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib-imap/imap-envelope.c')
-rw-r--r--src/lib-imap/imap-envelope.c248
1 files changed, 248 insertions, 0 deletions
diff --git a/src/lib-imap/imap-envelope.c b/src/lib-imap/imap-envelope.c
new file mode 100644
index 0000000..87297f4
--- /dev/null
+++ b/src/lib-imap/imap-envelope.c
@@ -0,0 +1,248 @@
+/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "istream.h"
+#include "str.h"
+#include "message-address.h"
+#include "message-part-data.h"
+#include "message-parser.h"
+#include "imap-parser.h"
+#include "imap-envelope.h"
+#include "imap-quote.h"
+
+/*
+ * Envelope write
+ */
+
+static void imap_write_address(string_t *str, struct message_address *addr)
+{
+ if (addr == NULL) {
+ str_append(str, "NIL");
+ return;
+ }
+
+ str_append_c(str, '(');
+ while (addr != NULL) {
+ str_append_c(str, '(');
+ if (addr->name == NULL)
+ str_append(str, "NIL");
+ else {
+ imap_append_string_for_humans(str,
+ (const void *)addr->name, strlen(addr->name));
+ }
+ str_append_c(str, ' ');
+ imap_append_nstring(str, addr->route);
+ str_append_c(str, ' ');
+ imap_append_nstring(str, addr->mailbox);
+ str_append_c(str, ' ');
+ imap_append_nstring(str, addr->domain);
+ str_append_c(str, ')');
+
+ addr = addr->next;
+ }
+ str_append_c(str, ')');
+}
+
+void imap_envelope_write(struct message_part_envelope *data,
+ string_t *str)
+{
+#define NVL(str, nullstr) ((str) != NULL ? (str) : (nullstr))
+ static const char *empty_envelope =
+ "NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL";
+
+ if (data == NULL) {
+ str_append(str, empty_envelope);
+ return;
+ }
+
+ imap_append_nstring_nolf(str, data->date);
+ str_append_c(str, ' ');
+ if (data->subject == NULL)
+ str_append(str, "NIL");
+ else {
+ imap_append_string_for_humans(str,
+ (const unsigned char *)data->subject,
+ strlen(data->subject));
+ }
+
+ str_append_c(str, ' ');
+ imap_write_address(str, data->from);
+ str_append_c(str, ' ');
+ imap_write_address(str, NVL(data->sender, data->from));
+ str_append_c(str, ' ');
+ imap_write_address(str, NVL(data->reply_to, data->from));
+ str_append_c(str, ' ');
+ imap_write_address(str, data->to);
+ str_append_c(str, ' ');
+ imap_write_address(str, data->cc);
+ str_append_c(str, ' ');
+ imap_write_address(str, data->bcc);
+
+ str_append_c(str, ' ');
+ imap_append_nstring_nolf(str, data->in_reply_to);
+ str_append_c(str, ' ');
+ imap_append_nstring_nolf(str, data->message_id);
+}
+
+/*
+ * ENVELOPE parsing
+ */
+
+static bool
+imap_envelope_parse_address(const struct imap_arg *arg,
+ pool_t pool, struct message_address **addr_r)
+{
+ struct message_address *addr;
+ const struct imap_arg *list_args;
+ const char *name, *route, *mailbox, *domain;
+ unsigned int list_count;
+
+ if (!imap_arg_get_list_full(arg, &list_args, &list_count))
+ return FALSE;
+
+ /* we require 4 arguments, strings or NILs */
+ if (list_count < 4)
+ return FALSE;
+
+ if (!imap_arg_get_nstring(&list_args[0], &name))
+ return FALSE;
+ if (!imap_arg_get_nstring(&list_args[1], &route))
+ return FALSE;
+ if (!imap_arg_get_nstring(&list_args[2], &mailbox))
+ return FALSE;
+ if (!imap_arg_get_nstring(&list_args[3], &domain))
+ return FALSE;
+
+ addr = p_new(pool, struct message_address, 1);
+ addr->name = p_strdup(pool, name);
+ addr->route = p_strdup(pool, route);
+ addr->mailbox = p_strdup(pool, mailbox);
+ addr->domain = p_strdup(pool, domain);
+
+ *addr_r = addr;
+ return TRUE;
+}
+
+static bool
+imap_envelope_parse_addresses(const struct imap_arg *arg,
+ pool_t pool, struct message_address **addrs_r)
+{
+ struct message_address *first, *addr, *prev;
+ const struct imap_arg *list_args;
+
+ if (arg->type == IMAP_ARG_NIL) {
+ *addrs_r = NULL;
+ return TRUE;
+ }
+
+ if (!imap_arg_get_list(arg, &list_args))
+ return FALSE;
+
+ first = addr = prev = NULL;
+ for (; !IMAP_ARG_IS_EOL(list_args); list_args++) {
+ if (!imap_envelope_parse_address
+ (list_args, pool, &addr))
+ return FALSE;
+ if (first == NULL)
+ first = addr;
+ if (prev != NULL)
+ prev->next = addr;
+ prev = addr;
+ }
+
+ *addrs_r = first;
+ return TRUE;
+}
+
+bool imap_envelope_parse_args(const struct imap_arg *args,
+ pool_t pool, struct message_part_envelope **envlp_r,
+ const char **error_r)
+{
+ struct message_part_envelope *envlp;
+
+ envlp = p_new(pool, struct message_part_envelope, 1);
+
+ if (!imap_arg_get_nstring(args++, &envlp->date)) {
+ *error_r = "Invalid date field";
+ return FALSE;
+ }
+ envlp->date = p_strdup(pool, envlp->date);
+
+ if (!imap_arg_get_nstring(args++, &envlp->subject)) {
+ *error_r = "Invalid subject field";
+ return FALSE;
+ }
+ envlp->subject = p_strdup(pool, envlp->subject);
+
+ if (!imap_envelope_parse_addresses(args++, pool, &envlp->from)) {
+ *error_r = "Invalid from field";
+ return FALSE;
+ }
+ if (!imap_envelope_parse_addresses(args++, pool, &envlp->sender)) {
+ *error_r = "Invalid sender field";
+ return FALSE;
+ }
+ if (!imap_envelope_parse_addresses(args++, pool, &envlp->reply_to)) {
+ *error_r = "Invalid reply_to field";
+ return FALSE;
+ }
+ if (!imap_envelope_parse_addresses(args++, pool, &envlp->to)) {
+ *error_r = "Invalid to field";
+ return FALSE;
+ }
+ if (!imap_envelope_parse_addresses(args++, pool, &envlp->cc)) {
+ *error_r = "Invalid cc field";
+ return FALSE;
+ }
+ if (!imap_envelope_parse_addresses(args++, pool, &envlp->bcc)) {
+ *error_r = "Invalid bcc field";
+ return FALSE;
+ }
+
+ if (!imap_arg_get_nstring(args++, &envlp->in_reply_to)) {
+ *error_r = "Invalid in_reply_to field";
+ return FALSE;
+ }
+ envlp->in_reply_to = p_strdup(pool, envlp->in_reply_to);
+
+ if (!imap_arg_get_nstring(args++, &envlp->message_id)) {
+ *error_r = "Invalid message_id field";
+ return FALSE;
+ }
+ envlp->message_id = p_strdup(pool, envlp->message_id);
+
+ *envlp_r = envlp;
+ return TRUE;
+}
+
+bool imap_envelope_parse(const char *envelope,
+ pool_t pool, struct message_part_envelope **envlp_r,
+ const char **error_r)
+{
+ struct istream *input;
+ struct imap_parser *parser;
+ const struct imap_arg *args;
+ int ret;
+ bool success;
+
+ input = i_stream_create_from_data(envelope, strlen(envelope));
+ (void)i_stream_read(input);
+
+ parser = imap_parser_create(input, NULL, SIZE_MAX);
+ ret = imap_parser_finish_line(parser, 0,
+ IMAP_PARSE_FLAG_LITERAL_TYPE, &args);
+ if (ret < 0) {
+ *error_r = t_strdup_printf("IMAP parser failed: %s",
+ imap_parser_get_error(parser, NULL));
+ success = FALSE;
+ } else if (ret == 0) {
+ *error_r = "Empty envelope";
+ success = FALSE;
+ } else {
+ success = imap_envelope_parse_args(args, pool, envlp_r, error_r);
+ }
+
+ imap_parser_unref(&parser);
+ i_stream_destroy(&input);
+ return success;
+}