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