xref: /AOO41X/main/svl/source/misc/adrparse.cxx (revision 40df464ee80f942fd2baf5effc726656f4be12a0)
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