xref: /AOO41X/main/svl/source/misc/adrparse.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_svl.hxx"
30 #include <tools/inetmime.hxx>
31 #include <svl/adrparse.hxx>
32 
33 namespace unnamed_svl_adrparse {}
34 using namespace unnamed_svl_adrparse;
35 	// unnamed namespaces don't work well yet
36 
37 //============================================================================
38 namespace unnamed_svl_adrparse {
39 
40 enum ElementType { ELEMENT_START, ELEMENT_DELIM, ELEMENT_ITEM, ELEMENT_END };
41 
42 //============================================================================
43 struct ParsedAddrSpec
44 {
45 	sal_Unicode const * m_pBegin;
46 	sal_Unicode const * m_pEnd;
47 	ElementType m_eLastElem;
48 	bool m_bAtFound;
49 	bool m_bReparse;
50 
51 	ParsedAddrSpec() { reset(); }
52 
53 	bool isPoorlyValid() const { return m_eLastElem >= ELEMENT_ITEM; }
54 
55 	bool isValid() const { return isPoorlyValid() && m_bAtFound; }
56 
57 	inline void reset();
58 
59 	inline void finish();
60 };
61 
62 inline void ParsedAddrSpec::reset()
63 {
64 	m_pBegin = 0;
65 	m_pEnd = 0;
66 	m_eLastElem = ELEMENT_START;
67 	m_bAtFound = false;
68 	m_bReparse = false;
69 }
70 
71 inline void ParsedAddrSpec::finish()
72 {
73 	if (isPoorlyValid())
74 		m_eLastElem = ELEMENT_END;
75 	else
76 		reset();
77 }
78 
79 }
80 
81 //============================================================================
82 class SvAddressParser_Impl
83 {
84 	enum State { BEFORE_COLON, BEFORE_LESS, AFTER_LESS, AFTER_GREATER };
85 
86 	enum TokenType { TOKEN_QUOTED = 0x80000000, TOKEN_DOMAIN, TOKEN_COMMENT,
87 					 TOKEN_ATOM };
88 
89 	sal_Unicode const * m_pInputPos;
90 	sal_Unicode const * m_pInputEnd;
91 	sal_uInt32 m_nCurToken;
92 	sal_Unicode const * m_pCurTokenBegin;
93 	sal_Unicode const * m_pCurTokenEnd;
94 	sal_Unicode const * m_pCurTokenContentBegin;
95 	sal_Unicode const * m_pCurTokenContentEnd;
96 	bool m_bCurTokenReparse;
97 	ParsedAddrSpec m_aOuterAddrSpec;
98 	ParsedAddrSpec m_aInnerAddrSpec;
99 	ParsedAddrSpec * m_pAddrSpec;
100 	sal_Unicode const * m_pRealNameBegin;
101 	sal_Unicode const * m_pRealNameEnd;
102 	sal_Unicode const * m_pRealNameContentBegin;
103 	sal_Unicode const * m_pRealNameContentEnd;
104 	bool m_bRealNameReparse;
105 	bool m_bRealNameFinished;
106 	sal_Unicode const * m_pFirstCommentBegin;
107 	sal_Unicode const * m_pFirstCommentEnd;
108 	bool m_bFirstCommentReparse;
109 	State m_eState;
110 	TokenType m_eType;
111 
112 	inline void resetRealNameAndFirstComment();
113 
114 	inline void reset();
115 
116 	inline void addTokenToAddrSpec(ElementType eTokenElem);
117 
118 	inline void addTokenToRealName();
119 
120 	bool readToken();
121 
122 	static UniString reparse(sal_Unicode const * pBegin,
123 							 sal_Unicode const * pEnd, bool bAddrSpec);
124 
125 	static UniString reparseComment(sal_Unicode const * pBegin,
126 									sal_Unicode const * pEnd);
127 
128 public:
129 	SvAddressParser_Impl(SvAddressParser * pParser, UniString const & rInput);
130 };
131 
132 inline void SvAddressParser_Impl::resetRealNameAndFirstComment()
133 {
134 	m_pRealNameBegin = 0;
135 	m_pRealNameEnd = 0;
136 	m_pRealNameContentBegin = 0;
137 	m_pRealNameContentEnd = 0;
138 	m_bRealNameReparse = false;
139 	m_bRealNameFinished = false;
140 	m_pFirstCommentBegin = 0;
141 	m_pFirstCommentEnd = 0;
142 	m_bFirstCommentReparse = false;
143 }
144 
145 inline void SvAddressParser_Impl::reset()
146 {
147 	m_aOuterAddrSpec.reset();
148 	m_aInnerAddrSpec.reset();
149 	m_pAddrSpec = &m_aOuterAddrSpec;
150 	resetRealNameAndFirstComment();
151 	m_eState = BEFORE_COLON;
152 	m_eType = TOKEN_ATOM;
153 }
154 
155 inline void SvAddressParser_Impl::addTokenToAddrSpec(ElementType eTokenElem)
156 {
157 	if (!m_pAddrSpec->m_pBegin)
158 		m_pAddrSpec->m_pBegin = m_pCurTokenBegin;
159 	else if (m_pAddrSpec->m_pEnd < m_pCurTokenBegin)
160 		m_pAddrSpec->m_bReparse = true;
161 	m_pAddrSpec->m_pEnd = m_pCurTokenEnd;
162 	m_pAddrSpec->m_eLastElem = eTokenElem;
163 }
164 
165 inline void SvAddressParser_Impl::addTokenToRealName()
166 {
167 	if (!m_bRealNameFinished && m_eState != AFTER_LESS)
168 	{
169 		if (!m_pRealNameBegin)
170 			m_pRealNameBegin = m_pRealNameContentBegin = m_pCurTokenBegin;
171 		else if (m_pRealNameEnd < m_pCurTokenBegin - 1
172 				 || (m_pRealNameEnd == m_pCurTokenBegin - 1
173 					&& *m_pRealNameEnd != ' '))
174 			m_bRealNameReparse = true;
175 		m_pRealNameEnd = m_pRealNameContentEnd = m_pCurTokenEnd;
176 	}
177 }
178 
179 //============================================================================
180 //
181 //  SvAddressParser_Impl
182 //
183 //============================================================================
184 
185 bool SvAddressParser_Impl::readToken()
186 {
187 	m_nCurToken = m_eType;
188 	m_bCurTokenReparse = false;
189 	switch (m_eType)
190 	{
191 		case TOKEN_QUOTED:
192 		{
193 			m_pCurTokenBegin = m_pInputPos - 1;
194 			m_pCurTokenContentBegin = m_pInputPos;
195 			bool bEscaped = false;
196 			for (;;)
197 			{
198 				if (m_pInputPos >= m_pInputEnd)
199 					return false;
200 				sal_Unicode cChar = *m_pInputPos++;
201 				if (bEscaped)
202 				{
203 					m_bCurTokenReparse = true;
204 					bEscaped = false;
205 				}
206 				else if (cChar == '"')
207 				{
208 					m_pCurTokenEnd = m_pInputPos;
209 					m_pCurTokenContentEnd = m_pInputPos - 1;
210 					return true;
211 				}
212 				else if (cChar == '\\')
213 					bEscaped = true;
214 			}
215 		}
216 
217 		case TOKEN_DOMAIN:
218 		{
219 			m_pCurTokenBegin = m_pInputPos - 1;
220 			m_pCurTokenContentBegin = m_pInputPos;
221 			bool bEscaped = false;
222 			for (;;)
223 			{
224 				if (m_pInputPos >= m_pInputEnd)
225 					return false;
226 				sal_Unicode cChar = *m_pInputPos++;
227 				if (bEscaped)
228 					bEscaped = false;
229 				else if (cChar == ']')
230 				{
231 					m_pCurTokenEnd = m_pInputPos;
232 					return true;
233 				}
234 				else if (cChar == '\\')
235 					bEscaped = true;
236 			}
237 		}
238 
239 		case TOKEN_COMMENT:
240 		{
241 			m_pCurTokenBegin = m_pInputPos - 1;
242 			m_pCurTokenContentBegin = 0;
243 			m_pCurTokenContentEnd = 0;
244 			bool bEscaped = false;
245 			xub_StrLen nLevel = 0;
246 			for (;;)
247 			{
248 				if (m_pInputPos >= m_pInputEnd)
249 					return false;
250 				sal_Unicode cChar = *m_pInputPos++;
251 				if (bEscaped)
252 				{
253 					m_bCurTokenReparse = true;
254 					m_pCurTokenContentEnd = m_pInputPos;
255 					bEscaped = false;
256 				}
257 				else if (cChar == '(')
258 				{
259 					if (!m_pCurTokenContentBegin)
260 						m_pCurTokenContentBegin = m_pInputPos - 1;
261 					m_pCurTokenContentEnd = m_pInputPos;
262 					++nLevel;
263 				}
264 				else if (cChar == ')')
265 					if (nLevel)
266 					{
267 						m_pCurTokenContentEnd = m_pInputPos;
268 						--nLevel;
269 					}
270 					else
271 						return true;
272 				else if (cChar == '\\')
273 				{
274 					if (!m_pCurTokenContentBegin)
275 						m_pCurTokenContentBegin = m_pInputPos - 1;
276 					bEscaped = true;
277 				}
278 				else if (cChar > ' ' && cChar != 0x7F) // DEL
279 				{
280 					if (!m_pCurTokenContentBegin)
281 						m_pCurTokenContentBegin = m_pInputPos - 1;
282 					m_pCurTokenContentEnd = m_pInputPos;
283 				}
284 			}
285 		}
286 
287 		default:
288 		{
289 			sal_Unicode cChar;
290 			for (;;)
291 			{
292 				if (m_pInputPos >= m_pInputEnd)
293 					return false;
294 				cChar = *m_pInputPos++;
295 				if (cChar > ' ' && cChar != 0x7F) // DEL
296 					break;
297 			}
298 			m_pCurTokenBegin = m_pInputPos - 1;
299 			if (cChar == '"' || cChar == '(' || cChar == ')' || cChar == ','
300 				|| cChar == '.' || cChar == ':' || cChar == ';'
301 				|| cChar == '<' || cChar == '>' || cChar == '@'
302 				|| cChar == '[' || cChar == '\\' || cChar == ']')
303 			{
304 				m_nCurToken = cChar;
305 				m_pCurTokenEnd = m_pInputPos;
306 				return true;
307 			}
308 			else
309 				for (;;)
310 				{
311 					if (m_pInputPos >= m_pInputEnd)
312 					{
313 						m_pCurTokenEnd = m_pInputPos;
314 						return true;
315 					}
316 					cChar = *m_pInputPos++;
317 					if (cChar <= ' ' || cChar == '"' || cChar == '('
318 						|| cChar == ')' || cChar == ',' || cChar == '.'
319 						|| cChar == ':' || cChar == ';' || cChar == '<'
320 						|| cChar == '>' || cChar == '@' || cChar == '['
321 						|| cChar == '\\' || cChar == ']'
322 						|| cChar == 0x7F) // DEL
323 					{
324 						m_pCurTokenEnd = --m_pInputPos;
325 						return true;
326 					}
327 				}
328 		}
329 	}
330 }
331 
332 //============================================================================
333 // static
334 UniString SvAddressParser_Impl::reparse(sal_Unicode const * pBegin,
335 										sal_Unicode const * pEnd,
336 										bool bAddrSpec)
337 {
338 	UniString aResult;
339 	TokenType eMode = TOKEN_ATOM;
340 	bool bEscaped = false;
341 	bool bEndsWithSpace = false;
342 	xub_StrLen nLevel = 0;
343 	while (pBegin < pEnd)
344 	{
345 		sal_Unicode cChar = *pBegin++;
346 		switch (eMode)
347 		{
348 			case TOKEN_QUOTED:
349 				if (bEscaped)
350 				{
351 					aResult += cChar;
352 					bEscaped = false;
353 				}
354 				else if (cChar == '"')
355 				{
356 					if (bAddrSpec)
357 						aResult += cChar;
358 					eMode = TOKEN_ATOM;
359 				}
360 				else if (cChar == '\\')
361 				{
362 					if (bAddrSpec)
363 						aResult += cChar;
364 					bEscaped = true;
365 				}
366 				else
367 					aResult += cChar;
368 				break;
369 
370 			case TOKEN_DOMAIN:
371 				if (bEscaped)
372 				{
373 					aResult += cChar;
374 					bEscaped = false;
375 				}
376 				else if (cChar == ']')
377 				{
378 					aResult += cChar;
379 					eMode = TOKEN_ATOM;
380 				}
381 				else if (cChar == '\\')
382 				{
383 					if (bAddrSpec)
384 						aResult += cChar;
385 					bEscaped = true;
386 				}
387 				else
388 					aResult += cChar;
389 				break;
390 
391 			case TOKEN_COMMENT:
392 				if (bEscaped)
393 					bEscaped = false;
394 				else if (cChar == '(')
395 					++nLevel;
396 				else if (cChar == ')')
397 					if (nLevel)
398 						--nLevel;
399 					else
400 						eMode = TOKEN_ATOM;
401 				else if (cChar == '\\')
402 					bEscaped = true;
403 				break;
404 
405 			case TOKEN_ATOM:
406 				if (cChar <= ' ' || cChar == 0x7F) // DEL
407 				{
408 					if (!bAddrSpec && !bEndsWithSpace)
409 					{
410 						aResult += ' ';
411 						bEndsWithSpace = true;
412 					}
413 				}
414 				else if (cChar == '(')
415 				{
416 					if (!bAddrSpec && !bEndsWithSpace)
417 					{
418 						aResult += ' ';
419 						bEndsWithSpace = true;
420 					}
421 					eMode = TOKEN_COMMENT;
422 				}
423 				else
424 				{
425 					bEndsWithSpace = false;
426 					if (cChar == '"')
427 					{
428 						if (bAddrSpec)
429 							aResult += cChar;
430 						eMode = TOKEN_QUOTED;
431 					}
432 					else if (cChar == '[')
433 					{
434 						aResult += cChar;
435 						eMode = TOKEN_QUOTED;
436 					}
437 					else
438 						aResult += cChar;
439 				}
440 				break;
441 		}
442 	}
443 	return aResult;
444 }
445 
446 //============================================================================
447 // static
448 UniString SvAddressParser_Impl::reparseComment(sal_Unicode const * pBegin,
449 											   sal_Unicode const * pEnd)
450 {
451 	UniString aResult;
452 	while (pBegin < pEnd)
453 	{
454 		sal_Unicode cChar = *pBegin++;
455 		if (cChar == '\\')
456 			cChar = *pBegin++;
457 		aResult += cChar;
458 	}
459 	return aResult;
460 }
461 
462 //============================================================================
463 SvAddressParser_Impl::SvAddressParser_Impl(SvAddressParser * pParser,
464 										   UniString const & rInput)
465 {
466 	m_pInputPos = rInput.GetBuffer();
467 	m_pInputEnd = m_pInputPos + rInput.Len();
468 
469 	reset();
470 	bool bDone = false;
471 	for (;;)
472 	{
473 		if (!readToken())
474 		{
475 			m_bRealNameFinished = true;
476 			if (m_eState == AFTER_LESS)
477 				m_nCurToken = '>';
478 			else
479 			{
480 				m_nCurToken = ',';
481 				bDone = true;
482 			}
483 		}
484 		switch (m_nCurToken)
485 		{
486 			case TOKEN_QUOTED:
487 				if (m_pAddrSpec->m_eLastElem != ELEMENT_END)
488 				{
489 					if (m_pAddrSpec->m_bAtFound
490 						|| m_pAddrSpec->m_eLastElem <= ELEMENT_DELIM)
491 						m_pAddrSpec->reset();
492 					addTokenToAddrSpec(ELEMENT_ITEM);
493 				}
494 				if (!m_bRealNameFinished && m_eState != AFTER_LESS)
495 				{
496 					if (m_bCurTokenReparse)
497 					{
498 						if (!m_pRealNameBegin)
499 							m_pRealNameBegin = m_pCurTokenBegin;
500 						m_pRealNameEnd = m_pCurTokenEnd;
501 						m_bRealNameReparse = true;
502 					}
503 					else if (m_bRealNameReparse)
504 						m_pRealNameEnd = m_pCurTokenEnd;
505 					else if (!m_pRealNameBegin)
506 					{
507 						m_pRealNameBegin = m_pCurTokenBegin;
508 						m_pRealNameContentBegin = m_pCurTokenContentBegin;
509 						m_pRealNameEnd = m_pRealNameContentEnd
510 							= m_pCurTokenContentEnd;
511 					}
512 					else
513 					{
514 						m_pRealNameEnd = m_pCurTokenEnd;
515 						m_bRealNameReparse = true;
516 					}
517 				}
518 				m_eType = TOKEN_ATOM;
519 				break;
520 
521 			case TOKEN_DOMAIN:
522 				if (m_pAddrSpec->m_eLastElem != ELEMENT_END)
523 				{
524 					if (m_pAddrSpec->m_bAtFound
525 						&& m_pAddrSpec->m_eLastElem == ELEMENT_DELIM)
526 						addTokenToAddrSpec(ELEMENT_ITEM);
527 					else
528 						m_pAddrSpec->reset();
529 				}
530 				addTokenToRealName();
531 				m_eType = TOKEN_ATOM;
532 				break;
533 
534 			case TOKEN_COMMENT:
535 				if (!m_bRealNameFinished && m_eState != AFTER_LESS
536 					&& !m_pFirstCommentBegin && m_pCurTokenContentBegin)
537 				{
538 					m_pFirstCommentBegin = m_pCurTokenContentBegin;
539 					m_pFirstCommentEnd = m_pCurTokenContentEnd;
540 					m_bFirstCommentReparse = m_bCurTokenReparse;
541 				}
542 				m_eType = TOKEN_ATOM;
543 				break;
544 
545 			case TOKEN_ATOM:
546 				if (m_pAddrSpec->m_eLastElem != ELEMENT_END)
547 				{
548 					if (m_pAddrSpec->m_eLastElem != ELEMENT_DELIM)
549 						m_pAddrSpec->reset();
550 					addTokenToAddrSpec(ELEMENT_ITEM);
551 				}
552 				addTokenToRealName();
553 				break;
554 
555 			case '(':
556 				m_eType = TOKEN_COMMENT;
557 				break;
558 
559 			case ')':
560 			case '\\':
561 			case ']':
562 				m_pAddrSpec->finish();
563 				addTokenToRealName();
564 				break;
565 
566 			case '<':
567 				switch (m_eState)
568 				{
569 					case BEFORE_COLON:
570 					case BEFORE_LESS:
571 						m_aOuterAddrSpec.finish();
572 						if (m_pRealNameBegin)
573 							m_bRealNameFinished = true;
574 						m_pAddrSpec = &m_aInnerAddrSpec;
575 						m_eState = AFTER_LESS;
576 						break;
577 
578 					case AFTER_LESS:
579 						m_aInnerAddrSpec.finish();
580 						break;
581 
582 					case AFTER_GREATER:
583 						m_aOuterAddrSpec.finish();
584 						addTokenToRealName();
585 						break;
586 				}
587 				break;
588 
589 			case '>':
590 				if (m_eState == AFTER_LESS)
591 				{
592 					m_aInnerAddrSpec.finish();
593 					if (m_aInnerAddrSpec.isValid())
594 						m_aOuterAddrSpec.m_eLastElem = ELEMENT_END;
595 					m_pAddrSpec = &m_aOuterAddrSpec;
596 					m_eState = AFTER_GREATER;
597 				}
598 				else
599 				{
600 					m_aOuterAddrSpec.finish();
601 					addTokenToRealName();
602 				}
603 				break;
604 
605 			case '@':
606 				if (m_pAddrSpec->m_eLastElem != ELEMENT_END)
607 				{
608 					if (!m_pAddrSpec->m_bAtFound
609 						&& m_pAddrSpec->m_eLastElem == ELEMENT_ITEM)
610 					{
611 						addTokenToAddrSpec(ELEMENT_DELIM);
612 						m_pAddrSpec->m_bAtFound = true;
613 					}
614 					else
615 						m_pAddrSpec->reset();
616 				}
617 				addTokenToRealName();
618 				break;
619 
620 			case ',':
621 			case ';':
622 				if (m_eState == AFTER_LESS)
623 					if (m_nCurToken == ',')
624 					{
625 						if (m_aInnerAddrSpec.m_eLastElem
626 							 != ELEMENT_END)
627 							m_aInnerAddrSpec.reset();
628 					}
629 					else
630 						m_aInnerAddrSpec.finish();
631 				else
632 				{
633 					m_pAddrSpec = m_aInnerAddrSpec.isValid()
634 						          || (!m_aOuterAddrSpec.isValid()
635 						                 && m_aInnerAddrSpec.isPoorlyValid()) ?
636 						              &m_aInnerAddrSpec :
637 						          m_aOuterAddrSpec.isPoorlyValid() ?
638 						              &m_aOuterAddrSpec : 0;
639 					if (m_pAddrSpec)
640 					{
641 						UniString aTheAddrSpec;
642 						if (m_pAddrSpec->m_bReparse)
643 							aTheAddrSpec = reparse(m_pAddrSpec->m_pBegin,
644 												   m_pAddrSpec->m_pEnd, true);
645 						else
646 						{
647 							xub_StrLen nLen =
648                                 sal::static_int_cast< xub_StrLen >(
649                                     m_pAddrSpec->m_pEnd
650                                     - m_pAddrSpec->m_pBegin);
651 							if (nLen == rInput.Len())
652 								aTheAddrSpec = rInput;
653 							else
654 								aTheAddrSpec
655 									= rInput.Copy(
656                                         sal::static_int_cast< xub_StrLen >(
657                                             m_pAddrSpec->m_pBegin
658                                             - rInput.GetBuffer()),
659                                         nLen);
660 						}
661 						UniString aTheRealName;
662 						if (!m_pRealNameBegin
663 							|| (m_pAddrSpec == &m_aOuterAddrSpec
664 							   && m_pRealNameBegin
665 							          == m_aOuterAddrSpec.m_pBegin
666 							   && m_pRealNameEnd == m_aOuterAddrSpec.m_pEnd
667 							   && m_pFirstCommentBegin))
668 							if (!m_pFirstCommentBegin)
669 								aTheRealName = aTheAddrSpec;
670 							else if (m_bFirstCommentReparse)
671 								aTheRealName
672 									= reparseComment(m_pFirstCommentBegin,
673 													 m_pFirstCommentEnd);
674 							else
675 								aTheRealName
676 									= rInput.Copy(
677                                         sal::static_int_cast< xub_StrLen >(
678                                             m_pFirstCommentBegin
679                                             - rInput.GetBuffer()),
680                                         sal::static_int_cast< xub_StrLen >(
681                                             m_pFirstCommentEnd
682                                             - m_pFirstCommentBegin));
683 						else if (m_bRealNameReparse)
684 							aTheRealName = reparse(m_pRealNameBegin,
685 												   m_pRealNameEnd, false);
686 						else
687 						{
688 							xub_StrLen nLen =
689                                 sal::static_int_cast< xub_StrLen >(
690                                     m_pRealNameContentEnd
691                                     - m_pRealNameContentBegin);
692 							if (nLen == rInput.Len())
693 								aTheRealName = rInput;
694 							else
695 								aTheRealName
696 									= rInput.Copy(
697                                         sal::static_int_cast< xub_StrLen >(
698                                             m_pRealNameContentBegin
699                                             - rInput.GetBuffer()),
700                                         nLen);
701 						}
702 						if (pParser->m_bHasFirst)
703 							pParser->m_aRest.Insert(new SvAddressEntry_Impl(
704 								                            aTheAddrSpec,
705 															aTheRealName),
706 													LIST_APPEND);
707 						else
708 						{
709 							pParser->m_bHasFirst = true;
710 							pParser->m_aFirst.m_aAddrSpec = aTheAddrSpec;
711 							pParser->m_aFirst.m_aRealName = aTheRealName;
712 						}
713 					}
714 					if (bDone)
715 						return;
716 					reset();
717 				}
718 				break;
719 
720 			case ':':
721 				switch (m_eState)
722 				{
723 					case BEFORE_COLON:
724 						m_aOuterAddrSpec.reset();
725 						resetRealNameAndFirstComment();
726 						m_eState = BEFORE_LESS;
727 						break;
728 
729 					case BEFORE_LESS:
730 					case AFTER_GREATER:
731 						m_aOuterAddrSpec.finish();
732 						addTokenToRealName();
733 						break;
734 
735 					case AFTER_LESS:
736 						m_aInnerAddrSpec.reset();
737 						break;
738 				}
739 				break;
740 
741 			case '"':
742 				m_eType = TOKEN_QUOTED;
743 				break;
744 
745 			case '.':
746 				if (m_pAddrSpec->m_eLastElem != ELEMENT_END)
747 				{
748 					if (m_pAddrSpec->m_eLastElem != ELEMENT_DELIM)
749 						addTokenToAddrSpec(ELEMENT_DELIM);
750 					else
751 						m_pAddrSpec->reset();
752 				}
753 				addTokenToRealName();
754 				break;
755 
756 			case '[':
757 				m_eType = TOKEN_DOMAIN;
758 				break;
759 		}
760 	}
761 }
762 
763 //============================================================================
764 //
765 //  SvAddressParser
766 //
767 //============================================================================
768 
769 SvAddressParser::SvAddressParser(UniString const & rInput): m_bHasFirst(false)
770 {
771 	SvAddressParser_Impl(this, rInput);
772 }
773 
774 //============================================================================
775 SvAddressParser::~SvAddressParser()
776 {
777 	for (sal_uLong i = m_aRest.Count(); i != 0;)
778 		delete m_aRest.Remove(--i);
779 }
780 
781 //============================================================================
782 // static
783 bool SvAddressParser::createRFC822Mailbox(String const & rPhrase,
784 										  String const & rAddrSpec,
785 										  String & rMailbox)
786 {
787 	String aTheAddrSpec;
788 	sal_Unicode const * p = rAddrSpec.GetBuffer();
789 	sal_Unicode const * pEnd = p + rAddrSpec.Len();
790 	{for (bool bSegment = false;;)
791 	{
792 		p = INetMIME::skipLinearWhiteSpaceComment(p, pEnd);
793 		if (p == pEnd)
794 			return false;
795 		if (bSegment)
796 		{
797 			sal_Unicode c = *p++;
798 			if (c == '@')
799 				break;
800 			else if (c != '.')
801 				return false;
802 			aTheAddrSpec += '.';
803 			p = INetMIME::skipLinearWhiteSpaceComment(p, pEnd);
804 			if (p == pEnd)
805 				return false;
806 		}
807 		else
808 			bSegment = true;
809 		if (*p == '"')
810 		{
811 			aTheAddrSpec += *p++;
812 			for (;;)
813 			{
814 				if (INetMIME::startsWithLineFolding(p, pEnd))
815 					p += 2;
816 				if (p == pEnd)
817 					return false;
818 				if (*p == '"')
819 					break;
820 				if (*p == '\x0D' || (*p == '\\' && ++p == pEnd)
821 					|| !INetMIME::isUSASCII(*p))
822 					return false;
823 				if (INetMIME::needsQuotedStringEscape(*p))
824 					aTheAddrSpec += '\\';
825 				aTheAddrSpec += *p++;
826 			}
827 			aTheAddrSpec += *p++;
828 		}
829 		else if (INetMIME::isAtomChar(*p))
830 			while (p != pEnd && INetMIME::isAtomChar(*p))
831 				aTheAddrSpec += *p++;
832 		else
833 			return false;
834 	}}
835 	aTheAddrSpec += '@';
836 	{for (bool bSegment = false;;)
837 	{
838 		p = INetMIME::skipLinearWhiteSpaceComment(p, pEnd);
839 		if (p == pEnd)
840 		{
841 			if (bSegment)
842 				break;
843 			else
844 				return false;
845 		}
846 		if (bSegment)
847 		{
848 			if (*p++ != '.')
849 				return false;
850 			aTheAddrSpec += '.';
851 			p = INetMIME::skipLinearWhiteSpaceComment(p, pEnd);
852 			if (p == pEnd)
853 				return false;
854 		}
855 		else
856 			bSegment = true;
857 		if (*p == '[')
858 		{
859 			aTheAddrSpec += *p++;
860 			for (;;)
861 			{
862 				if (INetMIME::startsWithLineFolding(p, pEnd))
863 					p += 2;
864 				if (p == pEnd)
865 					return false;
866 				if (*p == ']')
867 					break;
868 				if (*p == '\x0D' || *p == '[' || (*p == '\\' && ++p == pEnd)
869 					|| !INetMIME::isUSASCII(*p))
870 					return false;
871 				if (*p >= '[' && *p <= ']')
872 					aTheAddrSpec += '\\';
873 				aTheAddrSpec += *p++;
874 			}
875 			aTheAddrSpec += *p++;
876 		}
877 		else if (INetMIME::isAtomChar(*p))
878 			while (p != pEnd && INetMIME::isAtomChar(*p))
879 				aTheAddrSpec += *p++;
880 		else
881 			return false;
882 	}}
883 
884 	if (rPhrase.Len() == 0)
885 		rMailbox = aTheAddrSpec;
886 	else
887 	{
888 		bool bQuotedString = false;
889 		p = rPhrase.GetBuffer();
890 		pEnd = p + rPhrase.Len();
891 		for (;p != pEnd; ++p)
892 			if (!(INetMIME::isAtomChar(*p)))
893 			{
894 				bQuotedString = true;
895 				break;
896 			}
897 		String aTheMailbox;
898 		if (bQuotedString)
899 		{
900 			aTheMailbox = '"';
901 			for (p = rPhrase.GetBuffer(); p != pEnd; ++p)
902 			{
903 				if (INetMIME::needsQuotedStringEscape(*p))
904 					aTheMailbox += '\\';
905 				aTheMailbox += *p;
906 			}
907 			aTheMailbox += '"';
908 		}
909 		else
910 			aTheMailbox = rPhrase;
911 		aTheMailbox.AppendAscii(RTL_CONSTASCII_STRINGPARAM(" <"));
912 		aTheMailbox += aTheAddrSpec;
913 		aTheMailbox += '>';
914 		rMailbox = aTheMailbox;
915 	}
916 	return true;
917 }
918 
919