Coverage Report

Created: 2026-05-16 06:58

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/dovecot/src/lib-mail/message-part.c
Line
Count
Source
1
/* Copyright (c) 2014-2018 Dovecot authors, see the included COPYING file */
2
3
#include "lib.h"
4
#include "message-part.h"
5
6
static const struct message_part *
7
message_part_root(const struct message_part *part)
8
0
{
9
0
  while (part->parent != NULL)
10
0
    part = part->parent;
11
0
  return part;
12
0
}
13
14
static bool message_part_find(const struct message_part *siblings,
15
            const struct message_part *part,
16
            unsigned int *n)
17
0
{
18
0
  const struct message_part *p;
19
20
0
  for (p = siblings; p != NULL; p = p->next) {
21
0
    if (p == part)
22
0
      return TRUE;
23
0
    *n += 1;
24
0
    if (message_part_find(p->children, part, n))
25
0
      return TRUE;
26
0
  }
27
0
  return FALSE;
28
0
}
29
30
unsigned int message_part_to_idx(const struct message_part *part)
31
0
{
32
0
  const struct message_part *root;
33
0
  unsigned int n = 0;
34
35
0
  root = message_part_root(part);
36
0
  if (!message_part_find(root, part, &n))
37
0
    i_unreached();
38
0
  return n;
39
0
}
40
41
static struct message_part *
42
message_sub_part_by_idx(struct message_part *parts,
43
      unsigned int idx)
44
0
{
45
0
  struct message_part *part = parts;
46
47
0
  for (; part != NULL && idx > 0; part = part->next) {
48
0
    if (part->children_count >= idx)
49
0
      return message_sub_part_by_idx(part->children, idx-1);
50
0
    idx -= part->children_count + 1;
51
0
  }
52
0
  return part;
53
0
}
54
55
struct message_part *
56
message_part_by_idx(struct message_part *parts, unsigned int idx)
57
0
{
58
0
  i_assert(parts->parent == NULL);
59
60
0
  return message_sub_part_by_idx(parts, idx);
61
0
}
62
63
bool message_part_is_equal_ex(const struct message_part *p1,
64
            const struct message_part *p2,
65
            message_part_comparator_t *equals_ex)
66
0
{
67
  /* This cannot be p1 && p2, because then we would return
68
     TRUE when either part is NULL, and we should return FALSE */
69
0
  while (p1 != NULL || p2 != NULL) {
70
    /* If either part is NULL, return false */
71
0
    if ((p1 != NULL) != (p2 != NULL))
72
0
      return FALSE;
73
74
    /* Expect that both either have children, or both
75
       do not have children */
76
0
    if ((p1->children != NULL) != (p2->children != NULL))
77
0
      return FALSE;
78
79
    /* If there are children, ensure they are equal */
80
0
    if (p1->children != NULL) {
81
0
      if (!message_part_is_equal(p1->children, p2->children))
82
0
        return FALSE;
83
0
    }
84
85
    /* If any of these properties differ, then parts are not equal */
86
0
    if (p1->physical_pos != p2->physical_pos ||
87
0
        p1->header_size.physical_size != p2->header_size.physical_size ||
88
0
        p1->header_size.virtual_size != p2->header_size.virtual_size ||
89
0
        p1->header_size.lines != p2->header_size.lines ||
90
0
        p1->body_size.physical_size != p2->body_size.physical_size ||
91
0
        p1->body_size.virtual_size != p2->body_size.virtual_size ||
92
0
        p1->body_size.lines != p2->body_size.lines ||
93
0
        p1->children_count != p2->children_count ||
94
0
        p1->flags != p2->flags)
95
0
      return FALSE;
96
97
0
    if (equals_ex != NULL && !equals_ex(p1, p2))
98
0
      return FALSE;
99
100
    /* Move forward */
101
0
    p1 = p1->next;
102
0
    p2 = p2->next;
103
0
  }
104
105
  /* Parts are equal */
106
0
  return TRUE;
107
0
}
108
109
bool message_part_is_equal(const struct message_part *p1,
110
         const struct message_part *p2) ATTR_NULL(1, 2)
111
0
{
112
0
  return message_part_is_equal_ex(p1, p2, NULL);
113
0
}
114
115
bool message_parts_have_nuls(const struct message_part *parts)
116
0
{
117
0
  const struct message_part *part;
118
119
0
  for (part = parts; part != NULL; part = part->next) {
120
0
    if (message_part_has_nuls(part))
121
0
      return TRUE;
122
0
  }
123
0
  return FALSE;
124
0
}
125
126
bool message_part_has_nuls(const struct message_part *part)
127
0
{
128
0
  if (HAS_ALL_BITS(part->flags, MESSAGE_PART_FLAG_HAS_NULS))
129
0
    return TRUE;
130
131
0
  return message_parts_have_nuls(part->children);
132
0
}