1 package FS::part_export::communigate_pro;
4 use vars qw(@ISA %info %options $DEBUG);
10 @ISA = qw(FS::part_export);
14 tie %options, 'Tie::IxHash',
15 'port' => { label =>'Port number', default=>'106', },
16 'login' => { label =>'The administrator account name. The name can contain a domain part.', },
17 'password' => { label =>'The administrator account password.', },
18 'accountType' => { label => 'Type for newly-created accounts',
20 options => [qw(MultiMailbox TextMailbox MailDirMailbox)],
21 default => 'MultiMailbox',
23 'externalFlag' => { label => 'Create accounts with an external (visible for legacy mailers) INBOX.',
26 'AccessModes' => { label => 'Access modes',
27 default => 'Mail POP IMAP PWD WebMail WebSite',
29 'create_domain' => { label => 'Domain creation API call',
31 options => [qw( CreateDomain CreateSharedDomain )],
36 'svc' => [qw( svc_acct svc_domain )],
37 'desc' => 'Real-time export of accounts and domains to a CommuniGate Pro mail server',
38 'options' => \%options,
40 Real time export of accounts and domains to a
41 <a href="http://www.stalker.com/CommuniGatePro/">CommuniGate Pro</a>
43 <a href="http://www.stalker.com/CGPerl/">CommuniGate Pro Perl Interface</a>
44 must be installed as CGP::CLI.
48 sub rebless { shift; }
51 my($self, $svc_acct) = (shift, shift);
56 my( $self, $svc_x ) = (shift, shift);
60 if ( $svc_x->isa('FS::svc_acct') ) {
62 @options = ( $svc_x->svcnum, 'CreateAccount',
63 'accountName' => $self->export_username($svc_x),
64 'accountType' => $self->option('accountType'),
65 'AccessModes' => $self->option('AccessModes'),
66 'RealName' => $svc_x->finger,
67 'Password' => $svc_x->_password,
69 push @options, 'MaxAccountSize' => $svc_x->quota if $svc_x->quota;
70 push @options, 'externalFlag' => $self->option('externalFlag')
71 if $self->option('externalFlag');
73 } elsif ( $svc_x->isa('FS::svc_domain') ) {
75 my $create = $self->option('create_domain') || 'CreateDomain';
77 @options = ( $svc_x->svcnum, $create, $svc_x->domain,
78 #other domain creation options?
80 push @options, 'AccountsLimit' => $svc_x->max_accounts
81 if $svc_x->max_accounts;
84 die "guru meditation #14: $svc_x is not FS::svc_acct, or FS::svc_domain";
87 $self->communigate_pro_queue( @options );
91 my( $self, $new, $old ) = (shift, shift, shift);
93 if ( $new->isa('FS::svc_acct') ) {
95 #XXX they probably need the ability to change some of these
96 return "can't (yet) change username with CommuniGate Pro"
97 if $old->username ne $new->username;
98 return "can't (yet) change domain with CommuniGate Pro"
99 if $self->export_username($old) ne $self->export_username($new);
100 return "can't (yet) change GECOS with CommuniGate Pro"
101 if $old->finger ne $new->finger;
102 return "can't (yet) change quota with CommuniGate Pro"
103 if $old->quota ne $new->quota;
104 return '' unless $old->username ne $new->username
105 || $old->_password ne $new->_password
106 || $old->finger ne $new->finger
107 || $old->quota ne $new->quota;
109 return '' if '*SUSPENDED* '. $old->_password eq $new->_password;
111 #my $err_or_queue = $self->communigate_pro_queue( $new->svcnum,'RenameAccount',
112 # $old->email, $new->email );
113 #return $err_or_queue unless ref($err_or_queue);
114 #my $jobnum = $err_or_queue->jobnum;
116 $self->communigate_pro_queue( $new->svcnum, 'SetAccountPassword',
117 $self->export_username($new), $new->_password )
118 if $new->_password ne $old->_password;
120 } elsif ( $new->isa('FS::svc_domain') ) {
122 if ( $old->domain ne $new->domain ) {
123 $self->communigate_pro_queue( $new->svcnum, 'RenameDomain',
124 $old->domain, $new->domain,
128 if ( $old->max_accounts ne $new->max_accounts ) {
129 $self->communigate_pro_queue( $new->svcnum, 'UpdateDomainSettings',
130 $new->domain, 'AccountsLimit' => ($new->max_accounts || 'default'),
134 #other kinds of changes?
137 die "guru meditation #15: $new is not FS::svc_acct, or FS::svc_domain";
143 my( $self, $svc_x ) = (shift, shift);
145 if ( $svc_x->isa('FS::svc_acct') ) {
147 $self->communigate_pro_queue( $svc_x->svcnum, 'DeleteAccount',
148 $self->export_username($svc_x),
151 } elsif ( $svc_x->isa('FS::svc_domain') ) {
153 $self->communigate_pro_queue( $svc_x->svcnum, 'DeleteDomain',
155 #XXX turn on force option for domain deletion?
159 die "guru meditation #16: $svc_x is not FS::svc_acct, or FS::svc_domain";
164 sub _export_suspend {
165 my( $self, $svc_x ) = (shift, shift);
167 if ( $svc_x->isa('FS::svc_acct') ) {
169 $self->communigate_pro_queue( $svc_x->svcnum, 'UpdateAccountSettings',
170 'accountName' => $self->export_username($svc_x),
171 'AccessModes' => 'Mail',
174 } elsif ( $svc_x->isa('FS::svc_domain') ) {
176 #XXX domain operations
178 die "guru meditation #17: $svc_x is not FS::svc_acct, or FS::svc_domain";
183 sub _export_unsuspend {
184 my( $self, $svc_x ) = (shift, shift);
186 if ( $svc_x->isa('FS::svc_acct') ) {
188 $self->communigate_pro_queue( $svc_x->svcnum, 'UpdateAccountSettings',
189 'accountName' => $self->export_username($svc_x),
190 'AccessModes' => $self->option('AccessModes'),
192 } elsif ( $svc_x->isa('FS::svc_domain') ) {
194 #XXX domain operations
196 die "guru meditation #18: $svc_x is not FS::svc_acct, or FS::svc_domain";
201 sub export_getsettings {
202 my($self, $svc_x, $settingsref, $defaultref ) = @_;
204 my $settings = eval { $self->communigate_pro_runcommand(
210 my $effective_settings = eval { $self->communigate_pro_runcommand(
211 'GetDomainEffectiveSettings',
216 my %defaults = map { $_ => 1 }
217 grep !exists(${$settings}{$_}), keys %$effective_settings;
219 foreach my $key ( grep ref($effective_settings->{$_}),
220 keys %$effective_settings )
222 my $value = $effective_settings->{$key};
223 if ( ref($value) eq 'ARRAY' ) {
224 $effective_settings->{$key} = join(', ', @$value);
227 warn "serializing ". ref($value). " for table display not yet handled";
231 %{$settingsref} = %$effective_settings;
232 %{$defaultref} = %defaults;
237 sub communigate_pro_queue {
238 my( $self, $svcnum, $method ) = (shift, shift, shift);
239 my %kludge_methods = (
240 'CreateAccount' => 'CreateAccount',
241 'UpdateAccountSettings' => 'UpdateAccountSettings',
242 'CreateDomain' => 'cp_Scalar_Hash',
243 'CreateSharedDomain' => 'cp_Scalar_Hash',
244 'UpdateDomainSettings' => 'UpdateDomainSettings',
246 my $sub = exists($kludge_methods{$method})
247 ? $kludge_methods{$method}
248 : 'communigate_pro_command';
249 my $queue = new FS::queue {
251 'job' => "FS::part_export::communigate_pro::$sub",
255 $self->option('port'),
256 $self->option('login'),
257 $self->option('password'),
264 sub communigate_pro_runcommand {
265 my( $self, $method ) = (shift, shift);
267 communigate_pro_command(
269 $self->option('port'),
270 $self->option('login'),
271 $self->option('password'),
278 #XXX one sub per arg prototype is lame. more magic? i suppose queue needs
279 # to store data strctures properly instead of just an arg list. right.
282 my( $machine, $port, $login, $password, $method, $scalar, %hash ) = @_;
283 my @args = ( $scalar, \%hash );
284 communigate_pro_command( $machine, $port, $login, $password, $method, @args );
288 # my( $machine, $port, $login, $password, $method, %hash ) = @_;
289 # my @args = ( \%hash );
290 # communigate_pro_command( $machine, $port, $login, $password, $method, @args );
293 sub UpdateDomainSettings {
294 my( $machine, $port, $login, $password, $method, $domain, %settings ) = @_;
295 my @args = ( 'domain' => $domain, 'settings' => \%settings );
296 communigate_pro_command( $machine, $port, $login, $password, $method, @args );
300 my( $machine, $port, $login, $password, $method, %args ) = @_;
301 my $accountName = delete $args{'accountName'};
302 my $accountType = delete $args{'accountType'};
303 my $externalFlag = delete $args{'externalFlag'};
304 $args{'AccessModes'} = [ split(' ', $args{'AccessModes'}) ];
305 my @args = ( accountName => $accountName,
306 accountType => $accountType,
309 #externalFlag => $externalFlag,
310 push @args, externalFlag => $externalFlag if $externalFlag;
312 communigate_pro_command( $machine, $port, $login, $password, $method, @args );
316 sub UpdateAccountSettings {
317 my( $machine, $port, $login, $password, $method, %args ) = @_;
318 my $accountName = delete $args{'accountName'};
319 $args{'AccessModes'} = [ split(' ', $args{'AccessModes'}) ];
320 my @args = ( $accountName, \%args );
321 communigate_pro_command( $machine, $port, $login, $password, $method, @args );
324 sub communigate_pro_command { #subroutine, not method
325 my( $machine, $port, $login, $password, $method, @args ) = @_;
329 my $cli = new CGP::CLI( {
330 'PeerAddr' => $machine,
333 'password' => $password,
334 } ) or die "Can't login to CGPro: $CGP::ERR_STRING\n";
336 #warn "$method ". Dumper(@args) if $DEBUG;
338 my $return = $cli->$method(@args)
339 or die "Communigate Pro error: ". $cli->getErrMessage;
341 $cli->Logout; # or die "Can't logout of CGPro: $CGP::ERR_STRING\n";