Merge branch 'dpt_trans_entfernen'
[kivitendo-erp.git] / SL / User.pm
index a034e03..368a0a2 100644 (file)
 
 package User;
 
 
 package User;
 
-sub new {
-  $main::lxdebug->enter_sub();
-
-  my ($type, $memfile, $login) = @_;
-  my $self = {};
-
-  if ($login ne "") {
-    &error("", "$memfile locked!") if (-f "${memfile}.LCK");
-
-    open(MEMBER, "$memfile") or &error("", "$memfile : $!");
-
-    while (<MEMBER>) {
-      if (/^\[$login\]/) {
-        while (<MEMBER>) {
-          last if /^\[/;
-          next if /^(#|\s)/;
+use IO::File;
+use Fcntl qw(:seek);
 
 
-          # remove comments
-          s/\s#.*//g;
+#use SL::Auth;
+use SL::DBConnect;
+use SL::DBUpgrade2;
+use SL::DBUtils;
+use SL::Iconv;
+use SL::Inifile;
 
 
-          # remove any trailing whitespace
-          s/^\s*(.*?)\s*$/$1/;
+use strict;
 
 
-          ($key, $value) = split /=/, $_, 2;
-
-          if (($key eq "stylesheet") && ($value eq "sql-ledger.css")) {
-            $value = "lx-office-erp.css";
-          }
+sub new {
+  $main::lxdebug->enter_sub();
 
 
-          $self->{$key} = $value;
-        }
+  my ($type, %params) = @_;
 
 
-        $self->{login} = $login;
+  my $self = {};
 
 
-        last;
-      }
-    }
-    close MEMBER;
+  if ($params{id} || $params{login}) {
+    my %user_data = $main::auth->read_user(%params);
+    map { $self->{$_} = $user_data{$_} } keys %user_data;
   }
 
   $main::lxdebug->leave_sub();
   }
 
   $main::lxdebug->leave_sub();
+
   bless $self, $type;
 }
 
 sub country_codes {
   $main::lxdebug->enter_sub();
 
   bless $self, $type;
 }
 
 sub country_codes {
   $main::lxdebug->enter_sub();
 
+  local *DIR;
+
   my %cc       = ();
   my @language = ();
 
   # scan the locale directory and read in the LANGUAGE files
   my %cc       = ();
   my @language = ();
 
   # scan the locale directory and read in the LANGUAGE files
-  opendir DIR, "locale";
+  opendir(DIR, "locale");
 
 
-  my @dir = grep !/(^\.\.?$|\..*)/, readdir DIR;
+  my @dir = grep(!/(^\.\.?$|\..*)/, readdir(DIR));
 
   foreach my $dir (@dir) {
 
   foreach my $dir (@dir) {
-    next unless open(FH, "locale/$dir/LANGUAGE");
-    @language = <FH>;
-    close FH;
+    next unless open(my $fh, '<:encoding(UTF-8)', "locale/$dir/LANGUAGE");
+    @language = <$fh>;
+    close $fh;
 
     $cc{$dir} = "@language";
   }
 
     $cc{$dir} = "@language";
   }
@@ -107,33 +94,19 @@ sub country_codes {
 sub login {
   $main::lxdebug->enter_sub();
 
 sub login {
   $main::lxdebug->enter_sub();
 
-  my ($self, $form, $userspath) = @_;
+  my ($self, $form) = @_;
+  our $sid;
+
+  local *FH;
 
   my $rc = -3;
 
   if ($self->{login}) {
 
   my $rc = -3;
 
   if ($self->{login}) {
-
-    if ($self->{password}) {
-      $form->{password} = crypt $form->{password},
-        substr($self->{login}, 0, 2);
-      if ($self->{password} ne $form->{password}) {
-        $main::lxdebug->leave_sub();
-        return -1;
-      }
-    }
-
-    unless (-e "$userspath/$self->{login}.conf") {
-      $self->create_config("$userspath/$self->{login}.conf");
-    }
-
-    do "$userspath/$self->{login}.conf";
-    $myconfig{dbpasswd} = unpack 'u', $myconfig{dbpasswd};
+    my %myconfig = $main::auth->read_user(login => $self->{login});
 
     # check if database is down
 
     # check if database is down
-    my $dbh =
-      DBI->connect($myconfig{dbconnect}, $myconfig{dbuser},
-                   $myconfig{dbpasswd})
-      or $self->error(DBI::errstr);
+    my $dbh = SL::DBConnect->connect($myconfig{dbconnect}, $myconfig{dbuser}, $myconfig{dbpasswd})
+      or $self->error($DBI::errstr);
 
     # we got a connection, check the version
     my $query = qq|SELECT version FROM defaults|;
 
     # we got a connection, check the version
     my $query = qq|SELECT version FROM defaults|;
@@ -143,38 +116,45 @@ sub login {
     my ($dbversion) = $sth->fetchrow_array;
     $sth->finish;
 
     my ($dbversion) = $sth->fetchrow_array;
     $sth->finish;
 
-    # add login to employee table if it does not exist
-    # no error check for employee table, ignore if it does not exist
-    $query = qq|SELECT e.id FROM employee e WHERE e.login = '$self->{login}'|;
-    $sth   = $dbh->prepare($query);
-    $sth->execute;
+    $self->create_employee_entry($form, $dbh, \%myconfig);
 
 
-    my ($login) = $sth->fetchrow_array;
-    $sth->finish;
+    $self->create_schema_info_table($form, $dbh);
 
 
-    if (!$login) {
-      $query = qq|INSERT INTO employee (login, name, workphone, role)
-                  VALUES ('$self->{login}', '$myconfig{name}',
-                 '$myconfig{tel}', 'user')|;
-      $dbh->do($query);
+    my $dbupdater_auth = SL::DBUpgrade2->new(form => $form, dbdriver => 'Pg', auth => 1)->parse_dbupdate_controls;
+    if ($dbupdater_auth->unapplied_upgrade_scripts($::auth->dbconnect)) {
+      $::lxdebug->leave_sub;
+      return -3;
     }
     }
-    $dbh->disconnect;
 
     $rc = 0;
 
 
     $rc = 0;
 
-    if ($form->{dbversion} ne $dbversion) {
+    my $dbupdater = SL::DBUpgrade2->new(form => $form, dbdriver => $myconfig{dbdriver})->parse_dbupdate_controls;
 
 
-      # update the tables
-      open FH, ">$userspath/nologin" or die "
-$!";
+    map({ $form->{$_} = $myconfig{$_} } qw(dbname dbhost dbport dbdriver dbuser dbpasswd dbconnect dateformat));
+    dbconnect_vars($form, $form->{dbname});
+    my $update_available = $dbupdater->update_available($dbversion) || $dbupdater->update2_available($dbh);
+    $dbh->disconnect;
 
 
-      map { $form->{$_} = $myconfig{$_} }
-        qw(dbname dbhost dbport dbdriver dbuser dbpasswd);
+    if ($update_available) {
+      $form->{"title"} = $main::locale->text("Dataset upgrade");
+      $form->header();
+      print $form->parse_html_template("dbupgrade/header");
 
       $form->{dbupdate} = "db$myconfig{dbname}";
       $form->{ $form->{dbupdate} } = 1;
 
 
       $form->{dbupdate} = "db$myconfig{dbname}";
       $form->{ $form->{dbupdate} } = 1;
 
-      $form->info("Upgrading Dataset $myconfig{dbname} ...");
+      if ($form->{"show_dbupdate_warning"}) {
+        print $form->parse_html_template("dbupgrade/warning");
+        ::end_of_request();
+      }
+
+      # update the tables
+      if (!$::lx_office_conf{debug}->{keep_installation_unlocked} && !open(FH, ">", $::lx_office_conf{paths}->{userspath} . "/nologin")) {
+        $form->show_generic_error($main::locale->text('A temporary file could not be created. ' .
+                                                      'Please verify that the directory "#1" is writeable by the webserver.',
+                                                      $::lx_office_conf{paths}->{userspath}),
+                                  'back_button' => 1);
+      }
 
       # required for Oracle
       $form->{dbdefault} = $sid;
 
       # required for Oracle
       $form->{dbdefault} = $sid;
@@ -184,14 +164,17 @@ $!";
       $SIG{QUIT} = 'IGNORE';
 
       $self->dbupdate($form);
       $SIG{QUIT} = 'IGNORE';
 
       $self->dbupdate($form);
+      $self->dbupdate2($form, $dbupdater);
+      SL::DBUpgrade2->new(form => $::form, dbdriver => 'Pg', auth => 1)->apply_admin_dbupgrade_scripts(0);
+
+      close(FH);
 
       # remove lock file
 
       # remove lock file
-      unlink "$userspath/nologin";
+      unlink($::lx_office_conf{paths}->{userspath} . "/nologin");
 
 
-      $form->info("... done");
+      print $form->parse_html_template("dbupgrade/footer");
 
       $rc = -2;
 
       $rc = -2;
-
     }
   }
 
     }
   }
 
@@ -209,18 +192,14 @@ sub dbconnect_vars {
         'Pg' => { 'yy-mm-dd'   => 'set DateStyle to \'ISO\'',
                   'yyyy-mm-dd' => 'set DateStyle to \'ISO\'',
                   'mm/dd/yy'   => 'set DateStyle to \'SQL, US\'',
         'Pg' => { 'yy-mm-dd'   => 'set DateStyle to \'ISO\'',
                   'yyyy-mm-dd' => 'set DateStyle to \'ISO\'',
                   'mm/dd/yy'   => 'set DateStyle to \'SQL, US\'',
-                  'mm-dd-yy'   => 'set DateStyle to \'POSTGRES, US\'',
                   'dd/mm/yy'   => 'set DateStyle to \'SQL, EUROPEAN\'',
                   'dd/mm/yy'   => 'set DateStyle to \'SQL, EUROPEAN\'',
-                  'dd-mm-yy'   => 'set DateStyle to \'POSTGRES, EUROPEAN\'',
                   'dd.mm.yy'   => 'set DateStyle to \'GERMAN\''
         },
         'Oracle' => {
           'yy-mm-dd'   => 'ALTER SESSION SET NLS_DATE_FORMAT = \'YY-MM-DD\'',
           'yyyy-mm-dd' => 'ALTER SESSION SET NLS_DATE_FORMAT = \'YYYY-MM-DD\'',
           'mm/dd/yy'   => 'ALTER SESSION SET NLS_DATE_FORMAT = \'MM/DD/YY\'',
                   'dd.mm.yy'   => 'set DateStyle to \'GERMAN\''
         },
         'Oracle' => {
           'yy-mm-dd'   => 'ALTER SESSION SET NLS_DATE_FORMAT = \'YY-MM-DD\'',
           'yyyy-mm-dd' => 'ALTER SESSION SET NLS_DATE_FORMAT = \'YYYY-MM-DD\'',
           'mm/dd/yy'   => 'ALTER SESSION SET NLS_DATE_FORMAT = \'MM/DD/YY\'',
-          'mm-dd-yy'   => 'ALTER SESSION SET NLS_DATE_FORMAT = \'MM-DD-YY\'',
           'dd/mm/yy'   => 'ALTER SESSION SET NLS_DATE_FORMAT = \'DD/MM/YY\'',
           'dd/mm/yy'   => 'ALTER SESSION SET NLS_DATE_FORMAT = \'DD/MM/YY\'',
-          'dd-mm-yy'   => 'ALTER SESSION SET NLS_DATE_FORMAT = \'DD-MM-YY\'',
           'dd.mm.yy'   => 'ALTER SESSION SET NLS_DATE_FORMAT = \'DD.MM.YY\'',
         });
 
           'dd.mm.yy'   => 'ALTER SESSION SET NLS_DATE_FORMAT = \'DD.MM.YY\'',
         });
 
@@ -266,15 +245,15 @@ sub dbsources {
   $form->{sid} = $form->{dbdefault};
   &dbconnect_vars($form, $form->{dbdefault});
 
   $form->{sid} = $form->{dbdefault};
   &dbconnect_vars($form, $form->{dbdefault});
 
-  my $dbh =
-    DBI->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd})
+  my $dbh = SL::DBConnect->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd})
     or $form->dberror;
 
   if ($form->{dbdriver} eq 'Pg') {
     or $form->dberror;
 
   if ($form->{dbdriver} eq 'Pg') {
-
-    $query = qq|SELECT datname FROM pg_database|;
-    $sth   = $dbh->prepare($query);
-    $sth->execute || $form->dberror($query);
+    $query =
+      qq|SELECT datname FROM pg_database | .
+      qq|WHERE NOT datname IN ('template0', 'template1')|;
+    $sth = $dbh->prepare($query);
+    $sth->execute() || $form->dberror($query);
 
     while (my ($db) = $sth->fetchrow_array) {
 
 
     while (my ($db) = $sth->fetchrow_array) {
 
@@ -283,32 +262,32 @@ sub dbsources {
         next if ($db =~ /^template/);
 
         &dbconnect_vars($form, $db);
         next if ($db =~ /^template/);
 
         &dbconnect_vars($form, $db);
-        my $dbh =
-          DBI->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd})
+        my $dbh = SL::DBConnect->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd})
           or $form->dberror;
 
           or $form->dberror;
 
-        $query = qq|SELECT p.tablename FROM pg_tables p
-                   WHERE p.tablename = 'defaults'
-                   AND p.tableowner = '$form->{dbuser}'|;
+        $query =
+          qq|SELECT tablename FROM pg_tables | .
+          qq|WHERE (tablename = 'defaults') AND (tableowner = ?)|;
         my $sth = $dbh->prepare($query);
         my $sth = $dbh->prepare($query);
-        $sth->execute || $form->dberror($query);
+        $sth->execute($form->{dbuser}) ||
+          $form->dberror($query . " ($form->{dbuser})");
 
         if ($sth->fetchrow_array) {
 
         if ($sth->fetchrow_array) {
-          push @dbsources, $db;
+          push(@dbsources, $db);
         }
         $sth->finish;
         $dbh->disconnect;
         next;
       }
         }
         $sth->finish;
         $dbh->disconnect;
         next;
       }
-      push @dbsources, $db;
+      push(@dbsources, $db);
     }
   }
 
   if ($form->{dbdriver} eq 'Oracle') {
     if ($form->{only_acc_db}) {
     }
   }
 
   if ($form->{dbdriver} eq 'Oracle') {
     if ($form->{only_acc_db}) {
-      $query = qq|SELECT o.owner FROM dba_objects o
-                 WHERE o.object_name = 'DEFAULTS'
-                 AND o.object_type = 'TABLE'|;
+      $query =
+        qq|SELECT owner FROM dba_objects | .
+        qq|WHERE object_name = 'DEFAULTS' AND object_type = 'TABLE'|;
     } else {
       $query = qq|SELECT username FROM dba_users|;
     }
     } else {
       $query = qq|SELECT username FROM dba_users|;
     }
@@ -317,7 +296,7 @@ sub dbsources {
     $sth->execute || $form->dberror($query);
 
     while (my ($db) = $sth->fetchrow_array) {
     $sth->execute || $form->dberror($query);
 
     while (my ($db) = $sth->fetchrow_array) {
-      push @dbsources, $db;
+      push(@dbsources, $db);
     }
   }
 
     }
   }
 
@@ -329,30 +308,64 @@ sub dbsources {
   return @dbsources;
 }
 
   return @dbsources;
 }
 
+sub dbclusterencoding {
+  $main::lxdebug->enter_sub();
+
+  my ($self, $form) = @_;
+
+  $form->{dbdefault} ||= $form->{dbuser};
+
+  dbconnect_vars($form, $form->{dbdefault});
+
+  my $dbh                = SL::DBConnect->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd}) || $form->dberror();
+  my $query              = qq|SELECT pg_encoding_to_char(encoding) FROM pg_database WHERE datname = 'template0'|;
+  my ($cluster_encoding) = $dbh->selectrow_array($query);
+  $dbh->disconnect();
+
+  $main::lxdebug->leave_sub();
+
+  return $cluster_encoding;
+}
+
 sub dbcreate {
   $main::lxdebug->enter_sub();
 
   my ($self, $form) = @_;
 
 sub dbcreate {
   $main::lxdebug->enter_sub();
 
   my ($self, $form) = @_;
 
+  $form->{sid} = $form->{dbdefault};
+  &dbconnect_vars($form, $form->{dbdefault});
+  my $dbh =
+    SL::DBConnect->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd})
+    or $form->dberror;
+  $form->{db} =~ s/\"//g;
   my %dbcreate = (
     'Pg'     => qq|CREATE DATABASE "$form->{db}"|,
     'Oracle' =>
   my %dbcreate = (
     'Pg'     => qq|CREATE DATABASE "$form->{db}"|,
     'Oracle' =>
-      qq|CREATE USER "$form->{db}" DEFAULT TABLESPACE USERS TEMPORARY TABLESPACE TEMP IDENTIFIED BY "$form->{db}"|
+    qq|CREATE USER "$form->{db}" DEFAULT TABLESPACE USERS | .
+    qq|TEMPORARY TABLESPACE TEMP IDENTIFIED BY "$form->{db}"|
   );
 
   );
 
-  $dbcreate{Pg} .= " WITH ENCODING = '$form->{encoding}'" if $form->{encoding};
+  my %dboptions = (
+    'Pg' => [],
+  );
 
 
-  $form->{sid} = $form->{dbdefault};
-  &dbconnect_vars($form, $form->{dbdefault});
-  my $dbh =
-    DBI->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd})
-    or $form->dberror;
-  my $query = qq|$dbcreate{$form->{dbdriver}}|;
-  $dbh->do($query) || $form->dberror($query);
+  push(@{$dboptions{"Pg"}}, "ENCODING = " . $dbh->quote($form->{"encoding"}))
+    if ($form->{"encoding"});
+  if ($form->{"dbdefault"}) {
+    my $dbdefault = $form->{"dbdefault"};
+    $dbdefault =~ s/[^a-zA-Z0-9_\-]//g;
+    push(@{$dboptions{"Pg"}}, "TEMPLATE = $dbdefault");
+  }
+
+  my $query = $dbcreate{$form->{dbdriver}};
+  $query .= " WITH " . join(" ", @{$dboptions{"Pg"}}) if (@{$dboptions{"Pg"}});
+
+  # Ignore errors if the database exists.
+  $dbh->do($query);
 
   if ($form->{dbdriver} eq 'Oracle') {
 
   if ($form->{dbdriver} eq 'Oracle') {
-    $query = qq|GRANT CONNECT,RESOURCE TO "$form->{db}"|;
-    $dbh->do($query) || $form->dberror($query);
+    $query = qq|GRANT CONNECT, RESOURCE TO "$form->{db}"|;
+    do_query($form, $dbh, $query);
   }
   $dbh->disconnect;
 
   }
   $dbh->disconnect;
 
@@ -364,103 +377,47 @@ sub dbcreate {
 
   &dbconnect_vars($form, $form->{db});
 
 
   &dbconnect_vars($form, $form->{db});
 
-  $dbh = DBI->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd})
+  $dbh = SL::DBConnect->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd})
     or $form->dberror;
 
     or $form->dberror;
 
-  # create the tables
-  my $filename = qq|sql/lx-office.sql|;
-  $self->process_query($form, $dbh, $filename);
+  my $db_charset = $Common::db_encoding_to_charset{$form->{encoding}};
+  $db_charset ||= Common::DEFAULT_CHARSET;
 
 
-  # load gifi
-  ($filename) = split /_/, $form->{chart};
-  $filename =~ s/_//;
-  $self->process_query($form, $dbh, "sql/${filename}-gifi.sql");
+  my $dbupdater = SL::DBUpgrade2->new(form => $form, dbdriver => $form->{dbdriver});
+  # create the tables
+  $dbupdater->process_query($dbh, "sql/lx-office.sql", undef, $db_charset);
 
   # load chart of accounts
 
   # load chart of accounts
-  $filename = qq|sql/$form->{chart}-chart.sql|;
-  $self->process_query($form, $dbh, $filename);
+  $dbupdater->process_query($dbh, "sql/$form->{chart}-chart.sql", undef, $db_charset);
 
 
-  # create indices
-  # Indices sind auch in lx-office.sql
-  # $filename = qq|sql/$form->{dbdriver}-indices.sql|;
-  # $self->process_query($form, $dbh, $filename);
+  $query = "UPDATE defaults SET coa = ?";
+  do_query($form, $dbh, $query, $form->{chart});
+  $query = "UPDATE defaults SET accounting_method = ?";
+  do_query($form, $dbh, $query, $form->{accounting_method});
+  $query = "UPDATE defaults SET profit_determination = ?";
+  do_query($form, $dbh, $query, $form->{profit_determination});
+  $query = "UPDATE defaults SET inventory_system = ?";
+  do_query($form, $dbh, $query, $form->{inventory_system});
 
   $dbh->disconnect;
 
   $main::lxdebug->leave_sub();
 }
 
 
   $dbh->disconnect;
 
   $main::lxdebug->leave_sub();
 }
 
-sub process_query {
-  $main::lxdebug->enter_sub();
-
-  my ($self, $form, $dbh, $filename) = @_;
-
-  #  return unless (-f $filename);
-
-  open(FH, "$filename") or $form->error("$filename : $!\n");
-  my $query = "";
-  my $sth;
-  my @quote_chars;
-
-  while (<FH>) {
-
-    # Remove DOS and Unix style line endings.
-    s/[\r\n]//g;
-
-    # don't add comments or empty lines
-    next if /^(--.*|\s+)$/;
-
-    for (my $i = 0; $i < length($_); $i++) {
-      my $char = substr($_, $i, 1);
-
-      # Are we inside a string?
-      if (@quote_chars) {
-        if ($char eq $quote_chars[-1]) {
-          pop(@quote_chars);
-        }
-        $query .= $char;
-
-      } else {
-        if (($char eq "'") || ($char eq "\"")) {
-          push(@quote_chars, $char);
-
-        } elsif ($char eq ";") {
-
-          # Query is complete. Send it.
-
-          $sth = $dbh->prepare($query);
-          $sth->execute || $form->dberror($query);
-          $sth->finish;
-
-          $char  = "";
-          $query = "";
-        }
-
-        $query .= $char;
-      }
-    }
-  }
-
-  close FH;
-
-  $main::lxdebug->leave_sub();
-}
-
 sub dbdelete {
   $main::lxdebug->enter_sub();
 
   my ($self, $form) = @_;
 sub dbdelete {
   $main::lxdebug->enter_sub();
 
   my ($self, $form) = @_;
-
+  $form->{db} =~ s/\"//g;
   my %dbdelete = ('Pg'     => qq|DROP DATABASE "$form->{db}"|,
   my %dbdelete = ('Pg'     => qq|DROP DATABASE "$form->{db}"|,
-                  'Oracle' => qq|DROP USER $form->{db} CASCADE|);
+                  'Oracle' => qq|DROP USER "$form->{db}" CASCADE|);
 
   $form->{sid} = $form->{dbdefault};
   &dbconnect_vars($form, $form->{dbdefault});
 
   $form->{sid} = $form->{dbdefault};
   &dbconnect_vars($form, $form->{dbdefault});
-  my $dbh =
-    DBI->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd})
+  my $dbh = SL::DBConnect->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd})
     or $form->dberror;
     or $form->dberror;
-  my $query = qq|$dbdelete{$form->{dbdriver}}|;
-  $dbh->do($query) || $form->dberror($query);
+  my $query = $dbdelete{$form->{dbdriver}};
+  do_query($form, $dbh, $query);
 
   $dbh->disconnect;
 
 
   $dbh->disconnect;
 
@@ -470,39 +427,21 @@ sub dbdelete {
 sub dbsources_unused {
   $main::lxdebug->enter_sub();
 
 sub dbsources_unused {
   $main::lxdebug->enter_sub();
 
-  my ($self, $form, $memfile) = @_;
-
-  my @dbexcl    = ();
-  my @dbsources = ();
-
-  $form->error('File locked!') if (-f "${memfile}.LCK");
-
-  # open members file
-  open(FH, "$memfile") or $form->error("$memfile : $!");
-
-  while (<FH>) {
-    if (/^dbname=/) {
-      my ($null, $item) = split /=/;
-      push @dbexcl, $item;
-    }
-  }
-
-  close FH;
+  my ($self, $form) = @_;
 
   $form->{only_acc_db} = 1;
 
   $form->{only_acc_db} = 1;
-  my @db = &dbsources("", $form);
 
 
-  push @dbexcl, $form->{dbdefault};
+  my %members = $main::auth->read_all_users();
+  my %dbexcl  = map { $_ => 1 } grep { $_ } map { $_->{dbname} } values %members;
 
 
-  foreach $item (@db) {
-    unless (grep /$item$/, @dbexcl) {
-      push @dbsources, $item;
-    }
-  }
+  $dbexcl{$form->{dbdefault}}             = 1;
+  $dbexcl{$main::auth->{DB_config}->{db}} = 1;
+
+  my @dbunused = grep { !$dbexcl{$_} } dbsources("", $form);
 
   $main::lxdebug->leave_sub();
 
 
   $main::lxdebug->leave_sub();
 
-  return @dbsources;
+  return @dbunused;
 }
 
 sub dbneedsupdate {
 }
 
 sub dbneedsupdate {
@@ -510,95 +449,49 @@ sub dbneedsupdate {
 
   my ($self, $form) = @_;
 
 
   my ($self, $form) = @_;
 
-  my %dbsources = ();
-  my $query;
+  my %members   = $main::auth->read_all_users();
+  my $dbupdater = SL::DBUpgrade2->new(form => $form, dbdriver => $form->{dbdriver})->parse_dbupdate_controls;
 
 
-  $form->{sid} = $form->{dbdefault};
-  &dbconnect_vars($form, $form->{dbdefault});
+  my ($query, $sth, %dbs_needing_updates);
 
 
-  my $dbh =
-    DBI->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd})
-    or $form->dberror;
+  foreach my $login (grep /[a-z]/, keys %members) {
+    my $member = $members{$login};
 
 
-  if ($form->{dbdriver} eq 'Pg') {
+    map { $form->{$_} = $member->{$_} } qw(dbname dbuser dbpasswd dbhost dbport);
+    dbconnect_vars($form, $form->{dbname});
 
 
-    $query = qq|SELECT d.datname FROM pg_database d, pg_user u
-                WHERE d.datdba = u.usesysid
-               AND u.usename = '$form->{dbuser}'|;
-    my $sth = $dbh->prepare($query);
-    $sth->execute || $form->dberror($query);
+    my $dbh = SL::DBConnect->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd});
 
 
-    while (my ($db) = $sth->fetchrow_array) {
-
-      next if ($db =~ /^template/);
-
-      &dbconnect_vars($form, $db);
+    next unless $dbh;
 
 
-      my $dbh =
-        DBI->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd})
-        or $form->dberror;
-
-      $query = qq|SELECT t.tablename FROM pg_tables t
-                 WHERE t.tablename = 'defaults'|;
-      my $sth = $dbh->prepare($query);
-      $sth->execute || $form->dberror($query);
-
-      if ($sth->fetchrow_array) {
-        $query = qq|SELECT version FROM defaults|;
-        my $sth = $dbh->prepare($query);
-        $sth->execute;
+    my $version;
 
 
-        if (my ($version) = $sth->fetchrow_array) {
-          $dbsources{$db} = $version;
-        }
-        $sth->finish;
-      }
-      $sth->finish;
-      $dbh->disconnect;
+    $query = qq|SELECT version FROM defaults|;
+    $sth = prepare_query($form, $dbh, $query);
+    if ($sth->execute()) {
+      ($version) = $sth->fetchrow_array();
     }
     }
-    $sth->finish;
-  }
+    $sth->finish();
 
 
-  if ($form->{dbdriver} eq 'Oracle') {
-    $query = qq|SELECT o.owner FROM dba_objects o
-               WHERE o.object_name = 'DEFAULTS'
-               AND o.object_type = 'TABLE'|;
-
-    $sth = $dbh->prepare($query);
-    $sth->execute || $form->dberror($query);
-
-    while (my ($db) = $sth->fetchrow_array) {
+    $dbh->disconnect and next unless $version;
 
 
-      $form->{dbuser} = $db;
-      &dbconnect_vars($form, $db);
-
-      my $dbh =
-        DBI->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd})
-        or $form->dberror;
-
-      $query = qq|SELECT version FROM defaults|;
-      my $sth = $dbh->prepare($query);
-      $sth->execute;
+    my $update_available = $dbupdater->update_available($version) || $dbupdater->update2_available($dbh);
+    $dbh->disconnect;
 
 
-      if (my ($version) = $sth->fetchrow_array) {
-        $dbsources{$db} = $version;
-      }
-      $sth->finish;
-      $dbh->disconnect;
+   if ($update_available) {
+      my $dbinfo = {};
+      map { $dbinfo->{$_} = $member->{$_} } grep /^db/, keys %{ $member };
+      $dbs_needing_updates{$member->{dbhost} . "::" . $member->{dbname}} = $dbinfo;
     }
     }
-    $sth->finish;
   }
 
   }
 
-  $dbh->disconnect;
-
   $main::lxdebug->leave_sub();
 
   $main::lxdebug->leave_sub();
 
-  return %dbsources;
+  return values %dbs_needing_updates;
 }
 
 }
 
-## LINET
 sub calc_version {
 sub calc_version {
-  $main::lxdebug->enter_sub();
+  $main::lxdebug->enter_sub(2);
 
   my (@v, $version, $i);
 
 
   my (@v, $version, $i);
 
@@ -612,7 +505,7 @@ sub calc_version {
     $version += $v[$i];
   }
 
     $version += $v[$i];
   }
 
-  $main::lxdebug->leave_sub();
+  $main::lxdebug->leave_sub(2);
   return $version;
 }
 
   return $version;
 }
 
@@ -625,8 +518,8 @@ sub cmp_script_version {
   $my_a =~ s/.sql$//;
   $my_b =~ s/.*-upgrade-//;
   $my_b =~ s/.sql$//;
   $my_a =~ s/.sql$//;
   $my_b =~ s/.*-upgrade-//;
   $my_b =~ s/.sql$//;
-  ($my_a_from, $my_a_to) = split(/-/, $my_a);
-  ($my_b_from, $my_b_to) = split(/-/, $my_b);
+  my ($my_a_from, $my_a_to) = split(/-/, $my_a);
+  my ($my_b_from, $my_b_to) = split(/-/, $my_b);
 
   $res_a = calc_version($my_a_from);
   $res_b = calc_version($my_b_from);
 
   $res_a = calc_version($my_a_from);
   $res_b = calc_version($my_b_from);
@@ -638,13 +531,34 @@ sub cmp_script_version {
 
   return $res_a <=> $res_b;
 }
 
   return $res_a <=> $res_b;
 }
-## /LINET
+
+sub create_schema_info_table {
+  $main::lxdebug->enter_sub();
+
+  my ($self, $form, $dbh) = @_;
+
+  my $query = "SELECT tag FROM schema_info LIMIT 1";
+  if (!$dbh->do($query)) {
+    $dbh->rollback();
+    $query =
+      qq|CREATE TABLE schema_info (| .
+      qq|  tag text, | .
+      qq|  login text, | .
+      qq|  itime timestamp DEFAULT now(), | .
+      qq|  PRIMARY KEY (tag))|;
+    $dbh->do($query) || $form->dberror($query);
+  }
+
+  $main::lxdebug->leave_sub();
+}
 
 sub dbupdate {
   $main::lxdebug->enter_sub();
 
   my ($self, $form) = @_;
 
 
 sub dbupdate {
   $main::lxdebug->enter_sub();
 
   my ($self, $form) = @_;
 
+  local *SQLDIR;
+
   $form->{sid} = $form->{dbdefault};
 
   my @upgradescripts = ();
   $form->{sid} = $form->{dbdefault};
 
   my @upgradescripts = ();
@@ -654,16 +568,21 @@ sub dbupdate {
   if ($form->{dbupdate}) {
 
     # read update scripts into memory
   if ($form->{dbupdate}) {
 
     # read update scripts into memory
-    opendir SQLDIR, "sql/." or $form - error($!);
-    ## LINET
+    opendir(SQLDIR, "sql/" . $form->{dbdriver} . "-upgrade")
+      or &error("", "sql/" . $form->{dbdriver} . "-upgrade : $!");
     @upgradescripts =
       sort(cmp_script_version
     @upgradescripts =
       sort(cmp_script_version
-           grep(/$form->{dbdriver}-upgrade-.*?\.sql$/, readdir(SQLDIR)));
-    ## /LINET
-    closedir SQLDIR;
+           grep(/$form->{dbdriver}-upgrade-.*?\.(sql|pl)$/,
+                readdir(SQLDIR)));
+    closedir(SQLDIR);
   }
 
   }
 
-  foreach my $db (split / /, $form->{dbupdate}) {
+  my $db_charset = $::lx_office_conf{system}->{dbcharset};
+  $db_charset ||= Common::DEFAULT_CHARSET;
+
+  my $dbupdater = SL::DBUpgrade2->new(form => $form, dbdriver => $form->{dbdriver});
+
+  foreach my $db (split(/ /, $form->{dbupdate})) {
 
     next unless $form->{$db};
 
 
     next unless $form->{$db};
 
@@ -671,35 +590,27 @@ sub dbupdate {
     $db =~ s/^db//;
     &dbconnect_vars($form, $db);
 
     $db =~ s/^db//;
     &dbconnect_vars($form, $db);
 
-    my $dbh =
-      DBI->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd})
+    my $dbh = SL::DBConnect->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd})
       or $form->dberror;
 
       or $form->dberror;
 
+    $dbh->do($form->{dboptions}) if ($form->{dboptions});
+
     # check version
     $query = qq|SELECT version FROM defaults|;
     # check version
     $query = qq|SELECT version FROM defaults|;
-    my $sth = $dbh->prepare($query);
-
-    # no error check, let it fall through
-    $sth->execute;
-
-    my $version = $sth->fetchrow_array;
-    $sth->finish;
+    my ($version) = selectrow_query($form, $dbh, $query);
 
     next unless $version;
 
 
     next unless $version;
 
-    ## LINET
     $version = calc_version($version);
     $version = calc_version($version);
-    ## /LINET
 
     foreach my $upgradescript (@upgradescripts) {
       my $a = $upgradescript;
 
     foreach my $upgradescript (@upgradescripts) {
       my $a = $upgradescript;
-      $a =~ s/^$form->{dbdriver}-upgrade-|\.sql$//g;
+      $a =~ s/^\Q$form->{dbdriver}\E-upgrade-|\.(sql|pl)$//g;
 
       my ($mindb, $maxdb) = split /-/, $a;
 
       my ($mindb, $maxdb) = split /-/, $a;
-      ## LINET
+      my $str_maxdb = $maxdb;
       $mindb = calc_version($mindb);
       $maxdb = calc_version($maxdb);
       $mindb = calc_version($mindb);
       $maxdb = calc_version($maxdb);
-      ## /LINET
 
       next if ($version >= $maxdb);
 
 
       next if ($version >= $maxdb);
 
@@ -707,7 +618,8 @@ sub dbupdate {
       last if ($version < $mindb);
 
       # apply upgrade
       last if ($version < $mindb);
 
       # apply upgrade
-      $self->process_query($form, $dbh, "sql/$upgradescript");
+      $main::lxdebug->message(LXDebug->DEBUG2(), "Applying Update $upgradescript");
+      $dbupdater->process_file($dbh, "sql/" . $form->{"dbdriver"} . "-upgrade/$upgradescript", $str_maxdb, $db_charset);
 
       $version = $maxdb;
 
 
       $version = $maxdb;
 
@@ -723,113 +635,103 @@ sub dbupdate {
   return $rc;
 }
 
   return $rc;
 }
 
-sub create_config {
+sub dbupdate2 {
   $main::lxdebug->enter_sub();
 
   $main::lxdebug->enter_sub();
 
-  my ($self, $filename) = @_;
+  my ($self, $form, $dbupdater) = @_;
 
 
-  @config = &config_vars;
+  $form->{sid} = $form->{dbdefault};
 
 
-  open(CONF, ">$filename") or $self->error("$filename : $!");
+  my $rc         = -2;
+  my $db_charset = $::lx_office_conf{system}->{dbcharset} || Common::DEFAULT_CHARSET;
 
 
-  # create the config file
-  print CONF qq|# configuration file for $self->{login}
+  map { $_->{description} = SL::Iconv::convert($_->{charset}, $db_charset, $_->{description}) } values %{ $dbupdater->{all_controls} };
 
 
-\%myconfig = (
-|;
+  foreach my $db (split / /, $form->{dbupdate}) {
+    next unless $form->{$db};
 
 
-  foreach $key (sort @config) {
-    $self->{$key} =~ s/\'/\\\'/g;
-    print CONF qq|  $key => '$self->{$key}',\n|;
-  }
+    # strip db from dataset
+    $db =~ s/^db//;
+    &dbconnect_vars($form, $db);
 
 
-  print CONF qq|);\n\n|;
+    my $dbh = SL::DBConnect->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd}) or $form->dberror;
 
 
-  close CONF;
+    $dbh->do($form->{dboptions}) if ($form->{dboptions});
 
 
-  $main::lxdebug->leave_sub();
-}
+    $self->create_schema_info_table($form, $dbh);
 
 
-sub save_member {
-  $main::lxdebug->enter_sub();
+    my @upgradescripts = $dbupdater->unapplied_upgrade_scripts($dbh);
 
 
-  my ($self, $memberfile, $userspath) = @_;
+    $dbh->disconnect and next if !@upgradescripts;
 
 
-  my $newmember = 1;
+    foreach my $control (@upgradescripts) {
+      # apply upgrade
+      $main::lxdebug->message(LXDebug->DEBUG2(), "Applying Update $control->{file}");
+      print $form->parse_html_template("dbupgrade/upgrade_message2", $control);
 
 
-  # format dbconnect and dboptions string
-  &dbconnect_vars($self, $self->{dbname});
+      $dbupdater->process_file($dbh, "sql/" . $form->{"dbdriver"} . "-upgrade2/$control->{file}", $control, $db_charset);
+    }
 
 
-  $self->error('File locked!') if (-f "${memberfile}.LCK");
-  open(FH, ">${memberfile}.LCK") or $self->error("${memberfile}.LCK : $!");
-  close(FH);
+    $rc = 0;
+    $dbh->disconnect;
 
 
-  open(CONF, "+<$memberfile") or $self->error("$memberfile : $!");
+  }
 
 
-  @config = <CONF>;
+  $main::lxdebug->leave_sub();
 
 
-  seek(CONF, 0, 0);
-  truncate(CONF, 0);
+  return $rc;
+}
 
 
-  while ($line = shift @config) {
-    if ($line =~ /^\[$self->{login}\]/) {
-      $newmember = 0;
-      last;
-    }
-    print CONF $line;
-  }
+sub save_member {
+  $main::lxdebug->enter_sub();
 
 
-  # remove everything up to next login or EOF
-  while ($line = shift @config) {
-    last if ($line =~ /^\[/);
-  }
+  my ($self) = @_;
 
 
-  # this one is either the next login or EOF
-  print CONF $line;
+  # format dbconnect and dboptions string
+  dbconnect_vars($self, $self->{dbname});
 
 
-  while ($line = shift @config) {
-    print CONF $line;
-  }
+  map { $self->{$_} =~ s/\r//g; } qw(address signature);
 
 
-  print CONF qq|[$self->{login}]\n|;
+  $main::auth->save_user($self->{login}, map { $_, $self->{$_} } config_vars());
 
 
-  if ((($self->{dbpasswd} ne $self->{old_dbpasswd}) || $newmember)
-      && $self->{root}) {
-    $self->{dbpasswd} = pack 'u', $self->{dbpasswd};
-    chop $self->{dbpasswd};
-  }
-  if (defined($self->{new_password})) {
-    if ($self->{new_password} ne $self->{old_password}) {
-      $self->{password} = crypt $self->{new_password},
-        substr($self->{login}, 0, 2)
-        if $self->{new_password};
-    }
-  } else {
-    if ($self->{password} ne $self->{old_password}) {
-      $self->{password} = crypt $self->{password}, substr($self->{login}, 0, 2)
-        if $self->{password};
-    }
+  my $dbh = SL::DBConnect->connect($self->{dbconnect}, $self->{dbuser}, $self->{dbpasswd});
+  if ($dbh) {
+    $self->create_employee_entry($::form, $dbh, $self, 1);
+    $dbh->disconnect();
   }
 
   }
 
-  if ($self->{'root login'}) {
-    @config = ("password");
-  } else {
-    @config = &config_vars;
-  }
+  $main::lxdebug->leave_sub();
+}
+
+sub create_employee_entry {
+  $main::lxdebug->enter_sub();
+
+  my $self            = shift;
+  my $form            = shift;
+  my $dbh             = shift;
+  my $myconfig        = shift;
+  my $update_existing = shift;
 
 
-  # replace \r\n with \n
-  map { $self->{$_} =~ s/\r\n/\\n/g } qw(address signature);
-  foreach $key (sort @config) {
-    print CONF qq|$key=$self->{$key}\n|;
+  if (!does_table_exist($dbh, 'employee')) {
+    $main::lxdebug->leave_sub();
+    return;
   }
 
   }
 
-  print CONF "\n";
-  close CONF;
-  unlink "${memberfile}.LCK";
+  # add login to employee table if it does not exist
+  # no error check for employee table, ignore if it does not exist
+  my ($id)         = selectrow_query($form, $dbh, qq|SELECT id FROM employee WHERE login = ?|, $self->{login});
+  my ($good_db)    = selectrow_query($form, $dbh, qq|select * from pg_tables where tablename = ? and schemaname = ?|, 'schema_info', 'public');
+  my  $can_delete;
+     ($can_delete) = selectrow_query($form, $dbh, qq|SELECT tag FROM schema_info WHERE tag = ?|, 'employee_deleted') if $good_db;
 
 
-  # create conf file
-  $self->create_config("$userspath/$self->{login}.conf")
-    unless $self->{'root login'};
+  if (!$id) {
+    my $query = qq|INSERT INTO employee (login, name, workphone, role) VALUES (?, ?, ?, ?)|;
+    do_query($form, $dbh, $query, ($self->{login}, $myconfig->{name}, $myconfig->{tel}, "user"));
+
+  } elsif ($update_existing && $can_delete) {
+    my $query = qq|UPDATE employee SET name = ?, workphone = ?, role = 'user', deleted = 'f' WHERE id = ?|;
+    do_query($form, $dbh, $query, $myconfig->{name}, $myconfig->{tel}, $id);
+  }
 
   $main::lxdebug->leave_sub();
 }
 
   $main::lxdebug->leave_sub();
 }
@@ -837,11 +739,15 @@ sub save_member {
 sub config_vars {
   $main::lxdebug->enter_sub();
 
 sub config_vars {
   $main::lxdebug->enter_sub();
 
-  my @conf = qw(acs address admin businessnumber charset company countrycode
+  my @conf = qw(address admin businessnumber company countrycode
     currency dateformat dbconnect dbdriver dbhost dbport dboptions
     dbname dbuser dbpasswd email fax name numberformat password
     currency dateformat dbconnect dbdriver dbhost dbport dboptions
     dbname dbuser dbpasswd email fax name numberformat password
-    printer role sid signature stylesheet tel templates vclimit angebote bestellungen rechnungen
-    anfragen lieferantenbestellungen einkaufsrechnungen steuernummer ustid duns);
+    printer sid signature stylesheet tel templates vclimit angebote
+    bestellungen rechnungen anfragen lieferantenbestellungen einkaufsrechnungen
+    taxnumber co_ustid duns menustyle template_format default_media
+    default_printer_id copies show_form_details favorites
+    pdonumber sdonumber hide_cvar_search_options mandatory_departments
+    sepa_creditor_id taxincluded_checked);
 
   $main::lxdebug->leave_sub();
 
 
   $main::lxdebug->leave_sub();
 
@@ -853,6 +759,8 @@ sub error {
 
   my ($self, $msg) = @_;
 
 
   my ($self, $msg) = @_;
 
+  $main::lxdebug->show_backtrace();
+
   if ($ENV{HTTP_USER_AGENT}) {
     print qq|Content-Type: text/html
 
   if ($ENV{HTTP_USER_AGENT}) {
     print qq|Content-Type: text/html
 
@@ -870,5 +778,8 @@ sub error {
   $main::lxdebug->leave_sub();
 }
 
   $main::lxdebug->leave_sub();
 }
 
-1;
+sub data {
+  +{ %{ $_[0] } }
+}
 
 
+1;