File Coverage

blib/lib/Mail/DKIM/KeyValueList.pm
Criterion Covered Total %
statement 101 109 92.6
branch 31 36 86.1
condition 5 8 62.5
subroutine 9 10 90.0
pod 0 7 0.0
total 146 170 85.8


line stmt bran cond sub pod time code
1             package Mail::DKIM::KeyValueList;
2 14     14   133 use strict;
  14         29  
  14         417  
3 14     14   68 use warnings;
  14         31  
  14         575  
4             our $VERSION = '1.20230911'; # VERSION
5             # ABSTRACT: Represents a Key/Value list
6              
7             # Copyright 2005-2007 Messiah College. All rights reserved.
8             # Jason Long
9              
10             # Copyright (c) 2004 Anthony D. Urso. All rights reserved.
11             # This program is free software; you can redistribute it and/or
12             # modify it under the same terms as Perl itself.
13              
14 14     14   78 use Carp;
  14         53  
  14         24856  
15              
16             sub new {
17 0     0 0 0 my $class = shift;
18 0         0 my %args = @_;
19              
20 0         0 my $self = bless \%args, $class;
21 0         0 return $self;
22             }
23              
24             sub parse {
25 1265     1265 0 2344 my $self_or_class = shift;
26 1265 50       2917 croak 'wrong number of arguments' unless ( @_ == 1 );
27 1265         2459 my ($string) = @_;
28              
29 1265 100       4087 my $self = ref($self_or_class) ? $self_or_class : $self_or_class->new;
30              
31 1265         3111 $self->{tags} = [];
32 1265         3436 $self->{tags_by_name} = {};
33 1265         5628 foreach my $raw_tag ( split /;/, $string, -1 ) {
34 8368         16619 my $tag = { raw => $raw_tag };
35 8368         11377 push @{ $self->{tags} }, $tag;
  8368         15114  
36              
37             # strip preceding and trailing whitespace
38 8368         75778 $raw_tag =~ s/^\s+|\s*$//g;
39              
40 8368 100       17933 next if ( $raw_tag eq '' );
41              
42 8342         27873 my ( $tagname, $value ) = split( /\s*=\s*/, $raw_tag, 2 );
43 8342 100       17562 unless ( defined $value ) {
44 5         58 die "syntax error\n";
45             }
46              
47 8337         14499 $tag->{name} = $tagname;
48 8337         12174 $tag->{value} = $value;
49              
50 8337         17587 $self->{tags_by_name}->{$tagname} = $tag;
51             }
52              
53 1260         3986 return $self;
54             }
55              
56             sub clone {
57 419     419 0 649 my $self = shift;
58 419         983 my $str = $self->as_string;
59 419         1550 return ref($self)->parse($str);
60             }
61              
62             sub get_tag {
63 25522     25522 0 36153 my $self = shift;
64 25522         40512 my ($tagname) = @_;
65              
66 25522 100       56921 if ( $self->{tags_by_name}->{$tagname} ) {
67 17696         45503 return $self->{tags_by_name}->{$tagname}->{value};
68             }
69 7826         18235 return undef;
70             }
71              
72             sub set_tag {
73 6014     6014 0 8112 my $self = shift;
74 6014         12376 my ( $tagname, $value ) = @_;
75              
76 6014 50       14142 if ( $tagname =~ /[;=\015\012\t ]/ ) {
77 0         0 croak 'invalid tag name';
78             }
79              
80 6014 100       11166 if ( defined $value ) {
81 2718 50       5957 if ( $value =~ /;/ ) {
82 0         0 croak 'invalid tag value';
83             }
84 2718 50       5427 if ( $value =~ /\015\012[^\t ]/ ) {
85 0         0 croak 'invalid tag value';
86             }
87              
88 2718 100       6436 if ( $self->{tags_by_name}->{$tagname} ) {
89 368         925 $self->{tags_by_name}->{$tagname}->{value} = $value;
90             my ( $rawname, $rawvalue ) =
91 368         1168 split( /=/, $self->{tags_by_name}->{$tagname}->{raw}, 2 );
92 368         1331 $self->{tags_by_name}->{$tagname}->{raw} = "$rawname=$value";
93             }
94             else {
95 2350         8765 my $tag = {
96             name => $tagname,
97             value => $value,
98             raw => " $tagname=$value"
99             };
100 2350         3752 push @{ $self->{tags} }, $tag;
  2350         5120  
101 2350         6485 $self->{tags_by_name}->{$tagname} = $tag;
102             }
103             }
104             else {
105 3296 50       7003 if ( $self->{tags_by_name}->{$tagname} ) {
106 0         0 delete $self->{tags_by_name}->{$tagname};
107             }
108 3296         4392 @{ $self->{tags} } = grep { $_->{name} ne $tagname } @{ $self->{tags} };
  3296         8201  
  4754         10964  
  3296         6279  
109             }
110             }
111              
112             sub as_string {
113 931     931 0 1462 my $self = shift;
114 931 100       1931 if ($Mail::DKIM::SORTTAGS) {
115 96         155 return join( ';', sort map { $_->{raw} } @{ $self->{tags} } );
  736         2028  
  96         207  
116             }
117 835         1225 return join( ';', map { $_->{raw} } @{ $self->{tags} } );
  6765         19274  
  835         1841  
118             }
119              
120             # Start - length of the signature's prefix
121             # Margin - how far to the right the text can go
122             # Insert - characters to insert when wrapping a line
123             # Tags - special processing for tags
124             # Default - how to handle unspecified tags
125             # PreserveNames - if set, the name= part of the tag will be preserved
126             sub wrap {
127 127     127 0 240 my $self = shift;
128 127         448 my %args = @_;
129              
130 127         231 my $TEXTWRAP_CLASS = 'Mail::DKIM::TextWrap';
131 127 100       995 return unless ( UNIVERSAL::can( $TEXTWRAP_CLASS, 'new' ) );
132              
133 3         8 my $result = '';
134             my $wrap = $TEXTWRAP_CLASS->new(
135             Output => \$result,
136             Separator => $args{Insert} || "\015\012\t",
137             Margin => $args{Margin} || 72,
138 3   50     38 cur => $args{Start} || 0,
      50        
      50        
139             );
140 3         4 my $did_first;
141 3         36 foreach my $tag ( @{ $self->{tags} } ) {
  3         11  
142 20         32 my $tagname = $tag->{name};
143 20   100     68 my $tagtype = $args{Tags}->{$tagname} || $args{Default} || '';
144              
145 20         45 $wrap->{Break} = undef;
146 20         30 $wrap->{BreakBefore} = undef;
147 20 100       59 $did_first ? $wrap->add(';') : ( $did_first = 1 );
148              
149 20         58 my ( $raw_name, $raw_value ) = split( /=/, $tag->{raw}, 2 );
150 20 100       43 unless ( $args{PreserveNames} ) {
151 6         14 $wrap->flush; #allow a break before the tag name
152 6         23 $raw_name =~ s/^\s*/ /;
153 6         27 $raw_name =~ s/\s+$//;
154             }
155 20         66 $wrap->add( $raw_name . '=' );
156              
157 20 100       57 if ( $tagtype eq 'b64' ) {
    100          
    100          
158 3         16 $raw_value =~ s/\s+//gs; #removes all whitespace
159 3         12 $wrap->flush;
160 3         10 $wrap->{Break} = qr/./;
161             }
162             elsif ( $tagtype eq 'list' ) {
163 1         11 $raw_value =~ s/\s+/ /gs; #reduces any whitespace to single space
164 1         13 $raw_value =~ s/^\s|\s$//g; #trims preceding/trailing spaces
165 1         10 $raw_value =~ s/\s*:\s*/:/g;
166 1         5 $wrap->flush;
167 1         4 $wrap->{Break} = qr/[\s]/;
168 1         3 $wrap->{BreakBefore} = qr/[:]/;
169             }
170             elsif ( $tagtype eq '' ) {
171 4         15 $raw_value =~ s/\s+/ /gs; #reduces any whitespace to single space
172 4         20 $raw_value =~ s/^\s|\s$//g; #trims preceding/trailing spaces
173 4         11 $wrap->flush;
174 4         15 $wrap->{Break} = qr/\s/;
175             }
176 20         46 $wrap->add($raw_value);
177             }
178              
179 3         12 $wrap->finish;
180 3         9 parse( $self, $result );
181 3         23 return;
182             }
183              
184             1;
185              
186             __END__