]> git.donarmstrong.com Git - wannabuild.git/blobdiff - bin/wanna-build
wanna-build: ignore partial package overwrite with arch:all
[wannabuild.git] / bin / wanna-build
index 00ca7c46b30dabc73b6a2795f18d1914185b7020..6845901f17ad360e79e793d4df690732b9a20cc7 100755 (executable)
@@ -3,6 +3,7 @@
 # wanna-build: coordination script for Debian buildds
 # Copyright (C) 1998 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
 # Copyright (C) 2005-2008 Ryan Murray <rmurray@debian.org>
 # wanna-build: coordination script for Debian buildds
 # Copyright (C) 1998 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
 # Copyright (C) 2005-2008 Ryan Murray <rmurray@debian.org>
+# Copyright (C) 2010,2011 Andreas Barth <aba@not.so.argh.org>
 #
 # This program is free software; you can redistribute it and/or
 # modify it under the terms of the GNU General Public License as
 #
 # This program is free software; you can redistribute it and/or
 # modify it under the terms of the GNU General Public License as
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 #
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 #
+use strict;
+use warnings;
+use 5.010;
+
+die "wanna-build disabled" if -f "/org/wanna-build/NO-WANNA-BUILD";
 
 package conf;
 
 package conf;
+
+use vars qw< $basedir $dbbase $transactlog $mailprog $buildd_domain >;
 # defaults
 $basedir ||= "/var/lib/debbuild";
 $dbbase ||= "build-db";
 $transactlog ||= "transactions.log";
 $mailprog ||= "/usr/sbin/sendmail";
 # defaults
 $basedir ||= "/var/lib/debbuild";
 $dbbase ||= "build-db";
 $transactlog ||= "transactions.log";
 $mailprog ||= "/usr/sbin/sendmail";
-require "/etc/wanna-build.conf";
+require "/org/wanna-build/etc/wanna-build.conf";
 die "$conf::basedir is not a directory\n" if ! -d $conf::basedir;
 die "dbbase is empty\n" if ! $dbbase;
 die "transactlog is empty\n" if ! $transactlog;
 die "mailprog binary $conf::mailprog does not exist or isn't executable\n"
        if !-x $conf::mailprog;
 die "$conf::basedir is not a directory\n" if ! -d $conf::basedir;
 die "dbbase is empty\n" if ! $dbbase;
 die "transactlog is empty\n" if ! $transactlog;
 die "mailprog binary $conf::mailprog does not exist or isn't executable\n"
        if !-x $conf::mailprog;
-die "no distributions defined\n" if ! %distributions;
 package main;
 
 package main;
 
-use strict;
 use POSIX;
 use FileHandle;
 use File::Copy;
 use POSIX;
 use FileHandle;
 use File::Copy;
-use GDBM_File;
-use MLDBM qw(GDBM_File Storable);
+use DBI;
+use Getopt::Long qw ( :config gnu_getopt );
+use lib '/org/wanna-build/lib';
+#use lib 'lib';
 use WannaBuild;
 use WannaBuild;
+use YAML::Tiny;
+use Data::Dumper;
+use Hash::Merge qw ( merge );
+use String::Format;
+use Date::Parse;
+use List::Util qw[max];
+use Dpkg::Version (); # import nothing
+if ( defined $Dpkg::Version::VERSION ) {
+    *vercmp = \&Dpkg::Version::version_compare;
+} else {
+    *vercmp = \&Dpkg::Version::vercmp;
+}
+
+use Dpkg::Deps; # TODO: same
 
 our ($verbose, $mail_logs, $list_order, $list_state,
     $curr_date, $op_mode, $user, $real_user, $distribution,
 
 our ($verbose, $mail_logs, $list_order, $list_state,
     $curr_date, $op_mode, $user, $real_user, $distribution,
-    $fail_reason, $opt_override, $import_from, $export_to, $opt_create_db,
-    %db, %otherdb, %otherdb_lock, %prioval, %sectval,
+    $fail_reason, $opt_override, $import_from, $export_to,
+    %prioval, %sectval,
     $info_all_dists, $arch,
     $info_all_dists, $arch,
-    $category, %catval, %short_category,
-    $short_date, $list_min_age, $dbbase, @curr_time,
+    $short_date, $list_min_age, $list_max_age, $dbbase, @curr_time,
     $build_priority, %new_vers, $binNMUver, %merge_srcvers, %merge_binsrc,
     $build_priority, %new_vers, $binNMUver, %merge_srcvers, %merge_binsrc,
-    $lock_for_pid, $transactional);
+    $printformat, $ownprintformat, $privmode, $extra_depends, $extra_conflicts,
+    %distributions, %distribution_aliases, $actions,
+    $sshwrapper,
+    );
+our $Pas = '/org/buildd.debian.org/etc/packages-arch-specific/Packages-arch-specific';
+our $simulate = 0;
+our $simulate_edos = 0;
+our $api = undef; # allow buildds to specify an different api
+our $recorduser = undef;
 
 # global vars
 $ENV{'PATH'} = "/bin:/usr/bin:/usr/local/bin:/org/wanna-build/bin/";
 
 # global vars
 $ENV{'PATH'} = "/bin:/usr/bin:/usr/local/bin:/org/wanna-build/bin/";
+$ENV{'LC_ALL'} = 'C';
 $verbose = 0;
 $mail_logs = "";
 @curr_time = gmtime;
 $curr_date = strftime("%Y %b %d %H:%M:%S",@curr_time);
 $short_date = strftime("%m/%d/%y",@curr_time);
 $| = 1;
 $verbose = 0;
 $mail_logs = "";
 @curr_time = gmtime;
 $curr_date = strftime("%Y %b %d %H:%M:%S",@curr_time);
 $short_date = strftime("%m/%d/%y",@curr_time);
 $| = 1;
-$lock_for_pid = -1; # -1 means normal procedure
-$transactional = 0; # 0 means: work on main copy
-
-# map program invocation names to operation modes
-my %prognames = ( "uploaded-build"  => "set-uploaded",
-                                 "failed-build"    => "set-failed",
-                                 "no-build"            => "set-not-for-us",
-                                 "give-back-build" => "set-needs-build",
-                                 "dep-wait-build"  => "set-dep-wait",
-                                 "forget-build"        => "forget",
-                                 "merge-quinn"         => "merge-quinn",
-                                 "merge-packages"  => "merge-packages",
-                                 "merge-sources"   => "merge-sources",
-                                 "build-info"          => "info" );
-
-%short_category = ( u => "uploaded-fixed-pkg",
-                                   f => "fix-expected",
-                                       r => "reminder-sent",
-                                       n => "nmu-offered",
-                                       e => "easy",
-                                       m => "medium",
-                                       h => "hard",
-                                       c => "compiler-error",
-                                       "" => "none" );
-
-my $progname;
-($progname = $0) =~ s,.*/,,;
-if ($prognames{$progname}) {
-       $op_mode = $prognames{$progname};
-}
-elsif ($progname =~ /^list-(.*)$/) {
-       $op_mode = "list";
-       $list_state = ($1 eq "all") ? "" : $1;
-}
-
-my %options =
-       (# flags
-        verbose        => { short => "v", flag => \$verbose },
-        override               => { short => "o", flag => \$opt_override },
-        "create-db"    => { flag => \$opt_create_db },
-        "correct-compare" => { flag => \$WannaBuild::opt_correct_version_cmp },
-        # TODO: remove after buildds no longer pass to wanna-build
-        "no-propagation" => { short => "N" },
-        "no-down-propagation" => { short => "D" },
-        # normal actions
-        take                   => { mode => "set-building" },
-        failed                 => { short => "f", mode => "set-failed" },
-        uploaded               => { short => "u", mode => "set-uploaded" },
-        "no-build"             => { short => "n", mode => "set-not-for-us" },
-        built                  => { mode => "set-built" },
-        attempted              => { mode => "set-attempted" },
-        "give-back"            => { mode => "set-needs-build" },
-        "dep-wait"             => { mode => "set-dep-wait" },
-        forget                 => { mode => "forget" },
-        'forget-user' => { mode => 'forget-user' },
-        "merge-quinn"  => { mode => "merge-quinn" },
-        "merge-partial-quinn" => { mode => "merge-partial-quinn" },
-        "merge-packages" => { mode => "merge-packages" },
-        "merge-sources" => { mode => "merge-sources" },
-        "pretend-avail" => { short => "p", mode => "pretend-avail" },
-        "merge-all"     => { mode => "merge-all" },
-        info                   => { short => "i", mode => "info" },
-        'binNMU' => { mode => 'set-binary-nmu', arg => \$binNMUver, 
-                            code => sub { die "Invalid binNMU version: $binNMUver\n"
-                               if $binNMUver !~ /^([\d]*)$/ and $1 >= 0; } },
-        'perm-build-priority'    => { mode => "set-permanent-build-priority", arg => \$build_priority,
-                             code => sub { die "Invalid build priority: $build_priority\n"
-                               if $build_priority !~ /^-?[\d]+$/; } },
-        'build-priority'    => { mode => "set-build-priority", arg => \$build_priority,
-                             code => sub { die "Invalid build priority: $build_priority\n"
-                               if $build_priority !~ /^-?[\d]+$/; } },
-        list                   =>
-        { short => "l", mode => "list", arg => \$list_state,
-          code => sub {
-                  die "Unknown state to list: $list_state\n"
-                          if !isin( $list_state, qw(needs-build building uploaded
-                                                built build-attempted failed installed dep-wait
-                                                not-for-us all failed-removed
-                                                install-wait reupload-wait bd-uninstallable));} },
-        # options with args
-        dist           =>
-        { short => "d", arg => \$distribution,
-          code => sub {
-                  if ($distribution eq "a" || $distribution eq "all") {
-                          $info_all_dists = 1;
-                          $distribution = "";
-                  }
-                  else {
-                          $distribution = "oldstable"   if $distribution eq "o";
-                          $distribution = "stable"   if $distribution eq "s";
-                          $distribution = "testing"  if $distribution eq "t";
-                          $distribution = "unstable" if $distribution eq "u";
-                  }
-          } },
-        order          =>
-        { short => "O", arg => \$list_order,
-          code => sub {
-                  die "Bad ordering character\n"
-                          if $list_order !~ /^[PSpsncb]+$/;
-          } },
-        message        => { short => "m", arg => \$fail_reason },
-        database       => { short => "b", arg => \$conf::dbbase },
-        arch           => { short => "A", arg => \$arch },
-        user           => { short => "U", arg => \$user },
-        category               => { short => "c", arg => \$category,
-                                                code => sub {
-                                                        $category = $short_category{$category}
-                                                                if exists $short_category{$category};
-                                                        die "Unknown category: $category\n"
-                                                                if !isin( $category, values %short_category );
-                                                } },
-        "min-age"      => { short => "a", arg => \$list_min_age,
-                                                code => sub {
-                                                        die "Argument of --min-age must be a non-zero number\n"
-                                                                if $list_min_age == 0;
-                                                        $list_min_age *= 24*60*60;
-                                                } },
-        "max-age"      => { arg => \$list_min_age,
-                                                code => sub {
-                                                        die "Argument of --max-age must be a non-zero number\n"
-                                                                if $list_min_age == 0;
-                                                        $list_min_age *= -24*60*60;
-                                                } },
-        # special actions
-        import         => { arg => \$import_from, mode => "import" },
-        export         => { arg => \$export_to, mode => "export" },
-        "lock-for"     => { arg => \$lock_for_pid, mode => "lock-for" },
-        "unlock-for"   => { arg => \$lock_for_pid, mode => "unlock-for" },
-        "act-on-behalf-of" => { arg => \$lock_for_pid },
-        "start-transaction" => { mode => "start-transaction" },
-        "commit-transaction" => { mode => "commit-transaction" },
-        "transactional" => { flag => \$transactional },
-        "manual-edit"  => { mode => "manual-edit" },
-        "create-maintenance-lock" => { mode => "maintlock-create" },
-        "remove-maintenance-lock" => { mode => "maintlock-remove" },
-        "clean-db" => { mode => "clean-db" },
-        );
-
-while( @ARGV && $ARGV[0] =~ /^-/ ) {
-       $_ = shift @ARGV;
-       last if $_ eq "--";
-       my($opt, $optname, $arg);
-       if (/^--([^=]+)(=|$)/) {
-               $optname = $1;
-               $opt = $options{$optname};
-               $arg = $1 if /^--\Q$optname\E=((.|\n)*)$/;
-       }
-       else {
-               $optname = substr( $_, 1, 1 );
-               $opt = (grep { defined($_->{short}) ? $_->{short} eq $optname : 0} values %options)[0];
-               $arg = $1 if /^-$optname(.+)$/;
-       }
-       if (!$opt) {
-               warn "Unknown option: --$1\n";
-               usage();
-       }
-       if ($opt->{arg}) {
-               if (!defined $arg) {
-                       die "$optname option missing argument\n" if !@ARGV;
-                       $arg = shift @ARGV;
-               }
-               ${$opt->{arg}} = $arg;
-       }
-       elsif (defined $arg) {
-               die "Option $optname takes no argument\n";
-       }
-       
-       if ($opt->{mode}) {
-               die "Conflicting operation modes\n" if $op_mode;
-               $op_mode = $opt->{mode};
-       }
-       if ($opt->{flag}) {
-               ${$opt->{flag}}++;
-       }
-       if ($opt->{code}) {
-               &{$opt->{code}};
+
+# set mode of operation based on command line switch. Should be used
+# by GetOptions below.
+sub _set_mode_set { $op_mode = "set-$_[0]" }
+sub _set_mode { $op_mode = "$_[0]" }
+
+sub _option_deprecated { warn "Option $_[0] is deprecated" }
+
+my @wannabuildoptions = (
+    # this is not supported by all operations (yet)!
+    'simulate'      => \$simulate,
+    'simulate-edos' => \$simulate_edos,
+    'simulate-all'  => sub { $simulate = 1; $simulate_edos = 1; },
+    'api=i'         => sub {
+        $api = $_[1];
+        die "$api too large" unless $api <= 1;
+    },
+    'verbose|v'       => \$verbose,
+    'override|o'      => \$opt_override,
+    'correct-compare' => \$WannaBuild::opt_correct_version_cmp,
+
+    # TODO: remove after buildds no longer pass to wanna-build
+    'no-propagation|N'      => \&_option_deprecated,
+    'no-down-propagation|D' => \&_option_deprecated,
+
+    # normal actions
+    'building|take'         => \&_set_mode_set,
+    'failed|f'              => \&_set_mode_set,
+    'uploaded|u'            => \&_set_mode_set,
+    'not-for-us|no-build|n' => \&_set_mode_set,
+    'built'                 => \&_set_mode_set,
+    'attempted'             => \&_set_mode_set,
+    'needs-build|give-back' => \&_set_mode_set,
+    'dep-wait'              => \&_set_mode_set,
+    'update'                => \&_set_mode_set,
+    'forget'                => \&_set_mode,
+    'forget-user'           => \&_set_mode,
+    'merge-v3'              => \&_set_mode,
+    'info|i'                => \&_set_mode,
+    'binary-nmu|binNMU=i'   => sub {
+        _set_mode_set(@_);
+        $binNMUver = $_[1];
+    },
+    'permanent-build-priority|perm-build-priority=i' => sub {
+        _set_mode_set(@_);
+        $build_priority = $_[1];
+    },
+    'build-priority=i' => sub {
+        _set_mode_set(@_);
+        $build_priority = $_[1];
+    },
+    'list|l=s' => sub {
+        _set_mode(@_);
+        $list_state = $_[1];
+        die "Unknown state to list: $list_state\n"
+          if not $list_state ~~ [
+              qw( needs-build building uploaded built
+                  build-attempted failed installed
+                  dep-wait not-for-us auto-not-for-us
+                  all failed-removed install-wait
+                  reupload-wait bd-uninstallable ) ];
+    },
+    'dist|d=s' => sub {
+        $distribution = $_[1];
+        given ( $_[1] ) {
+            when ( [qw< a all >] ) {
+                $info_all_dists = 1;
+                $distribution   = '';
+            }
+            when ('o') { $distribution = 'oldstable'; }
+            when ('s') { $distribution = 'stable'; }
+            when ('t') { $distribution = 'testing'; }
+            when ('u') { $distribution = 'unstable'; }
+
+            if ($distribution eq 'any-priv') {
+                $privmode = 1;
+                $distribution = 'any';
+            }
+            if ($distribution eq 'any-unpriv') {
+                $privmode = 0;
+                $distribution = 'any';
+            }
+            $privmode = 1 if $distribution =~ /security/;
+        }
+    },
+    'order|O=s' => sub {
+        $list_order = $_[1];
+        die "Bad ordering character\n"
+          if $list_order !~ /^[PSpsncbCWT]+$/;
+    },
+    'message|m=s'  => \$fail_reason,
+    'database|b=s' => sub {
+        # If they didn't specify an arch, try to get it from database name which
+        # is in the form of $arch/build-db
+        # This is for backwards compatibity with older versions that didn't
+        # specify the arch yet.
+        warn "database is deprecated, please use 'arch' instead.\n";
+        $_[1] =~ m#^([^/]+)#;
+        $arch ||= $1;
+    },
+    'arch|A=s'     => \$arch,
+    'user|U=s'     => \$user,
+    'min-age|a=i'       => \$list_min_age,
+    'max-age=i'         => sub { $list_min_age = -1 * ($_[1]); },
+    'format=s'          => \$printformat,
+    'own-format=s'      => \$ownprintformat,
+    'Pas=s'             => \$Pas,
+    'extra-depends=s'   => \$extra_depends,
+    'extra-conflicts=s' => \$extra_conflicts,
+
+    # special actions
+    'export=s' => sub { _set_mode(@_); $export_to   = $_[1]; },
+    'import=s' => sub { _set_mode(@_); $import_from = $_[1]; },
+    'manual-edit'                => \&_set_mode,
+    'distribution-architectures' => \&_set_mode,
+    'distribution-aliases'       => \&_set_mode,
+
+    'ssh-wrapper'       => \$sshwrapper,
+    'recorduser'        => \$recorduser,
+    );
+
+GetOptions(@wannabuildoptions) or usage();
+
+my $dbh;
+
+END {
+       if (defined $dbh)
+       {
+               $dbh->disconnect or warn $dbh->errstr;
        }
 }
 
        }
 }
 
-$op_mode = $category ? "set-failed" : "set-building"
-       if !$op_mode; # default operation
-$list_order = $list_state eq "failed" ? 'fPcpsn' : 'PScpsn'
-       if !$list_order and $list_state;
-$distribution ||= "unstable";
-die "Bad distribution '$distribution'\n"
-       if !isin($distribution, keys %conf::distributions);
+my $schema_suffix = '';
+if ((isin( $op_mode, qw(list info distribution-architectures distribution-aliases)) && !$recorduser && !$privmode) || $simulate) {
+       $dbh = DBI->connect("DBI:Pg:service=wanna-build") || 
+               die "FATAL: Cannot open database: $DBI::errstr\n";
+       $schema_suffix = '_public';
+}
+else
+{
+       $dbh = DBI->connect("DBI:Pg:service=wanna-build-privileged") || 
+               die "FATAL: Cannot open database: $DBI::errstr\n";
+}
+
+# TODO: This shouldn't be needed, file a bug.
+$dbh->{pg_server_prepare} = 0;
+
+$dbh->begin_work or die $dbh->errstr;
+
+my $q = 'SELECT distribution, public, auto_dep_wait, build_dep_resolver, suppress_successful_logs, archive FROM distributions';
+my $rows = $dbh->selectall_hashref($q, 'distribution');
+foreach my $name (keys %$rows) {
+       $distributions{$name} = {};
+       $distributions{$name}->{'noadw'} = 1 if !($rows->{$name}->{'auto_dep_wait'});
+       $distributions{$name}->{'hidden'} = 1 if !($rows->{$name}->{'public'});
+       $distributions{$name}->{'build_dep_resolver'} = $rows->{$name}->{'build_dep_resolver'} if $rows->{$name}->{'build_dep_resolver'};
+       $distributions{$name}->{'suppress_successful_logs'} = $rows->{$name}->{'suppress_successful_logs'} if $rows->{$name}->{'suppress_successful_logs'};
+       $distributions{$name}->{'archive'} = $rows->{$name}->{'archive'} if $rows->{$name}->{'archive'};
+}
+
+$q = 'SELECT alias, distribution FROM distribution_aliases';
+$rows = $dbh->selectall_hashref($q, 'alias');
+foreach my $name (keys %$rows) {
+       $distribution_aliases{$name} = $rows->{$name}->{'distribution'};
+}
+$distribution = $distribution_aliases{$distribution} if (isin($distribution, keys %distribution_aliases));
+
+$op_mode ||= "set-building";
+if ($distribution) {
+    my @dists = split(/[, ]+/, $distribution);
+    foreach my $dist (@dists) {
+        die "Bad distribution '$distribution'\n"
+           if !isin($dist, keys %distributions, "any");
+    }
+}
+if (!isin ( $op_mode, qw(list) ) && ( ($distribution//"") =~ /[ ,]/)) {
+    die "multiple distributions are only allowed for list";
+}
+
+# TODO: Check that it's an known arch (for that dist), and give
+# a proper error.
 
 if ($verbose) {
 
 if ($verbose) {
-       my $version = '$Revision: db181a534e9d $ $Date: 2008/03/26 06:20:22 $ $Author: rmurray $';
-       $version =~ s/(^\$| \$ .*$)//g;
-       print "wanna-build $version for $distribution on $conf::dbbase\n";
+       my $version = '$Id$';
+       $version =~ s/^.* ([a-f0-9]+) .*$/$1/g;
+       print "wanna-build $version for ".($distribution//"sid")." on $arch\n";
 }
 
 if (!@ARGV && !isin( $op_mode, qw(list merge-quinn merge-partial-quinn import export
 }
 
 if (!@ARGV && !isin( $op_mode, qw(list merge-quinn merge-partial-quinn import export
-                                 merge-packages manual-edit maintlock-create lock-for unlock-for
-                                 start-transaction commit-transaction
-                                 merge-sources maintlock-remove clean-db))) {
+                                 merge-packages manual-edit
+                                 merge-sources distribution-architectures
+                                 distribution-aliases))) {
        warn "No packages given.\n";
        usage();
 }
        warn "No packages given.\n";
        usage();
 }
@@ -267,7 +292,7 @@ die "Can't determine your user name\n"
           !($user = $real_user);
 
 if (!$fail_reason) {
           !($user = $real_user);
 
 if (!$fail_reason) {
-       if ($op_mode eq "set-failed" && !$category) {
+       if ($op_mode eq "set-failed" ) {
                print "Enter reason for failing (end with '.' alone on ".
                      "its line):\n";
                my $line;
                print "Enter reason for failing (end with '.' alone on ".
                      "its line):\n";
                my $line;
@@ -295,89 +320,43 @@ if (!$fail_reason) {
                $fail_reason = $line;
        }
 }
                $fail_reason = $line;
        }
 }
-if ($op_mode eq "maintlock-create") {
-       create_maintlock();
-       exit 0;
-}
-if ($op_mode eq "maintlock-remove") {
-       remove_maintlock();
-       exit 0;
-}
-waitfor_maintlock() if $op_mode !~ /^(?:merge-|clean-db$)/;
-
-if (!-f db_filename( $distribution ) && !$opt_create_db) {
-       if ($transactional) {
-               die "No running transaction for $distribution\n";
-       } else {
-               die "Database for $distribution doesn't exist\n";
-       }
-}
 
 
-# Locking for another process means that a longer running process (most likely
-# wb) wants to do several steps at once, and manages the locks.
-if ($op_mode eq "lock-for") {
-       lock_db( $distribution );
-       exit 0;
+my $yamlmap = ();
+my $yamldir = "/org/wanna-build/etc/yaml";
+my @files = ('wanna-build.yaml');
+if ((getpwuid($>))[7]) { push (@files, ((getpwuid($>))[7])."/.wanna-build.yaml"); }
+if ($user && $user =~ /(buildd.*)-/) { push (@files, "$1.yaml") };
+if ($user) { push ( @files, "$user.yaml"); }
+foreach my $file (@files) {
+        my $cfile = File::Spec->rel2abs( $file, $yamldir );
+       if ($verbose >= 2) { print "Trying to read $file ($cfile) ...\n"; }
+       next unless -f $cfile;
+       if ($verbose >= 2) { print "Read $file ($cfile) ...\n"; }
+       my $m = YAML::Tiny->read( $cfile )->[0];
+       $yamlmap = merge($m, $yamlmap);
 }
 }
-if ($op_mode eq "unlock-for") {
-       unlock_db( $distribution );
-       exit 0;
+if (not $yamlmap) {
+       die "FATAL: no configuration found\n";
 }
 }
+$list_order = $yamlmap->{"list-order"}{$list_state} if !$list_order and $list_state;
+$list_order ||= $yamlmap->{"list-order"}{'default'};
+$api //= $yamlmap->{"api"};
+$api //= 0;
 
 
-lock_db( $distribution );
-
-if ($op_mode eq "start-transaction") {
-       copy ( db_filename_master( $distribution ), db_filename_transaction( $distribution ))
-               or die "Copy failed: $!";
-       open LOG, ">", db_transactlog_transaction( $distribution )
-               or die "Could not create logfile for transaction: $!";
-       close LOG;
-       exit 0;
-}
-
-if ($op_mode eq "commit-transaction") {
-       # we need to copy here to preserve the owner and group of the file
-       copy ( db_filename_transaction( $distribution ), db_filename_master( $distribution ))
-               or die "Copy failed: $!";
-       unlink db_filename_transaction( $distribution );
-       open TLOG, "<", db_transactlog_transaction( $distribution )
-               or die "Could not open logfile from transaction: $!";
-       open LOG, ">>", db_transactlog_master( $distribution )
-               or die "Could not open logfile: $!";
-       while (<TLOG>) { print LOG $_ };
-       close TLOG;
-       close LOG;
-       unlink db_transactlog_transaction( $distribution );
-       exit 0;
-}
-
-END {
-       untie %db;
-       if ($lock_for_pid == -1) {
-               unlock_db( $distribution );
-       }
-       foreach (keys %conf::distributions) {
-               untie %{$otherdb{$_}} if tied(%{$otherdb{$_}});
-               unlock_db( $_ ) if $otherdb_lock{$_};
-       }
+if (isin($op_mode, qw<forget-user merge-v3 import>) && defined @conf::admin_users && !isin( $real_user, @conf::admin_users) && !$simulate ) {
+    die "This operation is restricted to admin users";
 }
 }
-
-tie %db, 'MLDBM', db_filename( $distribution ), GDBM_WRCREAT, 0664
-       or die "FATAL: Cannot open database\n";
-
-process();
-
-if ($mail_logs && $conf::log_mail) {
-       send_mail( $conf::log_mail,
-                          "wanna-build $distribution state changes $curr_date",
-                          "State changes at $curr_date for distribution ".
-                          "$distribution:\n\n$mail_logs\n" );
+if (!isin($op_mode, qw<distribution-architectures distribution-aliases>)) {
+    die "need an architecture" unless $arch;
+    my $rows = $dbh->selectall_hashref('SELECT distribution as d from distribution_architectures where architecture=? and distribution=?', [qw<d>], undef, ($arch, $distribution//"sid")) if ($distribution//"") ne 'any';
+    $rows = $dbh->selectall_hashref('SELECT distribution as d from distribution_architectures where architecture=?', [qw<d>], undef, ($arch,)) unless $rows;
+    die "architecture ($arch) does not exist (at least not for ".($distribution//"sid").")" if !keys %$rows and $distribution//"sid" ne 'any';
+    die "architecture ($arch) does not exist" if !keys %$rows;
 }
 
 }
 
-exit 0;
-
-
-sub process {
+my $suite = $distribution;
+$distribution ||='sid';
+undef $distribution if $distribution eq 'any';
 
        SWITCH: foreach ($op_mode) {
                /^set-(.+)/ && do {
 
        SWITCH: foreach ($op_mode) {
                /^set-(.+)/ && do {
@@ -393,9 +372,6 @@ sub process {
                        last SWITCH;
                };
                /^forget-user/ && do {
                        last SWITCH;
                };
                /^forget-user/ && do {
-                       die "This operation is restricted to admin users\n"
-                               if (defined @conf::admin_users and
-                                   !isin( $real_user, @conf::admin_users));
                        forget_users( @ARGV );
                        last SWITCH;
                };
                        forget_users( @ARGV );
                        last SWITCH;
                };
@@ -403,160 +379,230 @@ sub process {
                        forget_packages( @ARGV );
                        last SWITCH;
                };
                        forget_packages( @ARGV );
                        last SWITCH;
                };
-               /^merge-partial-quinn/ && do {
-                       die "This operation is restricted to admin users\n"
-                               if (defined @conf::admin_users and
-                                   !isin( $real_user, @conf::admin_users));
-                       parse_quinn_diff(1);
-                       last SWITCH;
-               };
-               /^merge-quinn/ && do {
-                       die "This operation is restricted to admin users\n"
-                               if (defined @conf::admin_users and
-                                   !isin( $real_user, @conf::admin_users));
-                       parse_quinn_diff(0);
-                       last SWITCH;
-               };
-               /^merge-packages/ && do {
-                       die "This operation is restricted to admin users\n"
-                               if (defined @conf::admin_users and
-                                   !isin( $real_user, @conf::admin_users));
-                       parse_packages();
-                       last SWITCH;
-               };
-               /^merge-sources/ && do {
-                       die "This operation is restricted to admin users\n"
-                               if (defined @conf::admin_users and
-                                   !isin( $real_user, @conf::admin_users));
-                       parse_sources(0);
-                       last SWITCH;
-               };
-               /^pretend-avail/ && do {
-                       pretend_avail( @ARGV );
-                       last SWITCH;
-               };
-               /^merge-all/ && do {
-                       die "This operation is restricted to admin users\n"
-                               if (defined @conf::admin_users and
-                                   !isin( $real_user, @conf::admin_users));
-                       my @ARGS = @ARGV;
-                       @ARGV = ( $ARGS[0] );
-                       my $pkgs = parse_packages();
-                       @ARGV = ( $ARGS[1] );
-                       parse_quinn_diff(0);
-                       @ARGV = ( $ARGS[2] );
-                       my $srcs = parse_sources(1);
-                       call_edos_depcheck( $ARGS[0], $srcs );
-                       clean_db();
-                       last SWITCH;
+               /^merge-v3/ && do {
+                        # call with installed-packages+ . installed-sources+ [ . available-for-build-packages* [ . consider-as-installed-source* ]  ]
+                        # in case available-for-build-packages is not specified, installed-packages are used
+                        lock_table() unless $simulate;
+                        my $replacemap = { '%ARCH%' => $arch, '%SUITE%' => $distribution };
+                        map { my $k = $_; grep { $k =~ s,$_,$replacemap->{$_}, } keys %{$replacemap}; $_ = $k; } @ARGV;
+                        my @ipkgs = &parse_argv( \@ARGV, '.'); # installed packages
+                        my @isrcs = &parse_argv( \@ARGV, '.'); # installed sources
+                        my @bpkgs = &parse_argv( \@ARGV, '.'); # packages available for building (edos-debcheck)
+                        my @psrcs = &parse_argv( \@ARGV, '.'); # consider as installed sources
+                        use WB::QD;
+                        my $srcs = WB::QD::readsourcebins($arch, $Pas, \@isrcs, \@ipkgs);
+                        if (@psrcs) {
+                            # Installed sources of the base suite: only add them as related, not
+                            # installed; skip the entries if we got something in installed
+                            # sources already.
+                            my $psrcs = WB::QD::readsourcebins($arch, $Pas, \@psrcs, []);
+                            foreach my $k (keys %$$psrcs) {
+                                next if $$srcs->{$k};
+                                my $pkg = $$psrcs->{$k};
+                                $pkg->{'status'} = 'related';
+                                $$srcs->{$k} = $pkg;
+                            }
+                        }
+                        parse_all_v3($$srcs, {'arch' => $arch, 'suite' => $distribution, 'time' => $curr_date});
+                        # The packages passed to edos-debcheck are normally the binaries available,
+                        # unless you've also a base suite the builder will take packages from.
+                        @bpkgs = @ipkgs unless @bpkgs;
+                        call_edos_depcheck( {'arch' => $arch, 'pkgs' => \@bpkgs, 'srcs' => $$srcs, 'depwait' => 1 });
+                        last SWITCH;
                };
                /^import/ && do {
                };
                /^import/ && do {
-                       die "This operation is restricted to admin users\n"
-                               if (defined @conf::admin_users and
-                                   !isin( $real_user, @conf::admin_users));
-                       %db = (); # clear all current contents
+                       $dbh->do("DELETE from ".table_name()." WHERE distribution = ?", undef, $distribution)
+                               or die $dbh->errstr;
+                       forget_users();
                        read_db( $import_from );
                        last SWITCH;
                };
                /^export/ && do {
                        read_db( $import_from );
                        last SWITCH;
                };
                /^export/ && do {
-                       write_db( $export_to );
+                       export_db( $export_to );
                        last SWITCH;
                };
                        last SWITCH;
                };
-               /^manual-edit/ && do {
-                       die "This operation is restricted to admin users\n"
-                               if (defined @conf::admin_users and
-                                   !isin( $real_user, @conf::admin_users));
-                       my $tmpfile_pattern = "/tmp/wanna-build-$distribution.$$-";
-                       my ($tmpfile, $i);
-                       for( $i = 0;; ++$i ) {
-                               $tmpfile = $tmpfile_pattern . $i;
-                               last if ! -e $tmpfile;
-                       }
-                       write_db( $tmpfile );
-                       my $editor = $ENV{'VISUAL'} ||
-                                                "/usr/bin/sensible-editor";
-                       system "$editor $tmpfile";
-                       %db = (); # clear all current contents
-                       read_db( $tmpfile );
-                       unlink( $tmpfile );
+               /^distribution-architectures/ && do {
+                       show_distribution_architectures({'suite' => $suite});
                        last SWITCH;
                };
                        last SWITCH;
                };
-               /^clean-db/ && do {
-                       die "This operation is restricted to admin users\n"
-                               if (defined @conf::admin_users and
-                                   !isin( $real_user, @conf::admin_users));
-                       clean_db();
+               /^distribution-aliases/ && do {
+                       show_distribution_aliases();
                        last SWITCH;
                };
 
                die "Unexpected operation mode $op_mode\n";
        }
                        last SWITCH;
                };
 
                die "Unexpected operation mode $op_mode\n";
        }
-       if (not -t and $user =~ /-/) {
-               my $userinfo = $db{'_userinfo'};
-               $userinfo = {} if (!defined($userinfo));
+       if ($recorduser) {
+               my $userinfo = get_user_info($user);
+               if (!defined $userinfo)
+               {
+                       add_user_info($user);
+               }
+               else
+               {
+                       update_user_info($user);
+               }
+       }
 
 
-               my $ui = $userinfo->{$user};
-               $ui = {} if (!defined($ui));
 
 
-               $ui->{'Last-Seen'} = $curr_date;
-               $ui->{'User'} = $user;
+$dbh->commit unless $simulate;
+$dbh->disconnect;
 
 
-               $userinfo->{$user} = $ui;
-               $db{'_userinfo'} = $userinfo;
-       }
+if ($mail_logs && $conf::log_mail) {
+       send_mail( $conf::log_mail,
+                          "wanna-build $distribution state changes $curr_date",
+                          "State changes at $curr_date for distribution ".
+                          "$distribution:\n\n$mail_logs\n" );
+}
+
+exit 0;
+
+
+BEGIN {
+    $actions = {
+        'set-building'  => { 'noversion' => 1, 'nopkgdef' => 1, },
+        'set-built'     => { 'builder' => 1, to => 'Built', action => 'built', 'from' => [qw<Building Build-Attempted>]},
+        'set-attempted' => { 'builder' => 1, to => 'Build-Attempted', action => 'attempted', 'from' => [qw<Building Build-Attempted>]},
+        'set-uploaded'  => { 'builder' => 1, to => 'Uploaded', action => 'uploaded', 'from' => [qw<Building Built Build-Attempted>], binversion => 1, },
+        'set-failed'    => { 'builder' => 1, to => 'Failed', action => 'failed', from => [qw<Building Built Build-Attempted Dep-Wait Failed>], warnfrom => [qw<Needs-Build Uploaded Dep-Wait BD-Uninstallable>], },
+        'set-dep-wait'  => { 'builder' => 1, warnfrom => [qw<Needs-Build Failed BD-Uninstallable>], },
+        'set-update'    => { 'noversion' => 1, },
+        'set-needs-build' => { builder => 1, to => 'BD-Uninstallable', action => 'give-back'},
+    };
 }
 
 sub add_packages {
 }
 
 sub add_packages {
-       my $newstate = shift;
-       my( $package, $name, $version, $ok, $reason );
-       
-       foreach $package (@_) {
-               $package =~ s,^.*/,,; # strip path
-               $package =~ s/\.(dsc|diff\.gz|tar\.gz|deb)$//; # strip extension
-               $package =~ s/_[a-zA-Z\d-]+\.changes$//; # strip extension
-               if ($package =~ /^([\w\d.+-]+)_([\w\d:.+~-]+)/) {
-                       ($name,$version) = ($1,$2);
-               }
-               else {
-                       warn "$package: can't extract package name and version ".
-                                "(bad format)\n";
-                       next;
-               }
+    my $newstate = shift;
+    my( $package, $name, $version, $ok, $reason );
+
+    foreach $package (@_) {
+        $package =~ s,^.*/,,; # strip path
+        $package =~ s/\.(dsc|diff\.gz|tar\.gz|deb)$//; # strip extension
+        $package =~ s/_[a-zA-Z\d-]+\.changes$//; # strip extension
+        if ($package =~ /^([\w\d.+-]+)_([\w\d:.+~-]+)/) {
+            ($name,$version) = ($1,$2);
+        } else {
+           warn "$package: can't extract package name and version (bad format)\n";
+           next;
+       }
+
+       my $pkg = get_source_info($name);
+        if (!($actions->{$op_mode}) || !($actions->{$op_mode}->{'nopkgdef'})) {
+            if (!defined($pkg)) {
+                print "$name: not registered yet.\n";
+                next;
+            }
+        }
+        if ($actions->{$op_mode} && $actions->{$op_mode}->{'builder'}) {
+            if (($pkg->{'builder'} && $user ne $pkg->{'builder'}) &&
+               !($pkg->{'builder'} =~ /^(\w+)-\w+/ && $1 eq $user) &&
+               !$opt_override) {
+                print "$pkg->{'package'}: not taken by you, but by $pkg->{'builder'}. Skipping.\n";
+                next;
+            }
+        }
+        if (!($actions->{$op_mode}) || !($actions->{$op_mode}->{'noversion'})) {
+            my $nmuver = binNMU_version($pkg->{version}, $pkg->{'binary_nmu_version'});
+            if ((!pkg_version_eq($pkg,$version) || $actions->{$op_mode}->{'binversion'}) && !version_eq( $nmuver, $version )) {
+                print "$pkg->{package}: version mismatch ($nmuver";
+                print " by $pkg->{'builder'}" if $pkg->{'builder'};
+                print ")\n";
+                next;
+            }
+        }
 
 
-               if ($op_mode eq "set-building") {
-                       add_one_building( $name, $version );
-               }
-               elsif ($op_mode eq "set-built") {
-                       add_one_built( $name, $version );
-               }
-               elsif ($op_mode eq "set-attempted") {
-                       add_one_attempted( $name, $version );
-               }
-               elsif ($op_mode eq "set-uploaded") {
-                       add_one_uploaded( $name, $version );
-               }
-               elsif ($op_mode eq "set-failed") {
-                       add_one_failed( $name, $version );
-               }
-               elsif ($op_mode eq "set-not-for-us") {
-                       add_one_notforus( $name, $version );
-               }
-               elsif ($op_mode eq "set-needs-build") {
-                       add_one_needsbuild( $name, $version );
-               }
-               elsif ($op_mode eq "set-dep-wait") {
-                       add_one_depwait( $name, $version );
-               }
-               elsif ($op_mode eq "set-build-priority") {
-                       set_one_buildpri( $name, $version, 'BuildPri' );
-               }
-               elsif ($op_mode eq "set-permanent-build-priority") {
-                       set_one_buildpri( $name, $version, 'PermBuildPri' );
-               }
-               elsif ($op_mode eq "set-binary-nmu") {
-                       set_one_binnmu( $name, $version );
-               }
-       }
+        if ($actions->{$op_mode} && $actions->{$op_mode}->{'from'}) {
+            if (!isin($pkg->{'state'}, @{$actions->{$op_mode}->{'from'}}, @{$actions->{$op_mode}->{'warnfrom'}})) {
+                print "$name: skiping: state is $pkg->{'state'}, not in ".join(", ",@{$actions->{$op_mode}->{'from'}}, @{$actions->{$op_mode}->{'warnfrom'}})."\n";
+                next;
+            }
+        }
+        if ($actions->{$op_mode} && $actions->{$op_mode}->{'warnfrom'}) {
+            if (isin($pkg->{'state'}, @{$actions->{$op_mode}->{'warnfrom'}})) {
+                print "$name: warning: state is $pkg->{'state'}, processing anyways.\n";
+            }
+        }
+
+        if ($op_mode eq "set-building") {
+            add_one_building( $name, $version, $pkg );
+        }
+        elsif ($op_mode eq "set-failed") {
+           print "$pkg->{'package'}: already registered as failed; will append new message\n" if $pkg->{'state'} eq "Failed";
+           $pkg->{'builder'} = $user;
+           $pkg->{'failed'} .= "\n" if $pkg->{'failed'};
+           $pkg->{'failed'} .= $fail_reason;
+        }
+        elsif ($op_mode eq "set-not-for-us") {
+            add_one_notforus( $pkg );
+        }
+        elsif ($op_mode eq "set-needs-build") {
+           my $state = $pkg->{'state'};
+
+           if ($state eq "BD-Uninstallable") {
+               if ($opt_override) {
+                       print "$name: Forcing uninstallability mark to be removed. This is not permanent and might be reset with the next trigger run\n";
+
+                       change_state( \$pkg, 'Needs-Build' );
+                       delete $pkg->{'builder'};
+                       delete $pkg->{'depends'};
+                       log_ta( $pkg, "--give-back" );
+                       update_source_info($pkg);
+                       print "$name: given back\n" if $verbose;
+                       next;
+               }
+               else {
+                       print "$name: has uninstallable build-dependencies. Skipping\n  (use --override to clear dependency list and give back anyway)\n";
+                       next;
+               }
+            }
+            elsif ($state eq "Dep-Wait") {
+               if ($opt_override) {
+                       print "$name: Forcing source dependency list to be cleared\n";
+               }
+               else {
+                       print "$name: waiting for source dependencies. Skipping\n  (use --override to clear dependency list and give back anyway)\n";
+                       next;
+               }
+            }
+            elsif (!isin( $state, qw(Building Built Build-Attempted))) {
+               print "$name: not taken for building (state is $state).";
+               if ($opt_override) {
+                       print "\n$name: Forcing give-back\n";
+               }
+               else {
+                       print " Skipping.\n";
+                       next;
+               }
+            }
+            $pkg->{'builder'} = undef;
+            $pkg->{'depends'} = undef;
+        }
+        elsif ($op_mode eq "set-dep-wait") {
+            add_one_depwait( $pkg );
+        }
+        elsif ($op_mode eq "set-build-priority") {
+            set_one_buildpri( 'buildpri', $pkg );
+        }
+        elsif ($op_mode eq "set-permanent-build-priority") {
+            set_one_buildpri( 'permbuildpri', $pkg );
+        }
+        elsif ($op_mode eq "set-binary-nmu") {
+            set_one_binnmu( $name, $version, $pkg );
+        }
+        elsif ($op_mode eq "set-update") {
+            $pkg->{'version'} =~ s/\+b[0-9]+$//;
+
+           log_ta( $pkg, "--update" );
+           update_source_info($pkg);
+        }
+
+        if ($actions->{$op_mode} && $actions->{$op_mode}->{'action'} && $actions->{$op_mode}->{'to'}) {
+           change_state( \$pkg, $actions->{$op_mode}->{'to'} );
+           log_ta( $pkg, "--".$actions->{$op_mode}->{'action'} );
+           update_source_info($pkg);
+           print "$name: registered as ".$actions->{$op_mode}->{'action'}."\n" if $verbose;
+        }
+    }
 }
 
 sub add_one_building {
 }
 
 sub add_one_building {
@@ -565,64 +611,61 @@ sub add_one_building {
        my( $ok, $reason );
 
        $ok = 1;
        my( $ok, $reason );
 
        $ok = 1;
-       my $pkg = $db{$name};
+       my $pkg = shift;
        if (defined($pkg)) {
        if (defined($pkg)) {
-               if ($pkg->{'State'} eq "Not-For-Us") {
-                       $ok = 0;
-                       $reason = "not suitable for this architecture";
-               }
-               elsif ($pkg->{'State'} =~ /^Dep-Wait/) {
+            my $pkgnack = {
+                'Not-For-Us' => 'not suitable for this architecture',
+                'Dep-Wait' => 'not all source dependencies available yet',
+                'BD-Uninstallable' => 'source dependencies are not installable',
+            };
+               if ($pkgnack->{$pkg->{'state'}}) {
                        $ok = 0;
                        $ok = 0;
-                       $reason = "not all source dependencies available yet";
+                       $reason = $pkgnack->{$pkg->{'state'}};
                }
                }
-               elsif ($pkg->{'State'} =~ /^BD-Uninstallable/) {
+               elsif ($pkg->{'state'} eq "Uploaded" &&
+                          (version_lesseq($version, $pkg->{'version'}))) {
                        $ok = 0;
                        $ok = 0;
-                       $reason = "source dependencies are not installable";
-               }
-               elsif ($pkg->{'State'} eq "Uploaded" &&
-                          (version_lesseq($version, $pkg->{'Version'}))) {
-                       $ok = 0;
-                       $reason = "already uploaded by $pkg->{'Builder'}";
-                       $reason .= " (in newer version $pkg->{'Version'})"
+                       $reason = "already uploaded by $pkg->{'builder'}";
+                       $reason .= " (in newer version $pkg->{'version'})"
                                if !version_eq($pkg, $version);
                }
                                if !version_eq($pkg, $version);
                }
-               elsif ($pkg->{'State'} eq "Installed" &&
-                          version_less($version,$pkg->{'Version'})) {
+               elsif ($pkg->{'state'} eq "Installed" &&
+                          version_less($version,$pkg->{'version'})) {
                        if ($opt_override) {
                        if ($opt_override) {
-                               print "$name: Warning: newer version $pkg->{'Version'} ".
+                               print "$name: Warning: newer version $pkg->{'version'} ".
                                          "already installed, but overridden.\n";
                        }
                        else {
                                $ok = 0;
                                          "already installed, but overridden.\n";
                        }
                        else {
                                $ok = 0;
-                               $reason = "newer version $pkg->{'Version'} already in ".
+                               $reason = "newer version $pkg->{'version'} already in ".
                                                  "archive; doesn't need rebuilding";
                                print "$name: Note: If the following is due to an epoch ",
                                          " change, use --override\n";
                        }
                }
                                                  "archive; doesn't need rebuilding";
                                print "$name: Note: If the following is due to an epoch ",
                                          " change, use --override\n";
                        }
                }
-               elsif ($pkg->{'State'} eq "Installed" &&
+               elsif ($pkg->{'state'} eq "Installed" &&
                           pkg_version_eq($pkg,$version)) {
                        $ok = 0;
                        $reason = "is up-to-date in the archive; doesn't need rebuilding";
                }
                           pkg_version_eq($pkg,$version)) {
                        $ok = 0;
                        $reason = "is up-to-date in the archive; doesn't need rebuilding";
                }
-               elsif ($pkg->{'State'} eq "Needs-Build" &&
-                          version_less($version,$pkg->{'Version'})) {
+               elsif ($pkg->{'state'} eq "Needs-Build" &&
+                          version_less($version,$pkg->{'version'})) {
                        if ($opt_override) {
                        if ($opt_override) {
-                               print "$name: Warning: newer version $pkg->{'Version'} ".
+                               print "$name: Warning: newer version $pkg->{'version'} ".
                                          "needs building, but overridden.";
                        }
                        else {
                                $ok = 0;
                                          "needs building, but overridden.";
                        }
                        else {
                                $ok = 0;
-                               $reason = "newer version $pkg->{'Version'} needs building, ".
+                               $reason = "newer version $pkg->{'version'} needs building, ".
                                                  "not $version";
                        }
                }
                                                  "not $version";
                        }
                }
-               elsif (isin($pkg->{'State'},qw(Building Built Build-Attempted))) {
-                       if (version_less($pkg->{'Version'},$version)) {
-                               print "$name: Warning: Older version $pkg->{'Version'} ",
-                                     "is being built by $pkg->{'Builder'}\n";
-                               if ($pkg->{'Builder'} ne $user) {
-                                       send_mail( $pkg->{'Builder'},
+               elsif (isin($pkg->{'state'},qw(Building Built Build-Attempted))) {
+                       if (version_less($pkg->{'version'},$version)) {
+                               print "$name: Warning: Older version $pkg->{'version'} ",
+                                     "is being built by $pkg->{'builder'}\n";
+                               if ($pkg->{'builder'} ne $user) {
+                                       send_mail( $pkg->{'builder'},
                                                           "package takeover in newer version",
                                                           "You are building package '$name' in ".
                                                           "version $version\n".
                                                           "package takeover in newer version",
                                                           "You are building package '$name' in ".
                                                           "version $version\n".
@@ -634,293 +677,107 @@ sub add_one_building {
                        }
                        else {
                                if ($opt_override) {
                        }
                        else {
                                if ($opt_override) {
-                                       print "User $pkg->{'Builder'} had already ",
+                                       print "User $pkg->{'builder'} had already ",
                                              "taken the following package,\n",
                                                  "but overriding this as you request:\n";
                                              "taken the following package,\n",
                                                  "but overriding this as you request:\n";
-                                       send_mail( $pkg->{'Builder'}, "package takeover",
+                                       send_mail( $pkg->{'builder'}, "package takeover",
                                                           "The package '$name' (version $version) that ".
                                                           "The package '$name' (version $version) that ".
-                                                          "was locked by you\n".
+                                                          "was taken by you\n".
                                                           "has been taken over by $user\n" );
                                }
                                                           "has been taken over by $user\n" );
                                }
-                               elsif ($pkg->{'Builder'} eq $user) {
+                               elsif ($pkg->{'builder'} eq $user) {
                                        print "$name: Note: already taken by you.\n";
                                        print "$name: ok\n" if $verbose;
                                        return;
                                }
                                else {
                                        $ok = 0;
                                        print "$name: Note: already taken by you.\n";
                                        print "$name: ok\n" if $verbose;
                                        return;
                                }
                                else {
                                        $ok = 0;
-                                       $reason = "already taken by $pkg->{'Builder'}";
-                                       $reason .= " (in newer version $pkg->{'Version'})"
-                                               if !version_eq($pkg->{'Version'}, $version);
+                                       $reason = "already taken by $pkg->{'builder'}";
+                                       $reason .= " (in newer version $pkg->{'version'})"
+                                               if !version_eq($pkg->{'version'}, $version);
                                }
                        }
                }
                                }
                        }
                }
-               elsif ($pkg->{'State'} =~ /^Failed/ &&
+               elsif ($pkg->{'state'} =~ /^Failed/ &&
                           pkg_version_eq($pkg, $version)) {
                        if ($opt_override) {
                                print "The following package previously failed ",
                           pkg_version_eq($pkg, $version)) {
                        if ($opt_override) {
                                print "The following package previously failed ",
-                                         "(by $pkg->{'Builder'})\n",
+                                         "(by $pkg->{'builder'})\n",
                                          "but overriding this as you request:\n";
                                          "but overriding this as you request:\n";
-                               send_mail( $pkg->{'Builder'}, "failed package takeover",
+                               send_mail( $pkg->{'builder'}, "failed package takeover",
                                                   "The package '$name' (version $version) that ".
                                                   "The package '$name' (version $version) that ".
-                                                  "is locked by you\n".
+                                                  "is taken by you\n".
                                                   "and has failed previously has been taken over ".
                                                   "by $user\n" )
                                                   "and has failed previously has been taken over ".
                                                   "by $user\n" )
-                                       if $pkg->{'Builder'} ne $user;
+                                       if $pkg->{'builder'} ne $user;
                        }
                        else {
                                $ok = 0;
                                $reason = "build of $version failed previously:\n    ";
                        }
                        else {
                                $ok = 0;
                                $reason = "build of $version failed previously:\n    ";
-                               $reason .= join( "\n    ", split( "\n", $pkg->{'Failed'} ));
+                               $reason .= join( "\n    ", split( "\n", $pkg->{'failed'} ));
                                $reason .= "\nalso the package doesn't need builing"
                                $reason .= "\nalso the package doesn't need builing"
-                                       if $pkg->{'State'} eq 'Failed-Removed';
+                                       if $pkg->{'state'} eq 'Failed-Removed';
                        }
                }
        }
        if ($ok) {
                        }
                }
        }
        if ($ok) {
+            if ($api < 1) {
                my $ok = 'ok';
                my $ok = 'ok';
-               if ($pkg->{'Binary-NMU-Version'}) {
-                       print "$name: Warning: needs binary NMU $pkg->{'Binary-NMU-Version'}\n" .
-                             "$pkg->{'Binary-NMU-Changelog'}\n";
+               if ($pkg->{'binary_nmu_version'}) {
+                       print "$name: Warning: needs binary NMU $pkg->{'binary_nmu_version'}\n" .
+                             "$pkg->{'binary_nmu_changelog'}\n";
                        $ok = 'aok';
                } else {
                        print "$name: Warning: Previous version failed!\n"
                        $ok = 'aok';
                } else {
                        print "$name: Warning: Previous version failed!\n"
-                               if $pkg->{'Previous-State'} =~ /^Failed/ ||
-                                  $pkg->{'State'} =~ /^Failed/;
+                               if $pkg->{'previous_state'} =~ /^Failed/ ||
+                                  $pkg->{'state'} =~ /^Failed/;
                }
                }
+               print "$name: $ok\n" if $verbose;
+            } else {
+                print  "- $name:\n";
+                print  "    - status: ok\n";
+                printf "    - pkg-ver: %s_%s\n", $name, $version;
+                print  "    - binNMU: $pkg->{'binary_nmu_version'}\n" if $pkg->{'binary_nmu_version'};
+                print  "    - extra-changelog: $pkg->{'binary_nmu_changelog'}\n" if $pkg->{'binary_nmu_changelog'} && $pkg->{'binary_nmu_version'};
+                print  "    - extra-depends: $pkg->{'extra_depends'}\n" if $pkg->{'extra_depends'};
+                print  "    - extra-conflicts: $pkg->{'extra_conflicts'}\n" if $pkg->{'extra_conflicts'};
+                print  "    - archive: $distributions{$distribution}->{'archive'}\n" if $distributions{$distribution}->{'archive'};
+                print  "    - build_dep_resolver: $distributions{$distribution}->{'build_dep_resolver'}\n" if $distributions{$distribution}->{'build_dep_resolver'};
+                print  "    - arch_all: $pkg->{'build_arch_all'}\n" if $pkg->{'build_arch_all'};
+                print  "    - suppress_successful_logs: $distributions{$distribution}->{'suppress_successful_logs'}\n" if $distributions{$distribution}->{'suppress_successful_logs'};
+            }
                change_state( \$pkg, 'Building' );
                change_state( \$pkg, 'Building' );
-               $pkg->{'Package'} = $name;
-               $pkg->{'Version'} = $version;
-               $pkg->{'Builder'} = $user;
+               $pkg->{'package'} = $name;
+               $pkg->{'version'} = $version;
+               $pkg->{'builder'} = $user;
                log_ta( $pkg, "--take" );
                log_ta( $pkg, "--take" );
-               $db{$name} = $pkg;
-               print "$name: $ok\n" if $verbose;
+               update_source_info($pkg);
        }
        else {
        }
        else {
+            if ($api < 1) {
                print "$name: NOT OK!\n  $reason\n";
                print "$name: NOT OK!\n  $reason\n";
+            } else {
+               print "- $name:\n    - status: not ok\n    - reason: \"$reason\"\n";
+            }
        }
 }
 
        }
 }
 
-sub add_one_attempted {
-       my $name = shift;
-       my $version = shift;
-       my $pkg = $db{$name};
-
-       if (!defined($pkg)) {
-               print "$name: not registered yet.\n";
-               return;
-       }
-
-       if ($pkg->{'State'} ne "Building" ) {
-               print "$name: not taken for building (state is $pkg->{'State'}). ",
-                         "Skipping.\n";
-               return;
-       }
-       if ($pkg->{'Builder'} ne $user) {
-               print "$name: not taken by you, but by $pkg->{'Builder'}. Skipping.\n";
-               return;
-       }
-       elsif ( !pkg_version_eq($pkg, $version) ) {
-               print "$name: version mismatch ".
-                         "$(pkg->{'Version'} ".
-                         "by $pkg->{'Builder'})\n";
-               return;
-       }
-
-       change_state( \$pkg, 'Build-Attempted' );
-       log_ta( $pkg, "--attempted" );
-       $db{$name} = $pkg;
-       print "$name: registered as uploaded\n" if $verbose;
-}
-
-sub add_one_built {
-       my $name = shift;
-       my $version = shift;
-       my $pkg = $db{$name};
-
-       if (!defined($pkg)) {
-               print "$name: not registered yet.\n";
-               return;
-       }
-
-       if ($pkg->{'State'} ne "Building" ) {
-               print "$name: not taken for building (state is $pkg->{'State'}). ",
-                         "Skipping.\n";
-               return;
-       }
-       if ($pkg->{'Builder'} ne $user) {
-               print "$name: not taken by you, but by $pkg->{'Builder'}. Skipping.\n";
-               return;
-       }
-       elsif ( !pkg_version_eq($pkg, $version) ) {
-               print "$name: version mismatch ".
-                         "$(pkg->{'Version'} ".
-                         "by $pkg->{'Builder'})\n";
-               return;
-       }
-       change_state( \$pkg, 'Built' );
-       log_ta( $pkg, "--built" );
-       $db{$name} = $pkg;
-       print "$name: registered as built\n" if $verbose;
-}
-
-sub add_one_uploaded {
-       my $name = shift;
-       my $version = shift;
-       my $pkg = $db{$name};
-
-       if (!defined($pkg)) {
-               print "$name: not registered yet.\n";
-               return;
-       }
-
-       if ($pkg->{'State'} eq "Uploaded" &&
-               pkg_version_eq($pkg,$version)) {
-               print "$name: already uploaded\n";
-               return;
-       }
-       if (!isin( $pkg->{'State'}, qw(Building Built Build-Attempted))) {
-               print "$name: not taken for building (state is $pkg->{'State'}). ",
-                         "Skipping.\n";
-               return;
-       }
-       if ($pkg->{'Builder'} ne $user) {
-               print "$name: not taken by you, but by $pkg->{'Builder'}. Skipping.\n";
-               return;
-       }
-       # strip epoch -- buildd-uploader used to go based on the filename.
-       # (to remove at some point)
-       my $pkgver;
-       ($pkgver = $pkg->{'Version'}) =~ s/^\d+://;
-       $version =~ s/^\d+://; # for command line use
-       if ($pkg->{'Binary-NMU-Version'} ) {
-               my $nmuver = binNMU_version($pkgver, $pkg->{'Binary-NMU-Version'});
-               if (!version_eq( $nmuver, $version )) {
-                       print "$name: version mismatch ($nmuver registered). ",
-                                 "Skipping.\n";
-                       return;
-               }
-       } elsif (!version_eq($pkgver, $version)) {
-               print "$name: version mismatch ($pkg->{'Version'} registered). ",
-                         "Skipping.\n";
-               return;
-       }
-
-       change_state( \$pkg, 'Uploaded' );
-       log_ta( $pkg, "--uploaded" );
-       $db{$name} = $pkg;
-       print "$name: registered as uploaded\n" if $verbose;
-}
-
-sub add_one_failed {
-       my $name = shift;
-       my $version = shift;
-       my ($state, $cat);
-       my $pkg = $db{$name};
-
-       if (!defined($pkg)) {
-               print "$name: not registered yet.\n";
-               return;
-       }
-       $state = $pkg->{'State'};
-
-       if ($state eq "Not-For-Us") {
-               print "$name: not suitable for this architecture anyway. Skipping.\n";
-               return;
-       }
-       elsif ($state eq "Failed-Removed") {
-               print "$name: failed previously and doesn't need building. Skipping.\n";
-               return;
-       }
-       elsif ($state eq "Installed") {
-               print "$name: Is already installed in archive. Skipping.\n";
-               return;
-       }
-       elsif ($pkg->{'Builder'} &&
-                  (($user ne $pkg->{'Builder'}) &&
-                   !($pkg->{'Builder'} =~ /^(\w+)-\w+/ && $1 eq $user))) {
-               print "$name: not taken by you, but by ".
-                         "$pkg->{'Builder'}. Skipping.\n";
-               return;
-       }
-       elsif ( !pkg_version_eq($pkg, $version) ) {
-               print "$name: version mismatch ".
-                         "$(pkg->{'Version'} ".
-                         "by $pkg->{'Builder'})\n";
-               return;
-       }
-
-       $cat = $category;
-       if (!$cat && $fail_reason =~ /^\[([^\]]+)\]/) {
-               $cat = $1;
-               $cat = $short_category{$cat} if exists $short_category{$cat};
-               if (!isin( $cat, values %short_category )) {
-                       print "$name: Warning: unknown category $cat; discarded\n";
-                       $cat = "";
-               }
-               $fail_reason =~ s/^\[[^\]]+\][ \t]*\n*//;
-       }
-
-       if ($state eq "Needs-Build") {
-               print "$name: Warning: not registered for building previously, ".
-                         "but processing anyway.\n";
-       }
-       elsif ($state eq "Uploaded") {
-               print "$name: Warning: marked as uploaded previously, ".
-                         "but processing anyway.\n";
-       }
-       elsif ($state eq "Dep-Wait") {
-               print "$name: Warning: marked as waiting for dependencies, ".
-                         "but processing anyway.\n";
-       }
-       elsif ($state eq "BD-Uninstallable") {
-               print "$name: Warning: marked as having uninstallable build-dependencies, ".
-                         "but processing anyway.\n";
-       }
-       elsif ($state eq "Failed") {
-               print "$name: already registered as failed; will append new message\n"
-                       if $fail_reason;
-               print "$name: already registered as failed; changing category\n"
-                       if $cat;
-       }
-
-       if (($cat eq "reminder-sent" || $cat eq "nmu-offered") &&
-               exists $pkg->{'Failed-Category'} &&
-               $pkg->{'Failed-Category'} ne $cat) {
-               (my $action = $cat) =~ s/-/ /;
-               $fail_reason .= "\n$short_date: $action";
-       }
-
-       change_state( \$pkg, 'Failed' );
-       $pkg->{'Builder'} = $user;
-       $pkg->{'Failed'} .= "\n" if $pkg->{'Failed'};
-       $pkg->{'Failed'} .= $fail_reason;
-       $pkg->{'Failed-Category'} = $cat if $cat;
-       if (defined $pkg->{'PermBuildPri'}) {
-               $pkg->{'BuildPri'} = $pkg->{'PermBuildPri'};
-       } else {
-               delete $pkg->{'BuildPri'};
-       }
-       log_ta( $pkg, "--failed" );
-       $db{$name} = $pkg;
-       print "$name: registered as failed\n" if $verbose;
-}
 
 sub add_one_notforus {
 
 sub add_one_notforus {
-       my $name = shift;
-       my $version = shift;
-       my $pkg = $db{$name};
+       my $pkg = shift;
+       my $state = $pkg->{'state'};
+        my $name = $pkg->{'package'};
 
 
-       if ($pkg->{'State'} eq 'Not-For-Us') {
+       if ($pkg->{'state'} eq 'Not-For-Us') {
                # reset Not-For-Us state in case it's called twice; this is
                # the only way to get a package out of this state...
                # There is no really good state in which such packages should
                # be put :-( So use Failed for now.
                change_state( \$pkg, 'Failed' );
                # reset Not-For-Us state in case it's called twice; this is
                # the only way to get a package out of this state...
                # There is no really good state in which such packages should
                # be put :-( So use Failed for now.
                change_state( \$pkg, 'Failed' );
-               $pkg->{'Package'} = $name;
-               $pkg->{'Failed'} = "Was Not-For-Us previously";
-               delete $pkg->{'Builder'};
-               delete $pkg->{'Depends'};
+               $pkg->{'package'} = $name;
+               $pkg->{'failed'} = "Was Not-For-Us previously";
+               delete $pkg->{'builder'};
+               delete $pkg->{'depends'};
                log_ta( $pkg, "--no-build(rev)" );
                print "$name: now not unsuitable anymore\n";
 
                log_ta( $pkg, "--no-build(rev)" );
                print "$name: now not unsuitable anymore\n";
 
@@ -935,12 +792,11 @@ sub add_one_notforus {
        }
        else {
                change_state( \$pkg, 'Not-For-Us' );
        }
        else {
                change_state( \$pkg, 'Not-For-Us' );
-               $pkg->{'Package'} = $name;
-               delete $pkg->{'Builder'};
-               delete $pkg->{'Depends'};
-               delete $pkg->{'BuildPri'};
-               delete $pkg->{'Binary-NMU-Version'};
-               delete $pkg->{'Binary-NMU-Changelog'};
+               $pkg->{'package'} = $name;
+               delete $pkg->{'builder'};
+               delete $pkg->{'depends'};
+               delete $pkg->{'binary_nmu_version'};
+               delete $pkg->{'binary_nmu_changelog'};
                log_ta( $pkg, "--no-build" );
                print "$name: registered as unsuitable\n" if $verbose;
 
                log_ta( $pkg, "--no-build" );
                print "$name: registered as unsuitable\n" if $verbose;
 
@@ -953,119 +809,35 @@ sub add_one_notforus {
                                   "the Not-For-Us state is wrong.\n" )
                        if $conf::notforus_maint;
        }
                                   "the Not-For-Us state is wrong.\n" )
                        if $conf::notforus_maint;
        }
-       $db{$name} = $pkg;
-}
-
-sub add_one_needsbuild {
-       my $name = shift;
-       my $version = shift;
-       my $state;
-       my $pkg = $db{$name};
-
-       if (!defined($pkg)) {
-               print "$name: not registered; can't give back.\n";
-               return;
-       }
-       $state = $pkg->{'State'};
-
-       if ($state eq "BD-Uninstallable") {
-               if ($opt_override) {
-                       print "$name: Forcing uninstallability mark to be removed. This is not permanent and might be reset with the next trigger run\n";
-
-                       change_state( \$pkg, 'Needs-Build' );
-                       delete $pkg->{'Builder'};
-                       delete $pkg->{'Depends'};
-                       log_ta( $pkg, "--give-back" );
-                       $db{$name} = $pkg;
-                       print "$name: given back\n" if $verbose;
-                       return;
-               }
-               else {
-                       print "$name: has uninstallable build-dependencies. Skipping\n",
-                                 "  (use --override to clear dependency list and ",
-                                 "give back anyway)\n";
-                       return;
-               }
-       }
-       elsif ($state eq "Dep-Wait") {
-               if ($opt_override) {
-                       print "$name: Forcing source dependency list to be cleared\n";
-               }
-               else {
-                       print "$name: waiting for source dependencies. Skipping\n",
-                                 "  (use --override to clear dependency list and ",
-                                 "give back anyway)\n";
-                       return;
-               }
-       }
-       elsif (!isin( $state, qw(Building Built Build-Attempted))) {
-               print "$name: not taken for building (state is $state).";
-               if ($opt_override) {
-                       print "\n$name: Forcing give-back\n";
-               }
-               else {
-                       print " Skipping.\n";
-                       return;
-               }
-       }
-       if (defined ($pkg->{'Builder'}) && $user ne $pkg->{'Builder'} &&
-                   !($pkg->{'Builder'} =~ /^(\w+)-\w+/ && $1 eq $user)) {
-               print "$name: not taken by you, but by ".
-                         "$pkg->{'Builder'}. Skipping.\n";
-               return;
-       }
-       if (!pkg_version_eq($pkg, $version)) {
-               print "$name: version mismatch ($pkg->{'Version'} registered). ",
-                         "Skipping.\n";
-               return;
-       }
-       change_state( \$pkg, 'BD-Uninstallable' );
-       $pkg->{'BD-Problem'} = "Installability of build dependencies not tested yet";
-       delete $pkg->{'Builder'};
-       delete $pkg->{'Depends'};
-       log_ta( $pkg, "--give-back" );
-       $db{$name} = $pkg;
-       print "$name: given back\n" if $verbose;
+       update_source_info($pkg);
 }
 
 sub set_one_binnmu {
        my $name = shift;
        my $version = shift;
 }
 
 sub set_one_binnmu {
        my $name = shift;
        my $version = shift;
-       my $pkg = $db{$name};
-       my $state;
-
-       if (!defined($pkg)) {
-               print "$name: not registered; can't register for binNMU.\n";
-               return;
-       }
-       my $db_ver = $pkg->{'Version'};
-
-       if (!version_eq($db_ver, $version)) {
-               print "$name: version mismatch ($db_ver registered). ",
-                         "Skipping.\n";
-               return;
-       }
-       $state = $pkg->{'State'};
+       my $pkg = shift;
+       my $state = $pkg->{'state'};
 
 
-       if (defined $pkg->{'Binary-NMU-Version'}) {
+       if (defined $pkg->{'binary_nmu_version'}) {
                if ($binNMUver == 0) {
                        change_state( \$pkg, 'Installed' );
                if ($binNMUver == 0) {
                        change_state( \$pkg, 'Installed' );
-                       delete $pkg->{'Builder'};
-                       delete $pkg->{'Depends'};
-                       delete $pkg->{'Binary-NMU-Version'};
-                       delete $pkg->{'Binary-NMU-Changelog'};
-               } elsif ($binNMUver <= $pkg->{'Binary-NMU-Version'}) {
-                       print "$name: already building binNMU $pkg->{'Binary-NMU-Version'}\n";
+                       delete $pkg->{'builder'};
+                       delete $pkg->{'depends'};
+                       delete $pkg->{'binary_nmu_version'};
+                       delete $pkg->{'binary_nmu_changelog'};
+                        delete $pkg->{'buildpri'};
+               } elsif ($binNMUver <= $pkg->{'binary_nmu_version'}) {
+                       print "$name: already building binNMU $pkg->{'binary_nmu_version'}\n";
                        return;
                } else {
                        return;
                } else {
-                       $pkg->{'Binary-NMU-Version'} = $binNMUver;
-                       $pkg->{'Binary-NMU-Changelog'} = $fail_reason;
-                       $pkg->{'Notes'} = 'out-of-date';
-                       $pkg->{'BuildPri'} = $pkg->{'PermBuildPri'}
-                               if (defined $pkg->{'PermBuildPri'});
+                       $pkg->{'binary_nmu_version'} = $binNMUver;
+                       $pkg->{'binary_nmu_changelog'} = $fail_reason;
+                       $pkg->{'notes'} = 'out-of-date';
+                        delete $pkg->{'buildpri'};
+                       change_state( \$pkg, 'BD-Uninstallable' );
                }
                log_ta( $pkg, "--binNMU" );
                }
                log_ta( $pkg, "--binNMU" );
-               $db{$name} = $pkg;
+               update_source_info($pkg);
                return;
        } elsif ($binNMUver == 0) {
                 print "${name}_$version: no scheduled binNMU to cancel.\n";
                return;
        } elsif ($binNMUver == 0) {
                 print "${name}_$version: no scheduled binNMU to cancel.\n";
@@ -1078,623 +850,69 @@ sub set_one_binnmu {
        }
 
        my $fullver = binNMU_version($version,$binNMUver);
        }
 
        my $fullver = binNMU_version($version,$binNMUver);
-       if ( version_lesseq( $fullver, $pkg->{'Installed-Version'} ) )
+       if ( version_lesseq( $fullver, $pkg->{'installed_version'} ) )
        {
        {
-               print "$name: binNMU $fullver is not newer than current version $pkg->{'Installed-Version'}\n";
+               print "$name: binNMU $fullver is not newer than current version $pkg->{'installed_version'}\n";
                return;
        }
 
        change_state( \$pkg, 'BD-Uninstallable' );
                return;
        }
 
        change_state( \$pkg, 'BD-Uninstallable' );
-       $pkg->{'BD-Problem'} = "Installability of build dependencies not tested yet";
-       delete $pkg->{'Builder'};
-       delete $pkg->{'Depends'};
-       $pkg->{'Binary-NMU-Version'} = $binNMUver;
-       $pkg->{'Binary-NMU-Changelog'} = $fail_reason;
-       $pkg->{'Notes'} = 'out-of-date';
+       delete $pkg->{'builder'};
+       delete $pkg->{'depends'};
+       $pkg->{'binary_nmu_version'} = $binNMUver;
+       $pkg->{'binary_nmu_changelog'} = $fail_reason;
+       $pkg->{'notes'} = 'out-of-date';
+        delete $pkg->{'buildpri'};
        log_ta( $pkg, "--binNMU" );
        log_ta( $pkg, "--binNMU" );
-       $db{$name} = $pkg;
+       update_source_info($pkg);
        print "${name}: registered for binNMU $fullver\n" if $verbose;
 }
 
 sub set_one_buildpri {
        print "${name}: registered for binNMU $fullver\n" if $verbose;
 }
 
 sub set_one_buildpri {
-       my $name = shift;
-       my $version = shift;
        my $key = shift;
        my $key = shift;
-       my $pkg = $db{$name};
-       my $state;
-
-       if (!defined($pkg)) {
-               print "$name: not registered; can't set priority.\n";
-               return;
-       }
-       $state = $pkg->{'State'};
+       my $pkg = shift;
+        my $name = $pkg->{'package'};
 
 
-       if ($state eq "Not-For-Us") {
-               print "$name: not suitable for this architecture. Skipping.\n";
-               return;
-       } elsif ($state eq "Failed-Removed") {
-               print "$name: failed previously and doesn't need building. Skipping.\n";
-               return;
-        }
-       if (!pkg_version_eq($pkg, $version)) {
-               print "$name: version mismatch ($pkg->{'Version'} registered). ",
-                         "Skipping.\n";
-               return;
-       }
-       if ( $build_priority == 0 ) {
-               delete $pkg->{'BuildPri'}
-                       if $key eq 'PermBuildPri' and defined $pkg->{'BuildPri'}
-                       and $pkg->{'BuildPri'} == $pkg->{$key};
-               delete $pkg->{$key};
-       } else {
-               $pkg->{'BuildPri'} = $build_priority
-                       if $key eq 'PermBuildPri';
+       if ( $build_priority ) {
                $pkg->{$key} = $build_priority;
                $pkg->{$key} = $build_priority;
+       } else {
+               delete $pkg->{$key};
        }
        }
-       $db{$name} = $pkg;
+       update_source_info($pkg);
        print "$name: set to build priority $build_priority\n" if $verbose;
 }
 
 sub add_one_depwait {
        print "$name: set to build priority $build_priority\n" if $verbose;
 }
 
 sub add_one_depwait {
-       my $name = shift;
-       my $version = shift;
-       my $state;
-       my $pkg = $db{$name};
-
-       if (!defined($pkg)) {
-               print "$name: not registered yet.\n";
-               return;
-       }
-       $state = $pkg->{'State'};
+       my $pkg = shift;
+       my $state = $pkg->{'state'};
+        my $name = $pkg->{'package'};
 
        if ($state eq "Dep-Wait") {
                print "$name: merging with previously registered dependencies\n";
        }
        
 
        if ($state eq "Dep-Wait") {
                print "$name: merging with previously registered dependencies\n";
        }
        
-       if (isin( $state, qw(Needs-Build Failed BD-Uninstallable))) {
-               print "$name: Warning: not registered for building previously, ".
-                         "but processing anyway.\n";
-       }
-       elsif ($state eq "Not-For-Us") {
-               print "$name: not suitable for this architecture anyway. Skipping.\n";
-               return;
-       }
-       elsif ($state eq "Failed-Removed") {
-               print "$name: failed previously and doesn't need building. Skipping.\n";
-               return;
-       }
-       elsif ($state eq "Installed") {
-               print "$name: Is already installed in archive. Skipping.\n";
-               return;
-       }
-       elsif ($state eq "Uploaded") {
-               print "$name: Is already uploaded. Skipping.\n";
-               return;
-       }
-       elsif ($pkg->{'Builder'} &&
-                  $user ne $pkg->{'Builder'}) {
-               print "$name: not taken by you, but by ".
-                         "$pkg->{'Builder'}. Skipping.\n";
-               return;
-       }
-       elsif ( !pkg_version_eq($pkg,$version)) {
-               print "$name: version mismatch ".
-                         "($pkg->{'Version'} ".
-                         "by $pkg->{'Builder'})\n";
-               return;
-       }
-       elsif ($fail_reason =~ /^\s*$/ ||
-                  !parse_deplist( $fail_reason, 1 )) {
-               print "$name: Bad dependency list\n";
-               return;
-       }
-       change_state( \$pkg, 'Dep-Wait' );
-       $pkg->{'Builder'} = $user;
-       if (defined $pkg->{'PermBuildPri'}) {
-               $pkg->{'BuildPri'} = $pkg->{'PermBuildPri'};
-       } else {
-               delete $pkg->{'BuildPri'};
-       }
-       my $deplist = parse_deplist( $pkg->{'Depends'} );
-       my $new_deplist = parse_deplist( $fail_reason );
-       # add new dependencies, maybe overwriting old entries
-       foreach (keys %$new_deplist) {
-               $deplist->{$_} = $new_deplist->{$_};
-       }
-       $pkg->{'Depends'} = build_deplist($deplist);
-       log_ta( $pkg, "--dep-wait" );
-       $db{$name} = $pkg;
-       print "$name: registered as waiting for dependencies\n" if $verbose;
-}
-
-
-sub parse_sources {
-       my %pkgs;
-       my %srcver;
-       my $name;
-       my $full = shift;
-
-       local($/) = ""; # read in paragraph mode
-       while( <> ) {
-               my( $version, $arch, $section, $priority, $builddep, $buildconf, $binaries );
-               s/\s*$//m;
-               /^Package:\s*(\S+)$/mi and $name = $1;
-               /^Version:\s*(\S+)$/mi and $version = $1;
-               /^Architecture:\s*(\S+)$/mi and $arch = $1;
-               /^Section:\s*(\S+)$/mi and $section = $1;
-               /^Priority:\s*(\S+)$/mi and $priority = $1;
-               /^Build-Depends:\s*(.*)$/mi and $builddep = $1;
-               /^Build-Conflicts:\s*(.*)$/mi and $buildconf = $1;
-                /^Binary:\s*(.*)$/mi and $binaries = $1;
-
-               next if (defined $srcver{$name} and version_less( $version, $srcver{$name} ));
-               $srcver{$name} = $version;
-
-               $pkgs{$name}{'ver'} = $version;
-               $pkgs{$name}{'bin'} = $binaries;
-               $pkgs{$name}{'dep'} = $builddep;
-               $pkgs{$name}{'conf'} = $buildconf;
-               my $pkg = $db{$name};
-
-               if (defined $pkg) {
-                       my $change = 0;
-
-                       if ($arch eq "all" && !version_less( $version, $pkg->{'Version'} )) {
-                               # package is now Arch: all, delete it from db
-                               change_state( \$pkg, 'deleted' );
-                               log_ta( $pkg, "--merge-sources" );
-                               print "$name ($pkg->{'Version'}): deleted ".
-                                         "from database, because now Arch: all\n"
-                                                 if $verbose;
-                               delete $db{$name};
-                               next;
-                       }
-
-                       # The "Version" should always be the source version --
-                       # not a possible binNMU version number.
-                       $pkg->{'Version'} = $version, $change++
-                               if ($pkg->{'State'} eq 'Installed' and
-                               !version_eq( $pkg->{'Version'}, $version));
-                       # Always update priority and section, if available
-                       $pkg->{'Priority'} = $priority, $change++
-                               if defined $priority and (not defined($pkg->{'Priority'}) or $pkg->{'Priority'} ne $priority);
-
-                       $pkg->{'Section'} = $section, $change++
-                               if defined $section and (not defined($pkg->{'Section'}) or $pkg->{'Section'} ne $section);
-
-                       # Remove field from previous wanna-build versions
-                       for (qw/Reason Build-Depends Build-Conflicts/) {
-                               if (exists $pkg->{$_}) {
-                                       delete $pkg->{$_};
-                                       $change++;
-                               }
-                       }
-
-                       $db{$name} = $pkg if $change;
-               }
-       }
-        # Now that we only have the latest source version, build the list
-        # of binary packages from the Sources point of view
-        foreach $name (keys %pkgs) {
-            foreach my $bin (split( /\s*,\s*/, $pkgs{$name}{'bin'} ) ) {
-                $merge_binsrc{$bin} = $name;
-            }
+       if (isin( $state, qw<Installed Not-For-Us>)) {
+            print "add_one_depwait: $name: skiping in state $state\n";
+            return;
         }
         }
-       # remove installed packages that no longer have source available
-       # or binaries installed
-       foreach $name (keys %db) {
-               next if $name =~ /^_/;
-               my $pkg = $db{$name};
-               if (not defined($pkgs{$name})) {
-                       change_state( \$pkg, 'deleted' );
-                       log_ta( $pkg, "--merge-sources" );
-                       print "$name ($pkg->{'Version'}): ".
-                                 "deleted from database, because ".
-                                 "not in Sources anymore\n"
-                                         if $verbose;
-                       delete $db{$name};
-               } else {
-                       next if !isin( $pkg->{'State'}, qw(Installed) );
-                       if ($full && not defined $merge_srcvers{$name}) {
-                            change_state( \$pkg, 'deleted' );
-                            log_ta( $pkg, "--merge-sources" );
-                            print "$name ($pkg->{'Version'}): ".
-                                      "deleted from database, because ".
-                                      "binaries don't exist anymore\n"
-                                              if $verbose;
-                            delete $db{$name};
-                        } elsif ($full && version_less( $merge_srcvers{$name}, $pkg->{'Version'})) {
-                            print "$name ($pkg->{'Version'}): ".
-                                      "package is Installed but binaries are from ".
-                                      $merge_srcvers{$name}. "\n"
-                                              if $verbose;
-                        }
-                }
-       }
-       return \%pkgs;
-}
-
-# This function looks through a Packages file and sets the state of
-# packages to 'Installed'
-sub parse_packages {
-       my $installed;
-
-       local($/) = ""; # read in paragraph mode
-       while( <> ) {
-               my( $name, $version, $depends, $source, $sourcev, $architecture, $provides, $binaryv, $binnmu );
-               s/\s*$//m;
-               /^Package:\s*(\S+)$/mi and $name = $1;
-               /^Version:\s*(\S+)$/mi and $version = $1;
-               /^Depends:\s*(.*)$/mi and $depends = $1;
-               /^Source:\s*(\S+)(\s*\((\S+)\))?$/mi and ($source,$sourcev) = ($1, $3);
-               /^Architecture:\s*(\S+)$/mi and $architecture = $1;
-               /^Provides:\s*(.*)$/mi and $provides = $1;
-               next if !$name || !$version;
-               next if ($arch ne $architecture and $architecture ne "all");
-               next if (defined ($installed->{$name}) and $installed->{$name}{'Version'} ne "" and
-                       version_lesseq( $version, $installed->{$name}{'Version'} ));
-               $installed->{$name}{'Version'} = $version;
-               $installed->{$name}{'Depends'} = $depends;
-               $installed->{$name}{'all'} = 1 if $architecture eq "all";
-               undef $installed->{$name}{'Provider'};
-               $installed->{$name}{'Source'} = $source ? $source : $name;
-               if ($provides) {
-                    foreach (split( /\s*,\s*/, $provides )) {
-                        if (not defined ($installed->{$_})) {
-                            $installed->{$_}{'Version'} = "";
-                            $installed->{$_}{'Provider'} = $name;
-                        }
-                    }
-               }
-               if ( $version =~ /\+b(\d+)$/ ) {
-                    $binnmu = $1;
-               }
-               $version = $sourcev if $sourcev;
-               $binaryv = $version;
-               $binaryv =~ s/\+b\d+$//;
-               $installed->{$name}{'Sourcev'} = $sourcev ? $sourcev : $binaryv;
-               $binaryv .= "+b$binnmu" if defined($binnmu);
-
-               next if $architecture ne $arch;
-               $name = $source if $source;
-               next if defined($merge_srcvers{$name}) and $merge_srcvers{$name} eq $version;
-               $merge_srcvers{$name} = $version;
-
-               my $pkg = $db{$name};
-
-               if (defined $pkg) {
-                       if (isin( $pkg->{'State'}, qw(Not-For-Us)) ||
-                               (isin($pkg->{'State'}, qw(Installed)) &&
-                                version_lesseq($binaryv, $pkg->{'Installed-Version'}))) {
-                               print "Skipping $name because State == $pkg->{'State'}\n"
-                                       if $verbose >= 2;
-                               next;
-                       }
-                       if ($pkg->{'Binary-NMU-Version'} ) {
-                               my $nmuver = binNMU_version($pkg->{'Version'}, $pkg->{'Binary-NMU-Version'});
-                               if (version_less( $binaryv, $nmuver )) {
-                                       print "Skipping $name ($version) because have newer ".
-                                               "version ($nmuver) in db.\n"
-                                                       if $verbose >= 2;
-                                       next;
-                               }
-                       } elsif (version_less($version, $pkg->{'Version'})) {
-                               print "Skipping $name ($version) because have newer ".
-                                       "version ($pkg->{'Version'}) in db.\n"
-                                               if $verbose >= 2;
-                               next;
-                       }
-
-                       if (!pkg_version_eq($pkg, $version) &&
-                          $pkg->{'State'} ne "Installed") {
-                               warn "Warning: $name: newer version than expected appeared ".
-                                        "in archive ($version vs. $pkg->{'Version'})\n";
-                               delete $pkg->{'Builder'};
-                       }
-
-                       if (!isin( $pkg->{'State'}, qw(Uploaded) )) {
-                               warn "Warning: Package $name was not in uploaded state ".
-                                        "before (but in '$pkg->{'State'}').\n";
-                               delete $pkg->{'Builder'};
-                               delete $pkg->{'Depends'};
-                       }
-               } else {
-                       $pkg = {};
-                       $pkg->{'Version'} = $version;
-               }
-               
-               change_state( \$pkg, 'Installed' );
-               $pkg->{'Package'} = $name;
-               $pkg->{'Installed-Version'} = $binaryv;
-               if (defined $pkg->{'PermBuildPri'}) {
-                       $pkg->{'BuildPri'} = $pkg->{'PermBuildPri'};
-               } else {
-                       delete $pkg->{'BuildPri'};
-               }
-               $pkg->{'Version'} = $version
-                       if version_less( $pkg->{'Version'}, $version);
-               delete $pkg->{'Binary-NMU-Version'};
-               delete $pkg->{'Binary-NMU-Changelog'};
-               log_ta( $pkg, "--merge-packages" );
-               $db{$name} = $pkg;
-               print "$name ($version) is up-to-date now.\n" if $verbose;
-       }
-
-       check_dep_wait( "--merge-packages", $installed );
-       return $installed;
-}
-
-sub pretend_avail {
-       my ($package, $name, $version, $installed);
-       
-       foreach $package (@_) {
-               $package =~ s,^.*/,,; # strip path
-               $package =~ s/\.(dsc|diff\.gz|tar\.gz|deb)$//; # strip extension
-               $package =~ s/_[\w\d]+\.changes$//; # strip extension
-               if ($package =~ /^([\w\d.+-]+)_([\w\d:.+~-]+)/) {
-                       ($name,$version) = ($1,$2);
-               }
-               else {
-                       warn "$package: can't extract package name and version ".
-                                "(bad format)\n";
-                       next;
-               }
-               $installed->{$name}{'Version'} = $version;
-       }
-
-       check_dep_wait( "--pretend-avail", $installed );
-}
-
-sub check_dep_wait {
-       my $action = shift;
-       my $installed = shift;
-       
-       # check all packages in state Dep-Wait if dependencies are all
-       # available now
-       my $name;
-       foreach $name (keys %db) {
-               next if $name =~ /^_/;
-               my $pkg = $db{$name};
-               next if $pkg->{'State'} ne "Dep-Wait";
-               my $deps = $pkg->{'Depends'};
-               if (!$deps) {
-                       print "$name: was in state Dep-Wait, but with empty ",
-                                 "dependencies!\n";
-                       goto make_needs_build;
-               }
-               my $deplist = parse_deplist($deps);
-               my $new_deplist;
-               my $allok = 1;
-               my @removed_deps;
-               foreach (keys %$deplist) {
-                       if (!exists $installed->{$_} ||
-                               ($deplist->{$_}->{'Rel'} && $deplist->{$_}->{'Version'} &&
-                                !version_compare( $installed->{$_}{'Version'},
-                                                                  $deplist->{$_}->{'Rel'},
-                                                                  $deplist->{$_}->{'Version'}))) {
-                               $allok = 0;
-                               $new_deplist->{$_} = $deplist->{$_};
-                       }
-                       else {
-                               push( @removed_deps, $_ );
-                       }
-               }
-               if ($allok) {
-                 make_needs_build:
-                       change_state( \$pkg, 'Needs-Build' );
-                       log_ta( $pkg, $action );
-                       delete $pkg->{'Builder'};
-                       delete $pkg->{'Depends'};
-                       print "$name ($pkg->{'Version'}) has all ",
-                                 "dependencies available now\n" if $verbose;
-                       $new_vers{$name}++;
-                       $db{$name} = $pkg;
-               }
-               elsif (@removed_deps) {
-                       $pkg->{'Depends'} = build_deplist( $new_deplist );
-                       print "$name ($pkg->{'Version'}): some dependencies ",
-                                 "(@removed_deps) available now, but not all yet\n"
-                               if $verbose;
-                       $db{$name} = $pkg;
-               }
-       }
-}
-
-# This function accepts quinn-diff output (either from a file named on
-# the command line, or on stdin) and sets the packages named there to
-# state 'Needs-Build'.
-sub parse_quinn_diff {
-       my $partial = shift;
-       my %quinn_pkgs;
-       my $dubious = "";
-       
-       while( <> ) {
-               my $change = 0;
-               next if !m,^([-\w\d/]*)/                        # section
-                              ([-\w\d.+]+)_                    # package name
-                                  ([\w\d:.~+-]+)\.dsc\s*       # version
-                                  \[([^:]*):                           # priority
-                                  ([^]]+)\]\s*$,x;                     # rest of notes
-               my($section,$name,$version,$priority,$notes) = ($1, $2, $3, $4, $5);
-               $quinn_pkgs{$name}++;
-               $section ||= "unknown";
-               $priority ||= "unknown";
-               $priority = "unknown" if $priority eq "-";
-               $priority = "standard" if ($name eq "debian-installer");
-
-               my $pkg = $db{$name};
-
-               # Always update section and priority.
-               if (defined($pkg)) {
-
-                       $pkg->{'Section'}  = $section, $change++ if not defined
-                               $pkg->{'Section'} or $section ne "unknown";
-                       $pkg->{'Priority'} = $priority, $change++ if not defined
-                               $pkg->{'Priority'} or $priority ne "unknown";
-               }
-
-               if (defined($pkg) &&
-                       $pkg->{'State'} =~ /^Dep-Wait/ &&
-                       version_less( $pkg->{'Version'}, $version )) {
-                       change_state( \$pkg, 'Dep-Wait' );
-                       $pkg->{'Version'}  = $version;
-                       delete $pkg->{'Binary-NMU-Version'};
-                       delete $pkg->{'Binary-NMU-Changelog'};
-                       log_ta( $pkg, "--merge-quinn" );
-                       $change++;
-                       print "$name ($version) still waiting for dependencies.\n"
-                               if $verbose;
-               }
-               elsif (defined($pkg) &&
-                          $pkg->{'State'} =~ /-Removed$/ &&
-                          version_eq($pkg->{'Version'}, $version)) {
-                       # reinstantiate a package that has been removed earlier
-                       # (probably due to a quinn-diff malfunction...)
-                       my $newstate = $pkg->{'State'};
-                       $newstate =~ s/-Removed$//;
-                       change_state( \$pkg, $newstate );
-                       $pkg->{'Version'}  = $version;
-                       $pkg->{'Notes'}    = $notes;
-                       log_ta( $pkg, "--merge-quinn" );
-                       $change++;
-                       print "$name ($version) reinstantiated to $newstate.\n"
-                               if $verbose;
-               }
-               elsif (defined($pkg) &&
-                          $pkg->{'State'} eq "Not-For-Us" &&
-                          version_less( $pkg->{'Version'}, $version )) {
-                       # for Not-For-Us packages just update the version etc., but
-                       # keep the state
-                       change_state( \$pkg, "Not-For-Us" );
-                       $pkg->{'Package'}  = $name;
-                       $pkg->{'Version'}  = $version;
-                       $pkg->{'Notes'}    = $notes;
-                       delete $pkg->{'Builder'};
-                       log_ta( $pkg, "--merge-quinn" );
-                       $change++;
-                       print "$name ($version) still Not-For-Us.\n" if $verbose;
-               }
-               elsif (!defined($pkg) ||
-                          $pkg->{'State'} ne "Not-For-Us" &&
-                          (version_less( $pkg->{'Version'}, $version ) ||
-                          ($pkg->{'State'} eq "Installed" && version_less($pkg->{'Installed-Version'}, $version)))) {
-
-                       if (defined( $pkg->{'State'} ) && isin( $pkg->{'State'}, qw(Building Built Build-Attempted))) {
-                               send_mail( $pkg->{'Builder'},
-                                                  "new version of $name (dist=$distribution)",
-                                                  "As far as I'm informed, you're currently ".
-                                                  "building the package $name\n".
-                                                  "in version $pkg->{'Version'}.\n\n".
-                                                  "Now there's a new source version $version. ".
-                                                  "If you haven't finished\n".
-                                                  "compiling $name yet, you can stop it to ".
-                                                  "save some work.\n".
-                                                  "Just to inform you...\n".
-                                                  "(This is an automated message)\n" );
-                               print "$name: new version ($version) while building ".
-                                         "$pkg->{'Version'} -- sending mail ".
-                                         "to builder ($pkg->{'Builder'})\n"
-                                 if $verbose;
-                       }
-                       change_state( \$pkg, 'Needs-Build' );
-                       $pkg->{'Package'}  = $name;
-                       $pkg->{'Version'}  = $version;
-                       $pkg->{'Section'}  = $section;
-                       $pkg->{'Priority'} = $priority;
-                       $pkg->{'Notes'}    = $notes;
-                       delete $pkg->{'Builder'};
-                       delete $pkg->{'Binary-NMU-Version'};
-                       delete $pkg->{'Binary-NMU-Changelog'};
-                       log_ta( $pkg, "--merge-quinn" );
-                       $new_vers{$name}++;
-                       $change++;
-                       print "$name ($version) needs rebuilding now.\n" if $verbose;
-               }
-               elsif (defined($pkg) &&
-                          !version_eq( $pkg->{'Version'}, $version ) &&
-                          isin( $pkg->{'State'}, qw(Installed Not-For-Us) )) {
-                       print "$name: skipping because version in db ".
-                                 "($pkg->{'Version'}) is >> than ".
-                                 "what quinn-diff says ($version) ".
-                                 "(state is $pkg->{'State'})\n"
-                                         if $verbose;
-                       $dubious .= "$pkg->{'State'}: ".
-                                               "db ${name}_$pkg->{'Version'} >> ".
-                                               "quinn $version\n" if !$partial;
-               }
-               elsif ($verbose >= 2) {
-                       if ($pkg->{'State'} eq "Not-For-Us") {
-                               print "Skipping $name because State == ".
-                                         "$pkg->{'State'}\n";
-                       }
-                       elsif (!version_less($pkg->{'Version'}, $version)) {
-                               print "Skipping $name because version in db ".
-                                         "($pkg->{'Version'}) is >= than ".
-                                         "what quinn-diff says ($version)\n";
-                       }
-               }
-               $db{$name} = $pkg if $change;
-       }
-
-       if ($dubious) {
-               send_mail( $conf::db_maint,
-                                  "Dubious versions in $distribution $conf::dbbase database",
-                                  "The following packages have a newer version in the ".
-                                  "wanna-build database\n".
-                                  "than what quinn-diff says, and this is strange for ".
-                                  "their state\n".
-                                  "It could be caused by a lame mirror, or the version ".
-                                  "in the database\n".
-                                  "is wrong.\n\n".
-                                  $dubious );
-       }
-
-       # Now re-check the DB for packages in states Needs-Build, Failed,
-       # Dep-Wait or BD-Uninstallable and remove them if they're not listed
-       # anymore by quinn-diff.
-       if ( !$partial ) {
-               my $name;
-               foreach $name (keys %db) {
-                       next if $name =~ /^_/;
-                       my $pkg = $db{$name};
-                       next if defined $pkg->{'Binary-NMU-Version'};
-                       next if !isin( $pkg->{'State'},
-                                                  qw(Needs-Build Building Built Build-Attempted Uploaded Failed Dep-Wait BD-Uninstallable) );
-                       my $virtual_delete = $pkg->{'State'} eq 'Failed';
-                                                                
-                       if (!$quinn_pkgs{$name}) {
-                               change_state( \$pkg, $virtual_delete ?
-                                                         $pkg->{'State'}."-Removed" :
-                                                         'deleted' );
-                               log_ta( $pkg, "--merge-quinn" );
-                               print "$name ($pkg->{'Version'}): ".
-                                         ($virtual_delete ? "(virtually) " : "") . "deleted ".
-                                         "from database, because not in quinn-diff anymore\n"
-                                                 if $verbose;
-                               if ($virtual_delete) {
-                                   $db{$name} = $pkg;
-                               } else {
-                                   delete $db{$name};
-                               }
-                       }
-               }
+        
+       if ($fail_reason =~ /^\s*$/ ||
+                  !parse_deplist( $fail_reason, 1 )) {
+               print "$name: Bad dependency list\n";
+               return;
        }
        }
-}
-
-sub send_reupload_mail {
-       my $to = shift;
-       my $pkg = shift;
-       my $version = shift;
-       my $dist = shift;
-       my $other_dist = shift;
-
-       send_mail( $to,
-                          "Please reupload ${pkg}_${'Version'} for $dist",
-                          "You have recently built (or are currently building)\n".
-                          "${pkg}_${'Version'} for $other_dist.\n".
-                          "This version is now also needed in the $dist distribution.\n".
-                          "Please reupload the files now present in the Debian archive\n".
-                          "(best with buildd-reupload).\n" );
+       change_state( \$pkg, 'Dep-Wait' );
+       $pkg->{'builder'} = $user;
+       my $deplist = parse_deplist( $pkg->{'depends'} );
+       my $new_deplist = parse_deplist( $fail_reason );
+       # add new dependencies, maybe overwriting old entries
+       foreach (keys %$new_deplist) {
+               $deplist->{$_} = $new_deplist->{$_};
+       }
+       $pkg->{'depends'} = build_deplist($deplist);
+       log_ta( $pkg, "--dep-wait" ) unless $simulate;
+       update_source_info($pkg) unless $simulate;
+       print "$name: registered as waiting for dependencies\n" if $verbose || $simulate;
 }
 
 
 }
 
 
@@ -1767,196 +985,332 @@ BEGIN {
        }
        $sectval{'unknown'}     = -165;
 
        }
        $sectval{'unknown'}     = -165;
 
-       %catval =  ( "none"                           => -20,
-                                "uploaded-fixed-pkg" => -19,
-                                "fix-expected"       => -18,
-                                "reminder-sent"      => -17,
-                                "nmu-offered"        => -16,
-                                "easy"               => -15,
-                                "medium"                     => -14,
-                                "hard"                   => -13,
-                                "compiler-error"     => -12 );
 }
 
 sub sort_list_func {
 }
 
 sub sort_list_func {
-       my( $letter, $x, $ax, $bx );
-
-       foreach $letter (split( "", $list_order )) {
-         SWITCH: foreach ($letter) {
-                 /P/ && do {
-                       $x = $b->{'BuildPri'} <=> $a->{'BuildPri'};
-                       return $x if $x != 0;
-                       last SWITCH;
-                 };
-                 /p/ && do {
-                         $x = $prioval{$a->{'Priority'}} <=> $prioval{$b->{'Priority'}};
-                         return $x if $x != 0;
-                         last SWITCH;
-                 };
-                 /s/ && do {
-                         $x = $sectval{$a->{'Section'}} <=> $sectval{$b->{'Section'}};
-                         return $x if $x != 0;
-                         last SWITCH;
-                 };
-                 /n/ && do {
-                         $x = $a->{'Package'} cmp $b->{'Package'};
-                         return $x if $x != 0;
-                         last SWITCH;
-                 };
-                 /b/ && do {
-                         $x = $a->{'Builder'} cmp $b->{'Builder'};
-                         return $x if $x != 0;
-                         last SWITCH;
-                 };
-                 /c/ && do {
-                         $ax = ($a->{'Notes'} =~ /^(out-of-date|partial)/) ? 0 :
-                                   ($a->{'Notes'} =~ /^uncompiled/) ? 2 : 1;
-                         $bx = ($b->{'Notes'} =~ /^(out-of-date|partial)/) ? 0 :
-                                   ($b->{'Notes'} =~ /^uncompiled/) ? 2 : 1;
-                         $x = $ax <=> $bx;
-                         return $x if $x != 0;
-                         last SWITCH;
-                 };
-                 /f/ && do {
-                         my $ca = exists $a->{'Failed-Category'} ?
-                                 $a->{'Failed-Category'} : "none";
-                         my $cb = exists $b->{'Failed-Category'} ?
-                                 $b->{'Failed-Category'} : "none";
-                         $x = $catval{$ca} <=> $catval{$cb};
-                         return $x if $x != 0;
-                         last SWITCH;
-                 };
-                 /S/ && do {
-                         my $pa = $prioval{$a->{'Priority'}} >
-                                 $prioval{'standard'};
-                         my $pb = $prioval{$b->{'Priority'}} >
-                                 $prioval{'standard'};
-                         $x = $pa <=> $pb;
-                         return $x if $x != 0;
-                         last SWITCH;
-                 };
-         }
+    my $map_funcs = {
+        'C' => ['<->', sub { return $_[0]->{'calprio'}; }],
+        'W' => ['<->', sub { return $_[0]->{'state_days'}; }],
+        'P' => ['<->', sub { return ($_[0]->{'buildpri'}//0) + ($_[0]->{'permbuildpri'}//0); }],
+        'p' => ['<=>', sub { return $prioval{$_[0]->{'priority'}//""}//0; }],
+        's' => ['<=>', sub { return $sectval{$_[0]->{'section'}//""}//0; }],
+        'n' => ['cmp', sub { return $_[0]->{'package'}; }],
+        'b' => ['cmp', sub { return $_[0]->{'builder'}; }],
+        'c' => ['<=>', sub { return ($_[0]->{'notes'}//"" =~ /^(out-of-date|partial)/) ? 0: ($_[0]->{'notes'}//"" =~ /^uncompiled/) ? 2 : 1; }],
+        'S' => ['<->', sub { return isin($_[0]->{'priority'}, qw(required important standard)); }],
+        'T' => ['<->', sub { return $_[0]->{'state_time'} % 86400;} ], # Fractions of a day
+    };
+
+       foreach my $letter (split( //, $list_order )) {
+            my $r;
+            $r = (&{$map_funcs->{$letter}[1]}($b)//0 ) <=> (&{$map_funcs->{$letter}[1]}($a)//0 ) if $map_funcs->{$letter}[0] eq '<->';
+            $r = (&{$map_funcs->{$letter}[1]}($a)//0 ) <=> (&{$map_funcs->{$letter}[1]}($b)//0 ) if $map_funcs->{$letter}[0] eq '<=>';
+            $r = (&{$map_funcs->{$letter}[1]}($a)//"") cmp (&{$map_funcs->{$letter}[1]}($b)//"") if $map_funcs->{$letter}[0] eq 'cmp';
+            return $r if $r != 0;
        }
        return 0;
 }
 
        }
        return 0;
 }
 
+sub calculate_prio {
+       my $priomap = $yamlmap->{priority};
+       my $pkg = shift;
+        my @s=split("/", $pkg->{'section'}//"");
+        $pkg->{'component'} = $s[0] if $s[1];
+        $pkg->{'component'} ||= 'main';
+       $pkg->{'calprio'} = 0;
+       foreach my $k (keys %{$priomap->{keys}}) {
+               $pkg->{'calprio'} += $priomap->{keys}->{$k}{$pkg->{$k}} if $pkg->{$k} and $priomap->{keys}->{$k}{$pkg->{$k}};
+       }
+
+       my $days = $pkg->{'state_days'};
+       $days = $priomap->{'waitingdays'}->{'min'} if $priomap->{'waitingdays'}->{'min'} and $days < $priomap->{'waitingdays'}->{'min'};
+       $days = $priomap->{'waitingdays'}->{'max'} if $priomap->{'waitingdays'}->{'max'} and $days > $priomap->{'waitingdays'}->{'max'};
+       my $scale = $priomap->{'waitingdays'}->{'scale'} || 1;
+       $pkg->{'calprio'} += $days * $scale;
+
+        my $btime = max($pkg->{'anytime'}//0, $pkg->{'successtime'}//0);
+        my $bhours = $btime ? int($btime/3600) : ($priomap->{'buildhours'}->{'default'} || 2);
+       $bhours = $priomap->{'buildhours'}->{'min'} if $priomap->{'buildhours'}->{'min'} and $bhours < $priomap->{'buildhours'}->{'min'};
+       $bhours = $priomap->{'buildhours'}->{'max'} if $priomap->{'buildhours'}->{'max'} and $bhours > $priomap->{'buildhours'}->{'max'};
+       $scale = $priomap->{'buildhours'}->{'scale'} || 1;
+        $pkg->{'calprio'} -= $bhours * $scale;
+
+       $pkg->{'calprio'} += $pkg->{'permbuildpri'} if  $pkg->{'permbuildpri'};
+       $pkg->{'calprio'} += $pkg->{'buildpri'} if  $pkg->{'buildpri'};
+
+       return $pkg;
+}
+
+
+sub seconds2time {
+    my $t = shift;
+    return "" unless $t;
+    my $sec = $t % 60;
+    my $min = int($t/60) % 60;
+    my $hours = int($t / 3600);
+    return sprintf("%d:%02d:%02d", $hours, $min, $sec) if $hours;
+    return sprintf("%d:%02d", $min, $sec);
+}
+
+
+sub use_fmt {
+    my $r;
+
+    if (ref($_[0]) eq 'CODE') {
+        $r = &{$_[0]};
+    } else {
+        $r = $_[0];
+    }
+
+    shift;
+    my $t = shift;
+
+    $r ||= "";
+    return $r unless $t;
+
+    my $pkg = shift;
+    my $var = shift;
+    if (substr($t,0,1) eq '!') {
+        $t = substr($t,1);
+        return "" if $r;
+    } else {
+        return "" unless $r;
+    }
+    if ($t =~ /%/) {
+        return print_format($t, $pkg, $var);
+    }
+    return $t;
+}
+sub make_fmt { my $c = shift; my $pkg = shift; my $var = shift; return sub { use_fmt($c, $_[0], $pkg, $var); } };
+
+sub print_format {
+    my $printfmt = shift;
+    my $pkg = shift;
+    my $var = shift;
+
+=pod
+
+Within an format string, the following values are allowed (need to be preceded by %).
+This can be combined to e.g.
+wanna-build --format='wanna-build -A %a --give-back %p_%v' -A mipsel --list=failed
+
+a Architecture
+c section (e.g. libs or utils)
+D in case of BD-Uninstallable the reason for the uninstallability
+d distribution
+E in case of Dep-Wait the packages being waited on, in case of Needs-Build the number in the queue
+F in case of Failed the fail reason
+n newline
+o time of last successful build (seconds)
+O time of last successful build (formated)
+P previous state
+p Package name
+q time of last build (seconds)
+Q time of last build (formated)
+r max time of last (successful) build (seconds)
+R max time of last (successful) build (formated)
+S Package state
+s Time in this state in full seconds since epoch
+t time of state change
+T time since state change
+u Builder (e.g. buildd_mipsel-rem)
+v Package version
+V full Package version (i.e. with +b.., = %v%{+b}B%B
+X the string normally between [], e.g. optional:out-of-date:calprio{61}:days{25}
+
+%{Text}?  print Text in case ? is not empty; ? is never printed
+%{!Text}? print Text in case ? is empty; ? is never printed
+Text could contain further %. To start with !, use %!
+
+=cut
+
+    return stringf($printfmt, (
+        'p' => make_fmt( $pkg->{'package'}, $pkg, $var),
+        'a' => make_fmt( $arch, $pkg, $var),
+        's' => make_fmt( sub { return floor(str2time($pkg->{'state_change'})); }, $pkg, $var),
+        'v' => make_fmt( $pkg->{'version'}, $pkg, $var),
+        'V' => make_fmt( sub { $pkg->{'binary_nmu_version'} ? $pkg->{'version'}."+b".$pkg->{'binary_nmu_version'} : $pkg->{'version'} }, $pkg, $var),
+        'S' => make_fmt( $pkg->{'state'}, $pkg, $var),
+        'u' => make_fmt( $pkg->{'builder'}, $pkg, $var),
+        'X' => make_fmt( sub {
+            no warnings;
+            my $c = "$pkg->{'priority'}:$pkg->{'notes'}";
+            $c .= ":PREV-FAILED" if $pkg->{'previous_state'} && $pkg->{'previous_state'} =~ /^Failed/;
+            $c .= ":bp{" . (($pkg->{'buildpri'}//0)+($pkg->{'permbuildpri'}//0)) . "}" if (($pkg->{'buildpri'}//0)+($pkg->{'permbuildpri'}//0));
+            $c .= ":binNMU{" . $pkg->{'binary_nmu_version'} . "}" if defined $pkg->{'binary_nmu_version'};
+            $c .= ":calprio{". $pkg->{'calprio'}."}";
+            $c .= ":days{". $pkg->{'state_days'}."}";
+            return $c;
+            }, $pkg, $var),
+        'c' => make_fmt( $pkg->{'section'}, $pkg, $var),
+        'P' => make_fmt( $pkg->{'previous_state'} || "unknwon", $pkg, $var),
+        'E' => make_fmt( sub { return $pkg->{'depends'} if $pkg->{'state'} eq "Dep-Wait";
+            return $var->{scnt}{'Needs-Build'} + 1 if $pkg->{'state'} eq 'Needs-Build';
+            return ""; }, $pkg, $var),
+       'F' => make_fmt( sub { return "" unless $pkg->{'failed'};
+           my $failed = $pkg->{'failed'};
+           $failed =~ s/\\/\\\\/g;
+            return $pkg->{'package'}."#".$arch."-failure\n ".
+           join("\\0a",split("\n",$failed))."\\0a\n"; }, $pkg, $var),
+        'D' => make_fmt( sub { return "" unless $pkg->{'bd_problem'};
+            return $pkg->{'package'}."#".$arch."-bd-problem\n".
+            join("\\0a",split("\n",$pkg->{'bd_problem'}))."\\0a\n"; }, $pkg, $var),
+        'B' => make_fmt( sub { return $pkg->{'binary_nmu_version'} if defined $pkg->{'binary_nmu_version'}; }, $pkg, $var),
+        'd' => make_fmt( $pkg->{'distribution'}, $pkg, $var),
+        't' => make_fmt( $pkg->{'state_change'}, $pkg, $var),
+        'T' => make_fmt( sub { return seconds2time(time() - floor(str2time($pkg->{'state_change'}))); }, $pkg, $var),
+        'o' => make_fmt( $pkg->{'successtime'}, $pkg, $var),
+        'O' => make_fmt( sub { return seconds2time ( $pkg->{'successtime'}); }, $pkg, $var),
+        'q' => make_fmt( $pkg->{'anytime'}, $pkg, $var),
+        'Q' => make_fmt( sub { return seconds2time ( $pkg->{'anytime'}); }, $pkg, $var),
+        'r' => make_fmt( sub { my $c = max($pkg->{'successtime'}//0, $pkg->{'anytime'}//0); return $c if $c; return; }, $pkg, $var),
+        'R' => make_fmt( sub { return seconds2time ( max($pkg->{'successtime'}//0, $pkg->{'anytime'}//0)); }, $pkg, $var),
+    ));
+}
+
 sub list_packages {
        my $state = shift;
 sub list_packages {
        my $state = shift;
-       my( $name, $pkg, @list );
+       my @list;
        my $cnt = 0;
        my %scnt;
        my $ctime = time;
 
        my $cnt = 0;
        my %scnt;
        my $ctime = time;
 
-       foreach $name (keys %db) {
-               next if $name =~ /^_/;
-               $pkg = $db{$name};
-               next if $state ne "all" && $pkg->{'State'} !~ /^\Q$state\E$/i;
-               next if $user && (lc($state) ne 'needs-build' and $pkg->{'Builder'} ne $user);
-               next if $category && $pkg->{'State'} eq "Failed" &&
-                               $pkg->{'Failed-Category'} ne $category;
-               next if ($list_min_age > 0 &&
-                                ($ctime-parse_date($pkg->{'State-Change'})) < $list_min_age)||
-                               ($list_min_age < 0 &&
-                                ($ctime-parse_date($pkg->{'State-Change'})) > -$list_min_age);
-               push( @list, $pkg );
+       my $db = get_all_source_info(state => $state, user => $user, list_min_age => $list_min_age, multisuite => 1);
+       foreach my $key (keys %$db) {
+               next if $key =~ /^_/;
+               push @list, calculate_prio($db->{$key});
        }
 
        }
 
-       foreach $pkg (sort sort_list_func @list) {
-               print "$pkg->{'Section'}/$pkg->{'Package'}_$pkg->{'Version'}";
-               print ": $pkg->{'State'}"
+        # filter components
+        @list = grep { my $i = $_->{'component'}; grep { $i eq $_ } split /[, ]+/, $yamlmap->{"restrict"}{'component'} } @list;
+        # extra depends / conflicts only from api 1 on
+        @list = grep { !$_->{'extra_depends'} and !$_->{'extra_conflicts'} } @list if $api < 1 ;
+        # filter out packages for needs-build in noautobuild state - same could exist for weaknoautobuild if buildds would tell us what they do
+        if (($state eq 'needs-build') && ($yamlmap->{"restrict"}) && ($yamlmap->{"restrict"}{"noautobuild"})) {
+            foreach my $key (map {keys %$_} @{$yamlmap->{"restrict"}{"noautobuild"}}) {
+                @list = grep { $_->{'package'} ne $key } @list;
+            }
+        }
+
+        # first adjust ownprintformat, then set printformat accordingly
+        $printformat ||= $yamlmap->{"format"}{$ownprintformat} if $ownprintformat;
+        $printformat ||= $yamlmap->{"format"}{"default"}{$state};
+        $printformat ||= $yamlmap->{"format"}{"default"}{"default"};
+        undef $printformat if ($ownprintformat && $ownprintformat eq 'none');
+
+       foreach my $pkg (sort sort_list_func @list) {
+                no warnings;
+                if ($printformat) {
+                    print print_format($printformat, $pkg, {'cnt' => $cnt, 'scnt' => \%scnt})."\n";
+                   ++$cnt;
+                   $scnt{$pkg->{'state'}}++;
+                    next;
+                }
+               print print_format("%c/%p_%v", $pkg, {});
+               print print_format(": %S", $pkg, {})
                        if $state eq "all";
                        if $state eq "all";
-               print " by $pkg->{'Builder'}"
-                       if $pkg->{'State'} ne "Needs-Build" && $pkg->{'Builder'};
-               print " [$pkg->{'Priority'}:$pkg->{'Notes'}";
-               print ":PREV-FAILED"
-                       if $pkg->{'Previous-State'} =~ /^Failed/;
-               print ":bp{" . $pkg->{'BuildPri'} . "}"
-                       if exists $pkg->{'BuildPri'};
-               print ":binNMU{" . $pkg->{'Binary-NMU-Version'} . "}"
-                       if exists $pkg->{'Binary-NMU-Version'};
-               print "]\n";
+               print print_format("%{ by }u%u", $pkg, {})
+                       if $pkg->{'state'} ne "Needs-Build";
+               print print_format(" [%X]\n", $pkg, {});
                print "  Reasons for failing:\n",
                print "  Reasons for failing:\n",
-                         "    [Category: ",
-                         exists $pkg->{'Failed-Category'} ? $pkg->{'Failed-Category'} : "none",
-                         "]\n    ",
-                         join("\n    ",split("\n",$pkg->{'Failed'})), "\n"
-                       if $pkg->{'State'} =~ /^Failed/;
-               print "  Dependencies: $pkg->{'Depends'}\n"
-                       if $pkg->{'State'} eq "Dep-Wait";
-               print "  Reason: $pkg->{'BD-Problem'}\n"
-                       if $pkg->{'State'} eq "BD-Uninstallable";
-               print "  Previous state was $pkg->{'Previous-State'} until ",
-                         "$pkg->{'State-Change'}\n"
-                       if $verbose && $pkg->{'Previous-State'};
+                         join("\n    ",split("\n",$pkg->{'failed'})), "\n"
+                       if $pkg->{'state'} =~ /^Failed/;
+               print "  Dependencies: $pkg->{'depends'}\n"
+                       if $pkg->{'state'} eq "Dep-Wait";
+               print "  Reasons for BD-Uninstallable:\n    ",
+                         join("\n    ",split("\n",$pkg->{'bd_problem'})), "\n"
+                       if $pkg->{'state'} eq "BD-Uninstallable";
+               print "  Previous state was $pkg->{'previous_state'}\n"
+                       if $verbose && $pkg->{'previous_state'};
+               print "  No previous state recorded\n"
+                       if $verbose && !$pkg->{'previous_state'};
+               print "  State changed at $pkg->{'state_change'}\n"
+                       if $verbose && $pkg->{'state_change'};
+               print "  Previous state $pkg->{'previous_state'} left $pkg->{'state_time'} ago\n"
+                       if $verbose && $pkg->{'previous_state'};
                print "  Previous failing reasons:\n    ",
                print "  Previous failing reasons:\n    ",
-                     join("\n    ",split("\n",$pkg->{'Old-Failed'})), "\n"
-                       if $verbose && $pkg->{'Old-Failed'};
+                     join("\n    ",split("\n",$pkg->{'old_failed'})), "\n"
+                       if $verbose && $pkg->{'old_failed'};
                ++$cnt;
                ++$cnt;
-               $scnt{$pkg->{'State'}}++ if $state eq "all";
+               $scnt{$pkg->{'state'}}++ if $state eq "all";
        }
        }
-       if ($state eq "all") {
+       if ($state eq "all" && !$printformat) {
                foreach (sort keys %scnt) {
                        print "Total $scnt{$_} package(s) in state $_.\n";
                }
        }
                foreach (sort keys %scnt) {
                        print "Total $scnt{$_} package(s) in state $_.\n";
                }
        }
-       print "Total $cnt package(s)\n";
+       print "Total $cnt package(s)\n" unless $printformat;
        
 }
 
 sub info_packages {
        my( $name, $pkg, $key, $dist );
        
 }
 
 sub info_packages {
        my( $name, $pkg, $key, $dist );
-       my @firstkeys = qw(Package Version Builder State Section Priority
-                                          Installed-Version Previous-State State-Change);
-       my @dists = $info_all_dists ? keys %conf::distributions : ($distribution);
+       my @firstkeys = qw(package version builder state section priority
+                                          installed_version previous_state state_change);
+       my @dists = $info_all_dists ? keys %distributions : ($distribution);
+       my %beautykeys = ( 'package' => 'Package', 'version' => 'Version', 'builder' => 'Builder',
+               'state' => 'State', 'section' => 'Section', 'priority' => 'Priority',
+               'installed_version' => 'Installed-Version', 'previous_state' => 'Previous-State',
+               'state_change' => 'State-Change',
+               'bd_problem' => 'BD-Problem', 
+               'binary_nmu_changelog' => 'Binary-NMU-Changelog', 'binary_nmu_version' => 'Binary-NMU-Version',
+               'buildpri' => 'BuildPri', 'depends' => 'Depends', 'failed' => 'Failed',
+               'notes' => 'Notes',
+               'distribution' => 'Distribution', 'old_failed' => 'Old-Failed',
+               'permbuildpri' => 'PermBuildPri', 'rel' => 'Rel',
+               'calprio' => 'CalculatedPri', 'state_days' => 'State-Days', 'state_time' => 'State-Time',
+                'successtime' => 'Success-build-time',
+                'anytime' => 'Build-time',
+                'extra_depends' => 'Extra-Dependencies',
+                'extra_conflicts' => 'Extra-Conflicts',
+                'build_arch_all' => 'Build-Arch-All',
+                        );
        
        
-       foreach $dist (@dists) {
-               if ($dist ne $distribution) {
-                       if (!-f db_filename( $dist ) || !open_other_db( $dist )) {
-                               warn "Cannot open database for $dist!\n";
-                               @dists = grep { $_ ne $dist } @dists;
-                       }
-               }
-       }
-
        foreach $name (@_) {
                $name =~ s/_.*$//; # strip version
                foreach $dist (@dists) {
        foreach $name (@_) {
                $name =~ s/_.*$//; # strip version
                foreach $dist (@dists) {
-                       my $db = $dist ne $distribution ? $otherdb{$dist} : \%db;
                        my $pname = "$name" . ($info_all_dists ? "($dist)" : "");
                        
                        my $pname = "$name" . ($info_all_dists ? "($dist)" : "");
                        
-                       $pkg = $db->{$name};
+                       $pkg = get_readonly_source_info($name);
                        if (!defined( $pkg )) {
                                print "$pname: not registered\n";
                                next;
                        }
                        if (!defined( $pkg )) {
                                print "$pname: not registered\n";
                                next;
                        }
+                       $pkg = calculate_prio($pkg);
 
                        print "$pname:\n";
                        foreach $key (@firstkeys) {
 
                        print "$pname:\n";
                        foreach $key (@firstkeys) {
-                               next if !exists $pkg->{$key};
+                               next if !defined $pkg->{$key};
                                my $val = $pkg->{$key};
                                chomp( $val );
                                $val = "\n$val" if isin( $key, qw(Failed Old-Failed));
                                $val =~ s/\n/\n    /g;
                                my $val = $pkg->{$key};
                                chomp( $val );
                                $val = "\n$val" if isin( $key, qw(Failed Old-Failed));
                                $val =~ s/\n/\n    /g;
-                               printf "  %-20s: %s\n", $key, $val;
+                               my $print_key = $key;
+                               $print_key = $beautykeys{$print_key} if $beautykeys{$print_key};
+                               printf "  %-20s: %s\n", $print_key, $val;
                        }
                        foreach $key (sort keys %$pkg) {
                                next if isin( $key, @firstkeys );
                                my $val = $pkg->{$key};
                        }
                        foreach $key (sort keys %$pkg) {
                                next if isin( $key, @firstkeys );
                                my $val = $pkg->{$key};
+                               next if !defined($val);
                                chomp( $val );
                                $val = "\n$val" if isin( $key, qw(Failed Old-Failed));
                                $val =~ s/\n/\n    /g;
                                chomp( $val );
                                $val = "\n$val" if isin( $key, qw(Failed Old-Failed));
                                $val =~ s/\n/\n    /g;
-                               printf "  %-20s: %s\n", $key, $val;
+                               my $print_key = $key;
+                               $print_key = $beautykeys{$print_key} if $beautykeys{$print_key};
+                               printf "  %-20s: %s\n", $print_key, $val;
                        }
                }
        }
 }
 
 sub forget_packages {
                        }
                }
        }
 }
 
 sub forget_packages {
+        no warnings;
        my( $name, $pkg, $key, $data );
        
        foreach $name (@_) {
                $name =~ s/_.*$//; # strip version
        my( $name, $pkg, $key, $data );
        
        foreach $name (@_) {
                $name =~ s/_.*$//; # strip version
-               $pkg = $db{$name};
+               $pkg = get_source_info($name);
                if (!defined( $pkg )) {
                        print "$name: not registered\n";
                        next;
                if (!defined( $pkg )) {
                        print "$name: not registered\n";
                        next;
@@ -1970,180 +1324,32 @@ sub forget_packages {
                        $data .= sprintf "  %-20s: %s\n", $key, $val;
                }
                send_mail( $conf::db_maint,
                        $data .= sprintf "  %-20s: %s\n", $key, $val;
                }
                send_mail( $conf::db_maint,
-                                  "$name deleted from DB $conf::dbbase",
+                                  "$name deleted from DB " . table_name() . " " . $distribution,
                                   "The package '$name' has been deleted from the database ".
                                   "by $user.\n\n".
                                   "Data registered about the deleted package:\n".
                                   "$data\n" ) if $conf::db_maint;
                change_state( \$pkg, 'deleted' );
                log_ta( $pkg, "--forget" );
                                   "The package '$name' has been deleted from the database ".
                                   "by $user.\n\n".
                                   "Data registered about the deleted package:\n".
                                   "$data\n" ) if $conf::db_maint;
                change_state( \$pkg, 'deleted' );
                log_ta( $pkg, "--forget" );
-               delete $db{$name};
+               del_source_info($name);
                print "$name: deleted from database\n" if $verbose;
        }
 }
 
 sub forget_users {
                print "$name: deleted from database\n" if $verbose;
        }
 }
 
 sub forget_users {
-       my( $name, $ui );
-       my $change = 0;
-       
-       $ui = $db{'_userinfo'};
-       foreach $name (@_) {
-               if (!defined( $ui->{$name} )) {
-                       print "$name: not registered\n";
-                       next;
-               }
-
-               delete $ui->{$name};
-               $change++;
-               print "$name: deleted from database\n" if $verbose;
-       }
-       $db{'_userinfo'} = $ui if $change;
-}
-
-sub lock_db {
-       my $dist = shift;
-       my $try = 0;
-       my $lockfile = db_lockfilename($dist);
-       local( *F );
-       
-       print "Locking $dist database\n" if $verbose >= 2;
-  repeat:
-       if (!sysopen( F, $lockfile, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0644 )){
-               if ($! == EEXIST) {
-                       # lock file exists, wait
-                       goto repeat if !open( F, "<$lockfile" );
-                       my $line = <F>;
-                       close( F );
-                       if ($line !~ /^(\d+)\s+([\w\d.-]+)$/) {
-                               warn "Bad lock file contents -- still trying\n";
-                       }
-                       else {
-                               my($pid, $usr) = ($1, $2);
-                               if (kill( 0, $pid ) == 0 && $! == ESRCH) {
-                                       # process doesn't exist anymore, remove stale lock
-                                       print "Removing stale lock file (pid $pid, user $usr)\n";
-                                       unlink( $lockfile );
-                                       goto repeat;
-                               }
-                               if ($pid == $lock_for_pid) {
-                                       # We are allowed to use this lock.
-                                       return;
-                               }
-                               warn "Database locked by $usr -- please wait\n" if $try == 0;
-                       }
-                       if (++$try > 200) {
-                               # avoid the END routine removes the lock
-                               $main::keep_lock{$dist} = 1;
-                               die "Lock still present after 200 * 5 seconds.\n";
-                       }
-                       sleep 5;
-                       goto repeat;
-               }
-               die "Can't create lock file $lockfile: $!\n";
-       }
-       my $pid = $lock_for_pid == -1 ? $$ : $lock_for_pid;
-       F->print("$pid $real_user\n");
-       F->close();
-}
-
-sub unlock_db {
-       my $dist = shift;
-       my $lockfile = db_lockfilename($dist);
-
-       if (!$main::keep_lock{$dist}) {
-               print "Unlocking $dist database\n" if $verbose >= 2;
-               unlink $lockfile;
-       }
-}
-
-sub create_maintlock {
-       my $lockfile = db_lockfilename("maintenance");
-       my $try = 0;
-       local( *F );
-       
-       print "Creating maintenance lock\n" if $verbose >= 2;
-  repeat:
-       if (!sysopen( F, $lockfile, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0644 )){
-               if ($! == EEXIST) {
-                       # lock file exists, wait
-                       goto repeat if !open( F, "<$lockfile" );
-                       my $line = <F>;
-                       close( F );
-                       if ($line !~ /^(\d+)\s+([\w\d.-]+)$/) {
-                               warn "Bad maintenance lock file contents -- still trying\n";
-                       }
-                       else {
-                               my($pid, $usr) = ($1, $2);
-                               if (kill( 0, $pid ) == 0 && $! == ESRCH) {
-                                       # process doesn't exist anymore, remove stale lock
-                                       print "Removing stale lock file (pid $pid, user $usr)\n";
-                                       unlink( $lockfile );
-                                       goto repeat;
-                               }
-                               warn "Maintenance lock already exists by $usr -- ".
-                                        "please wait\n" if $try == 0;
-                       }
-                       if (++$try > 120) {
-                               die "Lock still present after 120 * 60 seconds.\n";
-                       }
-                       sleep 60;
-                       goto repeat;
-               }
-               die "Can't create maintenance lock $lockfile: $!\n";
-       }
-       F->print(getppid(), " $real_user\n");
-       F->close();
-}
-
-sub remove_maintlock {
-       my $lockfile = db_lockfilename("maintenance");
-
-       print "Removing maintenance lock\n" if $verbose >= 2;
-       unlink $lockfile;
-}
-
-sub waitfor_maintlock {
-       my $lockfile = db_lockfilename("maintenance");
-       my $try = 0;
-       local( *F );
-       
-       print "Checking for maintenance lock\n" if $verbose >= 2;
-  repeat:
-       if (open( F, "<$lockfile" )) {
-               my $line = <F>;
-               close( F );
-               if ($line !~ /^(\d+)\s+([\w\d.-]+)$/) {
-                       warn "Bad maintenance lock file contents -- still trying\n";
-               }
-               else {
-                       my($pid, $usr) = ($1, $2);
-                       if (kill( 0, $pid ) == 0 && $! == ESRCH) {
-                               # process doesn't exist anymore, remove stale lock
-                               print "Removing stale maintenance lock (pid $pid, user $usr)\n";
-                               unlink( $lockfile );
-                               return;
-                       }
-                       warn "Databases locked for general maintenance by $usr -- ".
-                                "please wait\n" if $try == 0;
-               }
-               if (++$try > 120) {
-                       die "Lock still present after 120 * 60 seconds.\n";
-               }
-               sleep 60;
-               goto repeat;
-       }
+       $dbh->do("DELETE from " . user_table_name() . 
+               " WHERE distribution = ?", undef, $distribution) or die $dbh->errstr;
 }
 
 }
 
-
 sub read_db {
        my $file = shift;
 
        print "Reading ASCII database from $file..." if $verbose >= 1;
 sub read_db {
        my $file = shift;
 
        print "Reading ASCII database from $file..." if $verbose >= 1;
-       open( F, "<$file" ) or
+       open( my $fh, '<', $file ) or
                die "Can't open database $file: $!\n";
 
        local($/) = ""; # read in paragraph mode
                die "Can't open database $file: $!\n";
 
        local($/) = ""; # read in paragraph mode
-       while( <F> ) {
+       while( <$fh> ) {
                my( %thispkg, $name );
                s/[\s\n]+$//;
                s/\n[ \t]+/\376\377/g;  # fix continuation lines
                my( %thispkg, $name );
                s/[\s\n]+$//;
                s/\n[ \t]+/\376\377/g;  # fix continuation lines
@@ -2151,26 +1357,27 @@ sub read_db {
   
                while( /^(\S+):[ \t]*(.*)[ \t]*$/mg ) {
                        my ($key, $val) = ($1, $2);
   
                while( /^(\S+):[ \t]*(.*)[ \t]*$/mg ) {
                        my ($key, $val) = ($1, $2);
+                       $key =~ s/-/_/g;
+                       $key =~ tr/A-Z/a-z/;
                        $val =~ s/\376\377/\n/g;
                        $thispkg{$key} = $val;
                }
                check_entry( \%thispkg );
                # add to db
                        $val =~ s/\376\377/\n/g;
                        $thispkg{$key} = $val;
                }
                check_entry( \%thispkg );
                # add to db
-               if (exists($thispkg{'Package'})) {
-                       $name = $thispkg{'Package'};
-                       $db{$name} = \%thispkg;
-               }
-               elsif(exists($thispkg{'User'})) {
-                       my $userinfo = $db{'_userinfo'};
-                       $userinfo = {} if (!defined($userinfo));
-
-                       $name = $thispkg{'User'};
-                       $userinfo->{$name} = \%thispkg;
-
-                       $db{'_userinfo'} = $userinfo;
+               if (exists($thispkg{'package'})) {
+                       update_source_info(\%thispkg);
+               }
+               elsif(exists($thispkg{'user'})) {
+                       # user in import, username in database.
+                       $dbh->do('INSERT INTO ' . user_table_name() .
+                                       ' (username, distribution, last_seen)' .
+                                       ' values (?, ?, ?)',
+                               undef, $thispkg{'user'}, $distribution,
+                               $thispkg{'last_seen'})
+                               or die $dbh->errstr;
                 }
        }
                 }
        }
-       close( F );
+       close( $fh );
        print "done\n" if $verbose >= 1;
 }
 
        print "done\n" if $verbose >= 1;
 }
 
@@ -2181,142 +1388,108 @@ sub check_entry {
        return if $op_mode eq "manual-edit"; # no checks then
        
        # check for required fields
        return if $op_mode eq "manual-edit"; # no checks then
        
        # check for required fields
-       if (exists $pkg->{'User'}) {
+       if (exists $pkg->{'user'}) {
                return;
        }
                return;
        }
-       if (!exists $pkg->{'Package'}) {
+       if (!exists $pkg->{'package'}) {
                print STDERR "Bad entry: ",
                          join( "\n", map { "$_: $pkg->{$_}" } keys %$pkg ), "\n";
                print STDERR "Bad entry: ",
                          join( "\n", map { "$_: $pkg->{$_}" } keys %$pkg ), "\n";
-               die "Database entry lacks Package or User: field\n";
-       }
-       if (!exists $pkg->{'Version'}) {
-               die "Database entry for $pkg->{'Package'} lacks Version: field\n";
+               die "Database entry lacks package or username field\n";
        }
        # if no State: field, generate one (for old db compat)
        }
        # if no State: field, generate one (for old db compat)
-       if (!exists($pkg->{'State'})) {
-               $pkg->{'State'} =
-                       exists $pkg->{'Failed'} ? 'Failed' : 'Building';
+       if (!exists($pkg->{'state'})) {
+               $pkg->{'state'} =
+                       exists $pkg->{'failed'} ? 'Failed' : 'Building';
+       }
+       if (!exists $pkg->{'version'} and $pkg->{'state'} ne 'Not-For-Us') {
+               die "Database entry for $pkg->{'package'} lacks Version: field\n";
        }
        # check state field
        }
        # check state field
-       die "Bad state $pkg->{'State'} of package $pkg->{Package}\n"
-               if !isin( $pkg->{'State'},
-                                 qw(Needs-Build Building Built Build-Attempted Uploaded Installed Dep-Wait
-                                        Failed Failed-Removed Not-For-Us BD-Uninstallable
+       die "Bad state $pkg->{'state'} of package $pkg->{Package}\n"
+               if !isin( $pkg->{'state'},
+                                 qw(Needs-Build Building Built Build-Attempted Uploaded Installed Dep-Wait Dep-Wait-Removed
+                                        Failed Failed-Removed Not-For-Us BD-Uninstallable Auto-Not-For-Us
                                         ) );
 }
 
                                         ) );
 }
 
-sub write_db {
+sub export_db {
        my $file = shift;
        my($name,$pkg,$key);
        my $file = shift;
        my($name,$pkg,$key);
-       
+
        print "Writing ASCII database to $file..." if $verbose >= 1;
        print "Writing ASCII database to $file..." if $verbose >= 1;
-       open( F, ">$file" ) or
-               die "Can't open database $file: $!\n";
+       open( my $fh, '>', $file ) or
+               die "Can't open export $file: $!\n";
 
 
-       foreach $name (sort keys %db) {
-               my $pkg = $db{$name};
-               if ($name eq '_userinfo') {
-                       foreach $user (sort keys %{$pkg}) {
-                           my $ui = $pkg->{$user};
-                           print F "User: $user\n"
-                               if (!defined($ui->{'User'}));
-                           foreach $key (keys %{$ui}) {
-                               my $val = $ui->{$key};
-                                $val =~ s/\n*$//;
-                               $val =~ s/^/ /mg;
-                               $val =~ s/^ +$/ ./mg;
-                               print F "$key: $val\n";
-                           }
-                           print F "\n";
-                       }
-               }
-               else {
-                       foreach $key (keys %{$pkg}) {
-                               my $val = $pkg->{$key};
-                                $val =~ s/\n*$//;
-                               $val =~ s/^/ /mg;
-                               $val =~ s/^ +$/ ./mg;
-                               print F "$key: $val\n";
-                       }
-                       print F "\n";
+        my $db = get_all_source_info();
+        foreach $name (keys %$db) {
+               next if $name =~ /^_/;
+               my $pkg = $db->{$name};
+               foreach $key (keys %{$pkg}) {
+                       my $val = $pkg->{$key};
+                       next if !defined($val);
+                       $val =~ s/\n*$//;
+                       $val =~ s/^/ /mg;
+                       $val =~ s/^ +$/ ./mg;
+                       print $fh "$key: $val\n";
                }
                }
-       }
-       close( F );
-       print "done\n" if $verbose >= 1;
+               print $fh "\n";
+       }
+       close( $fh );
+       print "done\n" if $verbose >= 1;
 }
 
 sub change_state {
        my $pkgr = shift;
        my $pkg = $$pkgr;
        my $newstate = shift;
 }
 
 sub change_state {
        my $pkgr = shift;
        my $pkg = $$pkgr;
        my $newstate = shift;
-       my $for_dist = shift;
-       my $db;
-       if ($for_dist) {
-               return if !open_other_db( $for_dist );
-               $db = $otherdb{$for_dist};
-               $pkg = \$db{$pkg->{'Package'}};
-       }
-       else {
-               $db = \%db;
-       }
-       my $state = \$pkg->{'State'};
+       my $state = \$pkg->{'state'};
        
        
+        $newstate = 'Needs-Build' if $newstate eq 'BD-Uninstallable' && $distributions{$distribution}{noadw};
        return if defined($$state) and $$state eq $newstate;
        return if defined($$state) and $$state eq $newstate;
-        $pkg->{'Previous-State'} = $$state if defined($$state);
-       $pkg->{'State-Change'} = $curr_date;
+        $pkg->{'previous_state'} = $$state if defined($$state);
+       $pkg->{'state_change'} = $curr_date;
+       $pkg->{'do_state_change'} = 1;
 
        if (defined($$state) and $$state eq 'Failed') {
 
        if (defined($$state) and $$state eq 'Failed') {
-               $pkg->{'Old-Failed'} =
-                       "-"x20 . " $pkg->{'Version'} " . "-"x20 . "\n" .
-                       $pkg->{'Failed'} . "\n" .
-                       $pkg->{'Old-Failed'};
-               delete $pkg->{'Failed'};
-               delete $pkg->{'Failed-Category'};
-       }
-       if (defined($$state) and $$state eq 'BD-Uninstallable') {
-               delete $pkg->{'BD-Problem'};
-       }
+               $pkg->{'old_failed'} =
+                       "-"x20 . " $pkg->{'version'} " . "-"x20 . "\n" .
+                       ($pkg->{'failed'} // ""). "\n" .
+                       ($pkg->{'old_failed'} // "");
+               delete $pkg->{'failed'};
+       }
+       delete $pkg->{'bd_problem'} if ($$state//"") eq 'BD-Uninstallable';
+        $pkg->{'bd_problem'} = "Installability of build dependencies not tested yet" if $newstate eq 'BD-Uninstallable';
        $$state = $newstate;
 }
 
        $$state = $newstate;
 }
 
-sub open_other_db {
-       my $dist = shift;
-
-       if (!tied(%{$otherdb{$dist}})) {
-               lock_db( $dist );
-               $otherdb_lock{$dist} = 1;
-               if (!(tie %{$otherdb{$dist}}, 'MLDBM', db_filename($dist), 0, 0664)){
-                       warn "Serious warning: Cannot open database for $dist\n";
-                       unlock_db( $dist );
-                       $otherdb_lock{$dist} = 0;
-                       return 0;
-               }
-       }
-       return 1;
-}
-
 sub log_ta {
        my $pkg = shift;
        my $action = shift;
 sub log_ta {
        my $pkg = shift;
        my $action = shift;
-        my $db = \%db;
         my $dist = $distribution;
        my $str;
        my $prevstate;
 
         my $dist = $distribution;
        my $str;
        my $prevstate;
 
-       $prevstate = $pkg->{'Previous-State'};
-       $str = "$action($dist): $pkg->{'Package'}_$pkg->{'Version'} ".
-                  "changed from $prevstate to $pkg->{'State'} ".
+       $prevstate = $pkg->{'previous_state'};
+       $str = "$action($dist): $pkg->{'package'}_$pkg->{'version'} ".
+                  "changed from $prevstate to $pkg->{'state'} ".
                   "by $real_user as $user";
        
                   "by $real_user as $user";
        
-       my $transactlog = db_transactlog( $distribution );
-       if (!open( LOG, ">>$transactlog" )) {
-               warn "Can't open log file $transactlog: $!\n";
-               return;
-       }
-       print LOG "$curr_date: $str\n";
-       close( LOG );
-
-       if (!($prevstate eq 'Failed' && $pkg->{'State'} eq 'Failed')) {
+        if ($simulate) {
+            printf "update transactions: %s %s %s %s %s %s %s %s\n",
+               $pkg->{'package'}, $distribution,
+               $pkg->{'version'}, $action, $prevstate, $pkg->{'state'},
+                $real_user, $user;
+            return;
+        }
+       $dbh->do('INSERT INTO ' . transactions_table_name() .
+                       ' (package, distribution, version, action, ' .
+                       ' prevstate, state, real_user, set_user, time) ' .
+                       ' values (?, ?, ?, ?, ?, ?, ?, ?, ?)',
+               undef, $pkg->{'package'}, $distribution,
+               $pkg->{'version'}, $action, $prevstate, $pkg->{'state'},
+               $real_user, $user, 'now()') or die $dbh->errstr;
+
+       if (!($prevstate eq 'Failed' && $pkg->{'state'} eq 'Failed')) {
                $str .= " (with --override)"
                        if $opt_override;
                $mail_logs .= "$str\n";
                $str .= " (with --override)"
                        if $opt_override;
                $mail_logs .= "$str\n";
@@ -2337,47 +1510,13 @@ sub send_mail {
        $to .= '@' . $domain if $to !~ /\@/;
        $text =~ s/^\.$/../mg;
        local $SIG{'PIPE'} = 'IGNORE';
        $to .= '@' . $domain if $to !~ /\@/;
        $text =~ s/^\.$/../mg;
        local $SIG{'PIPE'} = 'IGNORE';
-       open( PIPE,  "| $conf::mailprog -oem $to" )
+       open( my $pipe,  '|-', "$conf::mailprog -oem $to" )
                or die "Can't open pipe to $conf::mailprog: $!\n";
        chomp $text;
                or die "Can't open pipe to $conf::mailprog: $!\n";
        chomp $text;
-       print PIPE "From: $from\n";
-       print PIPE "Subject: $subject\n\n";
-       print PIPE "$text\n";
-       close( PIPE );
-}
-
-sub db_filename {
-       my $dist = shift;
-       return $transactional ? db_filename_transaction($dist) : db_filename_master($dist);
-}
-sub db_filename_master {
-       my $dist = shift;
-       return "$conf::basedir/$conf::dbbase-$dist";
-}
-sub db_filename_transaction {
-       my $dist = shift;
-       return "$conf::basedir/$conf::dbbase-$dist-transaction";
-}
-
-sub db_lockfilename {
-       my $dist = shift;
-       return db_filename_master($dist) . ".lock";
-}
-
-
-sub db_transactlog {
-       my $dist = shift;
-       return $transactional ? db_transactlog_transaction($dist) : db_transactlog_master($dist);
-}
-sub db_transactlog_master {
-       my $dist = shift;
-       $conf::dbbase =~ m#^([^/]+/)#;
-       return "$conf::basedir/$1$conf::transactlog";
-}
-sub db_transactlog_transaction {
-       my $dist = shift;
-       $conf::dbbase =~ m#^([^/]+/)#;
-       return "$conf::basedir/$1$conf::transactlog-$dist-transaction";
+       print $pipe "From: $from\n";
+       print $pipe "Subject: $subject\n\n";
+       print $pipe "$text\n";
+       close( $pipe );
 }
 
 # for parsing input to dep-wait
 }
 
 # for parsing input to dep-wait
@@ -2386,6 +1525,7 @@ sub parse_deplist {
     my $verify = shift;
     my %result;
     
     my $verify = shift;
     my %result;
     
+    return $verify ? 0 : \%result unless $deps;
     foreach (split( /\s*,\s*/, $deps )) {
         if ($verify) {
             # verification requires > starting prompts, no | crap
     foreach (split( /\s*,\s*/, $deps )) {
         if ($verify) {
             # verification requires > starting prompts, no | crap
@@ -2406,69 +1546,16 @@ sub parse_deplist {
         }
         my($dep, $rel, $relv) = ($1, $3, $4);
         $rel = ">>" if defined($rel) and $rel eq ">";
         }
         my($dep, $rel, $relv) = ($1, $3, $4);
         $rel = ">>" if defined($rel) and $rel eq ">";
-        $result{$dep}->{'Package'} = $dep;
+        $result{$dep}->{'package'} = $dep;
         if ($rel && $relv) {
         if ($rel && $relv) {
-            $result{$dep}->{'Rel'} = $rel;
-            $result{$dep}->{'Version'} = $relv;
+            $result{$dep}->{'rel'} = $rel;
+            $result{$dep}->{'version'} = $relv;
         }
     }
     return 1 if $verify;
     return \%result;
 }
 
         }
     }
     return 1 if $verify;
     return \%result;
 }
 
-# for parsing Build-Depends from Sources
-sub parse_srcdeplist {
-    my $pkg = shift;
-    my $deps = shift;
-    my $arch = shift;
-    my $dep;
-    my @results;
-    
-    foreach $dep (split( /\s*,\s*/, $deps )) {
-       my @alts = split( /\s*\|\s*/, $dep );
-        # Anything with an | is ignored, as it can be configured on a
-        # per-buildd basis what will be installed
-        next if $#alts != 0;
-       $_ = shift @alts;
-        if (!/^([^\s([]+)\s*(\(\s*([<=>]+)\s*(\S+)\s*\))?(\s*\[([^]]+)\])?/) {
-            warn( "parse_srcdeplist: bad dependency $_\n" );
-            next;
-        }
-        my($dep, $rel, $relv, $archlist) = ($1, $3, $4, $6);
-        if ($archlist) {
-            $archlist =~ s/^\s*(.*)\s*$/$1/;
-            my @archs = split( /\s+/, $archlist );
-            my ($use_it, $ignore_it, $include) = (0, 0, 0);
-            foreach (@archs) {
-                if (/^!/) {
-                    $ignore_it = 1 if substr($_, 1) eq $arch;
-                } else {
-                    $use_it = 1 if $_ eq $arch;
-                    $include = 1;
-                }
-            }
-            warn "Warning: inconsistent arch restriction on ",
-                 "$pkg: $dep depedency\n"
-                 if $ignore_it && $use_it;
-            next if $ignore_it || ($include && !$use_it);
-        }
-        my $neg = 0;
-        if ($dep =~ /^!/) {
-            $dep =~ s/^!\s*//;
-            $neg = 1;
-        }
-        my $result;
-        $result->{'Package'} = $dep;
-        $result->{'Neg'} = $neg;
-        if ($rel && $relv) {
-            $result->{'Rel'} = $rel;
-            $result->{'Version'} = $relv;
-        }
-        push @results, $result;
-    }
-    return \@results;
-}
-
 sub build_deplist {
        my $list = shift;
        my($key, $result);
 sub build_deplist {
        my $list = shift;
        my($key, $result);
@@ -2476,196 +1563,245 @@ sub build_deplist {
        foreach $key (keys %$list) {
                $result .= ", " if $result;
                $result .= $key;
        foreach $key (keys %$list) {
                $result .= ", " if $result;
                $result .= $key;
-               $result .= " ($list->{$key}->{'Rel'} $list->{$key}->{'Version'})"
-                       if $list->{$key}->{'Rel'} && $list->{$key}->{'Version'};
+               $result .= " ($list->{$key}->{'rel'} $list->{$key}->{'version'})"
+                       if $list->{$key}->{'rel'} && $list->{$key}->{'version'};
        }
        return $result;
 }
 
        }
        return $result;
 }
 
-sub clean_db {
-       my %new_db;
-       tie %new_db, 'MLDBM', db_filename( $distribution ) . ".new", GDBM_WRCREAT, 0664
-               or die "FATAL: Cannot create new database\n";
-       %new_db = %db;
-       untie %db or die "FATAL: Cannot untie old database\n";
-       system ("cp " . db_filename( $distribution ) . ".new " .
-               db_filename( $distribution ) ) == 0
-               or die "FATAL: Cannot overwrite old database";
-       unlink db_filename( $distribution ) . ".new";
-       %db = %new_db;
-}
-
-
-sub get_unsatisfied_dep {
-    my $bd  = shift;
-    my $pkgs = shift;
-    my $dep = shift;
-    my $savedep = shift;
 
 
-    my $pkgname = $dep->{'Package'};
-
-    if (defined $pkgs->{$pkgname}{'Provider'}) {
-        # provides.  leave them for buildd/sbuild.
-        return "";
+sub filterarch {
+    return "" unless $_[0];
+    return Dpkg::Deps::deps_parse($_[0], ("reduce_arch" => 1, "host_arch" => $_[1]))->output();
+}
+
+sub wb_edos_builddebcheck {
+# Copyright (C) 2008 Ralf Treinen <treinen@debian.org>
+# This program is free software: you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation, version 2 of the License.
+# integrated into wanna-builds code by Andreas Barth 2010
+
+    my $args = shift;
+    my $sourceprefix="source---";
+    my $architecture=$args->{'arch'};
+    my $edosoptions = "-failures -explain -quiet";
+    my $packagefiles = $args->{'pkgs'};
+    my $sourcesfile = $args->{'src'};
+
+    my $packagearch="";
+    foreach my $packagefile (@$packagefiles) {
+        open(my $fh,'<', $packagefile);
+        while (<$fh>) {
+            next unless /^Architecture/;
+            next if /^Architecture:\s*all/;
+            /Architecture:\s*([^\s]*)/;
+            if ($packagearch eq "") {
+               $packagearch = $1;
+            } elsif ( $packagearch ne $1) {
+               return "Package file contains different architectures: $packagearch, $1";
+            }
+        }
+        close $fh;
     }
 
     }
 
-    # check cache
-    return $pkgs->{$pkgname}{'Unsatisfied'} if $savedep and defined($pkgs->{$pkgname}{'Unsatisfied'});
-
-    # Return unsatisfied deps to a higher caller to process
-    if ((!defined($pkgs->{$pkgname})) or
-        (defined($dep->{'Rel'}) and !version_compare( $pkgs->{$pkgname}{'Version'}, $dep->{'Rel'}, $dep->{'Version'} ) ) ) {
-        my %deplist;
-        $deplist{$pkgname} = $dep;
-        my $deps = build_deplist(\%deplist);
-        $pkgs->{$pkgname}{'Unsatisfied'} = $deps if $savedep;
-        return $deps;
+    if ( $architecture eq "" ) {
+        if ( $packagearch eq "" ) {
+       return "No architecture option given, " .
+           "and no non-all architecture found in the Packages file";
+        } else {
+           $architecture = $packagearch;
+        }
+    } else {
+        if ( $packagearch ne "" & $architecture ne $packagearch) {
+           return "Architecture option is $architecture ".
+           "but the package file contains architecture $packagearch";
+        }   
     }
 
     }
 
-    # set cache to "" to avoid infinite recursion
-    $pkgs->{$pkgname}{'Unsatisfied'} = "" if $savedep;
-
-    if (defined $pkgs->{$dep->{'Package'}}{'Depends'}) {
-        my $deps = parse_deplist( $pkgs->{$dep->{'Package'}}{'Depends'} );
-        foreach (keys %$deps) {
-            $dep = $$deps{$_};
-            # recur on dep.
-            my $ret = get_unsatisfied_dep($bd,$pkgs,$dep,1);
-            if ($ret ne "") {
-                my $retdep = parse_deplist( $ret );
-                foreach (keys %$retdep) {
-                    $dep = $$retdep{$_};
-
-                    $dep->{'Rel'} = '>=' if defined($dep->{'Rel'}) and $dep->{'Rel'} =~ '^=';
-
-                    if (defined($dep->{'Rel'}) and $dep->{'Rel'} =~ '^>' and defined ($pkgs->{$dep->{'Package'}}) and
-                        version_compare($bd->{$pkgs->{$dep->{'Package'}}{'Source'}}{'ver'},'>>',$pkgs->{$dep->{'Package'}}{'Sourcev'})) {
-                        if (not defined($merge_binsrc{$dep->{'Package'}})) {
-                            # the uninstallable package doesn't exist in the new source; look for something else that does.
-                            delete $$retdep{$dep->{'Package'}};
-                            foreach (sort (split( /\s*,\s*/, $bd->{$pkgs->{$dep->{'Package'}}{'Source'}}{'bin'}))) {
-                                next if ($pkgs->{$_}{'all'} or not defined $pkgs->{$_}{'Version'});
-                                $dep->{'Package'} = $_;
-                                $dep->{'Rel'} = '>>';
-                                $dep->{'Version'} = $pkgs->{$_}{'Version'};
-                                $$retdep{$_} = $dep;
-                                last;
-                            }
-                        }
-                    } else {
-                        # sanity check to make sure the depending binary still exists, and the depended binary exists and dep-wait on a new version of it
-                        if ( defined($merge_binsrc{$pkgname}) and defined($pkgs->{$dep->{'Package'}}{'Version'}) ) {
-                            delete $$retdep{$dep->{'Package'}};
-                            $dep->{'Package'} = $pkgname;
-                            $dep->{'Rel'} = '>>';
-                            $dep->{'Version'} = $pkgs->{$pkgname}{'Version'};
-                            $$retdep{$pkgname} = $dep;
-                        }
-                        delete $$retdep{$dep->{'Package'}} if (defined ($dep->{'Rel'}) and $dep->{'Rel'} =~ '^>');
-                    }
-                }
-                $ret = build_deplist($retdep);
-                $pkgs->{$pkgname}{'Unsatisfied'} = $ret if $savedep;
-                return $ret;
+    print "calling: edos-debcheck $edosoptions < $sourcesfile ".join('', map {" -I ".$_ } @$packagefiles)."\n";
+    open(my $result_cmd, '-|',
+        "edos-debcheck $edosoptions < $sourcesfile ".join('', map {" -I ".$_ } @$packagefiles));
+
+    my $explanation="";
+    my $result={};
+    my $binpkg="";
+
+    while (<$result_cmd>) {
+# source---pulseaudio (= 0.9.15-4.1~bpo50+1): FAILED
+#   source---pulseaudio (= 0.9.15-4.1~bpo50+1) depends on missing:
+#   - libltdl-dev (>= 2.2.6a-2)
+# source---libcanberra (= 0.22-1~bpo50+1): FAILED
+#   source---libcanberra (= 0.22-1~bpo50+1) depends on missing:
+#   - libltdl-dev
+#   - libltdl7-dev (>= 2.2.6)
+
+        if (/^\s+/) {
+           s/^(\s*)$sourceprefix(.*)depends on/$1$2build-depends on/o;
+            s/^(\s*)$sourceprefix(.*) and (.*) conflict/$1$2 build-conflicts with $3/o;
+            $explanation .= $_;
+        } else {
+            if (/^$sourceprefix(.*) \(.*\): FAILED/o) {
+                $result->{$binpkg} = $explanation if $binpkg;
+                $explanation = "";
+                $binpkg = $1;
+            } elsif (/^(depwait---.*) \(.*\): FAILED/o) {
+                $result->{$binpkg} = $explanation if $binpkg;
+                $explanation = "";
+                $binpkg = $1;
+            } else { # else something broken is happening
+                #print "ignoring $_\n";
+                1;
             }
         }
     }
             }
         }
     }
-    return "";
+
+    close $result_cmd;
+    $result->{$binpkg} = $explanation if $binpkg;
+    return $result;
+
 }
 
 }
 
+
 sub call_edos_depcheck {
 sub call_edos_depcheck {
-    my $packagesfile = shift;
-    my $srcs = shift;
+    return if $simulate_edos;
+    my $args = shift;
+    my $srcs = $args->{'srcs'};
     my $key;
     my $key;
-    
-    return if defined ($conf::distributions{$distribution}{noadw});
+   
+    # Do not dispatch edos-debcheck if BD-Uninstallable is deactivated for the target.
+    # ("noadw")  Depwait will always be 1 in normal use.
+    return if defined ($distributions{$distribution}{noadw}) && not defined $args->{'depwait'};
 
     # We need to check all of needs-build, as any new upload could make
     # something in needs-build have uninstallable deps
     # We also check everything in bd-uninstallable, as any new upload could
     # make that work again
 
     # We need to check all of needs-build, as any new upload could make
     # something in needs-build have uninstallable deps
     # We also check everything in bd-uninstallable, as any new upload could
     # make that work again
-    my %interesting_packages;
-    foreach $key (keys %db) {
-       my $pkg = $db{$key};
-        if (defined $pkg and isin($pkg->{'State'}, qw/Needs-Build BD-Uninstallable/)) {
-               $interesting_packages{$key} = undef;
+    my (%interesting_packages, %interesting_packages_depwait);
+    my $db = get_all_source_info(); # TODO: Filter for needs-build bd-uninst dep-wait, that's all we need.
+    foreach $key (keys %$db) {
+       my $pkg = $db->{$key};
+        if (defined $pkg and isin($pkg->{'state'}, qw/Needs-Build BD-Uninstallable/) and not defined ($distributions{$distribution}{noadw})) {
+               $interesting_packages{$key} = undef; # add key to interesting packages
+       }
+        if (defined $pkg and isin($pkg->{'state'}, qw/Dep-Wait/) and defined $args->{'depwait'}) {
+                # Depwaits are checked by creating pseudo binaries for edos-debcheck, so collect them.
+               $interesting_packages_depwait{$key} = undef;
+                # we always check for BD-Uninstallability in depwait - could be that depwait is satisfied but package is uninstallable
+               $interesting_packages{$key} = undef unless defined ($distributions{$distribution}{noadw});
        }
     }
     
     #print "I would look at these sources with edos-depcheck:\n";
     #print join " ", keys %interesting_packages,"\n";
        }
     }
     
     #print "I would look at these sources with edos-depcheck:\n";
     #print join " ", keys %interesting_packages,"\n";
+    return unless %interesting_packages || %interesting_packages_depwait;
 
 
-    my $tmpfile_pattern = "/tmp/wanna-build-interesting-sources-$distribution.$$-";
-    my ($tmpfile, $i);
-    for( $i = 0;; ++$i ) {
-           $tmpfile = $tmpfile_pattern . $i;
-           last if ! -e $tmpfile;
-    }
-
-    open SOURCES, '>', $tmpfile or die "Could not open temporary file $tmpfile\n";
+    my $tmpfile_pattern = "/tmp/wanna-build-interesting-sources-$distribution.$$-XXXXX";
+    use File::Temp qw/ tempfile /;
+    my ($SOURCES, $tmpfile) = tempfile( $tmpfile_pattern, UNLINK => 1 );
     for my $key (keys %interesting_packages) {
     for my $key (keys %interesting_packages) {
-       my $pkg = $db{$key};
-       print SOURCES "Package: $key\n";
-       print SOURCES "Version: $pkg->{'Version'}\n";
-       print SOURCES "Build-Depends: $srcs->{$key}{'dep'}\n" if $srcs->{$key}{'dep'};
-       print SOURCES "Build-Conflicts: $srcs->{$key}{'conf'}\n" if $srcs->{$key}{'conf'};
-       print SOURCES "Architecture: all\n";
-       print SOURCES "\n";
+       my $pkg = $db->{$key};
+        # we print the source files as binary ones (with "source---"-prefixed),
+        # so we can try if these "binary" packages are installable.
+        # If such a "binary" package is installable, the corresponding source package is buildable.
+       print $SOURCES "Package: source---$key\n";
+       print $SOURCES "Version: $pkg->{'version'}\n";
+        my $t = &filterarch($srcs->{$key}{'dep'} || $srcs->{$key}{'depends'}, $args->{'arch'});
+        my $tt = &filterarch($pkg->{'extra_depends'}, $args->{'arch'});
+        $t = $t ? ($tt ? "$t, $tt" : $t) : $tt;
+       print $SOURCES "Depends: $t\n" if $t;
+        my $u = &filterarch($srcs->{$key}{'conf'} || $srcs->{$key}{'conflicts'}, $args->{'arch'});
+        my $uu = &filterarch($pkg->{'extra_conflicts'}, $args->{'arch'});
+        $u = $u ? ($uu ? "$u, $uu" : $u) : $uu;
+       print $SOURCES "Conflicts: $u\n" if $u;
+       print $SOURCES "Architecture: all\n";
+       print $SOURCES "\n";
     }
     }
-    close SOURCES;
-
-    if (open(EDOS,"-|","wb-edos-builddebcheck", "-a", $arch, $packagesfile, $tmpfile))
-    {
-       local($/) = ""; # read in paragraph mode
-       while( <EDOS> ) {
-               my( $key, $reason ) ;
-               s/\s*$//m;
-               /^Package:\s*(\S+)$/mi and $key = $1;
-               /^Failed-Why:(([^\n]|\n ([^\n]|\.))*)$/msi and $reason = $1;
-               $reason =~ s/^\s*//mg;
-               $reason ||= 'No reason given by edos-debcheck';
+    for my $key (keys %interesting_packages_depwait) {
+       my $pkg = $db->{$key};
+        # we print the source files as binary ones (with "depwait---"-prefixed),
+        # so we can try if these "binary" packages are installable.
+        # If such a "binary" package is installable, the corresponding source package goes out of depwait
+       print $SOURCES "Package: depwait---$key\n";
+       print $SOURCES "Version: $pkg->{'version'}\n";
+       print $SOURCES "Depends: $pkg->{'depends'}\n";
+       print $SOURCES "Architecture: all\n";
+       print $SOURCES "\n";
+    }
+    close $SOURCES;
 
 
+    my $edosresults = wb_edos_builddebcheck({'arch' => $args->{'arch'}, 'pkgs' => $args->{'pkgs'}, 'src' => $tmpfile});
+    if (ref($edosresults) eq 'HASH') {
+        foreach my $key (grep { $_ !~ /^depwait---/ } keys %$edosresults) {
                if (exists $interesting_packages{$key}) {
                if (exists $interesting_packages{$key}) {
-                   $interesting_packages{$key} = $reason;
+                   $interesting_packages{$key} = $edosresults->{$key};
                } else {
                    #print "TODO: edos reported a package we do not care about now\n" if $verbose;
                }
                } else {
                    #print "TODO: edos reported a package we do not care about now\n" if $verbose;
                }
-       }
-       close EDOS;
+        }
+        foreach my $key (grep { $_ =~ /^depwait---/ } keys %$edosresults) {
+                $key =~ /^depwait---(.*)/ and $key = $1;
+               if (exists $interesting_packages_depwait{$key}) {
+                   $interesting_packages_depwait{$key} = $edosresults->{"depwait---".$key};
+               } else {
+                   #print "TODO: edos reported a package we do not care about now\n" if $verbose;
+               }
+        }
     } else {
     } else {
-       print "ERROR: Could not run wb-edos-builddebcheck. I am continuing, assuming\n" .
-             "all packages have installable build-dependencies."
+        # if $edosresults isn't an hash, then something went wrong and the string is the error message
+        print "ERROR: Could not run wb-edos-builddebcheck. I am continuing, assuming\n" .
+             "all packages have installable build-dependencies."
     }
     
     unlink( $tmpfile );
 
     for my $key (keys %interesting_packages) {
     }
     
     unlink( $tmpfile );
 
     for my $key (keys %interesting_packages) {
-       my $pkg = $db{$key};
+        next if defined $interesting_packages_depwait{$key};
+       my $pkg = $db->{$key};
+        # (defined $interesting_packages{$key}) => edos found an uninstallability
        my $change = 
        my $change = 
-           (defined $interesting_packages{$key} and $pkg->{'State'} eq 'Needs-Build') ||
-           (not defined $interesting_packages{$key} and $pkg->{'State'} eq 'BD-Uninstallable');
-       my $problemchange = $interesting_packages{$key} ne $pkg->{'BD-Problem'};
+           (defined $interesting_packages{$key} and $pkg->{'state'} eq 'Needs-Build') ||
+           (not defined $interesting_packages{$key} and $pkg->{'state'} eq 'BD-Uninstallable');
+       my $problemchange = ($interesting_packages{$key}//"") ne ($pkg->{'bd_problem'}//"");
        if ($change) {
            if (defined $interesting_packages{$key}) {
                    change_state( \$pkg, 'BD-Uninstallable' );
        if ($change) {
            if (defined $interesting_packages{$key}) {
                    change_state( \$pkg, 'BD-Uninstallable' );
-                   $pkg->{'BD-Problem'} = $interesting_packages{$key};
+                   $pkg->{'bd_problem'} = $interesting_packages{$key};
            } else {
                    change_state( \$pkg, 'Needs-Build' );
            }
        }
        if ($problemchange) {
            if (defined $interesting_packages{$key}) {
            } else {
                    change_state( \$pkg, 'Needs-Build' );
            }
        }
        if ($problemchange) {
            if (defined $interesting_packages{$key}) {
-                   $pkg->{'BD-Problem'} = $interesting_packages{$key};
+                   $pkg->{'bd_problem'} = $interesting_packages{$key};
            }   
        }
        if ($change) {
            }   
        }
        if ($change) {
-           log_ta( $pkg, "--merge-all" );
-           print "edos-builddebchange changed state of ${key}_$pkg->{'Version'} to $pkg->{'State'}\n" if $verbose;
+           log_ta( $pkg, "--merge-all (edos)" ) unless $simulate;
+           print "edos-builddebchange changed state of ${key}_$pkg->{'version'} ($args->{'arch'}) to $pkg->{'state'}\n" if $verbose || $simulate;
        }
        if ($change || $problemchange) {
        }
        if ($change || $problemchange) {
-           $db{$key} = $pkg;
+           update_source_info($pkg) unless $simulate;
        }
     }
        }
     }
+
+    for my $key (keys %interesting_packages_depwait) {
+        if ($interesting_packages_depwait{$key}) {
+            print "dep-wait for $key ($args->{'arch'}) not fullfiled yet\n" if $verbose || $simulate;
+            next;
+        }
+       my $pkg = $db->{$key};
+        # The depwait could be cleared with the result still being uninstallable.
+        if (defined $interesting_packages{$key}) {
+           change_state( \$pkg, 'BD-Uninstallable' );
+           $pkg->{'bd_problem'} = $interesting_packages{$key};
+        } else {
+           change_state( \$pkg, 'Needs-Build' );
+        }
+       log_ta( $pkg, "edos_depcheck: depwait" ) unless $simulate;
+       update_source_info($pkg) unless $simulate;
+       print "edos-builddebchange changed state of ${key}_$pkg->{'version'} ($args->{'arch'}) from dep-wait to $pkg->{'state'}\n" if $verbose || $simulate;
+    }
 }
 
 sub usage {
 }
 
 sub usage {
@@ -2675,6 +1811,10 @@ sub usage {
 Usage: $prgname <options...> <package_version...>
 Options:
     -v, --verbose: Verbose execution.
 Usage: $prgname <options...> <package_version...>
 Options:
     -v, --verbose: Verbose execution.
+    --simulate: Do not actually execute the action.
+        (Not yet implemented for all operations.  Check the source.)
+    -A arch: Architecture this operation is for.  (REQUIRED)
+    -d dist: Distribution/suite this operation is for. Defaults to unstable.
     --take: Take package for building [default operation]
     -f, --failed: Record in database that a build failed due to
         deficiencies in the package (that aren't fixable without a new
     --take: Take package for building [default operation]
     -f, --failed: Record in database that a build failed due to
         deficiencies in the package (that aren't fixable without a new
@@ -2694,14 +1834,20 @@ Options:
         BD-Uninstallable, until the installability of its Build-Dependencies
         were verified. This happens at each call of --merge-all, usually
         every 15 minutes.
         BD-Uninstallable, until the installability of its Build-Dependencies
         were verified. This happens at each call of --merge-all, usually
         every 15 minutes.
-    --merge-quinn: Merge quinn-diff output into database.
-    --merge-packages: Merge Packages files into database.
-    --pretend-avail: Pretend that given packages are available now and give
-        free packages waiting for them
+    --build-priority=VALUE: Adjust the build priority of the currently
+        queued build.
+    --permanent-build-priority=VALUE: Adjust the permanent build
+        priority of a source package in a given distribution.
+    --extra-depends=BUILD-DEPENDS: Specify additional build-dependencies
+        used for the build.
+    --extra-conflicts=BUILD-DEPENDS: Specify additional build-conflicts
+        used for the build.
     -i SRC_PKG, --info SRC_PKG: Show information for source package
     -l STATE, --list=STATE: List all packages in state STATE; can be
         combined with -U to restrict to a specific user; STATE can
         also be 'all'
     -i SRC_PKG, --info SRC_PKG: Show information for source package
     -l STATE, --list=STATE: List all packages in state STATE; can be
         combined with -U to restrict to a specific user; STATE can
         also be 'all'
+    --min-age=VALUE, --max-age=VALUE: Filter the output of --list
+        by the age of the builds.
     -m MESSAGE, --message=MESSAGE: Give reason why package failed or
         source dependency list
         (used with -f, --dep-wait, and --binNMU)
     -m MESSAGE, --message=MESSAGE: Give reason why package failed or
         source dependency list
         (used with -f, --dep-wait, and --binNMU)
@@ -2713,22 +1859,16 @@ Options:
         automatically choosen
     --import FILE: Import database from a ASCII file FILE
     --export FILE: Export database to a ASCII file FILE
         automatically choosen
     --import FILE: Import database from a ASCII file FILE
     --export FILE: Export database to a ASCII file FILE
-    --lock-for PID: Locks the database for the process with this pid
-    --unlock-for PID: Unlocks the database for the process with this pid
-    --act-on-behalf-of PID: Ignores the lock (if it is held by this pid)
-    --start-transaction: Creates a copy of the state of the database, for
-       use with --transactional. This overrides any previous uncommited
-       transaction. Should only be used after --lock-for
-    --commit-transaction: Atomically moves the copy back to the main, thus
-       commiting the changes
-    --transactional: Flag to indicate that we want to work on the copy
+    --format string, --own-format name: specify how the listing of packages
+        should look like. Please check the source for details. Own-Format
+        definitions are in ~/.wanna-build.yaml within the format section.
+
+There are more options not relevant for normal usage - please check source
+if you need them.
 
 The remaining arguments (depending on operation) usually start with
 "name_version", the trailer is ignored. This allows to pass the names
 of .dsc files, for which file name completion can be used.
 
 The remaining arguments (depending on operation) usually start with
 "name_version", the trailer is ignored. This allows to pass the names
 of .dsc files, for which file name completion can be used.
---merge-packages and --merge-quinn take Package/quin--diff file names
-on the command line or read stdin. --list needs nothing more on the
-command line. --info takes source package names (without version).
 EOF
        exit 1;
 }
 EOF
        exit 1;
 }
@@ -2738,8 +1878,386 @@ sub pkg_version_eq {
        my $version = shift;
 
        return 1
        my $version = shift;
 
        return 1
-              if (defined $pkg->{'Binary-NMU-Version'}) and 
-              version_compare(binNMU_version($pkg->{'Version'},
-                       $pkg->{'Binary-NMU-Version'}),'=', $version);
-       return version_compare( $pkg->{'Version'}, "=", $version );
+              if (defined $pkg->{'binary_nmu_version'}) and 
+              version_compare(binNMU_version($pkg->{'version'},
+                       $pkg->{'binary_nmu_version'}),'=', $version);
+       return version_compare( $pkg->{'version'}, "=", $version );
+}
+
+sub table_name {
+       return '"' . $arch . $schema_suffix . '".packages';
+}
+
+sub user_table_name {
+       return '"' . $arch . $schema_suffix . '".users';
+}
+
+sub transactions_table_name {
+       return '"' . $arch . $schema_suffix . '".transactions';
+}
+
+sub pkg_history_table_name {
+       return '"' . $arch . $schema_suffix . '".pkg_history';
+}
+
+sub get_readonly_source_info {
+       my $name = shift;
+       # SELECT FLOOR(EXTRACT('epoch' FROM age(localtimestamp, '2010-01-22  23:45')) / 86400) -- change to that?
+        my $q = "SELECT rel, priority, state_change, permbuildpri, section, buildpri, failed, state, binary_nmu_changelog, bd_problem, version, package, distribution, installed_version, notes, builder, old_failed, previous_state, binary_nmu_version, depends, extract(days from date_trunc('days', now() - state_change)) as state_days, floor(extract(epoch from now()) - extract(epoch from state_change)) as state_time"
+            . ", (SELECT max(build_time) FROM ".pkg_history_table_name()." WHERE pkg_history.package = packages.package AND pkg_history.distribution = packages.distribution AND result = 'successful') AS successtime"
+            . ", (SELECT max(build_time) FROM ".pkg_history_table_name()." WHERE pkg_history.package = packages.package AND pkg_history.distribution = packages.distribution ) AS anytime"
+            . ", extra_depends, extra_conflicts, build_arch_all"
+            . " FROM " .  table_name()
+            . ' WHERE package = ? AND distribution = ?';
+       my $pkg = $dbh->selectrow_hashref( $q,
+               undef, $name, $distribution);
+       return $pkg;
+}
+
+sub get_source_info {
+       my $name = shift;
+        return get_readonly_source_info($name) if $simulate;
+       lock_table();
+       my $pkg = $dbh->selectrow_hashref('SELECT *, extract(days from date_trunc(\'days\', now() - state_change)) as state_days, floor(extract(epoch from now()) - extract(epoch from state_change)) as state_time FROM ' . 
+               table_name() . ' WHERE package = ? AND distribution = ?',
+               undef, $name, $distribution);
+       return $pkg;
+}
+
+sub get_all_source_info {
+       my %options = @_;
+
+        my $q = "SELECT rel, priority, state_change, permbuildpri, section, buildpri, failed, state, binary_nmu_changelog, bd_problem, version, package, distribution, installed_version, notes, builder, old_failed, previous_state, binary_nmu_version, depends, extract(days from date_trunc('days', now() - state_change)) as state_days, floor(extract(epoch from now()) - extract(epoch from state_change)) as state_time"
+#            . ", (SELECT max(build_time) FROM ".pkg_history_table_name()." WHERE pkg_history.package = packages.package AND pkg_history.distribution = packages.distribution AND result = 'successful') AS successtime"
+#            . ", (SELECT max(build_time) FROM ".pkg_history_table_name()." WHERE pkg_history.package = packages.package AND pkg_history.distribution = packages.distribution ) AS anytime"
+            . ", successtime.build_time as successtime, anytime.build_time as anytime, extra_depends, extra_conflicts"
+            . " FROM " .  table_name()
+                . " left join ( "
+                  . "select distinct on (package, distribution) build_time, package, distribution from ".pkg_history_table_name()." where result = 'successful' order by package, distribution, timestamp "
+                  . " ) as successtime using (package, distribution) "
+                . " left join ( "
+                  . "select distinct on (package, distribution) build_time, package, distribution from ".pkg_history_table_name()." order by package, distribution, timestamp desc"
+                  . " ) as anytime using (package, distribution) "
+           . " WHERE TRUE ";
+        my @args = ();
+        if ($distribution) {
+            my @dists = split(/[, ]+/, $distribution);
+            $q .= ' AND ( distribution = ? '.(' OR distribution = ? ' x $#dists).' )';
+            foreach my $d ( @dists ) {
+                push @args, ($d);
+            }
+        }
+       if ($options{state} && uc($options{state}) ne "ALL") {
+               $q .= ' AND upper(state) = ? ';
+               push @args, uc($options{state});
+       }
+
+       if ($options{user} && uc($options{state}) ne "NEEDS-BUILD") { # if it's NEEDS-BUILD, we don't look at users
+               #this basically means "this user, or no user at all":
+               $q .= " AND (builder = ? OR upper(state) = 'NEEDS-BUILD')";
+               push @args, $options{user};
+       }
+
+       if ($options{list_min_age} && $options{list_min_age} > 0) {
+               $q .= ' AND age(state_change) > ? ';
+               push @args, $options{list_min_age} . " days";
+       }
+
+       if ($options{list_min_age} && $options{list_min_age} < 0) {
+               $q .= ' AND age(state_change) < ? ';
+               push @args, -$options{list_min_age} . " days";
+       }
+
+       my $db;
+        if (($options{multisuite}) && (!$distribution || $distribution =~ / /)) {
+            # return packages in multiple suites - only for those functions marked as clean for that api change
+            $db = $dbh->selectall_hashref($q, [qw<package distribution>], undef, @args);
+            my $dbk = {};
+            foreach my $p ( keys %$db ) {
+                foreach my $d (keys %{$db->{$p}}) {
+                    $dbk->{"$p/$d"} = $db->{$p}->{$d};
+                }
+            }
+            $db = $dbk;
+        } else {
+            $db = $dbh->selectall_hashref($q, [qw<package>], undef, @args);
+        }
+       return $db;
+}
+
+sub show_distribution_architectures {
+        my $args = shift;
+       my $q = 'SELECT distribution, spacecat_all(architecture) AS architectures '.
+               'FROM distribution_architectures '.
+               'GROUP BY distribution';
+       my $rows = $dbh->selectall_hashref($q, 'distribution');
+        if ($args->{suite}) {
+            print $rows->{$args->{'suite'}}->{'architectures'}."\n";
+        } else {
+           foreach my $name (keys %$rows) {
+               print $name.': '.$rows->{$name}->{'architectures'}."\n";
+           }
+        }
+}
+
+sub show_distribution_aliases {
+       foreach my $alias (keys %distribution_aliases) {
+               print $alias.': '.$distribution_aliases{$alias}."\n";
+       }
+}
+
+sub update_source_info {
+       my $pkg = shift;
+        $pkg->{'extra_depends'} = $extra_depends if defined $extra_depends;
+        undef $pkg->{'extra_depends'} unless $pkg->{'extra_depends'};
+        $pkg->{'extra_conflicts'} = $extra_conflicts if defined $extra_conflicts;
+        undef $pkg->{'extra_conflicts'} unless $pkg->{'extra_conflicts'};
+        print Dumper $pkg if $verbose and $simulate;
+        return if $simulate;
+
+       my $pkg2 = get_source_info($pkg->{'package'});
+       if (! defined $pkg2)
+       {
+               add_source_info($pkg);
+       }
+
+       $dbh->do('UPDATE ' . table_name() . ' SET ' .
+                       'version = ?, ' .
+                       'state = ?, ' .
+                       'section = ?, ' .
+                       'priority = ?, ' .
+                       'installed_version = ?, ' .
+                       'previous_state = ?, ' .
+                       (($pkg->{'do_state_change'}) ? "state_change = now()," : "").
+                       'notes = ?, ' .
+                       'builder = ?, ' .
+                       'failed = ?, ' .
+                       'old_failed = ?, ' .
+                       'binary_nmu_version = ?, ' .
+                       'binary_nmu_changelog = ?, ' .
+                       'permbuildpri = ?, ' .
+                       'buildpri = ?, ' .
+                       'depends = ?, ' .
+                       'rel = ?, ' .
+                       'extra_depends = ?, ' .
+                       'extra_conflicts = ?, ' .
+                       'bd_problem = ? ' .
+                       'WHERE package = ? AND distribution = ?',
+               undef,
+               $pkg->{'version'},
+               $pkg->{'state'},
+               $pkg->{'section'},
+               $pkg->{'priority'},
+               $pkg->{'installed_version'},
+               $pkg->{'previous_state'},
+               $pkg->{'notes'},
+               $pkg->{'builder'},
+               $pkg->{'failed'},
+               $pkg->{'old_failed'},
+               $pkg->{'binary_nmu_version'},
+               $pkg->{'binary_nmu_changelog'},
+               $pkg->{'permbuildpri'},
+               $pkg->{'buildpri'},
+               $pkg->{'depends'},
+               $pkg->{'rel'},
+                $pkg->{'extra_depends'},
+                $pkg->{'extra_conflicts'},
+               $pkg->{'bd_problem'},
+               $pkg->{'package'},
+               $distribution) or die $dbh->errstr;
+}
+
+sub add_source_info {
+        return if $simulate;
+       my $pkg = shift;
+       $dbh->do('INSERT INTO ' . table_name() .
+                       ' (package, distribution) values (?, ?)',
+               undef, $pkg->{'package'}, $distribution) or die $dbh->errstr;
+}
+
+sub del_source_info {
+        return if $simulate;
+       my $name = shift;
+       $dbh->do('DELETE FROM ' . table_name() .
+                       ' WHERE package = ? AND distribution = ?',
+               undef, $name, $distribution) or die $dbh->errstr;
+}
+
+sub get_user_info {
+       my $name = shift;
+       my $user = $dbh->selectrow_hashref('SELECT * FROM ' . 
+               user_table_name() . ' WHERE username = ? AND distribution = ?',
+               undef, $name, $distribution);
+       return $user;
+}
+
+sub update_user_info {
+        return if $simulate;
+       my $user = shift;
+       $dbh->do('UPDATE ' . user_table_name() .
+                       ' SET last_seen = now() WHERE username = ?' .
+                       ' AND distribution = ?',
+               undef, $user, $distribution)
+               or die $dbh->errstr;
+}
+
+
+sub add_user_info {
+        return if $simulate;
+       my $user = shift;
+       $dbh->do('INSERT INTO ' . user_table_name() .
+                       ' (username, distribution, last_seen)' .
+                       ' values (?, ?, now())',
+               undef, $user, $distribution)
+               or die $dbh->errstr;
+}
+
+sub lock_table {
+        return if $simulate;
+       $q = 'SELECT 1 AS result FROM public.locks' .
+            ' WHERE architecture = ? AND distribution = ? FOR UPDATE';
+       my $result = $dbh->selectrow_hashref($q, undef, $arch, $distribution) or die $dbh->errstr;
+       die unless $result->{'result'} == 1;
+}
+
+sub parse_argv {
+# parts the array $_[0] and $_[1] and returns the sub-array (modifies the original one)
+    my @ret = ();
+    my $args = shift;
+    my $separator = shift;
+    while($args->[0] && $args->[0] ne $separator) { 
+        push @ret, shift @$args;
+    }
+    shift @$args if @$args;
+    return @ret;
+}
+
+sub parse_all_v3 {
+    my $srcs = shift;
+    my $vars = shift;
+    my $db = get_all_source_info();
+    my $binary = $srcs->{'_binary'};
+
+    SRCS:
+    foreach my $name (keys %$srcs) {
+        next if $name eq '_binary';
+
+        # state = installed, out-of-date, uncompiled, packages-arch-specific, overwritten-by-arch-all, arch-not-in-arch-list, arch-all-only
+        my $pkgs = $srcs->{$name};
+        next if isin($pkgs->{'status'}, qw <arch-all-only>);
+        my $pkg = $db->{$name};
+
+        unless ($pkg) {
+            next SRCS if $pkgs->{'status'} eq 'packages-arch-specific';
+            my $logstr = sprintf("merge-v3 %s %s_%s (%s, %s):", $vars->{'time'}, $name, $pkgs->{'version'}, $vars->{'arch'}, $vars->{'suite'});
+
+            # does at least one binary exist in the database and is more recent - if so, we're probably just outdated, ignore the source package
+            for my $bin (@{$pkgs->{'binary'}}) {
+                if ($binary->{$bin} and $binary->{$bin}->{'arch'} ne 'all' and vercmp($pkgs->{'version'}, $binary->{$bin}->{'version'}) < 0) {
+                   print Dumper($binary->{$bin}) . "\n";
+                    print "$logstr skipped because binaries (assumed to be) overwritten (" .
+                       $bin . ", " . $pkgs->{'version'} . " vs. " . $binary->{$bin}->{'version'} . ")\n" if $verbose || $simulate;
+                    next SRCS;
+                }
+            }
+            $pkg->{'package'}  = $name;
+        }
+        $pkg->{'version'} ||= "";
+        $pkg->{'state'} ||= "";
+        my $logstr = sprintf("merge-v3 %s %s_%s", $vars->{'time'}, $name, $pkgs->{'version'}).
+            ($pkgs->{'binnmu'} ? ";b".$pkgs->{'binnmu'} : "").
+            sprintf(" (%s, %s, previous: %s", $vars->{'arch'}, $vars->{'suite'}, $pkg->{'version'}//"").
+            ($pkg->{'binary_nmu_version'} ? ";b".$pkg->{'binary_nmu_version'} : "").
+            ", $pkg->{'state'}".($pkg->{'notes'} ? "/".$pkg->{'notes'} : "")."):";
+
+        if (isin($pkgs->{'status'}, qw (installed related)) && $pkgs->{'version'} eq $pkg->{'version'} && ($pkgs->{'binnmu'}//0) < int($pkg->{'binary_nmu_version'}//0)) {
+                $pkgs->{'status'} = 'out-of-date';
+        }
+        if (isin($pkgs->{'status'}, qw <installed related arch-not-in-arch-list packages-arch-specific overwritten-by-arch-all arch-all-only>)) {
+            my $change = 0;
+            my $tstate = {'installed' => 'Installed', 'related' => 'Installed', 
+                'arch-not-in-arch-list' => 'Auto-Not-For-Us', 'packages-arch-specific' => 'Auto-Not-For-Us', 'overwritten-by-arch-all' => 'Auto-Not-For-Us', 'arch-all-only' => 'Auto-Not-For-Us',
+                }->{$pkgs->{'status'}};
+            next if isin( $pkg->{'state'}, qw<Not-For-Us Failed Failed-Removed Dep-Wait Dep-Wait-Removed>) && isin( $tstate, qw<Auto-Not-For-Us>);
+            # if the package is currently current, the status is Installed, not not-for-us
+            if ($pkg->{'state'} ne $tstate) {
+                change_state( \$pkg, $tstate);
+                if (isin( $tstate, qw<Installed>)) {
+                    delete $pkg->{'depends'};
+                    delete $pkg->{'extra_depends'};
+                    delete $pkg->{'extra_conflicts'};
+                }
+                $change++;
+            }
+            my $attrs = { 'version' => 'version', 'installed_version' => 'version', 'binary_nmu_version' => 'binnmu', 'section' => 'section', 'priority' => 'priority' };
+            foreach my $k (keys %$attrs) {
+                next if isin( $tstate, qw<Auto-Not-For-Us>) && isin( $k, qw<installed_version binary_nmu_version>);
+                if (($pkg->{$k}//"") ne ($pkgs->{$attrs->{$k}}//"")) {
+                    $pkg->{$k} = $pkgs->{$attrs->{$k}};
+                    $change++;
+                }
+            }
+            if (isin($pkgs->{'status'}, qw <related packages-arch-specific overwritten-by-arch-all arch-not-in-arch-list arch-all-only>)) {
+                my $tnotes = $pkgs->{'status'};
+                if (($pkg->{'notes'}//"") ne $tnotes) {
+                    $pkg->{'notes'} = $tnotes;
+                    $change++;
+                }
+            }
+            if ($change) {
+                print "$logstr set to $tstate/".($pkg->{'notes'}//"")."\n" if $verbose || $simulate;
+                log_ta( $pkg, "--merge-v3: $tstate" ) unless $simulate;
+                update_source_info($pkg) unless $simulate;
+            }
+            next;
+        }
+
+        # only uncompiled / out-of-date are left, so check if anything new
+        if (!(isin($pkgs->{'status'}, qw (uncompiled out-of-date)))) {
+            print "$logstr package in unknown state: $pkgs->{'status'}\n";
+            next SRCS;
+        }
+        next if $pkgs->{'version'} eq $pkg->{'version'} and $pkgs->{'binnmu'}//0 >= int($pkg->{'binary_nmu_version'}//0);
+        next if $pkgs->{'version'} eq $pkg->{'version'} and !isin( $pkg->{'state'}, qw(Installed));
+        next if isin( $pkg->{'state'}, qw(Not-For-Us Failed-Removed));
+
+        if (defined( $pkg->{'state'} ) && isin( $pkg->{'state'}, qw(Building Built Build-Attempted))) {
+            send_mail( $pkg->{'builder'},
+                "new version of $name (dist=$distribution)",
+                "As far as I'm informed, you're currently building the package $name\n".
+                "in version $pkg->{'version'}.\n\n".
+                "Now there's a new source version $pkgs->{'version'}. If you haven't finished\n".
+                "compiling $name yet, you can stop it to save some work.\n".
+                "Just to inform you...\n".
+                "(This is an automated message)\n" ) unless $simulate;
+           print "$logstr new version while building $pkg->{'version'} -- sending mail to builder ($pkg->{'builder'})\n"
+                                 if $verbose || $simulate;
+           }
+        change_state( \$pkg, 'Needs-Build');
+        $pkg->{'notes'} = $pkgs->{'status'};
+        $pkg->{'version'} = $pkgs->{'version'};
+        $pkg->{'section'} = $pkgs->{'section'};
+        $pkg->{'priority'} = $pkgs->{'priority'};
+        $pkg->{'dep'} = $pkgs->{'depends'};
+        $pkg->{'conf'} = $pkgs->{'conflicts'};
+        delete $pkg->{'builder'};
+        delete $pkg->{'binary_nmu_version'} unless $pkgs->{'binnmu'};
+        delete $pkg->{'binary_nmu_changelog'} unless $pkgs->{'binnmu'};
+        delete $pkg->{'buildpri'};
+        log_ta( $pkg, "--merge-v3: needs-build" ) unless $simulate;
+        update_source_info($pkg) unless $simulate;
+        print "$logstr set to needs-builds\n" if $simulate || $verbose;
+    }
+
+    foreach my $name (keys %$db) {
+        next if $srcs->{$name};
+        my $pkg = $db->{$name};
+        my $logstr = "merge-v3 $vars->{'time'} ".$name."_$pkg->{'version'} ($vars->{'arch'}, $vars->{'suite'}, previous: $pkg->{'state'}):";
+        # package disappeared - delete
+        change_state( \$pkg, 'deleted' );
+        log_ta( $pkg, "--merge-v3: deleted" ) unless $simulate;
+       print "$logstr deleted from database\n" if $verbose || $simulate;
+        del_source_info($name) unless $simulate;
+        delete $db->{$name};
+    }
 }
 }