merging vpopmail support branch
[freeside.git] / bin / fs-migrate-svc_acct_sm
diff --git a/bin/fs-migrate-svc_acct_sm b/bin/fs-migrate-svc_acct_sm
new file mode 100755 (executable)
index 0000000..d0d4a94
--- /dev/null
@@ -0,0 +1,242 @@
+#!/usr/bin/perl -Tw
+#
+# $Id: fs-migrate-svc_acct_sm,v 1.2 2001-08-12 19:41:25 jeff Exp $
+#
+# jeff@cmh.net 01-Jul-20
+#
+# $Log: fs-migrate-svc_acct_sm,v $
+# Revision 1.2  2001-08-12 19:41:25  jeff
+# merging vpopmail support branch
+#
+# Revision 1.1.2.1  2001/08/08 17:45:35  jeff
+# initial vpopmail support
+#
+#
+#
+#   Initial vpopmail changes
+#
+
+#to delay loading dbdef until we're ready
+#BEGIN { $FS::Record::setup_hack = 1; }
+
+use strict;
+use Term::Query qw(query);
+#use DBI;
+#use DBIx::DBSchema;
+#use DBIx::DBSchema::Table;
+#use DBIx::DBSchema::Column;
+#use DBIx::DBSchema::ColGroup::Unique;
+#use DBIx::DBSchema::ColGroup::Index;
+use FS::Conf;
+use FS::UID qw(adminsuidsetup datasrc checkeuid getsecrets);
+use FS::Record qw(qsearch qsearchs);
+use FS::svc_domain;
+use FS::svc_forward;
+use vars qw( $conf $old_default_domain %part_domain_svc %part_acct_svc %part_forward_svc $svc_acct $svc_acct_sm $error);
+
+die "Not running uid freeside!" unless checkeuid();
+
+my $user = shift or die &usage;
+getsecrets($user);
+
+$conf = new FS::Conf;
+$old_default_domain = $conf->config('domain');
+
+#needs to match FS::Record
+#my($dbdef_file) = "/usr/local/etc/freeside/dbdef.". datasrc;
+
+###
+# This section would be the appropriate place to manipulate
+# the schema & tables.
+###
+
+##  we need to add the domsvc to svc_acct
+##  we must add a svc_forward record....
+##  I am thinking that the fields  svcnum (int), destsvc (int), and
+##  dest (varchar (80))  are appropriate, with destsvc/dest an either/or
+##  much in the spirit of cust_main_invoice
+
+###
+# massage the data
+###
+
+my($dbh)=adminsuidsetup $user;
+
+$|=1;
+
+$FS::svc_acct::nossh_hack = 1;
+$FS::svc_forward::nossh_hack = 1;
+$FS::svc_domain::whois_hack = 1;
+
+%part_domain_svc=map { $_->svcpart, $_ } qsearch('part_svc',{'svcdb'=>'svc_domain'});
+%part_acct_svc=map { $_->svcpart, $_ } qsearch('part_svc',{'svcdb'=>'svc_acct'});
+%part_forward_svc=map { $_->svcpart, $_ } qsearch('part_svc',{'svcdb'=>'svc_forward'});
+
+die "No services with svcdb svc_domain!\n" unless %part_domain_svc;
+die "No services with svcdb svc_acct!\n" unless %part_acct_svc;
+die "No services with svcdb svc_forward!\n" unless %part_forward_svc;
+
+my($svc_domain) = qsearchs('svc_domain', { 'domain' => $old_default_domain });
+if (! $svc_domain || $svc_domain->domain != $old_default_domain) {
+   print <<EOF;
+
+Your database currently does not contain a svc_domain record for the
+domain $old_default_domain.  Would you like me to add one for you?
+EOF
+
+   my($response)=scalar(<STDIN>);
+   chop $response;
+   if ($response =~ /^[yY]/) {
+      print "\n\n", &menu_domain_svc, "\n", <<END;
+I need to create new domain accounts.  Which service shall I use for that?
+END
+      my($domain_svcpart)=&getdomainpart;
+
+      $svc_domain = new FS::svc_domain {
+        'domain' => $old_default_domain,
+        'svcpart' => $domain_svcpart,
+        'action' => 'M',
+       };
+#      $error=$svc_domain->insert && die "Error adding domain $old_default_domain: $error";
+      $error=$svc_domain->insert;
+      die "Error adding domain $old_default_domain: $error" if $error;
+   }else{
+      print <<EOF;
+
+  This program cannot function properly until a svc_domain record matching
+your conf_dir/domain file exists.
+EOF
+
+      exit 1;
+   }
+}
+
+print "\n\n", &menu_acct_svc, "\n", <<END;
+I may need to create some new pop accounts and set up forwarding to them
+for some users.  Which service shall I use for that?
+END
+my($pop_svcpart)=&getacctpart;
+
+print "\n\n", &menu_forward_svc, "\n", <<END;
+I may need to create some new forwarding for some users.  Which service
+shall I use for that?
+END
+my($forward_svcpart)=&getforwardpart;
+
+sub menu_domain_svc {
+  ( join "\n", map "$_: ".$part_domain_svc{$_}->svc, sort keys %part_domain_svc ). "\n";
+}
+sub menu_acct_svc {
+  ( join "\n", map "$_: ".$part_acct_svc{$_}->svc, sort keys %part_acct_svc ). "\n";
+}
+sub menu_forward_svc {
+  ( join "\n", map "$_: ".$part_forward_svc{$_}->svc, sort keys %part_forward_svc ). "\n";
+}
+sub getdomainpart {
+  $^W=0; # Term::Query isn't -w-safe
+  my $return = query "Enter part number:", 'irk', [ keys %part_domain_svc ];
+  $^W=1;
+  $return;
+}
+sub getacctpart {
+  $^W=0; # Term::Query isn't -w-safe
+  my $return = query "Enter part number:", 'irk', [ keys %part_acct_svc ];
+  $^W=1;
+  $return;
+}
+sub getforwardpart {
+  $^W=0; # Term::Query isn't -w-safe
+  my $return = query "Enter part number:", 'irk', [ keys %part_forward_svc ];
+  $^W=1;
+  $return;
+}
+
+
+#migrate data
+
+my(@svc_accts) = qsearch('svc_acct', {});
+foreach $svc_acct (@svc_accts) {
+  my(@svc_acct_sms) = qsearch('svc_acct_sm', {
+      domuid => $svc_acct->getfield('uid'),
+      }
+    );
+
+  #  Ok.. we've got the svc_acct record, and an array of svc_acct_sm's
+  #  What do we do from here?
+
+  #  The intuitive:
+  #    plop the svc_acct into the 'default domain'
+  #    and then represent the svc_acct_sm's with svc_forwards
+  #    they can be gussied up manually, later
+  #
+  #  Perhaps better:
+  #    when no svc_acct_sm exists, place svc_acct in 'default domain'
+  #    when one svc_acct_sm exists, place svc_acct in corresponding
+  #      domain & possibly create a svc_forward in 'default domain'
+  #    when multiple svc_acct_sm's exists (in different domains) we'd
+  #    better use the 'intuitive' approach.
+  #
+  #  Specific way:
+  #    as 'perhaps better,' but we may be able to guess which domain
+  #    is correct by comparing the svcnum of domains to the username
+  #    of the svc_acct
+  #
+
+  # The intuitive way:
+
+  my $def_acct = new FS::svc_acct ( { $svc_acct->hash } );
+  $def_acct->setfield('domsvc' => $svc_domain->getfield('svcnum'));
+  $error = $def_acct->replace($svc_acct);
+  die "Error replacing svc_acct for " . $def_acct->username . " : $error" if $error;
+
+  foreach $svc_acct_sm (@svc_acct_sms) {
+
+    my($domrec)=qsearchs('svc_domain', {
+      svcnum => $svc_acct_sm->getfield('domsvc'),
+    }) || die  "svc_acct_sm references invalid domsvc $svc_acct_sm->getfield('domsvc')\n";
+
+    if ($svc_acct_sm->getfield('domuser') =~ /^\*$/) {
+      
+      my($newdom) = new FS::svc_domain ( { $domrec->hash } );
+      $newdom->setfield('catchall', $svc_acct->svcnum);
+      $newdom->setfield('action', "M");
+      $error = $newdom->replace($domrec);
+      die "Error replacing svc_domain for (anything)@" . $domrec->domain . " : $error" if $error;
+
+    } else {
+
+      my($newacct) = new FS::svc_acct {
+        'svcpart'  => $pop_svcpart,
+        'username' => $svc_acct_sm->getfield('domuser'),
+        'domsvc'   => $svc_acct_sm->getfield('domsvc'),
+        'dir'      => '/dev/null',
+      };
+      $error = $newacct->insert;
+      die "Error adding svc_acct for " . $newacct->username . " : $error" if $error;
+     
+      my($newforward) = new FS::svc_forward {
+        'svcpart'  => $forward_svcpart, 
+        'srcsvc'   => $newacct->getfield('svcnum'),
+        'dstsvc'   => $def_acct->getfield('svcnum'),
+      };
+      $error = $newforward->insert;
+      die "Error adding svc_forward for " . $newacct->username ." : $error" if $error;
+    }
+     
+    $error = $svc_acct_sm->delete;
+    die "Error deleting svc_acct_sm for " . $svc_acct_sm->domuser ." : $error" if $error;
+
+  };
+
+};
+
+
+$dbh->commit or die $dbh->errstr;
+$dbh->disconnect or die $dbh->errstr;
+
+print "svc_acct_sm records sucessfully migrated\n";
+
+sub usage {
+  die "Usage:\n  fs-migrate-svc_acct_sm user\n"; 
+}
+