File Coverage

blib/lib/Mail/Procmailrc.pm
Criterion Covered Total %
statement 314 336 93.4
branch 154 180 85.5
condition 12 15 80.0
subroutine 45 47 95.7
pod 14 18 77.7
total 539 596 90.4


line stmt bran cond sub pod time code
1             ## Scott Wiersdorf
2             ## Created: Thu Jan 24 11:29:59 MST 2002
3             ## $Id: Procmailrc.pm,v 1.12 2002/07/30 17:59:19 scottw Exp $
4              
5             ##################################
6             package Mail::Procmailrc;
7             ##################################
8              
9 14     14   118312 use strict;
  14         37  
  14         595  
10 14     14   85 use Carp qw(carp);
  14         29  
  14         864  
11              
12 14     14   505 use vars qw( $VERSION $Debug %RE );
  14         32  
  14         40522  
13              
14             $VERSION = '1.09';
15             $Debug = 0;
16             %RE = (
17             'flags' => qr/^\s*:0/o, ## flags
18             'flagsm' => qr/^\s*(:0.*)$/o, ## flags match
19             'var' => qr/^\s*[^#\$=]+=.*/o, ## var
20             'varm' => qr/^\s*([^#\$=]+=.*)$/o, ## var match
21             'varmlq' => qr/^[^\"]+=[^\"]*"[^\"]*$/so, ## var multiline quote
22             'blklinem' => qr/^\s*\{\s*(.*?)\s*\}\s*$/o, ## block line match
23             'blkopen' => qr/^\s*\{/o, ## block open
24             'blkclose' => qr/^\s*\}/o, ## block close
25             'blank' => qr/^\s*$/o, ## blank line
26             'cont' => qr/\\$/o, ## continuation
27             'comt' => qr/^\s*\#/o, ## comment
28             'comm' => qr/^\s*(\#.*)$/o, ## comment match
29             'condm' => qr/^\s*(\*.*)$/o, ## condition match
30             );
31              
32             sub new {
33 84     84 1 370 my $self = bless { }, shift;
34 84         118 my $data = shift;
35              
36 84         247 $self->init($data);
37 84         235 return $self;
38             }
39              
40             sub init {
41 84     84 1 105 my $self = shift;
42 84         100 my $data = shift;
43              
44             ## initialize data array
45 84         221 $self->rc([]); ## our internal keeper of the data
46              
47             #########################################
48             ## set parameters
49             #########################################
50              
51             ## named parameters
52 84 100       213 if( 'HASH' eq ref($data) ) {
53 72         250 $self->read( $data->{'file'} );
54 72         248 $self->level( $data->{'level'} );
55 72 50       342 $self->parse( $data->{'data'} ) if $data->{'data'};
56             }
57              
58             ## just a filename
59             else {
60 12         43 $self->read($data);
61             }
62              
63 84         120 return 1;
64             }
65              
66             sub read {
67 84     84 1 286 my $self = shift;
68 84         155 my $file = shift;
69              
70             ## reset file
71 84 100       195 return unless $file = $self->file($file);
72 3 50       56 return unless -f $file;
73              
74             ## FIXME: advisory lock here?
75             open FILE, $file
76 3 50       96 or do {
77 0         0 carp( "Error reading file '$file': $!\n" );
78 0         0 return;
79             };
80              
81             ## FIXME: this is bad... Should pass in a typeglob instead...
82 3         150 $self->parse( [] );
83 3         54 close FILE;
84             }
85              
86             sub parse {
87 95     95 1 152 my $self = shift;
88 95         127 my $data = shift; ## this may be a string or array reference
89 95         134 my @data = (); ## chunks to hand off to object creators
90              
91             ## state
92 95         590 my %ST = ( FILE => 0, 0 => 'FILE',
93             VARIABLE => 1, 1 => 'VARIABLE',
94             RECIPE => 2, 2 => 'RECIPE',
95             LITERAL => 3, 3 => 'LITERAL',
96             );
97 95         194 my @state = ( $ST{FILE} );
98              
99             ## initialize our data
100 95         209 $self->rc([]);
101              
102             ## make sure we're using an array reference
103 95 100       578 if( 'ARRAY' eq ref($data) ) {
104 67         265 chomp @$data;
105             }
106             else {
107             ## we don't know how to handle other kinds of refs here
108 28 50       90 return if ref($data);
109              
110             ## split the data (implicit chomping)
111 28         532 $data = [split(/\n/, $data)];
112             }
113              
114             ## this is the procmailrc parser
115 95         171 my $line;
116 95         290 while( defined ($line = shift @$data) ) {
117 411         1066 gubed( "LINE: $line" );
118              
119             ## block line gets rewritten (but noted with $obj->blockline(1))
120 411 100       2399 if( $line =~ s/$RE{'blklinem'}/$1/ ) {
121             ## if $line is now an empty line (or whitespace only),
122             ## we'll take that into consideration in the blank line
123             ## case below
124 37         78 $self->blockline(1);
125             }
126              
127             ## found a recipe
128 411 100       4902 if( $line =~ s/$RE{'flagsm'}/$1/ ) {
    100          
    100          
    100          
    100          
    100          
129 101         203 unshift @$data, $line;
130 101         216 $self->push( Mail::Procmailrc::Recipe->new($data, {'level' => $self->level} ) );
131             }
132              
133             ## found a variable assignment
134             elsif( $line =~ s/$RE{'varm'}/$1/ ) {
135 111         254 unshift @$data, $line;
136 111         232 $self->push( Mail::Procmailrc::Variable->new($data, {'level' => $self->level}) );
137             }
138              
139             ## a comment between chunks
140             elsif( $line =~ /$RE{'comm'}/ ) {
141 35         89 $self->push( Mail::Procmailrc::Literal->new($line, {'level' => $self->level}) );
142             }
143              
144             ## completely blank line
145             elsif( $line =~ /$RE{'blank'}/ ) {
146             ## if the next line is blank too...
147 102 100 66     1212 if( defined $data->[0] && $data->[0] =~ /$RE{'blank'}/ ) {
148             ## skip blank lines (unless this line is a block line)
149 9 100       30 next unless $self->blockline;
150             }
151 97         216 $self->push( Mail::Procmailrc::Literal->new($line, {'level' => $self->level}) );
152             }
153              
154             ## open block triggers special behavior for the object
155             elsif( $line =~ /$RE{'blkopen'}/ ) {
156 25         64 $self->push( Mail::Procmailrc::Literal->new($line, {'level' => $self->level}) );
157 25         52 $self->level($self->level + 1);
158             }
159              
160             ## close block triggers special behavior for the object
161             elsif( $line =~ /$RE{'blkclose'}/ ) {
162 25         53 $self->level($self->level - 1);
163 25         50 $self->push( Mail::Procmailrc::Literal->new($line, {'level' => $self->level}) );
164 25         38 last;
165             }
166              
167             ## something else
168             else {
169             ## do nothing? Could push a literal here...
170             }
171              
172             ## bail if we only expected one line
173 381 100       869 last if $self->blockline;
174             }
175              
176 95         427 return 1;
177             }
178              
179             ## FIXME: should be checks here for array refs/lists
180             sub rc {
181 724     724 1 903 my $self = shift;
182 724         765 my $data = shift;
183              
184 724 100       2368 return ( defined $data
185             ? $self->{RCDATA} = $data
186             : $self->{RCDATA} );
187             }
188              
189             sub recipes {
190 3     3 1 21 my $self = shift;
191 3         6 return [ grep { $_->isa('Mail::Procmailrc::Recipe') } @{$self->rc} ];
  46         234  
  3         8  
192             }
193              
194             sub variables {
195 4     4 1 15 my $self = shift;
196 4         11 return [ grep { $_->isa('Mail::Procmailrc::Variable') } @{$self->rc} ];
  51         256  
  4         10  
197             }
198              
199             sub literals {
200 3     3 1 5 my $self = shift;
201 3         5 return [ grep { $_->isa('Mail::Procmailrc::Literal') } @{$self->rc} ];
  24         150  
  3         14  
202             }
203              
204             sub push {
205 404     404 1 479 my $self = shift;
206 404         435 CORE::push @{$self->rc}, @_;
  404         750  
207             }
208              
209             ## FIXME: would be nice to do this w/o temporary arrays
210             sub delete {
211 1     1 1 7 my $self = shift;
212 1         1 my $seek = shift;
213 1         2 my $found = 0;
214              
215 1 50 33     10 return unless $seek && ref($seek);
216              
217 1         3 my @tmp = ();
218 1         3 for my $obj ( @{$self->rc} ) {
  1         3  
219 9         19 CORE::push @tmp, $obj;
220 9 100       27 next if $found;
221 7 100       31 next unless $obj == $seek;
222 1         2 pop @tmp;
223 1         2 $found++;
224             }
225 1         5 $self->rc(\@tmp);
226             }
227              
228             sub stringify {
229 2     2 1 5 return $_[0]->dump;
230             }
231              
232             sub dump {
233 116     116 1 551 my $self = shift;
234 116         150 my $output = '';
235 116 50       239 my $sp = ( defined $self->level ? $self->level * 2 : 0 );
236              
237             ## only one element in our list
238 116 100       228 if( $self->blockline ) {
239 37         103 $output .= (' ' x $sp) . "\{ " . $self->rc->[0]->stringify . ' }';
240 37         138 $output =~ s/\{\s*\}/{ }/; ## squeeze empties
241             }
242              
243             ## dump our stack
244             else {
245 79         96 for my $elem ( @{$self->rc} ) {
  79         150  
246 468 100       1079 next unless defined $elem;
247 467         2220 $output .= $elem->dump;
248             }
249             }
250              
251 116         479 return $output;
252             }
253              
254             sub flush {
255 3     3 1 22 my $self = shift;
256 3         696 my $file = shift;
257              
258             ## reset the file attribute
259 3         13 $file = $self->file($file);
260              
261             ## flush the object to disk
262 3 50       11 if( $file ) {
263             open FILE, ">$file"
264 3 50       432 or do {
265 0         0 carp "Could not open '$file' for write: $!\n";
266 0         0 return;
267             };
268             }
269              
270             ## no file, flush to stdout
271             else {
272 0 0       0 open FILE, ">&STDOUT" unless $file;
273             }
274 3         13 print FILE $self->dump;
275 3         189 close FILE;
276              
277 3         16 return 1;
278             }
279              
280             sub debug {
281 0     0 0 0 my $self = shift;
282 0         0 my $debug = shift;
283              
284 0 0       0 return ( defined $debug ? $Debug = $debug : $Debug );
285             }
286              
287             sub file {
288 87     87 1 101 my $self = shift;
289 87         115 my $file = shift;
290              
291 87 100       386 return ( defined $file ? $self->{File} = $file : $self->{File} );
292             }
293              
294             sub level {
295 800     800 0 1396 my $self = shift;
296 800         1346 my $level = shift;
297              
298 800 100       3691 return ( defined $level
    100          
299             ? $self->{Level} = $level
300             : ( defined $self->{Level}
301             ? $self->{Level}
302             : 0 ) );
303             }
304              
305             sub blockline {
306 543     543 0 606 my $self = shift;
307 543         567 my $blockline = shift;
308              
309 543 100       2383 return ( defined $blockline ? $self->{Blockline} = $blockline : $self->{Blockline} );
310             }
311              
312             sub gubed {
313 411 50   411 0 869 return unless $Debug;
314              
315 0         0 my $msg = shift;
316 0         0 chomp $msg;
317 0         0 print STDERR "$msg\n";
318             }
319              
320             ##################################
321             package Mail::Procmailrc::Literal;
322             ##################################
323              
324             sub new {
325 410     410   971 my $self = bless { }, shift;
326 410         641 my $data = shift;
327 410         435 my $defs = shift;
328              
329             ## set defaults
330 410 100       1054 $self->defaults($defs) if ref $defs;
331              
332             ## FIXME: would be simple to make a super object and have literal,
333             ## variable, and recipe inherit from it... Or recipe components
334             ## inherit from it... I should be careful here and in documenting
335             ## it so that I only mention the minimum necessary to keep a
336             ## consistent interface.
337              
338 410         961 $self->literal($data);
339              
340 410         994 return $self;
341             }
342              
343             sub defaults {
344 629     629   894 my $self = shift;
345 629         641 my $defaults = shift;
346 629         656 my $value = shift;
347              
348             ## nada: return whole hashref
349 629 50       1085 unless( $defaults ) {
350 0         0 return $self->{DEFAULTS};
351             }
352              
353             ## no hashref: return element of hashref
354 629 100       1113 unless( ref($defaults) ) {
355 446 50       2371 return ( defined $self->{DEFAULTS}->{$defaults}
    100          
356             ? ( defined $value
357             ? $self->{DEFAULTS}->{$defaults} = $value
358             : $self->{DEFAULTS}->{$defaults} )
359             : undef );
360             }
361              
362             ## hashref: assign hashref
363 183         449 return $self->{DEFAULTS} = $defaults;
364             }
365              
366             sub literal {
367 796     796   862 my $self = shift;
368 796         843 my $data = shift;
369              
370             ## clean data
371 796 100       1567 chomp $data if $data;
372 796 100       1962 $data =~ s/^\s*// if $data;
373 796 100       2462 $data =~ s/\s*$// if $data;
374              
375 796 100       3796 return ( defined $data ?
    100          
376             $self->{DATA} = $data
377             : ( $self->{DATA} ? $self->{DATA} : '' ) );
378             }
379              
380             sub stringify {
381 379     379   926 return $_[0]->literal;
382             }
383              
384             sub dump {
385 226     226   251 my $self = shift;
386 226 100       369 my $sp = ( defined $self->defaults('level') ? $self->defaults('level') * 2 : 0 );
387 226         493 return (' ' x $sp) . $self->stringify . "\n";
388             }
389              
390             ##################################
391             package Mail::Procmailrc::Variable;
392             ##################################
393 14     14   201 use Carp qw(carp);
  14         27  
  14         860  
394              
395             ## FIXME: handle comments on the assignment line
396              
397 14     14   77 use vars qw($Debug); $Debug = 0;
  14         34  
  14         11915  
398              
399             sub new {
400 123     123   414 my $self = bless { }, shift;
401 123         175 my $data = shift;
402 123         139 my $defs = shift; ## defaults
403              
404 123 100       358 $self->defaults($defs) if $defs;
405 123         257 $self->init($data);
406 123         300 return $self;
407             }
408              
409             sub defaults {
410 333     333   380 my $self = shift;
411 333         368 my $defaults = shift;
412 333         402 my $value = shift;
413              
414             ## nada: return whole hashref
415 333 50       616 unless( $defaults ) {
416 0         0 return $self->{DEFAULTS};
417             }
418              
419             ## no hashref: return element of hashref
420 333 100       611 unless( ref($defaults) ) {
421 221 50       1025 return ( defined $self->{DEFAULTS}->{$defaults}
    100          
422             ? ( defined $value
423             ? $self->{DEFAULTS}->{$defaults} = $value
424             : $self->{DEFAULTS}->{$defaults} )
425             : undef );
426             }
427              
428             ## hashref: assign hashref
429 112         304 return $self->{DEFAULTS} = $defaults;
430             }
431              
432             sub init {
433 123     123   142 my $self = shift;
434 123         133 my $data = shift;
435 123         141 my $line;
436              
437 123 100       238 return unless defined $data;
438              
439             ## get a variable declaration
440 120         207 $line .= shift @$data;
441              
442             ## check assignment
443 120 50       758 unless( $line =~ /$Mail::Procmailrc::RE{'var'}/ ) {
444 0         0 carp "Could not init: bad pattern in '$line'\n";
445 0         0 return;
446             }
447              
448             ## check for multiline quote
449 120 100       675 if( $line =~ $Mail::Procmailrc::RE{'varmlq'} ) {
450 7   100     77 while( @$data && $line =~ $Mail::Procmailrc::RE{'varmlq'} ) {
451 251         525 $line .= "\n";
452 251         5548 $line .= shift @$data;
453             }
454             }
455              
456             else {
457             ## check for continuation
458 113         510 while( $line =~ /$Mail::Procmailrc::RE{'cont'}/ ) {
459 32         59 $line .= "\n";
460 32         172 $line .= shift @$data;
461             }
462             }
463              
464 120         314 $self->variable($line);
465              
466 120         205 return 1;
467             }
468              
469             sub lval {
470 406     406   503 my $self = shift;
471 406         430 my $data = shift;
472 406 100       722 chomp $data if $data;
473              
474 406 100       1375 return ( defined $data ? $self->{LVAL} = $data : $self->{LVAL} );
475             }
476              
477             sub rval {
478 410     410   506 my $self = shift;
479 410         485 my $data = shift;
480 410 100       923 chomp $data if $data;
481              
482 410 100       1874 return ( defined $data ? $self->{RVAL} = $data : $self->{RVAL} );
483             }
484              
485             sub variable {
486 281     281   359 my $self = shift;
487 281         314 my $data = shift;
488              
489 281 100       519 if( $data ) {
490 120         315 chomp $data;
491 120         560 my( $lval, $rval ) = split(/=/, $data, 2);
492 120         288 $self->lval($lval);
493 120         231 $self->rval($rval);
494             }
495              
496 281         503 return join('=', $self->lval, $self->rval);
497             }
498              
499             sub stringify {
500 153     153   341 return $_[0]->variable;
501             }
502              
503             sub dump {
504 116     116   152 my $self = shift;
505 116 100       201 my $sp = ( defined $self->defaults('level') ? $self->defaults('level') * 2 : 0 );
506 116         371 return (' ' x $sp) . $self->stringify . "\n";
507             }
508              
509             ## debug output
510             sub gubed {
511 0 0   0   0 return unless $Debug;
512              
513 0         0 my $msg = shift;
514 0         0 chomp $msg;
515 0         0 print STDERR "$msg\n";
516             }
517              
518             ##################################
519             package Mail::Procmailrc::Recipe;
520             ##################################
521              
522             ## FIXME: handle comments on the flags line
523              
524 14     14   90 use Carp qw(carp);
  14         25  
  14         21829  
525              
526             sub new {
527 110     110   321 my $self = bless { }, shift;
528 110         676 my $data = shift;
529 110         684 my $defs = shift; ## defaults
530              
531 110 100       1975 $self->defaults($defs) if $defs;
532 110         308 $self->init($data);
533 110         264 return $self;
534             }
535              
536             sub defaults {
537 418     418   474 my $self = shift;
538 418         440 my $defaults = shift;
539 418         402 my $value = shift;
540              
541             ## nada: return whole hashref
542 418 50       1232 unless( $defaults ) {
543 0         0 return $self->{DEFAULTS};
544             }
545              
546             ## no hashref: return element of hashref
547 418 100       746 unless( ref($defaults) ) {
548 317 50       2067 return ( defined $self->{DEFAULTS}->{$defaults}
    100          
549             ? ( defined $value
550             ? $self->{DEFAULTS}->{$defaults} = $value
551             : $self->{DEFAULTS}->{$defaults} )
552             : undef );
553             }
554              
555             ## hashref: assign hashref
556 101         283 return $self->{DEFAULTS} = $defaults;
557             }
558              
559             sub init {
560 111     111   158 my $self = shift;
561 111         122 my $data = shift;
562 111         115 my $line;
563              
564 111         187 $self->{FLAGS} = undef;
565 111         166 $self->{INFO} = undef;
566 111         169 $self->{CONDITIONS} = undef;
567 111         143 $self->{ACTION} = undef;
568              
569             ## init members
570 111         224 $self->flags('');
571 111         265 $self->info([]);
572 111         245 $self->conditions([]);
573 111         244 $self->action('');
574              
575 111 100       214 return unless defined $data;
576              
577 106 100       227 if( 'ARRAY' eq ref($data) ) {
578 103         388 chomp @$data;
579             }
580             else {
581             ## we don't know how to handle other kinds of refs here
582 3 100       23 return if ref($data);
583              
584             ## split the data (implicit chomping)
585 2         12 $data = [split(/\n/, $data)];
586             }
587              
588             ## required: FLAGS
589 105         152 FLAGS: {
590 105         112 $line = shift @$data;
591 105         366 $line =~ s/^\s*//;
592 105 50       600 unless( $line =~ /$Mail::Procmailrc::RE{'flags'}/ ) {
593 0         0 carp( "Not a recipe: $line\n" );
594 0         0 return;
595             }
596 105         223 $self->flags($line);
597             }
598              
599             ## optional: INFO
600             INFO: {
601             ## get a line
602 105         262 $line = shift @$data;
  149         229  
603 149 100       1001 last INFO unless defined $line;
604 148         608 $line =~ s/^\s*//;
605              
606             ## comment/info
607 148 100       966 if( $line =~ s/$Mail::Procmailrc::RE{'comm'}/$1/ ) {
608 39         55 push @{$self->info}, $line;
  39         85  
609 39         83 redo INFO;
610             }
611              
612             ## skip empty lines
613 109 100       797 if( $line =~ /$Mail::Procmailrc::RE{'blank'}/ ) {
614 5         10 redo INFO;
615             }
616              
617             ## a non-empty, non-comment line. Maybe it's a condition...
618 104         237 unshift @$data, $line;
619             }
620              
621             ## optional: CONDITIONS
622             CONDITIONS: {
623             ## get a line
624 105         116 $line = shift @$data;
  374         840  
625 374 100       693 last CONDITIONS unless defined $line;
626 373         1111 $line =~ s/^\s*//;
627              
628             ## check for condition
629 373 100       2634 if( $line =~ s/$Mail::Procmailrc::RE{'condm'}/$1/ ) {
630 260         1494 while( $line =~ /$Mail::Procmailrc::RE{'cont'}/ ) {
631 94         191 $line .= "\n"; ## tack on the newline for quoted lines
632 94         349 $line .= shift @$data;
633             }
634              
635 260         266 push @{$self->conditions}, $line;
  260         449  
636 260         387 redo CONDITIONS;
637             }
638              
639             ## check for embedded comments and skip them
640 113 100       379 if( $line =~ /$Mail::Procmailrc::RE{'comt'}/ ) {
641 1         2 redo CONDITIONS;
642             }
643              
644             ## check for empty lines and skip them
645 112 100       434 if( $line =~ /$Mail::Procmailrc::RE{'blank'}/ ) {
646 8         12 redo CONDITIONS;
647             }
648              
649             ## non-empty, non-comment, non-condition. Maybe it's an action...
650 104         198 unshift @$data, $line;
651             }
652              
653             ## required: ACTION
654             ACTION: {
655             ## get a line
656 105         111 $line = shift @$data;
  105         199  
657 105 100       203 last ACTION unless defined $line;
658 104         301 $line =~ s/^\s*//;
659              
660             ## if contains a '{' we pass it to Procmailrc
661 104 100       453 if( $line =~ /$Mail::Procmailrc::RE{'blkopen'}/ ) {
662 62         123 unshift @$data, $line;
663 62         133 $self->action( Mail::Procmailrc->new( { 'data' => $data,
664             'level' => $self->defaults('level') } ));
665             }
666              
667             ## this is a plain old action line
668             else {
669 42         181 while( $line =~ /$Mail::Procmailrc::RE{'cont'}/ ) {
670 44         81 $line .= "\n";
671 44         200 $line .= shift @$data;
672             }
673 42         93 $self->action($line);
674             }
675             }
676              
677 105         233 return 1;
678             }
679              
680             sub stringify {
681 1     1   6 my $self = shift;
682 1         2 my $output = '';
683              
684 1         3 $output = $self->flags . "\n";
685              
686 1         3 $output .= ( scalar(@{$self->info})
  1         3  
687 1 50       2 ? join( "\n", @{$self->info} ) . "\n"
688             : '' );
689 1         3 $output .= ( scalar(@{$self->conditions})
  1         2  
690 1 50       2 ? join( "\n", @{$self->conditions} ) . "\n"
691             : '' );
692 1 50       4 $output .= ( ref($self->action)
693             ? $self->action->stringify
694             : $self->action );
695              
696 1         5 return $output;
697             }
698              
699             sub dump {
700 134     134   174 my $self = shift;
701 134 100       248 my $sp = ( defined $self->defaults('level') ? $self->defaults('level') * 2 : 0 );
702 134         201 my $output = '';
703              
704             ## flags
705 134         294 $output = (' ' x $sp) . $self->flags . "\n";
706              
707             ## info
708 134         231 $output .= ( scalar(@{$self->info})
  63         114  
709 134 100       223 ? (' ' x $sp) . join( "\n" . (' ' x $sp), @{$self->info} ) . "\n"
710             : '' );
711              
712             ## conditions
713 134         365 $output .= ( scalar(@{$self->conditions})
  103         169  
714 134 100       172 ? (' ' x $sp) . join( "\n" . (' ' x $sp), @{$self->conditions} ) . "\n"
715             : '' );
716              
717             ## action
718 134 100       295 $output .= ( ref($self->action)
719             ? $self->action->dump
720             : (' ' x $sp) . $self->action );
721              
722             ## kludge: we do this because sometimes the action object is
723             ## dumped and other times it is just a string. When we nest a few
724             ## of these, the newlines pile up and leave a lot of whitespace
725             ## at the end of the recipe dump.
726 134         216 chomp $output;
727 134         149 $output .= "\n";
728              
729 134         991 return $output;
730             }
731              
732             ## data will be a scalar like :0B:
733             sub flags {
734 360     360   748 my $self = shift;
735 360         392 my $data = shift;
736              
737 360 100       1002 return ( defined $data
738             ? $self->{FLAGS} = Mail::Procmailrc::Literal->new($data)
739             : $self->{FLAGS}->stringify );
740             }
741              
742             ## data will be an array ref; if the data is a scalar, split it and
743             ## make it a list ref
744             sub info {
745 363     363   486 my $self = shift;
746 363         368 my $data = shift;
747              
748 363 100 100     1224 if( defined $data && !ref($data) ) {
749 5         27 $data = [split(/\n/, $data)];
750             }
751              
752 363 100       4694 return ( defined $data ? $self->{INFO} = $data : $self->{INFO} );
753             }
754              
755             ## data will be an array ref upon which we push lines like '* 1^0 foo'
756             ## FIXME: do we want to split scalars like we do for 'info'?
757             sub conditions {
758 621     621   999 my $self = shift;
759 621         656 my $data = shift;
760              
761 621 100       3128 return ( defined $data ? $self->{CONDITIONS} = $data : $self->{CONDITIONS} );
762             }
763              
764             ## data will be scalar, possibly multiline; could be another rc object
765             sub action {
766 496     496   891 my $self = shift;
767 496         497 my $data = shift;
768 496 100 100     1266 chomp $data if $data && !ref($data);
769              
770 496 100       1580 return ( defined $data ? $self->{ACTION} = $data : $self->{ACTION} );
771             }
772              
773             1;
774             __END__