File Coverage

blib/lib/Net/APP.pm
Criterion Covered Total %
statement 20 88 22.7
branch 2 24 8.3
condition 1 15 6.6
subroutine 6 14 42.8
pod 5 5 100.0
total 34 146 23.2


line stmt bran cond sub pod time code
1             package Net::APP;
2              
3 1     1   884 use strict;
  1         3  
  1         42  
4 1     1   5 use vars qw($VERSION $APP_VERSION @ISA $AUTOLOAD);
  1         1  
  1         76  
5 1     1   6 use Carp;
  1         4  
  1         82  
6 1     1   856 use IO::Socket;
  1         31548  
  1         6  
7 1     1   1859 use Net::Cmd;
  1         14362  
  1         1226  
8             #use Text::CSV_XS;
9              
10             $VERSION = '0.2'; # $Id: APP.pm,v 1.3 2001/11/09 21:58:40 ivan Exp $
11             $APP_VERSION = '3.3';
12              
13             @ISA = qw(Net::Cmd IO::Socket::INET);
14              
15             =head1 NAME
16              
17             Net::APP - Critical Path Account Provisioning Protocol
18              
19             =head1 SYNOPSIS
20              
21             use Net::APP;
22              
23             #constructor
24             $app = new Net::APP ( 'host:port',
25             User => $user,
26             Domain => $domain,
27             Password => $password,
28             Timeout => 60,
29             Debug => 1,
30             ) or die $@;
31              
32             #commands
33             $app->ver( 'ver' => $Net::APP::APP_VERSION );
34             $app->login ( User => $user,
35             Domain => $domain,
36             Password => $password,
37             );
38              
39             $app->create_domain ( Domain => $domain );
40             $app->delete_domain ( Domain => $domain );
41             #etc. (see the Account Provisioning Protocol Developer's Guide, section 3.3)
42              
43             #command status
44             $message = $app->message;
45             $code = $app->code;
46             $bool = $app->ok();
47              
48             #destructor
49             $app->close();
50              
51             =head1 DESCRIPTION
52              
53             This module implements a client interface to Critical Path's Account
54             Provisioning Protocol, enabling a perl application to talk to APP servers.
55             This documentation assumes that you are familiar with the APP protocol
56             documented in the Account Provisioning Protocol Developer's Guide.
57              
58             A new Net::APP object must be created with the I method. Once this has
59             been done, all APP commands are accessed via method calls on the object.
60              
61             =head1 METHODS
62              
63             =over 4
64              
65             =item new ( HOST:PORT [ , OPTIONS ] )
66              
67             This is the constructor for a new Net::APP object. C and C
68             specify the host and port to connect to in cleartext. Typically this
69             connection is proxied via Safe Passage Secure Tunnel or Stunnel
70             http://www.stunnel.org/ using a command such as:
71              
72             stunnel -P none -c -d 8888 -r your.cp.address.and:port
73              
74             This method will connect to the APP server and execute the I method.
75              
76             I are passed in a hash like fastion, using key and value pairs.
77             Possible options are:
78              
79             I - Set a timeout value (defaults to 120)
80              
81             I - Enable debugging information (see the debug method in L)
82              
83             I, I, I - if these exist, the I method will also
84             execute the I method automatically.
85              
86             If the constructor fails I will be returned and an error message will be
87             in $@.
88              
89             =cut
90              
91             sub new {
92 1     1 1 16165 my $proto = shift;
93 1   33     41 my $class = ref($proto) || $proto;
94 1         23 my ($host, $port) = split(/:/, shift);
95 1         17 my %arg = @_;
96              
97 1 50       148 my $self = $class->SUPER::new( PeerAddr => $host,
    50          
98             PeerPort => $port,
99             Proto => 'tcp',
100             Timeout => defined $arg{Timeout}
101             ? $arg{Timeout}
102             : 120
103             ) or return undef;
104              
105 0           $self->autoflush(1);
106              
107 0 0         $self->debug(exists $arg{Debug} ? $arg{Debug} : undef);
108              
109 0           my $response = $self->_app_response;
110 0 0         unless ( $self->message =~ /^HI APP/ ) {
111 0           $@ = $self->code. " ". $self->message;
112 0           $self->close();
113 0           return undef;
114             }
115              
116 0           $self->ver( 'ver' => $APP_VERSION );
117 0 0         unless ( $self->ok ) {
118 0           $@ = $self->code. " ". $self->message;
119 0           $self->close();
120 0           return undef;
121             }
122              
123 0 0 0       if ( exists $arg{User} && exists $arg{Domain} && exists $arg{Password} ) {
      0        
124 0           $self->login( User => $arg{User},
125             Domain => $arg{Domain},
126             Password => $arg{Password},
127             );
128 0 0         unless ( $self->ok ) {
129 0           $@ = $self->code. " ". $self->message;
130 0           $self->close();
131 0           return undef;
132             }
133             }
134              
135 0           $self;
136             }
137              
138             =item ver
139              
140             =item login
141              
142             =item create_domain
143              
144             =item delete_domain
145              
146             =item etc.
147              
148             See the Account Provisioning Protocol Developer's Guide for details. Commands
149             need not be in upper case, and options are passed in a hash-like fashion, as
150             a list of key-value pairs.
151              
152             Unless noted below, all commands return a reference to a list containing the
153             lines of the reponse, or I upon failure. The first line is parsed for
154             the status code and message. You can check the status code and message using
155             the normal Net::Cmd I, I, I, and I methods.
156              
157             Some methods return additional response information, such as
158             get_num_domain_mailboxes, get_domain_mailboxes, get_mailbox_availability and
159             get_mailbox_status methods currently return any additional response
160             information. Unless specifically noted below, no attempt is (yet) made to
161             parse this data.
162              
163             =item get_domain_mailboxes
164              
165             Returns an arrayref of arrayrefs, each with three elements: username, mailbox
166             type, and workgroup. The protocol calls them: MAILBOX, TYPE, and WORKGROUP.
167              
168             =cut
169              
170             sub get_domain_mailboxes {
171 0     0 1   my $self = shift;
172             # my $command = $AUTOLOAD;
173             # $command =~ s/.*://;
174 0           my $command = 'get_domain_mailboxes';
175             # my $csv = new Text::CSV_XS;
176 0           $self->_app_command( $command, @_ );
177 0           [ map { chomp; [ map { s/(^"|"$)//g; $_ }
  0            
  0            
  0            
  0            
178             split(/(?<=[^"]")\s+(?="[^"])/, $_)
179             ]
180             }
181 0           grep { $_ !~ /^,$/ }
182 0           splice( @{$self->_app_response}, 2 )
183             ];
184             }
185              
186             =item get_mailbox_forward_only
187              
188             Returns the forward email address.
189              
190             =cut
191              
192             sub get_mailbox_forward_only {
193 0     0 1   my $self = shift;
194             # my $command = $AUTOLOAD;
195             # $command =~ s/.*://;
196 0           my $command = 'get_mailbox_forward_only';
197 0           $self->_app_command( $command, @_ );
198              
199 0           my $lines = $self->_app_response;
200              
201 0 0         unless ( $lines->[1] =~ /^FORWARD_EMAIL="([^"]+)"$/ ) {
202 0           warn $lines->[1];
203 0           $self->set_status ( -1, $lines->[0] );
204 0           return undef;
205             }
206              
207 0           $1;
208              
209             }
210              
211             =item message
212              
213             Returns the text message returned from the last command.
214              
215             =item code
216              
217             Returns the response code from the last command (see the Account Provisioning
218             Protcol Developer's Guide, chapter 4). The code `-1' is used to represent
219             unparsable output from the APP server, in which case the entire first line
220             of the response is returned by the I method.
221              
222             =item ok
223              
224             Returns true if the last response code was not an error. Since the only
225             non-error code is 0, this is just the negation of the code method.
226              
227             =cut
228              
229             sub ok {
230 0     0 1   my $self = shift;
231 0           ! $self->code();
232             }
233              
234             =item status
235              
236             Since the APP protocol has no concept of a "most significant digit" (see
237             L), this is a noisy synonym for I.
238              
239             =cut
240              
241             sub status {
242 0     0 1   carp "status method called (use code instead)";
243 0           my $self = shift;
244 0           $self->code();
245             }
246              
247             sub AUTOLOAD {
248 0     0     my $self = shift;
249 0           my $command = $AUTOLOAD;
250 0           $command =~ s/.*://;
251 0           $self->_app_command( $command, @_ );
252 0           $self->_app_response;
253             }
254              
255             =back
256              
257             =head1 INTERNAL METHODS
258              
259             These methods are not intended to be called by the user.
260              
261             =over 4
262              
263             =item _app_command ( COMMAND [ , OPTIONS ] )
264              
265             Sends I, encoded as per the Account Provisioning Protocol Developer's
266             Guide, section 3.2. I are passed in a hash like
267             fashion, using key and value pairs.
268              
269             =cut
270              
271             sub _app_command {
272 0     0     my $self = shift;
273 0           my $command = shift;
274 0           my %arg = @_;
275              
276 0           $self->command ( uc($command),
277             map "\U$_\E=\"". _quote($arg{$_}). '"', keys %arg
278             );
279 0           $self->command( '.' );
280             }
281              
282             =item _app_response
283              
284             Gets a response from the server. Returns a reference to a list containing
285             the lines, or I upon failure. You can check the status code and message
286             using the normal Net::Cmd I, I, I, and I methods.
287              
288             =cut
289              
290             sub _app_response {
291 0     0     my $self = shift;
292 0           my $lines = $self->read_until_dot;
293 0 0         if ( $self->debug ) {
294 0           foreach ( @{$lines}, ".\n" ) { $self->debug_print('', $_ ) }
  0            
  0            
295             }
296 0 0         if ( $lines->[0] =~ /^(OK|ER)\s+(\d+)\s+(.*)$/ ) {
297 0 0 0       warn 'OK response with non-zero status!' if $1 eq 'OK' && $2;
298 0 0 0       warn 'ER response with zero status!' if $1 eq 'ER' && ! $2;
299 0           $self->set_status ( $2, $3 );
300             } else {
301 0           $self->set_status ( -1, $lines->[0] );
302             }
303 0           $lines;
304             }
305              
306             =back
307              
308             =head1 INTERNAL SUBROUTINES
309              
310             These subroutines are not intended to be called by the user.
311              
312             =over 4
313              
314             =item _quote
315              
316             Doubles double quotes.
317              
318             =cut
319              
320             sub _quote {
321 0     0     my $string = shift;
322 0           $string =~ s/\"/\"\"/g; #consecutive quotes?
323 0           $string;
324             }
325              
326             =back
327              
328             =head1 AUTHOR
329              
330             Ivan Kohler .
331              
332             This module is not sponsored or endorsed by Critical Path.
333              
334             =head1 COPYRIGHT
335              
336             Copyright (c) 2001 Ivan Kohler.
337             All rights reserved.
338             This program is free software; you can redistribute it and/or modify it under
339             the same terms as Perl itself.
340              
341             =head1 PROTOCOL VERSION
342              
343             This module currently implements APP v3.3, as documented in the Account
344             Provisioning Protocol Developers Guide v3.3.
345              
346             =head1 BUGS
347              
348             The Account Provisioning Protocol Developer's Guide is not publicly available.
349              
350             It appears that Safe Passage Secure Tunnel and Stunnel establish standard SSL
351             connections. It should be possible to use Net::SSLeay and connect to the APP
352             server directly. Initial prototyping with IO::Socket::SSL was not promising. :(
353              
354             The get_num_domain_mailboxes, get_mailbox_availability and get_mailbox_status
355             methods currently return response information. No attempt is (yet) made to
356             parse this data.
357              
358             =head1 SEE ALSO
359              
360             Critical Path ,
361             APP documentation ,
362             Safe Passage Secure Tunnel ,
363             Stunnel ,
364             L, L, perl(1).
365              
366             =cut
367              
368             1;
369