initial vpopmail support
[freeside.git] / bin / fs-migrate-svc_acct_sm
1 #!/usr/bin/perl -Tw
2 #
3 # $Id: fs-migrate-svc_acct_sm,v 1.1.2.1 2001-08-08 17:45:35 jeff Exp $
4 #
5 # jeff@cmh.net 01-Jul-20
6 #
7 # $Log: fs-migrate-svc_acct_sm,v $
8 # Revision 1.1.2.1  2001-08-08 17:45:35  jeff
9 # initial vpopmail support
10 #
11 #
12 #
13 #   Initial vpopmail changes
14 #
15
16 #to delay loading dbdef until we're ready
17 #BEGIN { $FS::Record::setup_hack = 1; }
18
19 use strict;
20 use Term::Query qw(query);
21 #use DBI;
22 #use DBIx::DBSchema;
23 #use DBIx::DBSchema::Table;
24 #use DBIx::DBSchema::Column;
25 #use DBIx::DBSchema::ColGroup::Unique;
26 #use DBIx::DBSchema::ColGroup::Index;
27 use FS::Conf;
28 use FS::UID qw(adminsuidsetup datasrc checkeuid getsecrets);
29 use FS::Record qw(qsearch qsearchs);
30 use FS::svc_domain;
31 use FS::svc_forward;
32 use vars qw( $conf $old_default_domain %part_domain_svc %part_acct_svc %part_forward_svc $svc_acct $svc_acct_sm $error);
33
34 die "Not running uid freeside!" unless checkeuid();
35
36 my $user = shift or die &usage;
37 getsecrets($user);
38
39 $conf = new FS::Conf;
40 $old_default_domain = $conf->config('domain');
41
42 #needs to match FS::Record
43 #my($dbdef_file) = "/usr/local/etc/freeside/dbdef.". datasrc;
44
45 ###
46 # This section would be the appropriate place to manipulate
47 # the schema & tables.
48 ###
49
50 ##  we need to add the domsvc to svc_acct
51 ##  we must add a svc_forward record....
52 ##  I am thinking that the fields  svcnum (int), destsvc (int), and
53 ##  dest (varchar (80))  are appropriate, with destsvc/dest an either/or
54 ##  much in the spirit of cust_main_invoice
55
56 ###
57 # massage the data
58 ###
59
60 my($dbh)=adminsuidsetup $user;
61
62 $|=1;
63
64 $FS::svc_acct::nossh_hack = 1;
65 $FS::svc_forward::nossh_hack = 1;
66 $FS::svc_domain::whois_hack = 1;
67
68 %part_domain_svc=map { $_->svcpart, $_ } qsearch('part_svc',{'svcdb'=>'svc_domain'});
69 %part_acct_svc=map { $_->svcpart, $_ } qsearch('part_svc',{'svcdb'=>'svc_acct'});
70 %part_forward_svc=map { $_->svcpart, $_ } qsearch('part_svc',{'svcdb'=>'svc_forward'});
71
72 die "No services with svcdb svc_domain!\n" unless %part_domain_svc;
73 die "No services with svcdb svc_acct!\n" unless %part_acct_svc;
74 die "No services with svcdb svc_forward!\n" unless %part_forward_svc;
75
76 my($svc_domain) = qsearchs('svc_domain', { 'domain' => $old_default_domain });
77 if (! $svc_domain || $svc_domain->domain != $old_default_domain) {
78    print <<EOF;
79
80 Your database currently does not contain a svc_domain record for the
81 domain $old_default_domain.  Would you like me to add one for you?
82 EOF
83
84    my($response)=scalar(<STDIN>);
85    chop $response;
86    if ($response =~ /^[yY]/) {
87       print "\n\n", &menu_domain_svc, "\n", <<END;
88 I need to create new domain accounts.  Which service shall I use for that?
89 END
90       my($domain_svcpart)=&getdomainpart;
91
92       $svc_domain = new FS::svc_domain {
93         'domain' => $old_default_domain,
94         'svcpart' => $domain_svcpart,
95         'action' => 'M',
96        };
97 #      $error=$svc_domain->insert && die "Error adding domain $old_default_domain: $error";
98       $error=$svc_domain->insert;
99       die "Error adding domain $old_default_domain: $error" if $error;
100    }else{
101       print <<EOF;
102
103   This program cannot function properly until a svc_domain record matching
104 your conf_dir/domain file exists.
105 EOF
106
107       exit 1;
108    }
109 }
110
111 print "\n\n", &menu_acct_svc, "\n", <<END;
112 I may need to create some new pop accounts and set up forwarding to them
113 for some users.  Which service shall I use for that?
114 END
115 my($pop_svcpart)=&getacctpart;
116
117 print "\n\n", &menu_forward_svc, "\n", <<END;
118 I may need to create some new forwarding for some users.  Which service
119 shall I use for that?
120 END
121 my($forward_svcpart)=&getforwardpart;
122
123 sub menu_domain_svc {
124   ( join "\n", map "$_: ".$part_domain_svc{$_}->svc, sort keys %part_domain_svc ). "\n";
125 }
126 sub menu_acct_svc {
127   ( join "\n", map "$_: ".$part_acct_svc{$_}->svc, sort keys %part_acct_svc ). "\n";
128 }
129 sub menu_forward_svc {
130   ( join "\n", map "$_: ".$part_forward_svc{$_}->svc, sort keys %part_forward_svc ). "\n";
131 }
132 sub getdomainpart {
133   $^W=0; # Term::Query isn't -w-safe
134   my $return = query "Enter part number:", 'irk', [ keys %part_domain_svc ];
135   $^W=1;
136   $return;
137 }
138 sub getacctpart {
139   $^W=0; # Term::Query isn't -w-safe
140   my $return = query "Enter part number:", 'irk', [ keys %part_acct_svc ];
141   $^W=1;
142   $return;
143 }
144 sub getforwardpart {
145   $^W=0; # Term::Query isn't -w-safe
146   my $return = query "Enter part number:", 'irk', [ keys %part_forward_svc ];
147   $^W=1;
148   $return;
149 }
150
151
152 #migrate data
153
154 my(@svc_accts) = qsearch('svc_acct', {});
155 foreach $svc_acct (@svc_accts) {
156   my(@svc_acct_sms) = qsearch('svc_acct_sm', {
157       domuid => $svc_acct->getfield('uid'),
158       }
159     );
160
161   #  Ok.. we've got the svc_acct record, and an array of svc_acct_sm's
162   #  What do we do from here?
163
164   #  The intuitive:
165   #    plop the svc_acct into the 'default domain'
166   #    and then represent the svc_acct_sm's with svc_forwards
167   #    they can be gussied up manually, later
168   #
169   #  Perhaps better:
170   #    when no svc_acct_sm exists, place svc_acct in 'default domain'
171   #    when one svc_acct_sm exists, place svc_acct in corresponding
172   #      domain & possibly create a svc_forward in 'default domain'
173   #    when multiple svc_acct_sm's exists (in different domains) we'd
174   #    better use the 'intuitive' approach.
175   #
176   #  Specific way:
177   #    as 'perhaps better,' but we may be able to guess which domain
178   #    is correct by comparing the svcnum of domains to the username
179   #    of the svc_acct
180   #
181
182   # The intuitive way:
183
184   my $def_acct = new FS::svc_acct ( { $svc_acct->hash } );
185   $def_acct->setfield('domsvc' => $svc_domain->getfield('svcnum'));
186   $error = $def_acct->replace($svc_acct);
187   die "Error replacing svc_acct for " . $def_acct->username . " : $error" if $error;
188
189   foreach $svc_acct_sm (@svc_acct_sms) {
190
191     my($domrec)=qsearchs('svc_domain', {
192       svcnum => $svc_acct_sm->getfield('domsvc'),
193     }) || die  "svc_acct_sm references invalid domsvc $svc_acct_sm->getfield('domsvc')\n";
194
195     if ($svc_acct_sm->getfield('domuser') =~ /^\*$/) {
196       
197       my($newdom) = new FS::svc_domain ( { $domrec->hash } );
198       $newdom->setfield('catchall', $svc_acct->svcnum);
199       $newdom->setfield('action', "M");
200       $error = $newdom->replace($domrec);
201       die "Error replacing svc_domain for (anything)@" . $domrec->domain . " : $error" if $error;
202
203     } else {
204
205       my($newacct) = new FS::svc_acct {
206         'svcpart'  => $pop_svcpart,
207         'username' => $svc_acct_sm->getfield('domuser'),
208         'domsvc'   => $svc_acct_sm->getfield('domsvc'),
209         'dir'      => '/dev/null',
210       };
211       $error = $newacct->insert;
212       die "Error adding svc_acct for " . $newacct->username . " : $error" if $error;
213      
214       my($newforward) = new FS::svc_forward {
215         'svcpart'  => $forward_svcpart, 
216         'srcsvc'   => $newacct->getfield('svcnum'),
217         'dstsvc'   => $def_acct->getfield('svcnum'),
218       };
219       $error = $newforward->insert;
220       die "Error adding svc_forward for " . $newacct->username ." : $error" if $error;
221     }
222      
223     $error = $svc_acct_sm->delete;
224     die "Error deleting svc_acct_sm for " . $svc_acct_sm->domuser ." : $error" if $error;
225
226   };
227
228 };
229
230
231 $dbh->commit or die $dbh->errstr;
232 $dbh->disconnect or die $dbh->errstr;
233
234 print "svc_acct_sm records sucessfully migrated\n";
235
236 sub usage {
237   die "Usage:\n  fs-migrate-svc_acct_sm user\n"; 
238 }
239