1 package FS::part_export::acct_sql;
3 use vars qw(@ISA %info @saltset);
5 #use Digest::MD5 qw(md5_hex);
6 use FS::Record; #qw(qsearchs);
9 @ISA = qw(FS::part_export);
11 tie my %options, 'Tie::IxHash',
12 'datasrc' => { label => 'DBI data source' },
13 'username' => { label => 'Database username' },
14 'password' => { label => 'Database password' },
19 'desc' => 'Real-time export of accounts to SQL databases '.
20 '(Postfix+Courier IMAP, others?)',
21 'options' => \%options,
24 Export accounts (svc_acct records) to SQL databases. Written for
25 Postfix+Courier IMAP but intended to be generally useful for generic SQL
28 In contrast to sqlmail, this is newer and less well tested, and currently less
29 flexible. It is intended to export just svc_acct records only, rather than a
30 single export for svc_acct, svc_forward and svc_domain records, and to
31 be configured for different mail server setups through some subclassing
36 @saltset = ( 'a'..'z' , 'A'..'Z' , '0'..'9' , '.' , '/' );
38 #mapping needs to be configurable...
39 # export col => freeside col/method or callback
41 'username' => 'email',
42 'password' => '_password',
45 #false laziness w/shellcommands.pm
46 #eventually should check a "password-encoding" field
47 if ( length($svc_acct->_password) == 13
48 || $svc_acct->_password =~ /^\$(1|2a?)\$/ ) {
53 $saltset[int(rand(64))].$saltset[int(rand(64))]
59 'maildir' => sub { $_[0]->domain. '/maildirs/'. $_[0]->username. '/' },
60 'domain' => sub { shift->domain },
64 my $table = 'mailbox'; #also needs to be configurable...
66 my $primary_key = 'username';
68 sub rebless { shift; }
71 my($self, $svc_acct) = (shift, shift);
74 my %record = map { my $value = $map{$_};
76 ? &{$value}($svc_acct)
82 $self->acct_sql_queue( $svc_acct->svcnum, 'insert', $table, %record );
83 return $err_or_queue unless ref($err_or_queue);
93 my ( $self, $svc_acct ) = (shift, shift);
94 my $keymap = $map{$primary_key};
95 my $err_or_queue = $self->acct_sql_queue(
99 $primary_key => ref($keymap) ? &{$keymap}($svc_acct) : $svc_acct->$keymap()
104 my( $self, $svcnum, $method ) = (shift, shift, shift);
105 my $queue = new FS::queue {
107 'job' => "FS::part_export::acct_sql::acct_sql_$method",
110 $self->option('datasrc'),
111 $self->option('username'),
112 $self->option('password'),
117 sub acct_sql_insert { #subroutine, not method
118 my $dbh = acct_sql_connect(shift, shift, shift);
119 my( $table, %record ) = @_;
121 my $sth = $dbh->prepare(
122 "INSERT INTO $table ( ". join(", ", keys %record).
123 " ) VALUES ( ". join(", ", map '?', keys %record ). " )"
124 ) or die $dbh->errstr;
126 $sth->execute( map $record{$_}, keys %record )
127 or die "can't insert into $table table: ". $sth->errstr;
132 sub acct_sql_delete { #subroutine, not method
133 my $dbh = acct_sql_connect(shift, shift, shift);
134 my( $table, %record ) = @_;
136 my $sth = $dbh->prepare(
137 "DELETE FROM $table WHERE ". join(' AND ', map "$_ = ? ", keys %record )
138 ) or die $dbh->errstr;
140 $sth->execute( map $record{$_}, keys %record )
141 or die "can't delete from $table table: ". $sth->errstr;
146 sub acct_sql_connect {
147 #my($datasrc, $username, $password) = @_;
148 #DBI->connect($datasrc, $username, $password) or die $DBI::errstr;
149 DBI->connect(@_) or die $DBI::errstr;