1 //
2 // VMime library (http://www.vmime.org)
3 // Copyright (C) 2002-2013 Vincent Richard <vincent@vmime.org>
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License as
7 // published by the Free Software Foundation; either version 3 of
8 // the License, or (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License along
16 // with this program; if not, write to the Free Software Foundation, Inc.,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 //
19 // Linking this library statically or dynamically with other modules is making
20 // a combined work based on this library.  Thus, the terms and conditions of
21 // the GNU General Public License cover the whole combination.
22 //
23 
24 #include "vmime/propertySet.hpp"
25 #include "vmime/parserHelpers.hpp"
26 
27 
28 namespace vmime
29 {
30 
31 
propertySet()32 propertySet::propertySet()
33 {
34 }
35 
36 
propertySet(const string & props)37 propertySet::propertySet(const string& props)
38 {
39 	parse(props);
40 }
41 
42 
propertySet(const propertySet & set)43 propertySet::propertySet(const propertySet& set)
44 	: object()
45 {
46 	for (std::list <shared_ptr <property> >::const_iterator it = set.m_props.begin() ; it != set.m_props.end() ; ++it)
47 		m_props.push_back(make_shared <property>(**it));
48 }
49 
50 
~propertySet()51 propertySet::~propertySet()
52 {
53 	removeAllProperties();
54 }
55 
56 
operator =(const propertySet & set)57 propertySet& propertySet::operator=(const propertySet& set)
58 {
59 	removeAllProperties();
60 
61 	for (std::list <shared_ptr <property> >::const_iterator it = set.m_props.begin() ; it != set.m_props.end() ; ++it)
62 		m_props.push_back(make_shared <property>(**it));
63 
64 	return (*this);
65 }
66 
67 
setFromString(const string & props)68 void propertySet::setFromString(const string& props)
69 {
70 	parse(props);
71 }
72 
73 
removeAllProperties()74 void propertySet::removeAllProperties()
75 {
76 	m_props.clear();
77 }
78 
79 
removeProperty(const string & name)80 void propertySet::removeProperty(const string& name)
81 {
82 	std::list <shared_ptr <property> >::iterator it = std::find_if
83 		(m_props.begin(), m_props.end(), propFinder(name));
84 
85 	if (it != m_props.end())
86 		m_props.erase(it);
87 }
88 
89 
parse(const string & props)90 void propertySet::parse(const string& props)
91 {
92 	const string::const_iterator end = props.end();
93 	string::const_iterator pos = props.begin();
94 
95 	for ( ; pos != end ; )
96 	{
97 		// Skip white-spaces
98 		for ( ; pos != end && parserHelpers::isSpace(*pos) ; ++pos) {}
99 
100 		if (pos != end)
101 		{
102 			if (*pos == ';')
103 			{
104 				++pos;
105 				continue;
106 			}
107 
108 			// Extract the property name
109 			const string::const_iterator optStart = pos;
110 
111 			for ( ; pos != end && *pos != '=' ; ++pos) {}
112 
113 			string::const_iterator optEnd = pos;
114 
115 			for ( ; optEnd != optStart && parserHelpers::isSpace(*(optEnd - 1)) ; --optEnd) {}
116 
117 			const string option(optStart, optEnd);
118 			string value = "1";
119 
120 			if (pos != end)
121 			{
122 				++pos; // skip '='
123 
124 				// Extract the value
125 				for ( ; pos != end && parserHelpers::isSpace(*pos) ; ++pos) {}
126 
127 				if (pos != end)
128 				{
129 					// A quoted-string
130 					if (*pos == '"' || *pos == '\'')
131 					{
132 						value.reserve(50);
133 
134 						const char quoteChar = *pos;
135 						bool theEnd = false;
136 						bool escape = false;
137 
138 						for ( ; (pos != end) && !theEnd ; ++pos)
139 						{
140 							if (escape)
141 							{
142 								value += *pos;
143 								escape = false;
144 							}
145 							else
146 							{
147 								if (*pos == '\\')
148 									escape = true;
149 								else if (*pos == quoteChar)
150 									theEnd = true;
151 								else
152 									value += *pos;
153 							}
154 						}
155 
156 						if (pos != end)
157 							++pos;
158 					}
159 					// Simple value
160 					else
161 					{
162 						const string::const_iterator valStart = pos;
163 
164 						for ( ; pos != end && !parserHelpers::isSpace(*pos) ; ++pos) {}
165 
166 						value = string(valStart, pos);
167 					}
168 
169 					// Advance to the next ';'
170 					for ( ; pos != end && (*pos != ';') ; ++pos) {}
171 
172 					if (pos != end)
173 						++pos; // skip ';'
174 				}
175 			}
176 
177 			m_props.push_back(make_shared <property>(option, value));
178 		}
179 	}
180 }
181 
182 
find(const string & name) const183 shared_ptr <propertySet::property> propertySet::find(const string& name) const
184 {
185 	std::list <shared_ptr <property> >::const_iterator it = std::find_if
186 		(m_props.begin(), m_props.end(), propFinder(name));
187 
188 	return (it != m_props.end() ? *it : null);
189 }
190 
191 
findOrCreate(const string & name)192 shared_ptr <propertySet::property> propertySet::findOrCreate(const string& name)
193 {
194 	std::list <shared_ptr <property> >::const_iterator it = std::find_if
195 		(m_props.begin(), m_props.end(), propFinder(name));
196 
197 	if (it != m_props.end())
198 	{
199 		return (*it);
200 	}
201 	else
202 	{
203 		shared_ptr <property> prop = make_shared <property>(name, "");
204 		m_props.push_back(prop);
205 		return (prop);
206 	}
207 }
208 
209 
operator [](const string & name)210 propertySet::propertyProxy propertySet::operator[](const string& name)
211 {
212 	return (propertyProxy(name, this));
213 }
214 
215 
operator [](const string & name) const216 const propertySet::constPropertyProxy propertySet::operator[](const string& name) const
217 {
218 	return (constPropertyProxy(name, this));
219 }
220 
221 
hasProperty(const string & name) const222 bool propertySet::hasProperty(const string& name) const
223 {
224 	return (find(name) != NULL);
225 }
226 
227 
getPropertyList() const228 const std::vector <shared_ptr <const propertySet::property> > propertySet::getPropertyList() const
229 {
230 	std::vector <shared_ptr <const property> > res;
231 
232 	for (list_type::const_iterator it = m_props.begin() ; it != m_props.end() ; ++it)
233 		res.push_back(*it);
234 
235 	return (res);
236 }
237 
238 
getPropertyList()239 const std::vector <shared_ptr <propertySet::property> > propertySet::getPropertyList()
240 {
241 	std::vector <shared_ptr <property> > res;
242 
243 	for (list_type::const_iterator it = m_props.begin() ; it != m_props.end() ; ++it)
244 		res.push_back(*it);
245 
246 	return (res);
247 }
248 
249 
250 //
251 // propertySet::property
252 //
253 
property(const string & name,const string & value)254 propertySet::property::property(const string& name, const string& value)
255 	: m_name(name), m_value(value)
256 {
257 }
258 
259 
property(const string & name)260 propertySet::property::property(const string& name)
261 	: m_name(name)
262 {
263 }
264 
265 
property(const property & prop)266 propertySet::property::property(const property& prop)
267 	: object(), m_name(prop.m_name), m_value(prop.m_value)
268 {
269 }
270 
271 
getName() const272 const string& propertySet::property::getName() const
273 {
274 	return (m_name);
275 }
276 
277 
278 #ifndef _MSC_VER
279 
280 
getValue() const281 const string& propertySet::property::getValue() const
282 {
283 	return (m_value);
284 }
285 
286 
setValue(const string & value)287 void propertySet::property::setValue(const string& value)
288 {
289 	m_value = value;
290 }
291 
292 
293 #endif // !_MSC_VER
294 
295 
296 #ifndef VMIME_INLINE_TEMPLATE_SPECIALIZATION
297 
298 template <>
setValue(const string & value)299 void propertySet::property::setValue(const string& value)
300 {
301 	m_value = value;
302 }
303 
304 
305 template <>
setValue(const bool & value)306 void propertySet::property::setValue(const bool& value)
307 {
308 	m_value = value ? "true" : "false";
309 }
310 
311 
312 template <>
getValue() const313 string propertySet::property::getValue() const
314 {
315 	return (m_value);
316 }
317 
318 
319 template <>
getValue() const320 bool propertySet::property::getValue() const
321 {
322 	if (utility::stringUtils::toLower(m_value) == "true")
323 		return true;
324 	else
325 	{
326 		int val = 0;
327 
328 		std::istringstream iss(m_value);
329 		iss.imbue(std::locale::classic());  // no formatting
330 
331 		iss >> val;
332 
333 		return (!iss.fail() && val != 0);
334 	}
335 }
336 
337 
338 
339 
340 template <>
valueFromString(const string & value)341 string propertySet::valueFromString(const string& value)
342 {
343 	return value;
344 }
345 
346 
347 template <>
valueToString(const string & value)348 string propertySet::valueToString(const string& value)
349 {
350 	return value;
351 }
352 
353 
354 template <>
valueFromString(const string & value)355 bool propertySet::valueFromString(const string& value)
356 {
357 	if (utility::stringUtils::toLower(value) == "true")
358 		return true;
359 	else
360 	{
361 		int val = 0;
362 
363 		std::istringstream iss(value);
364 		iss.imbue(std::locale::classic());  // no formatting
365 
366 		iss >> val;
367 
368 		return (!iss.fail() && val != 0);
369 	}
370 }
371 
372 
373 template <>
valueToString(const bool & value)374 string propertySet::valueToString(const bool& value)
375 {
376 	return (value ? "true" : "false");
377 }
378 
379 #endif // VMIME_INLINE_TEMPLATE_SPECIALIZATION
380 
381 
382 } // vmime
383