xref: /trunk/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