import rt 2.0.14
[freeside.git] / FS / FS / part_export / vpopmail.pm
1 package FS::part_export::vpopmail;
2
3 use vars qw(@ISA @saltset $exportdir $rsync $ssh);
4 use File::Path;
5 use FS::UID qw( datasrc );
6 use FS::part_export;
7
8 @ISA = qw(FS::part_export);
9
10 @saltset = ( 'a'..'z' , 'A'..'Z' , '0'..'9' , '.' , '/' );
11
12 $rsync = "rsync";
13 $ssh = "ssh";
14
15 sub rebless { shift; }
16
17 sub _export_insert {
18   my($self, $svc_acct) = (shift, shift);
19   $self->vpopmail_queue( $svc_acct->svcnum, 'insert',
20     $svc_acct->username,
21     crypt($svc_acct->_password,$saltset[int(rand(64))].$saltset[int(rand(64))]),
22     $svc_acct->domain,
23   );
24 }
25
26 sub _export_replace {
27   my( $self, $new, $old ) = (shift, shift, shift);
28
29   my $cpassword = crypt(
30     $new->_password, $saltset[int(rand(64))].$saltset[int(rand(64))]
31   );
32
33   return "can't change username with vpopmail"
34     if $old->username ne $new->username;
35
36   #no.... if mail can't be preserved, better to disallow username changes
37   #if ($old->username ne $new->username || $old->domain ne $new->domain ) {
38   #  vpopmail_queue( $svc_acct->svcnum, 'delete', 
39   #    $old->username, $old->domain
40   #  );
41   #  vpopmail_queue( $svc_acct->svcnum, 'insert', 
42   #    $new->username,
43   #    $cpassword,
44   #    $new->domain,
45   #  );
46
47   return '' unless $old->_password ne $new->_password;
48
49   $self->vpopmail_queue( $new->svcnum, 'replace',
50     $new->username, $cpassword, $new->domain );
51 }
52
53 sub _export_delete {
54   my( $self, $svc_acct ) = (shift, shift);
55   $self->vpopmail_queue( $svc_acct->svcnum, 'delete',
56     $svc_acct->username, $svc_acct->domain );
57 }
58
59 #a good idea to queue anything that could fail or take any time
60 sub vpopmail_queue {
61   my( $self, $svcnum, $method ) = (shift, shift, shift);
62   my $exportdir = "/usr/local/etc/freeside/export." . datasrc;
63   my $queue = new FS::queue {
64     'svcnum' => $svcnum,
65     'job'    => "FS::part_export::vpopmail::vpopmail_$method",
66   };
67   $queue->insert(
68     $exportdir,
69     $self->option('machine'),
70     $self->option('dir'),
71     $self->option('uid'),
72     $self->option('gid'),
73     @_
74   );
75 }
76
77 sub vpopmail_insert { #subroutine, not method
78   my( $exportdir, $machine, $dir, $uid, $gid ) = splice @_,0,5;
79   my( $username, $password, $domain ) = @_;
80   
81   (open(VPASSWD, ">>$exportdir/domains/$domain/vpasswd")
82     and flock(VPASSWD,LOCK_EX)
83   ) or die "can't open vpasswd file for $username\@$domain: ".
84            "$exportdir/domains/$domain/vpasswd: $!";
85   print VPASSWD join(":",
86     $username,
87     $password,
88     '1',
89     '0',
90     $username,
91     "$dir/domains/$domain/$username",
92     'NOQUOTA',
93   ), "\n";
94
95   flock(VPASSWD,LOCK_UN);
96   close(VPASSWD);
97
98   for my $mkdir (
99     map { "$exportdir/domains/$domain/$username$_" }
100       ( '', qw( /Maildir /Maildir/cur /Maildir/new /Maildir/tmp ) )
101   ) {
102     mkdir $mkdir, 0700 or die "can't mkdir $mkdir: $!";
103   }
104
105   vpopmail_sync( $exportdir, $machine, $dir, $uid, $gid );
106
107 }
108
109 sub vpopmail_replace { #subroutine, not method
110   my( $exportdir, $machine, $dir, $uid, $gid ) = splice @_,0,5;
111   my( $username, $password, $domain ) = @_;
112   
113   (open(VPASSWD, "$exportdir/domains/$domain/vpasswd")
114     and flock(VPASSWD,LOCK_EX)
115   ) or die "can't open $exportdir/domains/$domain/vpasswd: $!";
116
117   open(VPASSWDTMP, ">$exportdir/domains/$domain/vpasswd.tmp")
118     or die "Can't open $exportdir/domains/$domain/vpasswd.tmp: $!";
119
120   while (<VPASSWD>) {
121     my ($mailbox, $pw, @rest) = split(':', $_);
122     print VPASSWDTMP $_ unless $username eq $mailbox;
123     print VPASSWDTMP join (':', ($mailbox, $password, @rest))
124       if $username eq $mailbox;
125   }
126
127   close(VPASSWDTMP);
128
129   rename "$exportdir/domains/$domain/vpasswd.tmp", "$exportdir/domains/$domain/vpasswd"
130     or die "Can't rename $exportdir/domains/$domain/vpasswd.tmp: $!";
131
132   flock(VPASSWD,LOCK_UN);
133   close(VPASSWD);
134
135   vpopmail_sync( $exportdir, $machine, $dir, $uid, $gid );
136
137 }
138
139 sub vpopmail_delete { #subroutine, not method
140   my( $exportdir, $machine, $dir, $uid, $gid ) = splice @_,0,5;
141   my( $username, $domain ) = @_;
142   
143   (open(VPASSWD, "$exportdir/domains/$domain/vpasswd")
144     and flock(VPASSWD,LOCK_EX)
145   ) or die "can't open $exportdir/domains/$domain/vpasswd: $!";
146
147   open(VPASSWDTMP, ">$exportdir/domains/$domain/vpasswd.tmp")
148     or die "Can't open $exportdir/domains/$domain/vpasswd.tmp: $!";
149
150   while (<VPASSWD>) {
151     my ($mailbox, $rest) = split(':', $_);
152     print VPASSWDTMP $_ unless $username eq $mailbox;
153   }
154
155   close(VPASSWDTMP);
156
157   rename "$exportdir/domains/$domain/vpasswd.tmp",
158          "$exportdir/domains/$domain/vpasswd"
159     or die "Can't rename $exportdir/domains/$domain/vpasswd.tmp: $!";
160
161   flock(VPASSWD,LOCK_UN);
162   close(VPASSWD);
163
164   rmtree "$exportdir/domains/$domain/$username"
165     or die "can't rmtree $exportdir/domains/$domain/$username: $!";
166
167   vpopmail_sync( $exportdir, $machine, $dir, $uid, $gid );
168 }
169
170 sub vpopmail_sync {
171   my( $exportdir, $machine, $dir, $uid, $gid ) = splice @_,0,5;
172   
173   chdir $exportdir;
174   my @args = ( $rsync, "-rlpt", "-e", $ssh, "domains/",
175                "vpopmail\@$machine:$dir/domains/"  );
176   system {$args[0]} @args;
177 }
178
179