File Coverage

blib/lib/Net/Growl.pm
Criterion Covered Total %
statement 42 115 36.5
branch 0 16 0.0
condition 0 22 0.0
subroutine 14 21 66.6
pod 2 2 100.0
total 58 176 32.9


line stmt bran cond sub pod time code
1             package Net::Growl;
2              
3 1     1   28688 use vars qw($VERSION); $VERSION = '0.99';
  1         3  
  1         73  
4 1     1   5 use warnings;
  1         2  
  1         33  
5 1     1   7 use strict;
  1         6  
  1         39  
6 1     1   999 use IO::Socket;
  1         31711  
  1         5  
7 1     1   672 use Exporter;
  1         2  
  1         40  
8 1     1   5 use Carp;
  1         2  
  1         101  
9              
10             # Derived from Rui Carmo's (http://the.taoofmac.com)
11             # netgrowl.php (http://the.taoofmac.com/space/Projects/netgrowl.php)
12             # by Nathan McFarland - (http://nmcfarl.org)
13              
14             our @ISA = qw(Exporter);
15             our @EXPORT = ( 'register', 'notify' );
16              
17 1     1   5 use constant GROWL_UDP_PORT => 9887;
  1         2  
  1         141  
18 1     1   5 use constant GROWL_PROTOCOL_VERSION => 1;
  1         5  
  1         49  
19 1     1   5 use constant GROWL_TYPE_REGISTRATION => 0;
  1         2  
  1         48  
20 1     1   4 use constant GROWL_TYPE_NOTIFICATION => 1;
  1         2  
  1         358  
21              
22             sub register {
23 0     0 1   my %args = @_;
24 0   0       my %addr = (
25             PeerAddr => $args{host} || "localhost",
26             PeerPort => Net::Growl::GROWL_UDP_PORT,
27             Proto => 'udp' );
28 0 0         die "A password is required" if ( !$args{password} );
29 0   0       my $s = IO::Socket::INET->new(%addr) || die "Could not create socket: $!\n";
30 0           my $p = Net::Growl::RegistrationPacket->new(%args);
31 0           $p->addNotification();
32 0           print( $s $p->payload() );
33 0           close($s);
34             }
35              
36             sub notify {
37 0     0 1   my %args = @_;
38 0   0       my %addr = (
39             PeerAddr => $args{host} || "localhost",
40             PeerPort => Net::Growl::GROWL_UDP_PORT,
41             Proto => 'udp' );
42 0 0         die "A password is required" if ( !$args{password} );
43 0   0       my $s = IO::Socket::INET->new(%addr) || die "Could not create socket: $!\n";
44 0           my $p = Net::Growl::NotificationPacket->new(%args);
45 0           print( $s $p->payload() );
46              
47 0           close($s);
48             }
49              
50             1;
51              
52             package Net::Growl::RegistrationPacket;
53 1     1   7 use Digest::MD5 qw( md5_hex );
  1         2  
  1         70  
54 1     1   5 use base 'Net::Growl';
  1         2  
  1         534  
55              
56             sub new {
57 0     0     my $class = shift;
58 0           my %args = @_;
59 0   0       $args{application} ||= "growl_notify";
60 0           my $self = bless \%args, $class;
61 0           $self->{notifications} = {};
62 0           utf8::encode( $self->{application} );
63 0           return $self;
64             }
65              
66             sub addNotification {
67 0     0     my ( $self, %args ) = @_;
68 0   0       $args{notification} ||= "Command-Line Growl Notification";
69 0 0         $args{enabled} = "True" if !defined $args{enabled};
70 0           $self->{notifications}->{ $args{notification} } = $args{enabled};
71             }
72              
73             sub payload {
74 0     0     my $self = shift;
75 0           my ( $name, $defaults );
76 0           my ( $name_count, $defaults_count );
77 0           for ( keys %{ $self->{notifications} } ) {
  0            
78 0           utf8::encode($_);
79 0           $name .= pack( "n", length($_) ) . $_;
80 0           $name_count++;
81 0 0         if ( $self->{notifications}->{$_} ) {
82 0           $defaults .= pack( "c", $name_count - 1 );
83 0           $defaults_count++;
84             }
85             }
86 0           $self->{data} = pack( "c2nc2",
87             $self->GROWL_PROTOCOL_VERSION,
88             $self->GROWL_TYPE_REGISTRATION,
89             length( $self->{application} ),
90             $name_count,
91             $defaults_count );
92 0           $self->{data} .= $self->{application} . $name . $defaults;
93              
94 0           my $checksum;
95 0 0         if ( $self->{password} ) {
96 0           $checksum = pack( "H32", md5_hex( $self->{data} . $self->{password} ) );
97             }
98             else {
99 0           $checksum = pack( "H32", md5_hex( $self->{data} ) );
100             }
101              
102 0           $self->{data} .= $checksum;
103 0           return $self->{data};
104             }
105              
106             1;
107              
108             package Net::Growl::NotificationPacket;
109 1     1   6 use Digest::MD5 qw( md5_hex );
  1         2  
  1         47  
110 1     1   26 use base 'Net::Growl';
  1         2  
  1         453  
111              
112             sub new {
113 0     0     my ( $class, %args ) = @_;
114 0   0       $args{application} ||= "growlnotify";
115 0   0       $args{notification} ||= "Command-Line Growl Notification";
116 0   0       $args{title} ||= "Title";
117 0   0       $args{description} ||= "Description";
118 0   0       $args{priority} ||= 0;
119 0           my $self = bless \%args, $class;
120              
121 0           utf8::encode( $self->{application} );
122 0           utf8::encode( $self->{notification} );
123 0           utf8::encode( $self->{title} );
124 0           utf8::encode( $self->{description} );
125 0           my $flags = ( $args{priority} & 0x07 ) * 2;
126 0 0         if ( $args{priority} < 0 ) {
127 0           $flags |= 0x08;
128             }
129 0 0         if ( $args{sticky} ) {
130 0           $flags = $flags | 0x0001;
131             }
132 0           $self->{data} = pack( "c2n5",
133             $self->GROWL_PROTOCOL_VERSION,
134             $self->GROWL_TYPE_NOTIFICATION,
135             $flags,
136             length( $self->{notification} ),
137             length( $self->{title} ),
138             length( $self->{description} ),
139             length( $self->{application} ) );
140 0           $self->{data} .= $self->{notification};
141 0           $self->{data} .= $self->{title};
142 0           $self->{data} .= $self->{description};
143 0           $self->{data} .= $self->{application};
144              
145 0 0         if ( $args{password} ) {
146 0           $self->{checksum} =
147             pack( "H32", md5_hex( $self->{data} . $args{password} ) );
148             }
149             else {
150 0           $self->{checksum} = pack( "H32", md5_hex( $self->{data} ) );
151             }
152 0           $self->{data} .= $self->{checksum};
153 0           return $self;
154             }
155              
156             sub payload {
157 0     0     my $self = shift;
158 0           return $self->{data};
159             }
160              
161             1;
162              
163             __END__