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