File Coverage

blib/lib/Palm/Mail.pm
Criterion Covered Total %
statement 67 140 47.8
branch 10 28 35.7
condition 0 2 0.0
subroutine 7 11 63.6
pod 6 6 100.0
total 90 187 48.1


line stmt bran cond sub pod time code
1             package Palm::Mail;
2             #
3             # ABSTRACT: Handler for Palm OS Mail databases
4             #
5             # Copyright (C) 1999, 2000, Andrew Arensburger.
6             #
7             # This program is free software; you can redistribute it and/or modify
8             # it under the same terms as Perl itself.
9             #
10             # This program is distributed in the hope that it will be useful,
11             # but WITHOUT ANY WARRANTY; without even the implied warranty of
12             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See either the
13             # GNU General Public License or the Artistic License for more details.
14              
15 2     2   6010 use strict;
  2         3  
  2         56  
16 2     2   450 use Palm::Raw();
  2         294  
  2         26  
17 2     2   351 use Palm::StdAppInfo();
  2         2  
  2         32  
18 2     2   7 use vars qw( $VERSION @ISA );
  2         2  
  2         1814  
19              
20             # One liner, to allow MakeMaker to work.
21             $VERSION = '1.015';
22             # This file is part of Palm 1.015 (February 14, 2015)
23              
24             @ISA = qw( Palm::StdAppInfo Palm::Raw );
25              
26             #'
27              
28             sub import
29             {
30 2     2   14 &Palm::PDB::RegisterPDBHandlers(__PACKAGE__,
31             [ "mail", "DATA" ],
32             );
33             }
34              
35             #'
36              
37             sub new
38             {
39 0     0 1 0 my $classname = shift;
40 0         0 my $self = $classname->SUPER::new(@_);
41             # Create a generic PDB. No need to rebless it,
42             # though.
43              
44 0         0 $self->{name} = "MailDB"; # Default
45 0         0 $self->{creator} = "mail";
46 0         0 $self->{type} = "DATA";
47 0         0 $self->{attributes}{resource} = 0;
48             # The PDB is not a resource database by
49             # default, but it's worth emphasizing,
50             # since MailDB is explicitly not a PRC.
51              
52             # Initialize the AppInfo block
53 0         0 $self->{appinfo} = {
54             sortOrder => undef, # XXX - ?
55             unsent => undef, # XXX - ?
56             sigOffset => 0, # XXX - ?
57             };
58              
59             # Add the standard AppInfo block stuff
60 0         0 &Palm::StdAppInfo::seed_StdAppInfo($self->{appinfo});
61              
62 0         0 $self->{sort} = undef; # Empty sort block
63              
64 0         0 $self->{records} = []; # Empty list of records
65              
66 0         0 return $self;
67             }
68              
69              
70             sub new_Record
71             {
72 0     0 1 0 my $classname = shift;
73 0         0 my $retval = $classname->SUPER::new_Record(@_);
74              
75             # Set the date and time on this message to today and now. This
76             # is arguably bogus, since the Date: header on a message ought
77             # to represent the time when the message was sent, rather than
78             # the time when the user started composing it, but this is
79             # better than nothing.
80              
81 0         0 ($retval->{year},
82             $retval->{month},
83             $retval->{day},
84             $retval->{hour},
85             $retval->{minute}) = (localtime(time))[5,4,3,2,1];
86              
87 0         0 $retval->{is_read} = 0; # Message hasn't been read yet.
88              
89             # No delivery service notification (DSN) by default.
90 0         0 $retval->{confirm_read} = 0;
91 0         0 $retval->{confirm_delivery} = 0;
92              
93 0         0 $retval->{priority} = 1; # Normal priority
94              
95 0         0 $retval->{addressing} = 0; # XXX - ?
96              
97             # All header fields empty by default.
98 0         0 $retval->{from} = undef;
99 0         0 $retval->{to} = undef;
100 0         0 $retval->{cc} = undef;
101 0         0 $retval->{bcc} = undef;
102 0         0 $retval->{replyTo} = undef;
103 0         0 $retval->{sentTo} = undef;
104              
105 0         0 $retval->{body} = "";
106              
107 0         0 return $retval;
108             }
109              
110             # ParseAppInfoBlock
111             # Parse the AppInfo block for Mail databases.
112             sub ParseAppInfoBlock
113             {
114 1     1 1 682 my $self = shift;
115 1         2 my $data = shift;
116 1         2 my $dirtyAppInfo;
117             my $sortOrder;
118 0         0 my $unsent;
119 0         0 my $sigOffset; # XXX - Offset of signature?
120 1         2 my $appinfo = {};
121 1         1 my $std_len;
122              
123             # Get the standard parts of the AppInfo block
124 1         5 $std_len = &Palm::StdAppInfo::parse_StdAppInfo($appinfo, $data);
125              
126 1         2 $data = $appinfo->{other}; # Look at the non-category part
127              
128             # Get the rest of the AppInfo block
129 1         2 my $unpackstr = # Argument to unpack()
130             "x2" . # Padding
131             "n" . # Dirty AppInfo (what is this?)
132             "Cx" . # Sort order
133             "N" . # Unique ID of unsent message (what is this?)
134             "n"; # Signature offset
135              
136 1         3 ($dirtyAppInfo, $sortOrder, $unsent, $sigOffset) =
137             unpack $unpackstr, $data;
138              
139 1         2 $appinfo->{dirty_AppInfo} = $dirtyAppInfo;
140 1         2 $appinfo->{sort_order} = $sortOrder;
141 1         2 $appinfo->{unsent} = $unsent;
142 1         1 $appinfo->{sig_offset} = $sigOffset;
143              
144 1         4 return $appinfo;
145             }
146              
147             sub PackAppInfoBlock
148             {
149 0     0 1 0 my $self = shift;
150 0         0 my $retval;
151              
152             # Pack the non-category part of the AppInfo block
153 0         0 $self->{appinfo}{other} = pack "x2 n Cx N n",
154             $self->{appinfo}{dirty_AppInfo},
155             $self->{appinfo}{sort_order},
156             $self->{appinfo}{unsent},
157             $self->{appinfo}{sig_offset};
158              
159             # Pack the AppInfo block
160 0         0 $retval = &Palm::StdAppInfo::pack_StdAppInfo($self->{appinfo});
161              
162 0         0 return $retval;
163             }
164              
165             sub ParseRecord
166             {
167 2     2 1 52 my $self = shift;
168 2         6 my %record = @_;
169 2         2 my $data = $record{data};
170              
171 2         4 delete $record{offset}; # This is useless
172 2         3 delete $record{data};
173              
174 2         1 my $date;
175             my $hour;
176 0         0 my $minute;
177 0         0 my $flags;
178 0         0 my $subject;
179 0         0 my $from;
180 0         0 my $to;
181 0         0 my $cc;
182 0         0 my $bcc;
183 0         0 my $replyTo;
184 0         0 my $sentTo;
185 0         0 my $body;
186 0         0 my $extra; # Extra field after body. I don't know what
187             # it is.
188 2         3 my $unpackstr =
189             "n" . # Date
190             "C" . # Hour
191             "C" . # Minute
192             "n"; # Flags
193              
194 2         4 ($date, $hour, $minute, $flags) = unpack $unpackstr, $data;
195              
196 2         1 my $year;
197             my $month;
198 0         0 my $day;
199              
200 2 50       6 if ($date != 0)
201             {
202 0         0 $day = $date & 0x001f; # 5 bits
203 0         0 $month = ($date >> 5) & 0x000f; # 4 bits
204 0         0 $year = ($date >> 9) & 0x007f; # 7 bits (years since 1904)
205 0         0 $year += 1904;
206              
207 0         0 $record{year} = $year;
208 0         0 $record{month} = $month;
209 0         0 $record{day} = $day;
210 0         0 $record{hour} = $hour;
211 0         0 $record{minute} = $minute;
212             }
213              
214 2         3 my $is_read = ($flags & 0x8000);
215 2         2 my $has_signature = ($flags & 0x4000);
216 2         2 my $confirm_read = ($flags & 0x2000);
217 2         3 my $confirm_delivery = ($flags & 0x1000);
218 2         1 my $priority = ($flags >> 10) & 0x03;
219 2         3 my $addressing = ($flags >> 8) & 0x03;
220              
221             # The signature is problematic: it's not stored in
222             # "MailDB.pdb": it's actually in "Saved Preferences.pdb". Work
223             # around this somehow; either read it from "Saved
224             # Preferences.pdb" or, more simply, just read ~/.signature if
225             # it exists.
226              
227 2 50       4 $record{is_read} = 1 if $is_read;
228 2 50       4 $record{has_signature} = 1 if $has_signature;
229 2 50       4 $record{confirm_read} = 1 if $confirm_read;
230 2 50       3 $record{confirm_delivery} = 1 if $confirm_delivery;
231 2         3 $record{priority} = $priority;
232 2         3 $record{addressing} = $addressing;
233              
234 2         2 my $fields = substr $data, 6;
235 2         10 my @fields = split /\0/, $fields;
236              
237 2         5 ($subject, $from, $to, $cc, $bcc, $replyTo, $sentTo, $body,
238             $extra) = @fields;
239              
240             # Clean things up a bit
241              
242             # Multi-line values are bad in these headers. Replace newlines
243             # with commas. Ideally, we'd use arrays for multiple
244             # recipients, but that would involve parsing addresses, which
245             # is non-trivial. Besides, most likely we'll just wind up
246             # sending these strings as they are to 'sendmail', which is
247             # better equipped to parse them.
248              
249 2 50       5 $to =~ s/\s*\n\s*(?!$)/, /gs if defined($to);
250 2 50       4 $cc =~ s/\s*\n\s*(?!$)/, /gs if defined($cc);
251 2 50       4 $bcc =~ s/\s*\n\s*(?!$)/, /gs if defined($bcc);
252 2 50       5 $replyTo =~ s/\s*\n\s*(?!$)/, /gs if defined($replyTo);
253 2 50       3 $sentTo =~ s/\s*\n\s*(?!$)/, /gs if defined($sentTo);
254              
255 2         2 $record{subject} = $subject;
256 2         3 $record{from} = $from;
257 2         3 $record{to} = $to;
258 2         3 $record{cc} = $cc;
259 2         3 $record{bcc} = $bcc;
260 2         2 $record{replyTo} = $replyTo;
261 2         4 $record{sentTo} = $sentTo;
262 2         1 $record{body} = $body;
263 2         3 $record{extra} = $extra;
264              
265 2         7 return \%record;
266             }
267              
268             sub PackRecord
269             {
270 0     0 1   my $self = shift;
271 0           my $record = shift;
272 0           my $retval;
273             my $rawDate;
274 0           my $flags;
275              
276 0           $rawDate = ($record->{day} & 0x001f) |
277             (($record->{month} & 0x000f) << 5) |
278             ((($record->{year} - 1904) & 0x07f) << 9);
279 0           $flags = 0;
280 0 0         $flags |= 0x8000 if $record->{is_read};
281 0 0         $flags |= 0x4000 if $record->{has_signature};
282 0 0         $flags |= 0x2000 if $record->{confirm_read};
283 0 0         $flags |= 0x1000 if $record->{confirm_delivery};
284 0           $flags |= (($record->{priority} & 0x03) << 10);
285 0           $flags |= (($record->{addressing} & 0x03) << 8);
286              
287 0           $retval = pack "n C C n",
288             $rawDate,
289             $record->{hour},
290             $record->{minute},
291             $flags;
292              
293             # can't leave any of these undef or join() complains
294 0           foreach (qw(subject from to cc bcc replyTo sentTo body) )
295             {
296 0   0       $record->{$_} ||= "";
297             }
298              
299 0           $retval .= join "\0",
300             $record->{subject},
301             $record->{from},
302             $record->{to},
303             $record->{cc},
304             $record->{bcc},
305             $record->{replyTo},
306             $record->{sentTo},
307             $record->{body};
308 0           $retval .= "\0";
309              
310 0           return $retval;
311             }
312              
313             1;
314              
315             __END__