diff options
Diffstat (limited to '')
-rw-r--r-- | src/lib-mail/message-part.c | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/src/lib-mail/message-part.c b/src/lib-mail/message-part.c new file mode 100644 index 0000000..340dbbb --- /dev/null +++ b/src/lib-mail/message-part.c @@ -0,0 +1,103 @@ +/* Copyright (c) 2014-2018 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "message-part.h" + +static const struct message_part * +message_part_root(const struct message_part *part) +{ + while (part->parent != NULL) + part = part->parent; + return part; +} + +static bool message_part_find(const struct message_part *siblings, + const struct message_part *part, + unsigned int *n) +{ + const struct message_part *p; + + for (p = siblings; p != NULL; p = p->next) { + if (p == part) + return TRUE; + *n += 1; + if (message_part_find(p->children, part, n)) + return TRUE; + } + return FALSE; +} + +unsigned int message_part_to_idx(const struct message_part *part) +{ + const struct message_part *root; + unsigned int n = 0; + + root = message_part_root(part); + if (!message_part_find(root, part, &n)) + i_unreached(); + return n; +} + +static struct message_part * +message_sub_part_by_idx(struct message_part *parts, + unsigned int idx) +{ + struct message_part *part = parts; + + for (; part != NULL && idx > 0; part = part->next) { + if (part->children_count >= idx) + return message_sub_part_by_idx(part->children, idx-1); + idx -= part->children_count + 1; + } + return part; +} + +struct message_part * +message_part_by_idx(struct message_part *parts, unsigned int idx) +{ + i_assert(parts->parent == NULL); + + return message_sub_part_by_idx(parts, idx); +} + +bool message_part_is_equal(const struct message_part *p1, + const struct message_part *p2) +{ + /* This cannot be p1 && p2, because then we would return + TRUE when either part is NULL, and we should return FALSE */ + while (p1 != NULL || p2 != NULL) { + /* If either part is NULL, return false */ + if ((p1 != NULL) != (p2 != NULL)) + return FALSE; + + /* Expect that both either have children, or both + do not have children */ + if ((p1->children != NULL) != (p2->children != NULL)) + return FALSE; + + /* If there are children, ensure they are equal */ + if (p1->children != NULL) { + if (!message_part_is_equal(p1->children, p2->children)) + return FALSE; + } + + /* If any of these properties differ, then parts are not equal */ + if (p1->physical_pos != p2->physical_pos || + p1->header_size.physical_size != p2->header_size.physical_size || + p1->header_size.virtual_size != p2->header_size.virtual_size || + p1->header_size.lines != p2->header_size.lines || + p1->body_size.physical_size != p2->body_size.physical_size || + p1->body_size.virtual_size != p2->body_size.virtual_size || + p1->body_size.lines != p2->body_size.lines || + p1->children_count != p2->children_count || + p1->flags != p2->flags) + return FALSE; + + /* Move forward */ + p1 = p1->next; + p2 = p2->next; + } + + /* Parts are equal */ + return TRUE; +} |