Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package perl-Email-Address-XS for 
openSUSE:Factory checked in at 2022-08-16 17:08:34
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/perl-Email-Address-XS (Old)
 and      /work/SRC/openSUSE:Factory/.perl-Email-Address-XS.new.1521 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "perl-Email-Address-XS"

Tue Aug 16 17:08:34 2022 rev:2 rq:997351 version:1.05

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/perl-Email-Address-XS/perl-Email-Address-XS.changes  
    2018-10-08 17:50:48.350072341 +0200
+++ 
/work/SRC/openSUSE:Factory/.perl-Email-Address-XS.new.1521/perl-Email-Address-XS.changes
    2022-08-16 17:08:39.820043163 +0200
@@ -1,0 +2,11 @@
+Mon Aug  8 03:08:40 UTC 2022 - Tina M??ller <[email protected]>
+
+- updated to 1.05
+   see /usr/share/doc/packages/perl-Email-Address-XS/Changes
+
+  1.05  Sun Aug 07 15:21:35 2022
+       - update dovecot parser from dovecot version 2.3.14
+       - mark the last parsed object as invalid if input string contains 
trailing garbage
+         https://github.com/pali/Email-Address-XS/issues/5
+
+-------------------------------------------------------------------

Old:
----
  Email-Address-XS-1.04.tar.gz

New:
----
  Email-Address-XS-1.05.tar.gz
  cpanspec.yml

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ perl-Email-Address-XS.spec ++++++
--- /var/tmp/diff_new_pack.xdrBDR/_old  2022-08-16 17:08:40.296044586 +0200
+++ /var/tmp/diff_new_pack.xdrBDR/_new  2022-08-16 17:08:40.300044598 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package perl-Email-Address-XS
 #
-# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2022 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -12,20 +12,19 @@
 # license that conforms to the Open Source Definition (Version 1.9)
 # published by the Open Source Initiative.
 
-# Please submit bugfixes or comments via http://bugs.opensuse.org/
+# Please submit bugfixes or comments via https://bugs.opensuse.org/
 #
 
 
+%define cpan_name Email-Address-XS
 Name:           perl-Email-Address-XS
-Version:        1.04
+Version:        1.05
 Release:        0
-%define cpan_name Email-Address-XS
-Summary:        Parse and format RFC 5322 email addresses and groups
 License:        Artistic-1.0 OR GPL-1.0-or-later
-Group:          Development/Libraries/Perl
-Url:            http://search.cpan.org/dist/Email-Address-XS/
+Summary:        Parse and format RFC 5322 email addresses and groups
+URL:            https://metacpan.org/release/%{cpan_name}
 Source0:        
https://cpan.metacpan.org/authors/id/P/PA/PALI/%{cpan_name}-%{version}.tar.gz
-BuildRoot:      %{_tmppath}/%{name}-%{version}-build
+Source1:        cpanspec.yml
 BuildRequires:  perl
 BuildRequires:  perl-macros
 %{perl_requires}
@@ -68,15 +67,15 @@
 Email::MIME::Header::AddressList.
 
 %prep
-%setup -q -n %{cpan_name}-%{version}
-find . -type f ! -name \*.pl -print0 | xargs -0 chmod 644
+%autosetup  -n %{cpan_name}-%{version}
+find . -type f ! -path "*/t/*" ! -name "*.pl" ! -path "*/bin/*" ! -path 
"*/script/*" ! -name "configure" -print0 | xargs -0 chmod 644
 
 %build
-%{__perl} Makefile.PL INSTALLDIRS=vendor OPTIMIZE="%{optflags}"
-%{__make} %{?_smp_mflags}
+perl Makefile.PL INSTALLDIRS=vendor OPTIMIZE="%{optflags}"
+%make_build
 
 %check
-%{__make} test
+make test
 
 %install
 %perl_make_install
@@ -84,7 +83,6 @@
 %perl_gen_filelist
 
 %files -f %{name}.files
-%defattr(-,root,root,755)
 %doc Changes README
 
 %changelog

++++++ Email-Address-XS-1.04.tar.gz -> Email-Address-XS-1.05.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Email-Address-XS-1.04/Changes 
new/Email-Address-XS-1.05/Changes
--- old/Email-Address-XS-1.04/Changes   2018-06-09 18:24:00.000000000 +0200
+++ new/Email-Address-XS-1.05/Changes   2022-08-07 15:31:30.000000000 +0200
@@ -1,5 +1,10 @@
 Revision history for Perl extension Email::Address::XS.
 
+1.05  Sun Aug 07 15:21:35 2022
+       - update dovecot parser from dovecot version 2.3.14
+       - mark the last parsed object as invalid if input string contains 
trailing garbage
+         https://github.com/pali/Email-Address-XS/issues/5
+
 1.04  Sat Jun 09 18:20:28 2018
        - fix docevot parser to disallow leading dot in dot-atom
        - fix generating and validating email addresses with empty user part
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Email-Address-XS-1.04/Email-Address-XS.xs 
new/Email-Address-XS-1.05/Email-Address-XS.xs
--- old/Email-Address-XS-1.04/Email-Address-XS.xs       2018-06-09 
18:24:00.000000000 +0200
+++ new/Email-Address-XS-1.05/Email-Address-XS.xs       2022-08-07 
15:31:30.000000000 +0200
@@ -681,7 +681,7 @@
                XSRETURN_EMPTY;
        }
 PPCODE:
-       first_address = message_address_parse(input, input_len, UINT_MAX, 
false);
+       first_address = message_address_parse(input, input_len, UINT_MAX, 
MESSAGE_ADDRESS_PARSE_FLAG_NON_STRICT_DOTS_AS_INVALID);
        count = count_address_groups(first_address);
        EXTEND(SP, count * 2);
        address = first_address;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Email-Address-XS-1.04/META.json 
new/Email-Address-XS-1.05/META.json
--- old/Email-Address-XS-1.04/META.json 2018-06-09 18:25:06.000000000 +0200
+++ new/Email-Address-XS-1.05/META.json 2022-08-07 15:31:38.000000000 +0200
@@ -59,6 +59,6 @@
          "web" : "https://github.com/pali/Email-Address-XS";
       }
    },
-   "version" : "1.04",
+   "version" : "1.05",
    "x_serialization_backend" : "JSON::PP version 2.97001"
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Email-Address-XS-1.04/META.yml 
new/Email-Address-XS-1.05/META.yml
--- old/Email-Address-XS-1.04/META.yml  2018-06-09 18:25:06.000000000 +0200
+++ new/Email-Address-XS-1.05/META.yml  2022-08-07 15:31:38.000000000 +0200
@@ -30,5 +30,5 @@
 resources:
   bugtracker: https://github.com/pali/Email-Address-XS/issues
   repository: git://github.com/pali/Email-Address-XS.git
-version: '1.04'
+version: '1.05'
 x_serialization_backend: 'CPAN::Meta::YAML version 0.018'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Email-Address-XS-1.04/dovecot-parser.c 
new/Email-Address-XS-1.05/dovecot-parser.c
--- old/Email-Address-XS-1.04/dovecot-parser.c  2018-06-09 18:24:00.000000000 
+0200
+++ new/Email-Address-XS-1.05/dovecot-parser.c  2022-08-07 15:31:30.000000000 
+0200
@@ -57,6 +57,9 @@
 struct rfc822_parser_context {
        const unsigned char *data, *end;
        string_t *last_comment;
+
+       /* Replace NUL characters with this string */
+       const char *nul_replacement_str;
 };
 
 struct message_address_parser_context {
@@ -65,7 +68,7 @@
        struct message_address *first_addr, *last_addr, addr;
        string_t *str;
 
-       bool fill_missing;
+       bool fill_missing, non_strict_dots, non_strict_dots_as_invalid;
 };
 
 static string_t *str_new(size_t initial_size)
@@ -309,6 +312,15 @@
        ctx->last_comment = last_comment;
 }
 
+static void rfc822_parser_deinit(struct rfc822_parser_context *ctx)
+{
+       /* make sure the parsing didn't trigger a bug that caused reading
+          past the end pointer. */
+       i_assert(ctx->data <= ctx->end);
+       /* make sure the parser is no longer accessed */
+       ctx->data = ctx->end = NULL;
+}
+
 /* The functions below return 1 = more data available, 0 = no more data
    available (but a value might have been returned now), -1 = invalid input.
 
@@ -319,6 +331,7 @@
 static int rfc822_skip_comment(struct rfc822_parser_context *ctx)
 {
        const unsigned char *start;
+       size_t len;
        int level = 1;
 
        i_assert(*ctx->data == '(');
@@ -329,6 +342,19 @@
        start = ++ctx->data;
        for (; ctx->data < ctx->end; ctx->data++) {
                switch (*ctx->data) {
+               case '\0':
+                       if (ctx->nul_replacement_str != NULL) {
+                               if (ctx->last_comment != NULL) {
+                                       str_append_data(ctx->last_comment, 
start,
+                                                       ctx->data - start);
+                                       str_append(ctx->last_comment,
+                                                  ctx->nul_replacement_str);
+                                       start = ctx->data + 1;
+                               }
+                       } else {
+                               return -1;
+                       }
+                       break;
                case '(':
                        level++;
                        break;
@@ -336,22 +362,41 @@
                        if (--level == 0) {
                                if (ctx->last_comment != NULL) {
                                        str_append_data(ctx->last_comment, 
start,
-                                                    ctx->data - start);
+                                                       ctx->data - start);
                                }
                                ctx->data++;
                                return ctx->data < ctx->end ? 1 : 0;
                        }
                        break;
-               case '\\':
-                       if (ctx->last_comment != NULL) {
-                               str_append_data(ctx->last_comment, start,
-                                            ctx->data - start);
-                       }
+               case '\n':
+                       /* folding whitespace, remove the (CR)LF */
+                       if (ctx->last_comment == NULL)
+                               break;
+                       len = ctx->data - start;
+                       if (len > 0 && start[len-1] == '\r')
+                               len--;
+                       str_append_data(ctx->last_comment, start, len);
                        start = ctx->data + 1;
-
+                       break;
+               case '\\':
                        ctx->data++;
                        if (ctx->data >= ctx->end)
                                return -1;
+#if 0
+                       if (*ctx->data == '\r' || *ctx->data == '\n' ||
+                           *ctx->data == '\0') {
+                               /* quoted-pair doesn't allow CR/LF/NUL.
+                                  They are part of the obs-qp though, so don't
+                                  return them as error. */
+                               ctx->data--;
+                               break;
+                       }
+#endif
+                       if (ctx->last_comment != NULL) {
+                               str_append_data(ctx->last_comment, start,
+                                               ctx->data - start - 1);
+                       }
+                       start = ctx->data;
                        break;
                }
        }
@@ -379,10 +424,36 @@
        return ctx->data < ctx->end ? 1 : 0;
 }
 
+/* Stop at next non-atext char */
+int rfc822_parse_atom(struct rfc822_parser_context *ctx, string_t *str)
+{
+       const unsigned char *start;
+
+       /*
+          atom            = [CFWS] 1*atext [CFWS]
+          atext           =
+            ; Any character except controls, SP, and specials.
+       */
+       if (ctx->data >= ctx->end || !IS_ATEXT(*ctx->data))
+               return -1;
+
+       for (start = ctx->data++; ctx->data < ctx->end; ctx->data++) {
+               if (IS_ATEXT(*ctx->data))
+                       continue;
+
+               str_append_data(str, start, ctx->data - start);
+               return rfc822_skip_lwsp(ctx);
+       }
+
+       str_append_data(str, start, ctx->data - start);
+       return 0;
+}
+
 /* Like parse_atom() but don't stop at '.' */
-static int rfc822_parse_dot_atom(struct rfc822_parser_context *ctx, string_t 
*str)
+static int rfc822_parse_dot_atom(struct rfc822_parser_context *ctx, string_t 
*str, bool stop_trailing_dot)
 {
        const unsigned char *start;
+       const unsigned char *last_dot_ptr;
        bool last_is_dot;
        bool dot_problem;
        int ret;
@@ -399,6 +470,7 @@
        if (ctx->data >= ctx->end || !IS_ATEXT(*ctx->data))
                return -1;
 
+       last_dot_ptr = ctx->data;
        last_is_dot = false;
        dot_problem = false;
 
@@ -408,6 +480,10 @@
                        continue;
                }
 
+#if 0
+               if (start == ctx->data)
+                       dot_problem = true;
+#endif
                str_append_data(str, start, ctx->data - start);
 
                if (ctx->data - start > 0)
@@ -416,21 +492,30 @@
                if ((ret = rfc822_skip_lwsp(ctx)) <= 0)
                        return (dot_problem && ret >= 0) ? -2 : ret;
 
-               if (*ctx->data != '.')
+               if (*ctx->data != '.') {
+                       if (last_is_dot && stop_trailing_dot) {
+                               ctx->data = last_dot_ptr;
+                               return dot_problem ? -2 : 1;
+                       }
                        return (last_is_dot || dot_problem) ? -2 : 1;
+               }
 
                if (last_is_dot)
                        dot_problem = true;
 
+               last_dot_ptr = ctx->data;
                ctx->data++;
                str_append_c(str, '.');
                last_is_dot = true;
 
-               if ((ret = rfc822_skip_lwsp(ctx)) <= 0)
+               if (rfc822_skip_lwsp(ctx) <= 0)
                        return (dot_problem && ret >= 0) ? -2 : ret;
                start = ctx->data;
        }
 
+#if 0
+       i_assert(start != ctx->data);
+#endif
        str_append_data(str, start, ctx->data - start);
        return dot_problem ? -2 : 0;
 }
@@ -439,33 +524,65 @@
 static int rfc822_parse_quoted_string(struct rfc822_parser_context *ctx, 
string_t *str)
 {
        const unsigned char *start;
+       bool char_problem;
+       int ret;
        size_t len;
 
        i_assert(ctx->data < ctx->end);
        i_assert(*ctx->data == '"');
        ctx->data++;
+       char_problem = false;
 
        for (start = ctx->data; ctx->data < ctx->end; ctx->data++) {
                switch (*ctx->data) {
+               case '\0':
+                       if (ctx->nul_replacement_str != NULL) {
+                               str_append_data(str, start, ctx->data - start);
+                               str_append(str, ctx->nul_replacement_str);
+                               start = ctx->data + 1;
+                       } else {
+                               char_problem = true;
+                       }
+                       break;
                case '"':
                        str_append_data(str, start, ctx->data - start);
                        ctx->data++;
-                       return rfc822_skip_lwsp(ctx);
+                       ret = rfc822_skip_lwsp(ctx);
+                       return (char_problem && ret >= 0) ? -2 : ret;
+               case '\r':
+                       if (ctx->data+1 < ctx->end && *(ctx->data+1) != '\n')
+                               char_problem = true;
+                       break;
                case '\n':
+#if 0
                        /* folding whitespace, remove the (CR)LF */
                        len = ctx->data - start;
                        if (len > 0 && start[len-1] == '\r')
                                len--;
                        str_append_data(str, start, len);
                        start = ctx->data + 1;
+#endif
+                       len = ctx->data - start;
+                       if (len <= 0 || start[len-1] != '\r')
+                               char_problem = true;
                        break;
                case '\\':
                        ctx->data++;
                        if (ctx->data >= ctx->end)
                                return -1;
-
+#if 0
+                       if (*ctx->data == '\r' || *ctx->data == '\n' ||
+                           *ctx->data == '\0') {
+                               /* quoted-pair doesn't allow CR/LF/NUL.
+                                  They are part of the obs-qp though, so don't
+                                  return them as error. */
+                               ctx->data--;
+                               break;
+                       }
+#endif
                        str_append_data(str, start, ctx->data - start - 1);
-                       start = ctx->data;
+                       str_append_c(str, *ctx->data);
+                       start = ctx->data+1;
                        break;
                }
        }
@@ -503,6 +620,9 @@
 static int rfc822_parse_phrase(struct rfc822_parser_context *ctx, string_t 
*str)
 {
        int ret;
+       bool char_problem;
+
+       char_problem = false;
 
        /*
           phrase     = 1*word / obs-phrase
@@ -521,21 +641,29 @@
                else
                        ret = rfc822_parse_atom_or_dot(ctx, str);
 
-               if (ret <= 0)
-                       return ret;
+               if (ret <= 0 && ret != -2)
+                       return (char_problem && ret == 0) ? -2 : ret;
+
+               if (ret == -2) {
+                       char_problem = true;
+                       if (ctx->data >= ctx->end)
+                               return -2;
+               }
 
                if (!IS_ATEXT(*ctx->data) && *ctx->data != '"'
                    && *ctx->data != '.')
                        break;
                str_append_c(str, ' ');
        }
-       return rfc822_skip_lwsp(ctx);
+       ret = rfc822_skip_lwsp(ctx);
+       return (char_problem && ret >= 0) ? -2 : ret;
 }
 
 static int
 rfc822_parse_domain_literal(struct rfc822_parser_context *ctx, string_t *str)
 {
        const unsigned char *start;
+       size_t len;
 
        /*
           domain-literal  = [CFWS] "[" *([FWS] dcontent) [FWS] "]" [CFWS]
@@ -548,15 +676,50 @@
        i_assert(ctx->data < ctx->end);
        i_assert(*ctx->data == '[');
 
-       for (start = ctx->data; ctx->data < ctx->end; ctx->data++) {
-               if (*ctx->data == '\\') {
+       for (start = ctx->data++; ctx->data < ctx->end; ctx->data++) {
+               switch (*ctx->data) {
+               case '\0':
+                       if (ctx->nul_replacement_str != NULL) {
+                               str_append_data(str, start, ctx->data - start);
+                               str_append(str, ctx->nul_replacement_str);
+                               start = ctx->data + 1;
+                       } else {
+                               return -1;
+                       }
+                       break;
+               case '[':
+                       /* not allowed */
+                       return -1;
+               case ']':
+                       str_append_data(str, start, ctx->data - start + 1);
+                       ctx->data++;
+                       return rfc822_skip_lwsp(ctx);
+               case '\n':
+                       /* folding whitespace, remove the (CR)LF */
+                       len = ctx->data - start;
+                       if (len > 0 && start[len-1] == '\r')
+                               len--;
+                       str_append_data(str, start, len);
+                       start = ctx->data + 1;
+                       break;
+               case '\\':
+                       /* note: the '\' is preserved in the output */
                        ctx->data++;
                        if (ctx->data >= ctx->end)
+                               return -1;
+#if 0
+                       if (*ctx->data == '\r' || *ctx->data == '\n' ||
+                           *ctx->data == '\0') {
+                               /* quoted-pair doesn't allow CR/LF/NUL.
+                                  They are part of the obs-qp though, so don't
+                                  return them as error. */
+                               str_append_data(str, start, ctx->data - start);
+                               start = ctx->data;
+                               ctx->data--;
                                break;
-               } else if (*ctx->data == ']') {
-                       ctx->data++;
-                       str_append_data(str, start, ctx->data - start);
-                       return rfc822_skip_lwsp(ctx);
+                       }
+#endif
+                       break;
                }
        }
 
@@ -582,7 +745,7 @@
        if (*ctx->data == '[')
                return rfc822_parse_domain_literal(ctx, str);
        else
-               return rfc822_parse_dot_atom(ctx, str);
+               return rfc822_parse_dot_atom(ctx, str, false);
 }
 
 static void add_address(struct message_address_parser_context *ctx)
@@ -603,9 +766,33 @@
        ctx->last_addr = addr;
 }
 
+static int
+parse_nonstrict_dot_atom(struct rfc822_parser_context *ctx, string_t *str)
+{
+       int ret = -1;
+
+       do {
+               while (*ctx->data == '.') {
+                       str_append_c(str, '.');
+                       ctx->data++;
+                       if (ctx->data == ctx->end) {
+                               /* @domain is missing, but local-part
+                                  parsing was successful */
+                               return 0;
+                       }
+                       ret = 1;
+               }
+               if (*ctx->data == '@')
+                       break;
+               ret = rfc822_parse_atom(ctx, str);
+       } while (ret > 0 && *ctx->data == '.');
+       return ret;
+}
+
 static int parse_local_part(struct message_address_parser_context *ctx)
 {
        int ret;
+       bool char_problem;
 
        /*
           local-part      = dot-atom / quoted-string / obs-local-part
@@ -614,12 +801,40 @@
        i_assert(ctx->parser.data < ctx->parser.end);
 
        str_truncate(ctx->str, 0);
-       if (*ctx->parser.data == '"')
-               ret = rfc822_parse_quoted_string(&ctx->parser, ctx->str);
-       else
-               ret = rfc822_parse_dot_atom(&ctx->parser, ctx->str);
-       if (ret < 0 && ret != -2)
-               return -1;
+       char_problem = false;
+
+       while (ctx->parser.data < ctx->parser.end) {
+               if (*ctx->parser.data == '"')
+                       ret = rfc822_parse_quoted_string(&ctx->parser, 
ctx->str);
+               else if (!ctx->non_strict_dots || 
ctx->non_strict_dots_as_invalid)
+                       ret = rfc822_parse_dot_atom(&ctx->parser, ctx->str, 
true);
+               else
+                       ret = parse_nonstrict_dot_atom(&ctx->parser, ctx->str);
+               if (ret < 0 && (ret != -2 || (!ctx->non_strict_dots && 
!ctx->non_strict_dots_as_invalid)))
+                       return -1;
+               if (ret == -2)
+                       char_problem = true;
+               if (ctx->parser.data >= ctx->parser.end)
+                       break;
+               if ((ret = rfc822_skip_lwsp(&ctx->parser)) <= 0)
+                       break;
+               if (*ctx->parser.data != '.')
+                       break;
+               ctx->parser.data++;
+               if (ctx->parser.data >= ctx->parser.end) {
+                       char_problem = true;
+                       break;
+               }
+               if ((ret = rfc822_skip_lwsp(&ctx->parser)) <= 0)
+                       break;
+               if (ctx->parser.data >= ctx->parser.end || *ctx->parser.data == 
'@') {
+                       char_problem = true;
+                       break;
+               }
+       }
+
+       if (char_problem || ret < 0)
+               ctx->addr.invalid_syntax = true;
 
        ctx->addr.mailbox = str_ccopy(ctx->str);
        ctx->addr.mailbox_len = str_len(ctx->str);
@@ -631,7 +846,7 @@
        int ret;
 
        str_truncate(ctx->str, 0);
-       if ((ret = rfc822_parse_domain(&ctx->parser, ctx->str)) < 0 && ret != 
-2)
+       if ((ret = rfc822_parse_domain(&ctx->parser, ctx->str)) < 0 && (ret != 
-2 || (!ctx->non_strict_dots && !ctx->non_strict_dots_as_invalid)))
                return -1;
 
        ctx->addr.domain = str_ccopy(ctx->str);
@@ -658,7 +873,7 @@
                        str_append_c(ctx->str, ',');
 
                str_append_c(ctx->str, '@');
-               if ((ret = rfc822_parse_domain(&ctx->parser, ctx->str)) <= 0 && 
ret != -2)
+               if ((ret = rfc822_parse_domain(&ctx->parser, ctx->str)) <= 0 && 
(ret != -2 || (!ctx->non_strict_dots && !ctx->non_strict_dots_as_invalid)))
                        return ret;
 
                if (ret == -2)
@@ -673,7 +888,8 @@
        return dot_problem ? -2 : 1;
 }
 
-static int parse_angle_addr(struct message_address_parser_context *ctx)
+static int parse_angle_addr(struct message_address_parser_context *ctx,
+                           bool parsing_path)
 {
        int ret;
 
@@ -681,11 +897,15 @@
        i_assert(*ctx->parser.data == '<');
        ctx->parser.data++;
 
-       if ((ret = rfc822_skip_lwsp(&ctx->parser)) <= 0)
-               return ret;
+       if (rfc822_skip_lwsp(&ctx->parser) <= 0)
+               return -1;
 
        if (*ctx->parser.data == '@') {
-               if ((ret = parse_domain_list(ctx)) <= 0 || *ctx->parser.data != 
':') {
+               if ((ret = parse_domain_list(ctx)) > 0 && *ctx->parser.data == 
':') {
+                       ctx->parser.data++;
+               } else if (parsing_path && (ctx->parser.data >= ctx->parser.end 
|| *ctx->parser.data != ':')) {
+                       return -1;
+               } else {
                        if (ctx->fill_missing && ret != -2)
                                ctx->addr.route = strdup("INVALID_ROUTE");
                        ctx->addr.invalid_syntax = true;
@@ -694,26 +914,23 @@
                        if (ret == -2)
                                ctx->parser.data++;
                        /* try to continue anyway */
-               } else {
-                       ctx->parser.data++;
                }
-               ctx->parser.data++;
-               if ((ret = rfc822_skip_lwsp(&ctx->parser)) <= 0)
-                       return ret;
+               if (rfc822_skip_lwsp(&ctx->parser) <= 0)
+                       return -1;
        }
 
        if (*ctx->parser.data == '>') {
                /* <> address isn't valid */
        } else {
-               if ((ret = parse_local_part(ctx)) <= 0 && ret != -2)
-                       return ret;
+               if ((ret = parse_local_part(ctx)) <= 0 && (ret != -2 || 
(!ctx->non_strict_dots && !ctx->non_strict_dots_as_invalid)))
+                       return -1;
                if (ret == -2)
                        ctx->addr.invalid_syntax = true;
                if (ctx->parser.data >= ctx->parser.end)
                        return 0;
                if (*ctx->parser.data == '@') {
-                       if ((ret = parse_domain(ctx)) <= 0 && ret != -2)
-                               return ret;
+                       if ((ret = parse_domain(ctx)) <= 0 && (ret != -2 || 
(!ctx->non_strict_dots && !ctx->non_strict_dots_as_invalid)))
+                               return -1;
                        if (ret == -2)
                                ctx->addr.invalid_syntax = true;
                        if (ctx->parser.data >= ctx->parser.end)
@@ -730,15 +947,21 @@
 
 static int parse_name_addr(struct message_address_parser_context *ctx)
 {
+       int ret;
+
        /*
           name-addr       = [display-name] angle-addr
           display-name    = phrase
        */
        str_truncate(ctx->str, 0);
-       if (rfc822_parse_phrase(&ctx->parser, ctx->str) <= 0 ||
+       ret = rfc822_parse_phrase(&ctx->parser, ctx->str);
+       if ((ret <= 0 && (ret != -2 || (!ctx->non_strict_dots && 
!ctx->non_strict_dots_as_invalid))) ||
            *ctx->parser.data != '<')
                return -1;
 
+       if (ret == -2)
+               ctx->addr.invalid_syntax = true;
+
        if (str_len(ctx->str) == 0) {
                /* Cope with "<address>" without display name */
                ctx->addr.name = NULL;
@@ -750,7 +973,7 @@
        if (ctx->parser.last_comment != NULL)
                str_truncate(ctx->parser.last_comment, 0);
 
-       if (parse_angle_addr(ctx) < 0) {
+       if (parse_angle_addr(ctx, false) < 0) {
                /* broken */
                if (ctx->fill_missing)
                        ctx->addr.domain = strdup("SYNTAX_ERROR");
@@ -913,10 +1136,14 @@
           display-name    = phrase
        */
        str_truncate(ctx->str, 0);
-       if (rfc822_parse_phrase(&ctx->parser, ctx->str) <= 0 ||
+       ret = rfc822_parse_phrase(&ctx->parser, ctx->str);
+       if ((ret <= 0 && (ret != -2 || (!ctx->non_strict_dots && 
!ctx->non_strict_dots_as_invalid))) ||
            *ctx->parser.data != ':')
                return -1;
 
+       if (ret == -2)
+               ctx->addr.invalid_syntax = true;
+
        /* from now on don't return -1 even if there are problems, so that
           the caller knows this is a group */
        ctx->parser.data++;
@@ -989,6 +1216,7 @@
                        break;
                if (ctx->parser.data >= ctx->parser.end ||
                    *ctx->parser.data != ',') {
+                       ctx->last_addr->invalid_syntax = true;
                        ret = -1;
                        break;
                }
@@ -1087,7 +1315,8 @@
 
 struct message_address *
 message_address_parse(const char *input, size_t input_len,
-                     unsigned int max_addresses, bool fill_missing)
+                     unsigned int max_addresses,
+                     enum message_address_parse_flags flags)
 {
        string_t *str;
        struct message_address_parser_context ctx;
@@ -1105,13 +1334,17 @@
        }
 
        ctx.str = str_new(128);
-       ctx.fill_missing = fill_missing;
+       ctx.fill_missing = (flags & MESSAGE_ADDRESS_PARSE_FLAG_FILL_MISSING) != 
0;
+       ctx.non_strict_dots = (flags & MESSAGE_ADDRESS_PARSE_FLAG_STRICT_DOTS) 
== 0;
+       ctx.non_strict_dots_as_invalid = (flags & 
MESSAGE_ADDRESS_PARSE_FLAG_NON_STRICT_DOTS_AS_INVALID) != 0;
 
        (void)parse_address_list(&ctx, max_addresses);
 
        str_free(&ctx.str);
        str_free(&str);
 
+       rfc822_parser_deinit(&ctx.parser);
+
        return ctx.first_addr;
 }
 
@@ -1140,6 +1373,18 @@
 
        str = str_new(128);
 
+#if 0
+       if (addr == NULL)
+               return;
+
+       /* <> path */
+       if (addr->mailbox == NULL && addr->domain == NULL) {
+               i_assert(addr->next == NULL);
+               str_append(str, "<>");
+               return;
+       }
+#endif
+
        /* a) mailbox@domain
           b) name <@route:mailbox@domain>
           c) group: .. ; */
@@ -1278,6 +1523,8 @@
 
        ctx.str = str_new(128);
        ctx.fill_missing = false;
+       ctx.non_strict_dots = false;
+       ctx.non_strict_dots_as_invalid = false;
 
        ret = rfc822_skip_lwsp(&ctx.parser);
 
@@ -1286,6 +1533,9 @@
        else
                ret = -1;
 
+       if (ret >= 0)
+               ret = rfc822_skip_lwsp(&ctx.parser);
+
        if (ret < 0 || ctx.parser.data != ctx.parser.end || 
ctx.addr.invalid_syntax) {
                free(ctx.addr.mailbox);
                free(ctx.addr.domain);
@@ -1305,6 +1555,8 @@
        free(ctx.addr.name);
        free(ctx.addr.original);
 
+       rfc822_parser_deinit(&ctx.parser);
+
        str_free(&ctx.str);
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Email-Address-XS-1.04/dovecot-parser.h 
new/Email-Address-XS-1.05/dovecot-parser.h
--- old/Email-Address-XS-1.04/dovecot-parser.h  2018-06-09 18:23:51.000000000 
+0200
+++ new/Email-Address-XS-1.05/dovecot-parser.h  2022-08-07 15:31:30.000000000 
+0200
@@ -3,6 +3,20 @@
 
 #include <stdbool.h>
 
+enum message_address_parse_flags {
+       /* If enabled, missing mailbox and domain are set to MISSING_MAILBOX
+          and MISSING_DOMAIN strings. Otherwise they're set to "". */
+       MESSAGE_ADDRESS_PARSE_FLAG_FILL_MISSING = (1 << 0),
+       /* Require local-part to strictly adhere to RFC5322 when parsing dots.
+          For example ".user", "us..ser" and "user." will be invalid. This
+          isn't enabled by default, because these kind of invalid addresses
+          are commonly used in Japan. */
+       MESSAGE_ADDRESS_PARSE_FLAG_STRICT_DOTS = (1 << 1),
+       /* Same as MESSAGE_ADDRESS_PARSE_FLAG_STRICT_DOTS, but accept also
+          non-strict input. Flag invalid_syntax will be set to true. */
+       MESSAGE_ADDRESS_PARSE_FLAG_NON_STRICT_DOTS_AS_INVALID = (1 << 2),
+};
+
 /* group: ... ; will be stored like:
    {name = NULL, NULL, "group", NULL}, ..., {NULL, NULL, NULL, NULL}
 */
@@ -28,14 +42,10 @@
        bool invalid_syntax;
 };
 
-/* Parse message addresses from given data. If fill_missing is TRUE, missing
-   mailbox and domain are set to MISSING_MAILBOX and MISSING_DOMAIN strings.
-   Otherwise they're set to "".
-
-   Note that giving an empty string will return NULL since there are no
-   addresses. */
+/* Parse message addresses from given data. Note that giving an empty string
+   will return NULL since there are no addresses. */
 struct message_address *
-message_address_parse(const char *str, size_t len, unsigned int max_addresses, 
bool fill_missing);
+message_address_parse(const char *str, size_t len, unsigned int max_addresses, 
enum message_address_parse_flags flags);
 
 void message_address_add(struct message_address **first, struct 
message_address **last,
                         const char *name, size_t name_len, const char *route, 
size_t route_len,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Email-Address-XS-1.04/lib/Email/Address/XS.pm 
new/Email-Address-XS-1.05/lib/Email/Address/XS.pm
--- old/Email-Address-XS-1.04/lib/Email/Address/XS.pm   2018-06-09 
18:24:00.000000000 +0200
+++ new/Email-Address-XS-1.05/lib/Email/Address/XS.pm   2022-08-07 
15:31:30.000000000 +0200
@@ -6,7 +6,7 @@
 use strict;
 use warnings;
 
-our $VERSION = '1.04';
+our $VERSION = '1.05';
 
 use Carp;
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Email-Address-XS-1.04/t/Email-Address-XS.t 
new/Email-Address-XS-1.05/t/Email-Address-XS.t
--- old/Email-Address-XS-1.04/t/Email-Address-XS.t      2018-06-09 
18:24:00.000000000 +0200
+++ new/Email-Address-XS-1.05/t/Email-Address-XS.t      2022-08-07 
15:31:30.000000000 +0200
@@ -19,7 +19,7 @@
 $Carp::Internal{'Test::Builder'} = 1;
 $Carp::Internal{'Test::More'} = 1;
 
-use Test::More tests => 511;
+use Test::More tests => 516;
 use Test::Builder;
 
 local $SIG{__WARN__} = sub {
@@ -698,6 +698,16 @@
                is($address->address(), '"winston.smith."@recdep.minitrue', 
$subtest);
        }
 
+       {
+               my $subtest = 'test method parse() in scalar context with valid 
address followed by garbage';
+               my $address = 
Email::Address::XS->parse('[email protected] garbage');
+               ok(!$address->is_valid(), $subtest);
+               is($address->original(), '[email protected] ', 
$subtest);
+               is($address->user(), 'winston.smith', $subtest);
+               is($address->host(), 'recdep.minitrue', $subtest);
+               is($address->address(), '[email protected]', 
$subtest);
+       }
+
 }
 
 #########################

++++++ cpanspec.yml ++++++
---
#description_paragraphs: 3
#description: |-
#  override description from CPAN
#summary: override summary from CPAN
#no_testing: broken upstream
#sources:
#  - source1
#  - source2
#patches:
#  foo.patch: -p1
#  bar.patch:
#  baz.patch: PATCH-FIX-OPENSUSE
#preamble: |-
# BuildRequires:  gcc-c++
#post_prep: |-
# hunspell=`pkg-config --libs hunspell | sed -e 's,-l,,; s,  *,,g'`
# sed -i -e "s,hunspell-X,$hunspell," t/00-prereq.t Makefile.PL 
#post_build: |-
# rm unused.files
#post_install: |-
# sed on %{name}.files
#license: SUSE-NonFree
#skip_noarch: 1
#custom_build: |-
#./Build build flags=%{?_smp_mflags} --myflag
#custom_test: |-
#startserver && make test
#ignore_requires: Bizarre::Module
#skip_doc: regexp_to_skip_for_doc.*
#add_doc: files to add to docs
#misc: |-
#anything else to be added to spec file
#follows directly after %files section, so it can contain new blocks or also
#changes to %files section

Reply via email to