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   126 use strict;
  14         28  
  14         413  
3 14     14   81 use warnings;
  14         35  
  14         537  
4             our $VERSION = '1.20230630'; # 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   109 use Carp;
  14         38  
  14         24151  
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 2120 my $self_or_class = shift;
26 1265 50       3008 croak 'wrong number of arguments' unless ( @_ == 1 );
27 1265         2321 my ($string) = @_;
28              
29 1265 100       4189 my $self = ref($self_or_class) ? $self_or_class : $self_or_class->new;
30              
31 1265         2912 $self->{tags} = [];
32 1265         3362 $self->{tags_by_name} = {};
33 1265         5624 foreach my $raw_tag ( split /;/, $string, -1 ) {
34 8368         16283 my $tag = { raw => $raw_tag };
35 8368         12011 push @{ $self->{tags} }, $tag;
  8368         15291  
36              
37             # strip preceding and trailing whitespace
38 8368         75447 $raw_tag =~ s/^\s+|\s*$//g;
39              
40 8368 100       17848 next if ( $raw_tag eq '' );
41              
42 8342         27612 my ( $tagname, $value ) = split( /\s*=\s*/, $raw_tag, 2 );
43 8342 100       17449 unless ( defined $value ) {
44 5         63 die "syntax error\n";
45             }
46              
47 8337         15203 $tag->{name} = $tagname;
48 8337         12195 $tag->{value} = $value;
49              
50 8337         17829 $self->{tags_by_name}->{$tagname} = $tag;
51             }
52              
53 1260         4060 return $self;
54             }
55              
56             sub clone {
57 419     419 0 668 my $self = shift;
58 419         923 my $str = $self->as_string;
59 419         1566 return ref($self)->parse($str);
60             }
61              
62             sub get_tag {
63 25522     25522 0 34956 my $self = shift;
64 25522         39959 my ($tagname) = @_;
65              
66 25522 100       51295 if ( $self->{tags_by_name}->{$tagname} ) {
67 17696         44392 return $self->{tags_by_name}->{$tagname}->{value};
68             }
69 7826         17509 return undef;
70             }
71              
72             sub set_tag {
73 6014     6014 0 8346 my $self = shift;
74 6014         12121 my ( $tagname, $value ) = @_;
75              
76 6014 50       14277 if ( $tagname =~ /[;=\015\012\t ]/ ) {
77 0         0 croak 'invalid tag name';
78             }
79              
80 6014 100       10873 if ( defined $value ) {
81 2718 50       5751 if ( $value =~ /;/ ) {
82 0         0 croak 'invalid tag value';
83             }
84 2718 50       5323 if ( $value =~ /\015\012[^\t ]/ ) {
85 0         0 croak 'invalid tag value';
86             }
87              
88 2718 100       6377 if ( $self->{tags_by_name}->{$tagname} ) {
89 368         961 $self->{tags_by_name}->{$tagname}->{value} = $value;
90             my ( $rawname, $rawvalue ) =
91 368         1198 split( /=/, $self->{tags_by_name}->{$tagname}->{raw}, 2 );
92 368         1199 $self->{tags_by_name}->{$tagname}->{raw} = "$rawname=$value";
93             }
94             else {
95 2350         8313 my $tag = {
96             name => $tagname,
97             value => $value,
98             raw => " $tagname=$value"
99             };
100 2350         3775 push @{ $self->{tags} }, $tag;
  2350         5054  
101 2350         6620 $self->{tags_by_name}->{$tagname} = $tag;
102             }
103             }
104             else {
105 3296 50       6836 if ( $self->{tags_by_name}->{$tagname} ) {
106 0         0 delete $self->{tags_by_name}->{$tagname};
107             }
108 3296         4342 @{ $self->{tags} } = grep { $_->{name} ne $tagname } @{ $self->{tags} };
  3296         8227  
  4754         10649  
  3296         6191  
109             }
110             }
111              
112             sub as_string {
113 931     931 0 1503 my $self = shift;
114 931 100       1862 if ($Mail::DKIM::SORTTAGS) {
115 96         142 return join( ';', sort map { $_->{raw} } @{ $self->{tags} } );
  736         2057  
  96         194  
116             }
117 835         1217 return join( ';', map { $_->{raw} } @{ $self->{tags} } );
  6765         19590  
  835         1872  
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 227 my $self = shift;
128 127         413 my %args = @_;
129              
130 127         221 my $TEXTWRAP_CLASS = 'Mail::DKIM::TextWrap';
131 127 100       1004 return unless ( UNIVERSAL::can( $TEXTWRAP_CLASS, 'new' ) );
132              
133 3         7 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     29 cur => $args{Start} || 0,
      50        
      50        
139             );
140 3         4 my $did_first;
141 3         40 foreach my $tag ( @{ $self->{tags} } ) {
  3         10  
142 20         37 my $tagname = $tag->{name};
143 20   100     69 my $tagtype = $args{Tags}->{$tagname} || $args{Default} || '';
144              
145 20         37 $wrap->{Break} = undef;
146 20         29 $wrap->{BreakBefore} = undef;
147 20 100       57 $did_first ? $wrap->add(';') : ( $did_first = 1 );
148              
149 20         56 my ( $raw_name, $raw_value ) = split( /=/, $tag->{raw}, 2 );
150 20 100       45 unless ( $args{PreserveNames} ) {
151 6         18 $wrap->flush; #allow a break before the tag name
152 6         21 $raw_name =~ s/^\s*/ /;
153 6         21 $raw_name =~ s/\s+$//;
154             }
155 20         64 $wrap->add( $raw_name . '=' );
156              
157 20 100       58 if ( $tagtype eq 'b64' ) {
    100          
    100          
158 3         15 $raw_value =~ s/\s+//gs; #removes all whitespace
159 3         10 $wrap->flush;
160 3         11 $wrap->{Break} = qr/./;
161             }
162             elsif ( $tagtype eq 'list' ) {
163 1         10 $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         9 $raw_value =~ s/\s*:\s*/:/g;
166 1         4 $wrap->flush;
167 1         5 $wrap->{Break} = qr/[\s]/;
168 1         3 $wrap->{BreakBefore} = qr/[:]/;
169             }
170             elsif ( $tagtype eq '' ) {
171 4         30 $raw_value =~ s/\s+/ /gs; #reduces any whitespace to single space
172 4         19 $raw_value =~ s/^\s|\s$//g; #trims preceding/trailing spaces
173 4         12 $wrap->flush;
174 4         12 $wrap->{Break} = qr/\s/;
175             }
176 20         44 $wrap->add($raw_value);
177             }
178              
179 3         11 $wrap->finish;
180 3         9 parse( $self, $result );
181 3         22 return;
182             }
183              
184             1;
185              
186             __END__