File Coverage

blib/lib/Palm/TreoPhoneCallDB.pm
Criterion Covered Total %
statement 35 41 85.3
branch 7 8 87.5
condition 1 2 50.0
subroutine 7 7 100.0
pod 1 1 100.0
total 51 59 86.4


line stmt bran cond sub pod time code
1             package Palm::TreoPhoneCallDB;
2              
3 3     3   61923 use strict;
  3         7  
  3         118  
4 3     3   14 use warnings;
  3         4  
  3         101  
5              
6 3     3   1565 use Palm::Raw();
  3         1228  
  3         59  
7 3     3   2635 use DateTime;
  3         341980  
  3         177  
8              
9 3     3   31 use vars qw($VERSION @ISA $timezone $incl_raw);
  3         4  
  3         1649  
10              
11             $VERSION = '1.2';
12             @ISA = qw(Palm::Raw);
13             $timezone = 'Europe/London';
14             $incl_raw = 0;
15              
16             sub import {
17 3     3   27 my $class = shift;
18 3         9 my %opts = @_;
19 3 100       15 $timezone = $opts{timezone} if(exists($opts{timezone}));
20 3 100       10 $incl_raw = $opts{incl_raw} if(exists($opts{incl_raw}));
21 3         14 Palm::PDB::RegisterPDBHandlers(__PACKAGE__, [HsPh => 'call']);
22             }
23              
24             =head1 NAME
25              
26             Palm::TreoPhoneCallDB - Handler for Treo PhoneCallDB databases
27              
28             =head1 SYNOPSIS
29              
30             use Palm::PDB;
31             use Palm::TreoPhoneCallDB timezone => 'Europe/London';
32              
33             my $pdb = Palm::PDB->new();
34             $pdb->Load("PhoneCallDB.pdb");
35             print Dumper(@{$pdb->{records}})'
36              
37             =head1 DESCRIPTION
38              
39             This is a helper class for the Palm::PDB package, which parses the database
40             generated by Palm Treos as a record who you called, when, and for how long.
41              
42             =head1 OPTIONS
43              
44             You can set some global options when you 'use' the module:
45              
46             =over
47              
48             =item timezone
49              
50             Defaults to 'Europe/London'.
51              
52             =item incl_raw
53              
54             Whether to include the raw binary blob of data in the parsed records.
55             Only really useful for debuggering, and so defaults to false.
56              
57             =back
58              
59             =head1 METHODS
60              
61             This class inherits from Palm::Raw, so has all of its methods. The following
62             are over-ridden, and differ from that in the parent class thus:
63              
64             =head2 ParseRecord
65              
66             Returns data structures with the following keys:
67              
68             =over
69              
70             =item rawdata
71              
72             The raw data blob passed to the method. This is only present if the
73             incl_raw option is true.
74              
75             =item date
76              
77             The date the call started, in YYYY-MM-DD format
78              
79             =item time
80              
81             The time the call started, in HH:MM format
82              
83             =item epoch
84              
85             The epoch time the call started. Note that because the database doesn't
86             store the timezone, we assume 'Europe/London'. If you want to change
87             that, then suppy a timezone option when you 'use' the module.
88              
89             Internally, this uses the DateTime module. In the case of ambiguous times
90             then it uses the latest UTC time. For invalid local times, the epoch is
91             set to -1, an impossible number as it's before Palm even existed.
92              
93             Note that this is always the Unix epoch time. See L for details
94             of what this means.
95              
96             =item duration
97              
98             The length of the call in seconds
99              
100             =item name
101              
102             The name of the other party, which the Treo extracts from the SIM phone-book
103             or from the Palm address book at the time the call is connected.
104              
105             =item number
106              
107             The number of the other party. This is not normalised so you might see the
108             same number in different formats, eg 02079813000 and +442079813000. I may
109             add number normalisation in the future.
110              
111             =item direction
112              
113             Either 'Incoming', 'Outgoing' or 'Missed'.
114              
115             =back
116              
117             Other fields may be added in the future.
118              
119             =cut
120              
121             sub ParseRecord {
122 282     282 1 10731 my $self = shift;
123 282         990 my %record = @_;
124              
125 282         528 $record{rawdata} = delete($record{data});
126              
127 282         297 my($flags, $date, $time, $duration, $name, $number);
128             # the unpack() doesn't seem to work in 5.6.2
129 282 50       489 if($] >= 5.008) {
130 282         1258 ($flags, $date, $time, $duration, $name, $number) = unpack(
131             'n3N1Z*Z*', $record{rawdata}
132             );
133             } else {
134             # pick the record apart a byte at a time. probably makes horrible
135             # charset assumptions, but that's ok, 5.6 doesn't do unicode anyway
136 0         0 my @bytes = (split(//, $record{rawdata}));
137 0         0 $flags = 256 * ord($bytes[0]) + ord($bytes[1]);
138 0         0 $date = 256 * ord($bytes[2]) + ord($bytes[3]);
139 0         0 $time = 256 * ord($bytes[4]) + ord($bytes[5]);
140            
141 0         0 $duration = 0x1000000 * ord($bytes[6]) +
142             0x10000 * ord($bytes[7]) +
143             0x100 * ord($bytes[8]) +
144             ord($bytes[9]);
145            
146 0         0 ($name, $number) = split(/\x00/, join('', @bytes[10 .. $#bytes]));
147             }
148              
149 282         459 my $year = 1904 + (($date & 0b1111111000000000) >> 9);
150 282         835 my $month = sprintf('%02d', ($date & 0b111100000) >> 5);
151 282         437 my $day = sprintf('%02d', $date & 0b11111);
152 282         362 my $hour = sprintf('%02d', $time >> 8);
153 282         350 my $minute = sprintf('%02d', $time & 255);
154              
155 282         1770 @record{qw(date time duration name number direction)} = (
156             "$year-$month-$day",
157             "$hour:$minute",
158             $duration,
159             $name,
160             $number,
161             (qw(Incoming Missed Outgoing))[$record{category} - 1]
162             );
163 282   50     432 $record{epoch} = eval { DateTime->new(
164             year => $year,
165             month => $month,
166             day => $day,
167             hour => $hour,
168             minute => $minute,
169             time_zone => $timezone
170             )->epoch(); } || -1;
171              
172 282 100       163286 delete $record{rawdata} unless($incl_raw);
173              
174 282         913 return \%record;
175             }
176              
177             =head1 LIMITATIONS
178              
179             There is currently no support for creating a new database, or for editing
180             the contents of an existing database. If you need that functionality,
181             please submit a patch with tests. I will *not* write this myself
182             unless I need it.
183              
184             Behaviour if you try to create or edit a database is currently undefined.
185              
186             =head1 BUGS and FEEDBACK
187              
188             Online documentation claims that there are various flags in the
189             records to indicate whether calls are incoming or outgoing and
190             so on. I can't find these flags anywhere in the data generated by
191             my Treo 680. Instead, it seems to be stored in the 'category'
192             field. It is, however, possible that the category numbers for each
193             type of call vary from one Treo to another maybe depending on the
194             order in which the first calls are made.
195              
196             If you find any other bugs please report them either using
197             L or by email. Ideally, I would like to receive a
198             sample database and a test file, which fails with the latest version of
199             the module but will pass when I fix the bug.
200              
201             =head1 SEE ALSO
202              
203             L
204              
205             L
206              
207             =head1 AUTHOR
208              
209             David Cantrell EFE
210              
211             =head1 COPYRIGHT and LICENCE
212              
213             Copyright 2007 David Cantrell
214              
215             This module is free-as-in-speech software, and may be used, distributed,
216             and modified under the same terms as Perl itself.
217              
218             =head1 CONSPIRACY
219              
220             This module is also free-as-in-mason software.
221              
222             =cut
223              
224             1;