<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;"># Copyright (c) 2016-2017 by Pali &lt;pali@cpan.org&gt;

package Email::MIME::Header::AddressList;
$Email::MIME::Header::AddressList::VERSION = '1.946';
use strict;
use warnings;

use Carp ();
use Email::Address::XS;
use Email::MIME::Encode;

#pod =encoding utf8
#pod
#pod =head1 NAME
#pod
#pod Email::MIME::Header::AddressList - MIME support for list of Email::Address::XS objects
#pod
#pod =head1 SYNOPSIS
#pod
#pod   my $address1 = Email::Address::XS-&gt;new('Name1' =&gt; 'address1@host.com');
#pod   my $address2 = Email::Address::XS-&gt;new("Name2 \N{U+263A}" =&gt; 'address2@host.com');
#pod   my $mime_address = Email::Address::XS-&gt;new('=?UTF-8?B?TmFtZTIg4pi6?=' =&gt; 'address2@host.com');
#pod
#pod   my $list1 = Email::MIME::Header::AddressList-&gt;new($address1, $address2);
#pod
#pod   $list1-&gt;append_groups('undisclosed-recipients' =&gt; []);
#pod
#pod   $list1-&gt;first_address();
#pod   # returns $address1
#pod
#pod   $list1-&gt;groups();
#pod   # returns (undef, [ $address1, $address2 ], 'undisclosed-recipients', [])
#pod
#pod   $list1-&gt;as_string();
#pod   # returns 'Name1 &lt;address1@host.com&gt;, "Name2 â˜º" &lt;address2@host.com&gt;, undisclosed-recipients:;'
#pod
#pod   $list1-&gt;as_mime_string();
#pod   # returns 'Name1 &lt;address1@host.com&gt;, =?UTF-8?B?TmFtZTIg4pi6?= &lt;address2@host.com&gt;, undisclosed-recipients:;'
#pod
#pod   my $list2 = Email::MIME::Header::AddressList-&gt;new_groups(Group =&gt; [ $address1, $address2 ]);
#pod
#pod   $list2-&gt;append_addresses($address2);
#pod
#pod   $list2-&gt;addresses();
#pod   # returns ($address2, $address1, $address2)
#pod
#pod   $list2-&gt;groups();
#pod   # returns (undef, [ $address2 ], 'Group', [ $address1, $address2 ])
#pod
#pod   my $list3 = Email::MIME::Header::AddressList-&gt;new_mime_groups('=?UTF-8?B?4pi6?=' =&gt; [ $mime_address ]);
#pod   $list3-&gt;as_string();
#pod   # returns 'â˜º: "Name2 â˜º" &lt;address2@host.com&gt;;'
#pod
#pod   my $list4 = Email::MIME::Header::AddressList-&gt;from_string('Name1 &lt;address1@host.com&gt;, "Name2 â˜º" &lt;address2@host.com&gt;, undisclosed-recipients:;');
#pod   my $list5 = Email::MIME::Header::AddressList-&gt;from_string('Name1 &lt;address1@host.com&gt;', '"Name2 â˜º" &lt;address2@host.com&gt;', 'undisclosed-recipients:;');
#pod
#pod   my $list6 = Email::MIME::Header::AddressList-&gt;from_mime_string('Name1 &lt;address1@host.com&gt;, =?UTF-8?B?TmFtZTIg4pi6?= &lt;address2@host.com&gt;, undisclosed-recipients:;');
#pod   my $list7 = Email::MIME::Header::AddressList-&gt;from_mime_string('Name1 &lt;address1@host.com&gt;', '=?UTF-8?B?TmFtZTIg4pi6?= &lt;address2@host.com&gt;', 'undisclosed-recipients:;');
#pod
#pod =head1 DESCRIPTION
#pod
#pod This module implements object representation for the list of the
#pod L&lt;Email::Address::XS|Email::Address::XS&gt; objects. It provides methods for
#pod L&lt;RFC 2047|https://tools.ietf.org/html/rfc2047&gt; MIME encoding and decoding
#pod suitable for L&lt;RFC 2822|https://tools.ietf.org/html/rfc2822&gt; address-list
#pod structure.
#pod
#pod =head2 EXPORT
#pod
#pod None
#pod
#pod =head2 Class Methods
#pod
#pod =over 4
#pod
#pod =item new_empty
#pod
#pod Construct new empty C&lt;Email::MIME::Header::AddressList&gt; object.
#pod
#pod =cut

sub new_empty {
  my ($class) = @_;
  return bless { addresses =&gt; [], groups =&gt; [] }, $class;
}

#pod =item new
#pod
#pod Construct new C&lt;Email::MIME::Header::AddressList&gt; object from list of
#pod L&lt;Email::Address::XS|Email::Address::XS&gt; objects.
#pod
#pod =cut

sub new {
  my ($class, @addresses) = @_;
  my $self = $class-&gt;new_empty();
  $self-&gt;append_addresses(@addresses);
  return $self;
}

#pod =item new_groups
#pod
#pod Construct new C&lt;Email::MIME::Header::AddressList&gt; object from named groups of
#pod L&lt;Email::Address::XS|Email::Address::XS&gt; objects.
#pod
#pod =cut

sub new_groups {
  my ($class, @groups) = @_;
  my $self = $class-&gt;new_empty();
  $self-&gt;append_groups(@groups);
  return $self;
}

#pod =item new_mime_groups
#pod
#pod Like L&lt;C&lt;new_groups&gt;|/new_groups&gt; but in this method group names and objects properties are
#pod expected to be already MIME encoded, thus ASCII strings.
#pod
#pod =cut

sub new_mime_groups {
  my ($class, @groups) = @_;
  if (scalar @groups % 2) {
    Carp::carp 'Odd number of elements in argument list';
    return;
  }
  foreach (0 .. scalar @groups / 2 - 1) {
    $groups[2 * $_] = Email::MIME::Encode::mime_decode($groups[2 * $_])
      if defined $groups[2 * $_] and $groups[2 * $_] =~ /=\?/;
    $groups[2 * $_ + 1] = [ @{$groups[2 * $_ + 1]} ];
    foreach (@{$groups[2 * $_ + 1]}) {
      next unless Email::Address::XS-&gt;is_obj($_);
      my $decode_phrase = (defined $_-&gt;phrase and $_-&gt;phrase =~ /=\?/);
      my $decode_comment = (defined $_-&gt;comment and $_-&gt;comment =~ /=\?/);
      next unless $decode_phrase or $decode_comment;
      $_ = ref($_)-&gt;new(copy =&gt; $_);
      $_-&gt;phrase(Email::MIME::Encode::mime_decode($_-&gt;phrase))
        if $decode_phrase;
      $_-&gt;comment(Email::MIME::Encode::mime_decode($_-&gt;comment))
        if $decode_comment;
    }
  }
  return $class-&gt;new_groups(@groups);
}

#pod =item from_string
#pod
#pod Construct new C&lt;Email::MIME::Header::AddressList&gt; object from input string arguments.
#pod Calls L&lt;Email::Address::XS::parse_email_groups|Email::Address::XS/parse_email_groups&gt;.
#pod
#pod =cut

sub from_string {
  my ($class, @strings) = @_;
  return $class-&gt;new_groups(map { Email::Address::XS::parse_email_groups($_) } @strings);
}

#pod =item from_mime_string
#pod
#pod Like L&lt;C&lt;from_string&gt;|/from_string&gt; but input string arguments are expected to
#pod be already MIME encoded.
#pod
#pod =cut

sub from_mime_string {
  my ($class, @strings) = @_;
  return $class-&gt;new_mime_groups(map { Email::Address::XS::parse_email_groups($_) } @strings);
}

#pod =back
#pod
#pod =head2 Object Methods
#pod
#pod =over 4
#pod
#pod =item as_string
#pod
#pod Returns string representation of C&lt;Email::MIME::Header::AddressList&gt; object.
#pod Calls L&lt;Email::Address::XS::format_email_groups|Email::Address::XS/format_email_groups&gt;.
#pod
#pod =cut

sub as_string {
  my ($self) = @_;
  return Email::Address::XS::format_email_groups($self-&gt;groups());
}

#pod =item as_mime_string
#pod
#pod Like L&lt;C&lt;as_string&gt;|/as_string&gt; but output string will be properly and
#pod unambiguously MIME encoded. MIME encoding is done before calling
#pod L&lt;Email::Address::XS::format_email_groups|Email::Address::XS/format_email_groups&gt;.
#pod
#pod =cut

sub as_mime_string {
  my ($self, $arg) = @_;
  my $charset = $arg-&gt;{charset};
  my $header_name_length = $arg-&gt;{header_name_length};

  my @groups = $self-&gt;groups();
  foreach (0 .. scalar @groups / 2 - 1) {
    $groups[2 * $_] = Email::MIME::Encode::mime_encode($groups[2 * $_], $charset)
      if Email::MIME::Encode::_needs_mime_encode_addr($groups[2 * $_]);
    $groups[2 * $_ + 1] = [ @{$groups[2 * $_ + 1]} ];
    foreach (@{$groups[2 * $_ + 1]}) {
      my $encode_phrase = Email::MIME::Encode::_needs_mime_encode_addr($_-&gt;phrase);
      my $encode_comment = Email::MIME::Encode::_needs_mime_encode_addr($_-&gt;comment);
      next unless $encode_phrase or $encode_comment;
      $_ = ref($_)-&gt;new(copy =&gt; $_);
      $_-&gt;phrase(Email::MIME::Encode::mime_encode($_-&gt;phrase, $charset))
        if $encode_phrase;
      $_-&gt;comment(Email::MIME::Encode::mime_encode($_-&gt;comment, $charset))
        if $encode_comment;
    }
  }
  return Email::Address::XS::format_email_groups(@groups);
}

#pod =item first_address
#pod
#pod Returns first L&lt;Email::Address::XS|Email::Address::XS&gt; object.
#pod
#pod =cut

sub first_address {
  my ($self) = @_;
  return $self-&gt;{addresses}-&gt;[0] if @{$self-&gt;{addresses}};
  my $groups = $self-&gt;{groups};
  foreach (0 .. @{$groups} / 2 - 1) {
    next unless @{$groups-&gt;[2 * $_ + 1]};
    return $groups-&gt;[2 * $_ + 1]-&gt;[0];
  }
  return undef;
}

#pod =item addresses
#pod
#pod Returns list of all L&lt;Email::Address::XS|Email::Address::XS&gt; objects.
#pod
#pod =cut

sub addresses {
  my ($self) = @_;
  my $t = 1;
  my @addresses = @{$self-&gt;{addresses}};
  push @addresses, map { @{$_} } grep { $t ^= 1 } @{$self-&gt;{groups}};
  return @addresses;
}

#pod =item groups
#pod
#pod Like L&lt;C&lt;addresses&gt;|/addresses&gt; but returns objects with named groups.
#pod
#pod =cut

sub groups {
  my ($self) = @_;
  my @groups = @{$self-&gt;{groups}};
  $groups[2 * $_ + 1] = [ @{$groups[2 * $_ + 1]} ]
    foreach 0 .. scalar @groups / 2 - 1;
  unshift @groups, undef, [ @{$self-&gt;{addresses}} ]
    if @{$self-&gt;{addresses}};
  return @groups;
}

#pod =item append_addresses
#pod
#pod Append L&lt;Email::Address::XS|Email::Address::XS&gt; objects.
#pod
#pod =cut

sub append_addresses {
  my ($self, @addresses) = @_;
  my @valid_addresses = grep { Email::Address::XS-&gt;is_obj($_) } @addresses;
  Carp::carp 'Argument is not an Email::Address::XS object' if scalar @valid_addresses != scalar @addresses;
  push @{$self-&gt;{addresses}}, @valid_addresses;
}

#pod =item append_groups
#pod
#pod Like L&lt;C&lt;append_addresses&gt;|/append_addresses&gt; but arguments are pairs of name of
#pod group and array reference of L&lt;Email::Address::XS|Email::Address::XS&gt; objects.
#pod
#pod =cut

sub append_groups {
  my ($self, @groups) = @_;
  if (scalar @groups % 2) {
    Carp::carp 'Odd number of elements in argument list';
    return;
  }
  my $carp_invalid = 1;
  my @valid_groups;
  foreach (0 .. scalar @groups / 2 - 1) {
    push @valid_groups, $groups[2 * $_];
    my $addresses = $groups[2 * $_ + 1];
    my @valid_addresses = grep { Email::Address::XS-&gt;is_obj($_) } @{$addresses};
    if ($carp_invalid and scalar @valid_addresses != scalar @{$addresses}) {
      Carp::carp 'Array element is not an Email::Address::XS object';
      $carp_invalid = 0;
    }
    push @valid_groups, \@valid_addresses;
  }
  push @{$self-&gt;{groups}}, @valid_groups;
}

#pod =back
#pod
#pod =head1 SEE ALSO
#pod
#pod L&lt;RFC 2047|https://tools.ietf.org/html/rfc2047&gt;,
#pod L&lt;RFC 2822|https://tools.ietf.org/html/rfc2822&gt;,
#pod L&lt;Email::MIME&gt;,
#pod L&lt;Email::Address::XS&gt;
#pod
#pod =head1 AUTHOR
#pod
#pod Pali E&lt;lt&gt;pali@cpan.orgE&lt;gt&gt;
#pod
#pod =cut

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Email::MIME::Header::AddressList

=head1 VERSION

version 1.946

=head1 SYNOPSIS

  my $address1 = Email::Address::XS-&gt;new('Name1' =&gt; 'address1@host.com');
  my $address2 = Email::Address::XS-&gt;new("Name2 \N{U+263A}" =&gt; 'address2@host.com');
  my $mime_address = Email::Address::XS-&gt;new('=?UTF-8?B?TmFtZTIg4pi6?=' =&gt; 'address2@host.com');

  my $list1 = Email::MIME::Header::AddressList-&gt;new($address1, $address2);

  $list1-&gt;append_groups('undisclosed-recipients' =&gt; []);

  $list1-&gt;first_address();
  # returns $address1

  $list1-&gt;groups();
  # returns (undef, [ $address1, $address2 ], 'undisclosed-recipients', [])

  $list1-&gt;as_string();
  # returns 'Name1 &lt;address1@host.com&gt;, "Name2 â˜º" &lt;address2@host.com&gt;, undisclosed-recipients:;'

  $list1-&gt;as_mime_string();
  # returns 'Name1 &lt;address1@host.com&gt;, =?UTF-8?B?TmFtZTIg4pi6?= &lt;address2@host.com&gt;, undisclosed-recipients:;'

  my $list2 = Email::MIME::Header::AddressList-&gt;new_groups(Group =&gt; [ $address1, $address2 ]);

  $list2-&gt;append_addresses($address2);

  $list2-&gt;addresses();
  # returns ($address2, $address1, $address2)

  $list2-&gt;groups();
  # returns (undef, [ $address2 ], 'Group', [ $address1, $address2 ])

  my $list3 = Email::MIME::Header::AddressList-&gt;new_mime_groups('=?UTF-8?B?4pi6?=' =&gt; [ $mime_address ]);
  $list3-&gt;as_string();
  # returns 'â˜º: "Name2 â˜º" &lt;address2@host.com&gt;;'

  my $list4 = Email::MIME::Header::AddressList-&gt;from_string('Name1 &lt;address1@host.com&gt;, "Name2 â˜º" &lt;address2@host.com&gt;, undisclosed-recipients:;');
  my $list5 = Email::MIME::Header::AddressList-&gt;from_string('Name1 &lt;address1@host.com&gt;', '"Name2 â˜º" &lt;address2@host.com&gt;', 'undisclosed-recipients:;');

  my $list6 = Email::MIME::Header::AddressList-&gt;from_mime_string('Name1 &lt;address1@host.com&gt;, =?UTF-8?B?TmFtZTIg4pi6?= &lt;address2@host.com&gt;, undisclosed-recipients:;');
  my $list7 = Email::MIME::Header::AddressList-&gt;from_mime_string('Name1 &lt;address1@host.com&gt;', '=?UTF-8?B?TmFtZTIg4pi6?= &lt;address2@host.com&gt;', 'undisclosed-recipients:;');

=head1 DESCRIPTION

This module implements object representation for the list of the
L&lt;Email::Address::XS|Email::Address::XS&gt; objects. It provides methods for
L&lt;RFC 2047|https://tools.ietf.org/html/rfc2047&gt; MIME encoding and decoding
suitable for L&lt;RFC 2822|https://tools.ietf.org/html/rfc2822&gt; address-list
structure.

=head2 EXPORT

None

=head2 Class Methods

=over 4

=item new_empty

Construct new empty C&lt;Email::MIME::Header::AddressList&gt; object.

=item new

Construct new C&lt;Email::MIME::Header::AddressList&gt; object from list of
L&lt;Email::Address::XS|Email::Address::XS&gt; objects.

=item new_groups

Construct new C&lt;Email::MIME::Header::AddressList&gt; object from named groups of
L&lt;Email::Address::XS|Email::Address::XS&gt; objects.

=item new_mime_groups

Like L&lt;C&lt;new_groups&gt;|/new_groups&gt; but in this method group names and objects properties are
expected to be already MIME encoded, thus ASCII strings.

=item from_string

Construct new C&lt;Email::MIME::Header::AddressList&gt; object from input string arguments.
Calls L&lt;Email::Address::XS::parse_email_groups|Email::Address::XS/parse_email_groups&gt;.

=item from_mime_string

Like L&lt;C&lt;from_string&gt;|/from_string&gt; but input string arguments are expected to
be already MIME encoded.

=back

=head2 Object Methods

=over 4

=item as_string

Returns string representation of C&lt;Email::MIME::Header::AddressList&gt; object.
Calls L&lt;Email::Address::XS::format_email_groups|Email::Address::XS/format_email_groups&gt;.

=item as_mime_string

Like L&lt;C&lt;as_string&gt;|/as_string&gt; but output string will be properly and
unambiguously MIME encoded. MIME encoding is done before calling
L&lt;Email::Address::XS::format_email_groups|Email::Address::XS/format_email_groups&gt;.

=item first_address

Returns first L&lt;Email::Address::XS|Email::Address::XS&gt; object.

=item addresses

Returns list of all L&lt;Email::Address::XS|Email::Address::XS&gt; objects.

=item groups

Like L&lt;C&lt;addresses&gt;|/addresses&gt; but returns objects with named groups.

=item append_addresses

Append L&lt;Email::Address::XS|Email::Address::XS&gt; objects.

=item append_groups

Like L&lt;C&lt;append_addresses&gt;|/append_addresses&gt; but arguments are pairs of name of
group and array reference of L&lt;Email::Address::XS|Email::Address::XS&gt; objects.

=back

=head1 NAME

Email::MIME::Header::AddressList - MIME support for list of Email::Address::XS objects

=head1 SEE ALSO

L&lt;RFC 2047|https://tools.ietf.org/html/rfc2047&gt;,
L&lt;RFC 2822|https://tools.ietf.org/html/rfc2822&gt;,
L&lt;Email::MIME&gt;,
L&lt;Email::Address::XS&gt;

=head1 AUTHOR

Pali E&lt;lt&gt;pali@cpan.orgE&lt;gt&gt;

=head1 AUTHORS

=over 4

=item *

Ricardo SIGNES &lt;rjbs@cpan.org&gt;

=item *

Casey West &lt;casey@geeknest.com&gt;

=item *

Simon Cozens &lt;simon@cpan.org&gt;

=back

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2004 by Simon Cozens and Casey West.

This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.

=cut
</pre></body></html>