4 use vars qw($VERSION $APP_VERSION @ISA $AUTOLOAD);
10 $VERSION = '0.2'; # $Id: APP.pm,v 1.3 2001-11-09 21:58:40 ivan Exp $
13 @ISA = qw(Net::Cmd IO::Socket::INET);
17 Net::APP - Critical Path Account Provisioning Protocol
24 $app = new Net::APP ( 'host:port',
27 Password => $password,
33 $app->ver( 'ver' => $Net::APP::APP_VERSION );
34 $app->login ( User => $user,
36 Password => $password,
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)
44 $message = $app->message;
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.
58 A new Net::APP object must be created with the I<new> method. Once this has
59 been done, all APP commands are accessed via method calls on the object.
65 =item new ( HOST:PORT [ , OPTIONS ] )
67 This is the constructor for a new Net::APP object. C<HOST> and C<PORT>
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:
72 stunnel -P none -c -d 8888 -r your.cp.address.and:port
74 This method will connect to the APP server and execute the I<ver> method.
76 I<OPTIONS> are passed in a hash like fastion, using key and value pairs.
79 I<Timeout> - Set a timeout value (defaults to 120)
81 I<Debug> - Enable debugging information (see the debug method in L<Net::Cmd>)
83 I<User>, I<Domain>, I<Password> - if these exist, the I<new> method will also
84 execute the I<login> method automatically.
86 If the constructor fails I<undef> will be returned and an error message will be
93 my $class = ref($proto) || $proto;
94 my ($host, $port) = split(/:/, shift);
97 my $self = $class->SUPER::new( PeerAddr => $host,
100 Timeout => defined $arg{Timeout}
107 $self->debug(exists $arg{Debug} ? $arg{Debug} : undef);
109 my $response = $self->_app_response;
110 unless ( $self->message =~ /^HI APP/ ) {
111 $@ = $self->code. " ". $self->message;
116 $self->ver( 'ver' => $APP_VERSION );
117 unless ( $self->ok ) {
118 $@ = $self->code. " ". $self->message;
123 if ( exists $arg{User} && exists $arg{Domain} && exists $arg{Password} ) {
124 $self->login( User => $arg{User},
125 Domain => $arg{Domain},
126 Password => $arg{Password},
128 unless ( $self->ok ) {
129 $@ = $self->code. " ". $self->message;
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.
152 Unless noted below, all commands return a reference to a list containing the
153 lines of the reponse, or I<undef> 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<message>, I<code>, I<ok>, and I<status> methods.
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
163 =item get_domain_mailboxes
165 Returns an arrayref of arrayrefs, each with three elements: username, mailbox
166 type, and workgroup. The protocol calls them: MAILBOX, TYPE, and WORKGROUP.
170 sub get_domain_mailboxes {
172 # my $command = $AUTOLOAD;
173 # $command =~ s/.*://;
174 my $command = 'get_domain_mailboxes';
175 # my $csv = new Text::CSV_XS;
176 $self->_app_command( $command, @_ );
177 [ map { chomp; [ map { s/(^"|"$)//g; $_ }
178 split(/(?<=[^"]")\s+(?="[^"])/, $_)
182 splice( @{$self->_app_response}, 2 )
186 =item get_mailbox_forward_only
188 Returns the forward email address.
192 sub get_mailbox_forward_only {
194 # my $command = $AUTOLOAD;
195 # $command =~ s/.*://;
196 my $command = 'get_mailbox_forward_only';
197 $self->_app_command( $command, @_ );
199 my $lines = $self->_app_response;
201 unless ( $lines->[1] =~ /^FORWARD_EMAIL="([^"]+)"$/ ) {
203 $self->set_status ( -1, $lines->[0] );
213 Returns the text message returned from the last command.
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<messsage> method.
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.
236 Since the APP protocol has no concept of a "most significant digit" (see
237 L<Net::Cmd/status>), this is a noisy synonym for I<code>.
242 carp "status method called (use code instead)";
249 my $command = $AUTOLOAD;
251 $self->_app_command( $command, @_ );
252 $self->_app_response;
257 =head1 INTERNAL METHODS
259 These methods are not intended to be called by the user.
263 =item _app_command ( COMMAND [ , OPTIONS ] )
265 Sends I<COMMAND>, encoded as per the Account Provisioning Protocol Developer's
266 Guide, section 3.2. I<OPTIONS> are passed in a hash like
267 fashion, using key and value pairs.
276 $self->command ( uc($command),
277 map "\U$_\E=\"". _quote($arg{$_}). '"', keys %arg
279 $self->command( '.' );
284 Gets a response from the server. Returns a reference to a list containing
285 the lines, or I<undef> upon failure. You can check the status code and message
286 using the normal Net::Cmd I<message>, I<code>, I<ok>, and I<status> methods.
292 my $lines = $self->read_until_dot;
293 if ( $self->debug ) {
294 foreach ( @{$lines}, ".\n" ) { $self->debug_print('', $_ ) }
296 if ( $lines->[0] =~ /^(OK|ER)\s+(\d+)\s+(.*)$/ ) {
297 warn 'OK response with non-zero status!' if $1 eq 'OK' && $2;
298 warn 'ER response with zero status!' if $1 eq 'ER' && ! $2;
299 $self->set_status ( $2, $3 );
301 $self->set_status ( -1, $lines->[0] );
308 =head1 INTERNAL SUBROUTINES
310 These subroutines are not intended to be called by the user.
316 Doubles double quotes.
322 $string =~ s/\"/\"\"/g; #consecutive quotes?
330 Ivan Kohler <ivan-netapp_pod@420.am>.
332 This module is not sponsored or endorsed by Critical Path.
336 Copyright (c) 2001 Ivan Kohler.
338 This program is free software; you can redistribute it and/or modify it under
339 the same terms as Perl itself.
341 =head1 PROTOCOL VERSION
343 This module currently implements APP v3.3, as documented in the Account
344 Provisioning Protocol Developers Guide v3.3.
348 The Account Provisioning Protocol Developer's Guide is not publicly available.
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. :(
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
360 Critical Path <http://www.cp.net/>,
361 APP documentation <http://support.cp.net/products/email_messaging/documentation/index.jsp>,
362 Safe Passage Secure Tunnel <http://www.int.c2.net/external/?link=spst/index.php3>,
363 Stunnel <http://www.stunnel.org>,
364 L<IO::Socket>, L<Net::Cmd>, perl(1).