1 /**
2  * @file
3  * Store attributes associated with a MIME part
4  *
5  * @authors
6  * Copyright (C) 2017 Richard Russon <rich@flatcap.org>
7  *
8  * @copyright
9  * This program is free software: you can redistribute it and/or modify it under
10  * the terms of the GNU General Public License as published by the Free Software
11  * Foundation, either version 2 of the License, or (at your option) any later
12  * version.
13  *
14  * This program is distributed in the hope that it will be useful, but WITHOUT
15  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
17  * details.
18  *
19  * You should have received a copy of the GNU General Public License along with
20  * this program.  If not, see <http://www.gnu.org/licenses/>.
21  */
22 
23 /**
24  * @page email_parameter Attributes for a MIME part
25  *
26  * Store attributes associated with a MIME part
27  */
28 
29 #include "config.h"
30 #include <stddef.h>
31 #include <stdbool.h>
32 #include "mutt/lib.h"
33 #include "parameter.h"
34 
35 /**
36  * mutt_param_new - Create a new Parameter
37  * @retval ptr Newly allocated Parameter
38  */
mutt_param_new(void)39 struct Parameter *mutt_param_new(void)
40 {
41   return mutt_mem_calloc(1, sizeof(struct Parameter));
42 }
43 
44 /**
45  * mutt_param_free_one - Free a Parameter
46  * @param[out] p Parameter to free
47  */
mutt_param_free_one(struct Parameter ** p)48 void mutt_param_free_one(struct Parameter **p)
49 {
50   if (!p || !*p)
51     return;
52   FREE(&(*p)->attribute);
53   FREE(&(*p)->value);
54   FREE(p);
55 }
56 
57 /**
58  * mutt_param_free - Free a ParameterList
59  * @param pl ParameterList to free
60  */
mutt_param_free(struct ParameterList * pl)61 void mutt_param_free(struct ParameterList *pl)
62 {
63   if (!pl)
64     return;
65 
66   struct Parameter *np = TAILQ_FIRST(pl);
67   struct Parameter *next = NULL;
68   while (np)
69   {
70     next = TAILQ_NEXT(np, entries);
71     mutt_param_free_one(&np);
72     np = next;
73   }
74   TAILQ_INIT(pl);
75 }
76 
77 /**
78  * mutt_param_get - Find a matching Parameter
79  * @param pl ParameterList
80  * @param s  String to match
81  * @retval ptr Matching Parameter
82  * @retval NULL No match
83  */
mutt_param_get(const struct ParameterList * pl,const char * s)84 char *mutt_param_get(const struct ParameterList *pl, const char *s)
85 {
86   if (!pl)
87     return NULL;
88 
89   struct Parameter *np = NULL;
90   TAILQ_FOREACH(np, pl, entries)
91   {
92     if (mutt_istr_equal(s, np->attribute))
93       return np->value;
94   }
95 
96   return NULL;
97 }
98 
99 /**
100  * mutt_param_set - Set a Parameter
101  * @param[in]  pl        ParameterList
102  * @param[in]  attribute Attribute to match
103  * @param[in]  value     Value to set
104  *
105  * @note If value is NULL, the Parameter will be deleted
106  *
107  * @note If a matching Parameter isn't found a new one will be allocated.
108  *       The new Parameter will be inserted at the front of the list.
109  */
mutt_param_set(struct ParameterList * pl,const char * attribute,const char * value)110 void mutt_param_set(struct ParameterList *pl, const char *attribute, const char *value)
111 {
112   if (!pl)
113     return;
114 
115   if (!value)
116   {
117     mutt_param_delete(pl, attribute);
118     return;
119   }
120 
121   struct Parameter *np = NULL;
122   TAILQ_FOREACH(np, pl, entries)
123   {
124     if (mutt_istr_equal(attribute, np->attribute))
125     {
126       mutt_str_replace(&np->value, value);
127       return;
128     }
129   }
130 
131   np = mutt_param_new();
132   np->attribute = mutt_str_dup(attribute);
133   np->value = mutt_str_dup(value);
134   TAILQ_INSERT_HEAD(pl, np, entries);
135 }
136 
137 /**
138  * mutt_param_delete - Delete a matching Parameter
139  * @param[in] pl        ParameterList
140  * @param[in] attribute Attribute to match
141  */
mutt_param_delete(struct ParameterList * pl,const char * attribute)142 void mutt_param_delete(struct ParameterList *pl, const char *attribute)
143 {
144   if (!pl)
145     return;
146 
147   struct Parameter *np = NULL;
148   TAILQ_FOREACH(np, pl, entries)
149   {
150     if (mutt_istr_equal(attribute, np->attribute))
151     {
152       TAILQ_REMOVE(pl, np, entries);
153       mutt_param_free_one(&np);
154       return;
155     }
156   }
157 }
158 
159 /**
160  * mutt_param_cmp_strict - Strictly compare two ParameterLists
161  * @param pl1 First parameter
162  * @param pl2 Second parameter
163  * @retval true Parameters are strictly identical
164  */
mutt_param_cmp_strict(const struct ParameterList * pl1,const struct ParameterList * pl2)165 bool mutt_param_cmp_strict(const struct ParameterList *pl1, const struct ParameterList *pl2)
166 {
167   if (!pl1 && !pl2)
168     return false;
169 
170   if ((pl1 == NULL) ^ (pl2 == NULL))
171     return true;
172 
173   struct Parameter *np1 = TAILQ_FIRST(pl1);
174   struct Parameter *np2 = TAILQ_FIRST(pl2);
175 
176   while (np1 && np2)
177   {
178     if (!mutt_str_equal(np1->attribute, np2->attribute) ||
179         !mutt_str_equal(np1->value, np2->value))
180     {
181       return false;
182     }
183 
184     np1 = TAILQ_NEXT(np1, entries);
185     np2 = TAILQ_NEXT(np2, entries);
186   }
187 
188   if (np1 || np2)
189     return false;
190 
191   return true;
192 }
193