1 /* GNU Mailutils -- a suite of utilities for electronic mail
2    Copyright (C) 2008-2021 Free Software Foundation, Inc.
3 
4    This library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 3 of the License, or (at your option) any later version.
8 
9    This library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Lesser General Public License for more details.
13 
14    You should have received a copy of the GNU Lesser General
15    Public License along with this library.  If not, see
16    <http://www.gnu.org/licenses/>. */
17 
18 /* Mail header iterators. */
19 
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
23 #include <stdlib.h>
24 #include <string.h>
25 
26 #include <mailutils/sys/header.h>
27 #include <mailutils/errno.h>
28 
29 struct header_iterator
30 {
31   mu_header_t header;
32   size_t index;
33   int backwards;
34 };
35 
36 static int
hdr_first(void * owner)37 hdr_first (void *owner)
38 {
39   struct header_iterator *itr = owner;
40   if (itr->backwards)
41     {
42       if (mu_header_get_field_count (itr->header, &itr->index))
43 	return 1;
44     }
45   else
46     itr->index = 1;
47   return 0;
48 }
49 
50 static int
hdr_next(void * owner)51 hdr_next (void *owner)
52 {
53   struct header_iterator *itr = owner;
54   if (itr->backwards)
55     {
56       if (itr->index != 0)
57 	itr->index--;
58     }
59   else
60     itr->index++;
61   return 0;
62 }
63 
64 static int
hdr_getitem(void * owner,void ** pret,const void ** pkey)65 hdr_getitem (void *owner, void **pret, const void **pkey)
66 {
67   struct header_iterator *itr = owner;
68   int rc;
69   size_t count;
70 
71   rc = mu_header_get_field_count (itr->header, &count);
72   if (rc)
73     return rc;
74   if (itr->index < 1 || itr->index > count)
75     return MU_ERR_NOENT;
76 
77   rc = mu_header_sget_field_value (itr->header, itr->index,
78 				   (const char**) pret);
79   if (rc == 0)
80     {
81       if (pkey)
82 	rc = mu_header_sget_field_name (itr->header, itr->index,
83 					(const char**) pkey);
84     }
85   return rc;
86 }
87 
88 static int
hdr_finished_p(void * owner)89 hdr_finished_p (void *owner)
90 {
91   struct header_iterator *itr = owner;
92   size_t count;
93 
94   if (itr->backwards)
95     return itr->index < 1;
96 
97   if (mu_header_get_field_count (itr->header, &count))
98     return 1;
99   return itr->index > count;
100 }
101 
102 static int
hdr_destroy(mu_iterator_t iterator,void * data)103 hdr_destroy (mu_iterator_t iterator, void *data)
104 {
105   struct header_iterator *itr = data;
106   mu_iterator_detach (&itr->header->itr, iterator);
107   free (data);
108   return 0;
109 }
110 
111 static int
hdr_delitem(void * owner,void * item)112 hdr_delitem (void *owner, void *item)
113 {
114   struct header_iterator *itr = owner;
115   const void *ptr;
116 
117   if (mu_header_get_itemptr (itr->header, itr->index, &ptr))
118     return MU_ITR_DELITEM_NOTHING;
119   if (ptr == item && !itr->backwards)
120     return MU_ITR_DELITEM_ADVANCE;
121   return MU_ITR_DELITEM_NOTHING;
122 }
123 
124 static int
hdr_data_dup(void ** ptr,void * owner)125 hdr_data_dup (void **ptr, void *owner)
126 {
127   struct header_iterator *itr = owner;
128 
129   *ptr = malloc (sizeof (struct header_iterator));
130   if (*ptr == NULL)
131     return ENOMEM;
132   memcpy (*ptr, owner, sizeof (struct header_iterator));
133   mu_iterator_attach (&itr->header->itr, *ptr);
134   return 0;
135 }
136 
137 static int
hdr_itrctl(void * owner,enum mu_itrctl_req req,void * arg)138 hdr_itrctl (void *owner, enum mu_itrctl_req req, void *arg)
139 {
140   struct header_iterator *itr = owner;
141 
142   switch (req)
143     {
144     case mu_itrctl_tell:
145       /* Return current position in the object */
146       if (hdr_finished_p (owner))
147 	return MU_ERR_NOENT;
148       else
149 	*(size_t*)arg = itr->index;
150       return 0;
151       break;
152 
153     case mu_itrctl_delete:
154       /* Delete current element */
155       if (hdr_finished_p (owner))
156 	return MU_ERR_NOENT;
157       else
158 	return mu_header_remove (itr->header, NULL, itr->index);
159       break;
160 
161     case mu_itrctl_qry_direction:
162       if (!arg)
163 	return EINVAL;
164       else
165 	*(int*)arg = itr->backwards;
166       break;
167 
168     case mu_itrctl_set_direction:
169       if (!arg)
170 	return EINVAL;
171       else
172 	itr->backwards = !!*(int*)arg;
173       break;
174 
175     case mu_itrctl_count:
176       if (!arg)
177 	return EINVAL;
178       return mu_header_get_field_count (itr->header, arg);
179 
180     default:
181       return ENOSYS;
182     }
183   return 0;
184 }
185 
186 
187 int
mu_header_get_iterator(mu_header_t hdr,mu_iterator_t * piterator)188 mu_header_get_iterator (mu_header_t hdr, mu_iterator_t *piterator)
189 {
190   mu_iterator_t iterator;
191   int status;
192   struct header_iterator *itr;
193 
194   if (!hdr)
195     return EINVAL;
196 
197   itr = calloc (1, sizeof *itr);
198   if (!itr)
199     return ENOMEM;
200   itr->header = hdr;
201   itr->index = 1;
202 
203   status = mu_iterator_create (&iterator, itr);
204   if (status)
205     {
206       free (itr);
207       return status;
208     }
209 
210   mu_iterator_set_first (iterator, hdr_first);
211   mu_iterator_set_next (iterator, hdr_next);
212   mu_iterator_set_getitem (iterator, hdr_getitem);
213   mu_iterator_set_finished_p (iterator, hdr_finished_p);
214   mu_iterator_set_delitem (iterator, hdr_delitem);
215   mu_iterator_set_destroy (iterator, hdr_destroy);
216   mu_iterator_set_dup (iterator, hdr_data_dup);
217   mu_iterator_set_itrctl (iterator, hdr_itrctl);
218 
219   mu_iterator_attach (&hdr->itr, iterator);
220 
221   *piterator = iterator;
222   return 0;
223 }
224 
225 
226 
227 
228 
229 
230 
231 
232