File Coverage

blib/lib/Mail/IMAP/Util.pm
Criterion Covered Total %
statement 12 48 25.0
branch 0 18 0.0
condition n/a
subroutine 4 6 66.6
pod 0 2 0.0
total 16 74 21.6


line stmt bran cond sub pod time code
1             package Mail::IMAP::Util;
2 2     2   12 use strict;
  2         4  
  2         79  
3 2     2   12 use warnings;
  2         4  
  2         81  
4 2     2   1311 use utf8;
  2         14  
  2         14  
5              
6 2     2   65 use parent qw/Exporter/;
  2         5  
  2         19  
7              
8             our @EXPORT = qw(imap_string_quote imap_parse_tokens);
9              
10             sub imap_string_quote {
11 0     0 0   local $_ = shift;
12 0           s/\\/\\\\/g;
13 0           s/\"/\\\"/g;
14 0           "\"$_\"";
15             }
16              
17             ##### parse imap response #####
18             #
19             # This is probably the simplest/dumbest way to parse the IMAP output.
20             # Nevertheless it seems to be very stable and fast.
21             #
22             # $input is an array ref containing IMAP output. Normally it will
23             # contain only one entry -- a line of text -- but when IMAP sends
24             # literal data, we read it separately (see _read_literal) and store it
25             # as a scalar reference, therefore it can be like this:
26             #
27             # [ '* 11 FETCH (RFC822.TEXT ', \$DATA, ')' ]
28             #
29             # so that's why the routine looks a bit more complicated.
30             #
31             # It returns an array of tokens. Literal strings are dereferenced so
32             # for the above text, the output will be:
33             #
34             # [ '*', '11', 'FETCH', [ 'RFC822.TEXT', $DATA ] ]
35             #
36             # note that lists are represented as arrays.
37             #
38             sub imap_parse_tokens {
39 0     0 0   my ($input, $no_deref) = @_;
40              
41 0           my @tokens = ();
42 0           my @stack = (\@tokens);
43              
44 0           while (my $text = shift @$input) {
45 0 0         if (ref $text) {
46 0 0         push @{$stack[-1]}, ($no_deref ? $text : $$text);
  0            
47 0           next;
48             }
49 0           while (1) {
50 0           $text =~ m/\G\s+/gc;
51 0 0         if ($text =~ m/\G[([]/gc) {
    0          
    0          
    0          
    0          
    0          
52 0           my $sub = [];
53 0           push @{$stack[-1]}, $sub;
  0            
54 0           push @stack, $sub;
55             } elsif ($text =~ m/\G(BODY\[[a-zA-Z0-9._() -]*\])/gc) {
56 0           push @{$stack[-1]}, $1; # let's consider this an atom too
  0            
57             } elsif ($text =~ m/\G[])]/gc) {
58 0           pop @stack;
59             } elsif ($text =~ m/\G\"((?:\\.|[^\"\\])*)\"/gc) {
60 0           my $str = $1;
61             # unescape
62 0           $str =~ s/\\\"/\"/g;
63 0           $str =~ s/\\\\/\\/g;
64 0           push @{$stack[-1]}, $str; # found string
  0            
65             } elsif ($text =~ m/\G(\d+)/gc) {
66 0           push @{$stack[-1]}, $1 + 0; # found numeric
  0            
67             } elsif ($text =~ m/\G([a-zA-Z0-9_\$\\.+\/*&-]+)/gc) {
68 0           my $atom = $1;
69 0 0         if (lc $atom eq 'nil') {
70 0           $atom = undef;
71             }
72 0           push @{$stack[-1]}, $atom; # found atom
  0            
73             } else {
74 0           last;
75             }
76             }
77             }
78              
79 0           return \@tokens;
80             }
81              
82             1;
83