From ddcb9685d9ab3c59cabfdd69614315af668435ec Mon Sep 17 00:00:00 2001
From: Christian Pointner <equinox@spreadspace.org>
Date: Wed, 7 Oct 2015 01:59:23 +0200
Subject: renamed most utils from rd-* to rhrd-*


diff --git a/MANIFEST b/MANIFEST
index 6a4343f..684057c 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -7,8 +7,9 @@ MANIFEST
 META.yml
 utils/get-rd-token
 utils/get-rd-week
-utils/rd-group
-utils/rd-show
-utils/rd-user
-utils/rhrd-ws-login
 utils/update-rd-tokens
+utils/rhrd-group
+utils/rhrd-show
+utils/rhrd-user
+utils/rhrd-sanity-check
+utils/rhrd-ws-login
diff --git a/Makefile.PL b/Makefile.PL
index d71fe5a..7a1b2de 100644
--- a/Makefile.PL
+++ b/Makefile.PL
@@ -1,7 +1,7 @@
 use ExtUtils::MakeMaker;
 use 5.004;
 
-my @utils = qw(get-rd-token rhrd-ws-login get-rd-week update-rd-tokens rd-user rd-group rd-show);
+my @utils = qw(get-rd-token get-rd-week update-rd-tokens rhrd-user rhrd-group rhrd-show rhrd-ws-login rhrd-sanity-check);
 
 WriteMakefile(
   NAME       => 'RHRD',
diff --git a/debian/control b/debian/control
index 69a12f8..b8ae9a5 100644
--- a/debian/control
+++ b/debian/control
@@ -20,10 +20,11 @@ Description: Radio Helsinki Rivendell Utilities
  This package contains the following tools
   * get-rd-token
   * get-rd-week
-  * rd-group
-  * rd-show
-  * rd-user
   * update-rd-tokens
+  * rhrd-group
+  * rhrd-show
+  * rhrd-user
+  * rhrd-sanity-check
 
 Package: rhrd-utils-ws
 Architecture: all
diff --git a/debian/rhrd-utils.install b/debian/rhrd-utils.install
index 24e18cc..9828367 100644
--- a/debian/rhrd-utils.install
+++ b/debian/rhrd-utils.install
@@ -1,6 +1,7 @@
 usr/bin/get-rd-token
 usr/bin/get-rd-week
-usr/bin/rd-group
-usr/bin/rd-show
-usr/bin/rd-user
 usr/bin/update-rd-tokens
+usr/bin/rhrd-group
+usr/bin/rhrd-show
+usr/bin/rhrd-user
+usr/bin/rhrd-sanity-check
diff --git a/utils/rd-group b/utils/rd-group
deleted file mode 100755
index 246d450..0000000
--- a/utils/rd-group
+++ /dev/null
@@ -1,321 +0,0 @@
-#!/usr/bin/perl -w
-#
-#  rhrdlibs
-#
-#  Copyright (C) 2015 Christian Pointner <equinox@helsinki.at>
-#
-#  This file is part of rhrdlibs.
-#
-#  rhrdlibs is free software: you can redistribute it and/or modify
-#  it under the terms of the GNU Affero General Public License as published by
-#  the Free Software Foundation, either version 3 of the License, or
-#  any later version.
-#
-#  rhrdlibs is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU Affero General Public License for more details.
-#
-#  You should have received a copy of the GNU Affero General Public License
-#  along with rhrdlibs. If not, see <http://www.gnu.org/licenses/>.
-#
-
-use strict;
-use lib "../lib/";
-use RHRD::rddb;
-
-# this is ridiculous but makes it a little harder to create/remove users...
-# if ($> != 0 ) {
-#   print STDERR "this must be run as root!\n";
-#   exit 1;
-# }
-
-sub print_usage
-{
-  print STDERR "Usage: rd-group list\n" .
-               "       rd-group (check|remove|get-members|get-carts|get-reports) <groupname>\n" .
-               "       rd-group add <groupname> [ <description> ]\n" .
-               "       rd-group (add-member|remove-member|is-member) <groupname> <user>\n" .
-               "       rd-group set-carts <groupname> [ <low> [ <high> [ <type> [ <enforce range> ]]]\n" .
-               "       rd-group set-reports <groupname> [ <nownext> [ <traffic> [ <music> ]]]\n";
-}
-
-sub list
-{
-  my ($ctx) = @_;
-
-  my @groups = RHRD::rddb::list_groups($ctx);
-  if(!defined $groups[0] && defined $groups[1]) {
-    print STDERR "$groups[1]: $groups[2]";
-    return 1;
-  }
-  for my $group (@groups) {
-    print $group . "\n";
-  }
-  return 0;
-}
-
-sub check
-{
-  my ($ctx, $groupname) = @_;
-
-  my ($result, $status, $errorstring) = RHRD::rddb::check_group($ctx, $groupname);
-  print STDERR "$result, $status: $errorstring\n";
-  return $result;
-}
-
-sub add
-{
-  my ($ctx, $groupname, $description) = @_;
-
-  my ($cnt, $status, $errorstring) = RHRD::rddb::add_group($ctx, $groupname, $description);
-  unless(defined $cnt) {
-    print STDERR "$errorstring\n";
-    return 1;
-  }
-  print int($cnt) . " rows affected\n";
-  return 0;
-}
-
-sub remove
-{
-  my ($ctx, $groupname) = @_;
-
-  my @results = RHRD::rddb::remove_group($ctx, $groupname);
-  if(!defined $results[0] && defined $results[2]) {
-    print STDERR "$results[2]\n";
-    return 1;
-  }
-  for my $href (@results) {
-    print int($href->{cnt}) . " " . $href->{name} . " deleted\n";
-  }
-  return 0;
-}
-
-sub get_members
-{
-  my ($ctx, $groupname) = @_;
-
-  my @users = RHRD::rddb::get_group_members($ctx, $groupname);
-  if(!defined $users[0] && defined $users[1]) {
-    print STDERR "$users[2]\n";
-    return 1;
-  }
-  for my $user (sort @users) {
-    print "$user\n";
-  }
-  return 0;
-}
-
-sub add_member
-{
-  my ($ctx, $groupname, $username) = @_;
-
-  my ($cnt, undef, $errorstring) = RHRD::rddb::add_group_member($ctx, $groupname, $username);
-  unless(defined $cnt) {
-    print STDERR "$errorstring\n";
-    return 1;
-  }
-  print int($cnt) . " rows affected\n";
-  return 0;
-}
-
-sub remove_member
-{
-  my ($ctx, $groupname, $username) = @_;
-
-  my ($cnt, undef, $errorstring) = RHRD::rddb::remove_group_member($ctx, $groupname, $username);
-  unless(defined $cnt) {
-    print STDERR "$errorstring\n";
-    return 1;
-  }
-  print int($cnt) . " rows affected\n";
-  return 0;
-}
-
-sub is_member
-{
-  my ($ctx, $groupname, $username) = @_;
-
-  my ($cnt, undef, $errorstring) = RHRD::rddb::is_group_member($ctx, $groupname, $username);
-  unless(defined $cnt) {
-    print STDERR "$errorstring\n";
-    return 1;
-  }
-  print $ARGV[2] . " is" . (($cnt) ? "" : " not") . " a member\n";
-  return (($cnt) ? 0 : 1);
-}
-
-sub get_carts
-{
-  my ($ctx, $groupname) = @_;
-
-  my ($low, $high, $type, $enforce_range) = RHRD::rddb::get_group_carts($ctx, $groupname);
-  unless(defined $low) {
-    print STDERR "$type\n";
-    return 1;
-  }
-  print "Range: " . int($low) . " - " . int($high) . ", Type: " . int($type) . ", Enforce Range: " . $enforce_range . "\n";
-  return 0;
-}
-
-sub set_carts
-{
-  my ($ctx, $groupname, $low_cart, $high_cart, $cart_type, $enforce_cart_range) = @_;
-
-  my ($cnt, undef, $errorstring) = RHRD::rddb::set_group_carts($ctx, $groupname, $low_cart, $high_cart, $cart_type, $enforce_cart_range);
-  unless(defined $cnt) {
-    print STDERR "$errorstring\n";
-    return 1;
-  }
-  print int($cnt) . " rows affected\n";
-  return 0;
-}
-
-sub get_reports
-{
-  my ($ctx, $groupname) = @_;
-
-  my ($nownext, $traffic, $music) = RHRD::rddb::get_group_reports($ctx, $groupname);
-  unless(defined $nownext) {
-    print STDERR "$music\n";
-    return 1;
-  }
-  print "Now-Next: " . $nownext . ", Traffic: " . $traffic . ", Music: " . $music . "\n";
-  return 0;
-}
-
-sub set_reports
-{
-  my ($ctx, $groupname, $now_next, $traffic, $music) = @_;
-
-  my ($cnt, undef, $errorstring) = RHRD::rddb::set_group_reports($ctx, $groupname, $now_next, $traffic, $music);
-  unless(defined $cnt) {
-    print STDERR "$errorstring\n";
-    return 1;
-  }
-  print int($cnt) . " rows affected\n";
-
-  return 0;
-}
-
-
-my $num_args = $#ARGV + 1;
-if($num_args < 1) {
-  print_usage();
-  exit(1);
-}
-my $cmd = $ARGV[0];
-my $groupname = $ARGV[1];
-my $ret = 0;
-
-my ($ctx, $status, $errorstring) = RHRD::rddb::init();
-if(defined $ctx) {
-  if($cmd eq "list") {
-    if($num_args != 1) {
-      print_usage();
-      $ret = 1;
-    } else {
-      $ret = list($ctx);
-    }
-  }
-  elsif($cmd eq "check") {
-    if($num_args != 2) {
-      print_usage();
-      $ret = 1;
-    } else {
-      $ret = check($ctx, $groupname);
-    }
-  }
-  elsif($cmd eq "add") {
-    if($num_args < 2 || $num_args > 3) {
-      print_usage();
-      $ret = 1;
-    } else {
-      $ret = add($ctx, $groupname, $ARGV[2]);
-    }
-  }
-  elsif($cmd eq "remove") {
-    if($num_args != 2) {
-      print_usage();
-      $ret = 1;
-    } else {
-      $ret = remove($ctx, $groupname);
-    }
-  }
-  elsif($cmd eq "get-members") {
-    if($num_args != 2) {
-      print_usage();
-      $ret = 1;
-    } else {
-      $ret = get_members($ctx, $groupname);
-    }
-  }
-  elsif($cmd eq "add-member") {
-    if($num_args != 3) {
-      print_usage();
-      $ret = 1;
-    } else {
-      $ret = add_member($ctx, $groupname, $ARGV[2]);
-    }
-  }
-  elsif($cmd eq "remove-member") {
-    if($num_args != 3) {
-      print_usage();
-      $ret = 1;
-    } else {
-      $ret = remove_member($ctx, $groupname, $ARGV[2]);
-    }
-  }
-  elsif($cmd eq "is-member") {
-    if($num_args != 3) {
-      print_usage();
-      $ret = 1;
-    } else {
-      $ret = is_member($ctx, $groupname, $ARGV[2]);
-    }
-  }
-  elsif($cmd eq "get-carts") {
-    if($num_args != 2) {
-      print_usage();
-      $ret = 1;
-    } else {
-      $ret = get_carts($ctx, $groupname);
-    }
-  }
-  elsif($cmd eq "set-carts") {
-    if($num_args < 2 || $num_args > 6) {
-      print_usage();
-      $ret = 1;
-    } else {
-      $ret = set_carts($ctx, $groupname, $ARGV[2], $ARGV[3], $ARGV[4], $ARGV[5]);
-    }
-  }
-  elsif($cmd eq "get-reports") {
-    if($num_args != 2) {
-      print_usage();
-      $ret = 1;
-    } else {
-      $ret = get_reports($ctx, $groupname);
-    }
-  }
-  elsif($cmd eq "set-reports") {
-    if($num_args < 2 || $num_args > 5) {
-      print_usage();
-      $ret = 1;
-    } else {
-      $ret = set_reports($ctx, $groupname, $ARGV[2], $ARGV[3], $ARGV[4]);
-    }
-  }
-  else {
-    print_usage();
-    $ret = 1;
-  }
-
-  RHRD::rddb::destroy($ctx);
-} else {
-  print STDERR "$errorstring\n";
-  $ret = 1;
-}
-
-exit $ret;
diff --git a/utils/rd-show b/utils/rd-show
deleted file mode 100755
index 0ad2426..0000000
--- a/utils/rd-show
+++ /dev/null
@@ -1,326 +0,0 @@
-#!/usr/bin/perl -w
-#
-#  rhrdlibs
-#
-#  Copyright (C) 2015 Christian Pointner <equinox@helsinki.at>
-#
-#  This file is part of rhrdlibs.
-#
-#  rhrdlibs is free software: you can redistribute it and/or modify
-#  it under the terms of the GNU Affero General Public License as published by
-#  the Free Software Foundation, either version 3 of the License, or
-#  any later version.
-#
-#  rhrdlibs is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU Affero General Public License for more details.
-#
-#  You should have received a copy of the GNU Affero General Public License
-#  along with rhrdlibs. If not, see <http://www.gnu.org/licenses/>.
-#
-
-use strict;
-use lib "../lib/";
-use RHRD::rddb;
-
-# this is ridiculous but makes it a little harder to create/remove users...
-# if ($> != 0 ) {
-#   print STDERR "this must be run as root!\n";
-#   exit 1;
-# }
-
-sub print_usage
-{
-  print STDERR "Usage: rd-show list\n" .
-               "       rd-show (show|remove) <show-id>\n" .
-               "       rd-show add <groupname> <name> <title> <num-carts> <rhythm> <dow> <starttime> <len>\n";
-}
-
-sub list
-{
-  my ($ctx) = @_;
-
-  my @shows = RHRD::rddb::list_shows($ctx);
-  if(!defined $shows[0] && defined $shows[1]) {
-    print STDERR "$shows[1]: $shows[2]";
-    return 1;
-  }
-  for my $href (@shows) {
-    print $href->{'ID'} . ": " . $href->{'TITLE'} . "\n";
-  }
-  return 0;
-}
-
-sub show
-{
-  my ($ctx, $show_id) = @_;
-
-  my @carts = RHRD::rddb::get_show_carts($ctx, $show_id);
-  if(!defined $carts[0] && defined $carts[1]) {
-    print STDERR "$carts[1]: $carts[2]\n";
-    return 1;
-  }
-  my ($title, undef, $status, $errorstring) = RHRD::rddb::get_show_title_and_log($ctx, $show_id);
-  unless (defined $title) {
-    print STDERR "$errorstring\n";
-    return 1;
-  }
-  print $title . ":\n";
-  for my $cart (@carts) {
-    print " > " . $cart . "\n";
-  }
-  return 0;
-}
-
-
-
-sub add__check_arguments
-{
-  my ($name, $title, $num_carts, $rhythm, $dow, $starttime, $len) = @_;
-
-  if($name !~ m/^[a-zA-Z0-9_]{1,10}$/) {
-    print STDERR "name '" . $name . "' contains illegal characters or is too long/short\n";
-    print STDERR "  only a-z, A-Z, 0-9 and _ are allowed and the length must be between 1 and 10\n";
-    return 1;
-  }
-
-  if($num_carts <= 0) {
-    print STDERR "num-carts '" . $num_carts . "' must be > 0\n";
-    return 1;
-  }
-
-  if($rhythm !~ m/^[01]{4}$/ || $rhythm eq '0000') {
-    print STDERR "rhythm '" . $rhythm . "' contains illegal characters or is too long/short\n";
-    print STDERR "  only 0 or 1 are allowed and, length must be exactly 4 and it must not be '0000'\n";
-    return 1;
-  }
-
-  if($dow < 1 || $dow > 7) {
-    print STDERR "dow '" . $dow . "' is out of range, must be between 1 and 7 (1=Monday, ..., 7=Sunday)\n";
-    return 1;
-  }
-
-  if($starttime !~ m/^[0-2][0-9][0-5][0-9]$/ || $starttime > 2359) {
-    print STDERR "starttime '" . $starttime . "' is not a valid time must be HHMM\n";
-    return 1;
-  }
-
-  if($len <= 0) {
-    print STDERR "len '" . $len . "' must be > 0\n";
-    return 1;
-  }
-
-  return 0;
-}
-
-sub add__get_show_carts
-{
-  my ($ctx, $groupname, $num_carts) = @_;
-
-  my ($result, $status, $errorstring) = RHRD::rddb::check_group($ctx, $groupname);
-  unless(defined $result) {
-    print STDERR $status . ": " . $errorstring . "\n";
-    return undef;
-  }
-
-  my $low_cart = 0;
-  if($result) {
-    print "   > using existing group '" . $groupname . "'\n";
-    $low_cart = add__get_free_group_carts($ctx, $groupname, $num_carts);
-  } else {
-    print "   > '" . $groupname . "' does not exist - creating it .. ";
-    $low_cart = add__create_group($ctx, $groupname);
-  }
-
-  return $low_cart;
-}
-
-sub add__create_group
-{
-  my ($ctx, $groupname) = @_;
-
-  my ($cnt, $status, $errorstring) = RHRD::rddb::add_group($ctx, $groupname);
-  unless(defined $cnt) {
-    print STDERR $status . ": " . $errorstring . "\n";
-    return undef;
-  }
-  print int($cnt) . " rows affected\n";
-
-  (my $low_cart, my $high_cart, $errorstring) = RHRD::rddb::get_shows_next_free_slot($ctx);
-  if(!$low_cart) {
-    print $high_cart . ": " . $errorstring . "\n";
-    return undef;
-  }
-  print "     using carts " . $low_cart . " - " . $high_cart . " for new group .. ";
-
-  ($cnt, $status, $errorstring) = RHRD::rddb::set_group_carts($ctx, $groupname, $low_cart, $high_cart, 1, 'Y');
-  unless(defined $cnt) {
-    print STDERR $status . ": " . $errorstring . "\n";
-    return undef;
-  }
-  print int($cnt) . " rows affected\n";
-
-  print "     enabling reports  .. ";
-  ($cnt, $status, $errorstring) = RHRD::rddb::set_group_reports($ctx, $groupname, 'Y', 'Y', 'Y');
-  unless(defined $cnt) {
-    print STDERR $status . ": " . $errorstring . "\n";
-    return undef;
-  }
-  print int($cnt) . " rows affected\n";
-
-  return $low_cart;
-}
-
-sub add__get_free_group_carts
-{
-  my ($ctx, $groupname, $num_carts) = @_;
-
-  my ($low_cart, $high_cart, $type, undef) = RHRD::rddb::get_group_carts($ctx, $groupname);
-  unless(defined $low_cart) {
-    print STDERR $high_cart . ": " . $type . "\n";
-    return undef;
-  }
-
-  my @dropboxes = RHRD::rddb::get_dropboxes($ctx, $ctx->{'config'}{'shows'}{'defaultuser'}, $groupname, 'S');
-  if(!defined $dropboxes[0]) {
-    if(defined $dropboxes[1]) {
-      print STDERR "$dropboxes[1]: $dropboxes[2]";
-      return undef;
-    }
-    return $low_cart;
-  }
-
-  my @carts = ();
-  for my $db (@dropboxes) {
-    my @show_carts = RHRD::rddb::get_show_carts($ctx, $db->{'SHOWID'});
-    if(!defined $show_carts[0] && defined $show_carts[1]) {
-      print STDERR "$show_carts[1]: $show_carts[2]\n";
-      return undef;
-    }
-    @carts = (@carts, @show_carts) if defined($show_carts[0])
-  }
-
-  @carts = sort(@carts);
-  for my $cart (@carts) {
-    last if(($low_cart + $num_carts - 1) < $cart);
-    $low_cart += 1;
-  }
-  if(($low_cart + $num_carts -1) > $high_cart) {
-    print STDERR "there are not enough free carts\n";
-    return undef;
-  }
-
-  return $low_cart;
-}
-
-sub add
-{
-  my ($ctx, $groupname, $name, $title, $num_carts, $rhythm, $dow, $starttime, $len) = @_;
-
-  my $ret = add__check_arguments($name, $title, $num_carts, $rhythm, $dow, $starttime, $len);
-  if($ret) {
-    return $ret;
-  }
-
-  print " * creating show: " . $title . " (" . $name . ") for group '" . $groupname . "'\n";
-
-  my $low_cart = add__get_show_carts($ctx, $groupname, $num_carts);
-  return 1 unless defined($low_cart);
-  my $high_cart = $low_cart + $num_carts - 1;
-  print " * will be using carts: " . $low_cart . " - " . $high_cart . "\n";
-
-  my ($result, $status, $errorstring) = RHRD::rddb::create_show_log($ctx, $name, $low_cart, $high_cart);
-  unless(defined $result) {
-    print STDERR $status . ": " . $errorstring . "\n";
-    return 1;
-  }
-  print " * created log with name: " . $name . "\n";
-
-  (my $show_id, $status, $errorstring) = RHRD::rddb::create_show_macro_cart($ctx, $name, $title);
-  unless(defined $result) {
-    print STDERR $status . ": " . $errorstring . "\n";
-    return 1;
-  }
-  print " * created macro cart -> new show-id = " . $show_id . "\n";
-
-  ($result, $status, $errorstring) = RHRD::rddb::create_show_dropbox($ctx, $groupname, $show_id, $rhythm, $dow, $starttime, $len);
-  unless(defined $result) {
-    print STDERR $status . ": " . $errorstring . "\n";
-    return 1;
-  }
-  print " * created dropbox for show .. " . $result . " rows affected\n";
-
-  print " * finished\n";
-
-  return 0;
-}
-
-sub remove
-{
-  my ($ctx, $show_id) = @_;
-
-  my @results = RHRD::rddb::remove_show($ctx, $show_id);
-  if(!defined $results[0] && defined $results[2]) {
-    print STDERR "$results[2]\n";
-    return 1;
-  }
-  for my $href (@results) {
-    print int($href->{cnt}) . " " . $href->{name} . " deleted\n";
-  }
-  return 0;
-}
-
-my $num_args = $#ARGV + 1;
-if($num_args < 1) {
-  print_usage();
-  exit(1);
-}
-my $cmd = $ARGV[0];
-my $ret = 0;
-
-my ($ctx, $status, $errorstring) = RHRD::rddb::init();
-if(defined $ctx) {
-  if($cmd eq "list") {
-    if($num_args != 1) {
-      print_usage();
-      $ret = 1;
-    } else {
-      $ret = list($ctx)
-    }
-  }
-  elsif($cmd eq "show") {
-    if($num_args != 2) {
-      print_usage();
-      $ret = 1;
-    } else {
-      $ret = show($ctx, $ARGV[1])
-    }
-  }
-  elsif($cmd eq "remove") {
-    if($num_args != 2) {
-      print_usage();
-      $ret = 1;
-    } else {
-      $ret = remove($ctx, $ARGV[1]);
-    }
-  }
-  elsif($cmd eq "add") {
-    if($num_args != 9) {
-      print_usage();
-      $ret = 1;
-    } else {
-      $ret = add($ctx, $ARGV[1], $ARGV[2], $ARGV[3], $ARGV[4], $ARGV[5], $ARGV[6], $ARGV[7], $ARGV[8]);
-    }
-  }
-  else {
-    print_usage();
-    $ret = 1;
-  }
-  RHRD::rddb::destroy($ctx);
-} else {
-  print STDERR "$errorstring\n";
-  $ret = 1;
-}
-
-exit $ret;
diff --git a/utils/rd-user b/utils/rd-user
deleted file mode 100755
index 8689cb4..0000000
--- a/utils/rd-user
+++ /dev/null
@@ -1,145 +0,0 @@
-#!/usr/bin/perl -w
-#
-#  rhrdlibs
-#
-#  Copyright (C) 2015 Christian Pointner <equinox@helsinki.at>
-#
-#  This file is part of rhrdlibs.
-#
-#  rhrdlibs is free software: you can redistribute it and/or modify
-#  it under the terms of the GNU Affero General Public License as published by
-#  the Free Software Foundation, either version 3 of the License, or
-#  any later version.
-#
-#  rhrdlibs is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU Affero General Public License for more details.
-#
-#  You should have received a copy of the GNU Affero General Public License
-#  along with rhrdlibs. If not, see <http://www.gnu.org/licenses/>.
-#
-
-use strict;
-use RHRD::rddb;
-use String::MkPasswd qw(mkpasswd);
-
-# this is ridiculous but makes it a little harder to create/remove users...
-if ($> != 0 ) {
-  print STDERR "this must be run as root!\n";
-  exit 1;
-}
-
-sub print_usage
-{
-  print STDERR "Usage: rd-user list\n" .
-               "       rd-user (check|remove) <username>\n" .
-               "       rd-user add <username> [ <fullname> ]\n";
-}
-
-sub list
-{
-  my ($ctx) = @_;
-
-  my @users = RHRD::rddb::list_users($ctx);
-  if(!defined $users[0] && defined $users[1]) {
-    print STDERR "$users[1]: $users[2]";
-    return 1;
-  }
-  for my $user (@users) {
-    print $user . "\n";
-  }
-  return 0;
-}
-
-sub check
-{
-  my ($ctx, $username) = @_;
-
-  my ($result, $status, $errorstring) = RHRD::rddb::check_user($ctx, $username);
-  print STDERR "$result, $status: $errorstring\n";
-  return $result;
-}
-
-sub add
-{
-  my ($ctx, $username, $fullname) = @_;
-
-  my $token = mkpasswd(-length => 16, -minnum => 3, -minupper => 3, -minspecial => 0);
-  my ($cnt, undef, $errorstring) = RHRD::rddb::add_user($ctx, $username, $token, $fullname);
-  unless(defined $cnt) {
-    print STDERR "$errorstring\n";
-    return 1;
-  }
-  print int($cnt) . " rows affected\n";
-  return 0;
-}
-
-sub remove
-{
-  my ($ctx, $username) = @_;
-
-  my @results = RHRD::rddb::remove_user($ctx, $username);
-  if(!defined $results[0] && defined $results[2]) {
-    print STDERR "$results[2]\n";
-    return 1;
-  }
-  for my $href (@results) {
-    print int($href->{cnt}) . " " . $href->{name} . " deleted\n";
-  }
-  return 0;
-}
-
-
-my $num_args = $#ARGV + 1;
-if($num_args < 1) {
-  print_usage();
-  exit(1);
-}
-my $cmd = $ARGV[0];
-my $username = $ARGV[1];
-my $ret = 0;
-
-my ($ctx, undef, $errorstring) = RHRD::rddb::init();
-if(defined $ctx) {
-  if($cmd eq "list") {
-    if($num_args != 1) {
-      print_usage();
-      $ret = 1;
-    } else {
-      $ret = list($ctx);
-    }
-  }
-  elsif($cmd eq "check") {
-    if($num_args != 2) {
-      print_usage();
-      $ret = 1;
-    } else {
-      $ret = check($ctx, $username);
-    }
-  } elsif($cmd eq "add") {
-    if($num_args < 2 || $num_args > 3) {
-      print_usage();
-      $ret = 1;
-    } else {
-      $ret = add($ctx, $username, $ARGV[2]);
-    }
-  } elsif($cmd eq "remove") {
-    if($num_args != 2) {
-      print_usage();
-      $ret = 1;
-    } else {
-      $ret = remove($ctx, $username);
-    }
-  } else {
-    print_usage();
-    $ret = 1;
-  }
-
-  RHRD::rddb::destroy($ctx);
-} else {
-  print STDERR "$errorstring\n";
-  $ret = 1;
-}
-
-exit $ret;
diff --git a/utils/rhrd-group b/utils/rhrd-group
new file mode 100755
index 0000000..246d450
--- /dev/null
+++ b/utils/rhrd-group
@@ -0,0 +1,321 @@
+#!/usr/bin/perl -w
+#
+#  rhrdlibs
+#
+#  Copyright (C) 2015 Christian Pointner <equinox@helsinki.at>
+#
+#  This file is part of rhrdlibs.
+#
+#  rhrdlibs is free software: you can redistribute it and/or modify
+#  it under the terms of the GNU Affero General Public License as published by
+#  the Free Software Foundation, either version 3 of the License, or
+#  any later version.
+#
+#  rhrdlibs is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU Affero General Public License for more details.
+#
+#  You should have received a copy of the GNU Affero General Public License
+#  along with rhrdlibs. If not, see <http://www.gnu.org/licenses/>.
+#
+
+use strict;
+use lib "../lib/";
+use RHRD::rddb;
+
+# this is ridiculous but makes it a little harder to create/remove users...
+# if ($> != 0 ) {
+#   print STDERR "this must be run as root!\n";
+#   exit 1;
+# }
+
+sub print_usage
+{
+  print STDERR "Usage: rd-group list\n" .
+               "       rd-group (check|remove|get-members|get-carts|get-reports) <groupname>\n" .
+               "       rd-group add <groupname> [ <description> ]\n" .
+               "       rd-group (add-member|remove-member|is-member) <groupname> <user>\n" .
+               "       rd-group set-carts <groupname> [ <low> [ <high> [ <type> [ <enforce range> ]]]\n" .
+               "       rd-group set-reports <groupname> [ <nownext> [ <traffic> [ <music> ]]]\n";
+}
+
+sub list
+{
+  my ($ctx) = @_;
+
+  my @groups = RHRD::rddb::list_groups($ctx);
+  if(!defined $groups[0] && defined $groups[1]) {
+    print STDERR "$groups[1]: $groups[2]";
+    return 1;
+  }
+  for my $group (@groups) {
+    print $group . "\n";
+  }
+  return 0;
+}
+
+sub check
+{
+  my ($ctx, $groupname) = @_;
+
+  my ($result, $status, $errorstring) = RHRD::rddb::check_group($ctx, $groupname);
+  print STDERR "$result, $status: $errorstring\n";
+  return $result;
+}
+
+sub add
+{
+  my ($ctx, $groupname, $description) = @_;
+
+  my ($cnt, $status, $errorstring) = RHRD::rddb::add_group($ctx, $groupname, $description);
+  unless(defined $cnt) {
+    print STDERR "$errorstring\n";
+    return 1;
+  }
+  print int($cnt) . " rows affected\n";
+  return 0;
+}
+
+sub remove
+{
+  my ($ctx, $groupname) = @_;
+
+  my @results = RHRD::rddb::remove_group($ctx, $groupname);
+  if(!defined $results[0] && defined $results[2]) {
+    print STDERR "$results[2]\n";
+    return 1;
+  }
+  for my $href (@results) {
+    print int($href->{cnt}) . " " . $href->{name} . " deleted\n";
+  }
+  return 0;
+}
+
+sub get_members
+{
+  my ($ctx, $groupname) = @_;
+
+  my @users = RHRD::rddb::get_group_members($ctx, $groupname);
+  if(!defined $users[0] && defined $users[1]) {
+    print STDERR "$users[2]\n";
+    return 1;
+  }
+  for my $user (sort @users) {
+    print "$user\n";
+  }
+  return 0;
+}
+
+sub add_member
+{
+  my ($ctx, $groupname, $username) = @_;
+
+  my ($cnt, undef, $errorstring) = RHRD::rddb::add_group_member($ctx, $groupname, $username);
+  unless(defined $cnt) {
+    print STDERR "$errorstring\n";
+    return 1;
+  }
+  print int($cnt) . " rows affected\n";
+  return 0;
+}
+
+sub remove_member
+{
+  my ($ctx, $groupname, $username) = @_;
+
+  my ($cnt, undef, $errorstring) = RHRD::rddb::remove_group_member($ctx, $groupname, $username);
+  unless(defined $cnt) {
+    print STDERR "$errorstring\n";
+    return 1;
+  }
+  print int($cnt) . " rows affected\n";
+  return 0;
+}
+
+sub is_member
+{
+  my ($ctx, $groupname, $username) = @_;
+
+  my ($cnt, undef, $errorstring) = RHRD::rddb::is_group_member($ctx, $groupname, $username);
+  unless(defined $cnt) {
+    print STDERR "$errorstring\n";
+    return 1;
+  }
+  print $ARGV[2] . " is" . (($cnt) ? "" : " not") . " a member\n";
+  return (($cnt) ? 0 : 1);
+}
+
+sub get_carts
+{
+  my ($ctx, $groupname) = @_;
+
+  my ($low, $high, $type, $enforce_range) = RHRD::rddb::get_group_carts($ctx, $groupname);
+  unless(defined $low) {
+    print STDERR "$type\n";
+    return 1;
+  }
+  print "Range: " . int($low) . " - " . int($high) . ", Type: " . int($type) . ", Enforce Range: " . $enforce_range . "\n";
+  return 0;
+}
+
+sub set_carts
+{
+  my ($ctx, $groupname, $low_cart, $high_cart, $cart_type, $enforce_cart_range) = @_;
+
+  my ($cnt, undef, $errorstring) = RHRD::rddb::set_group_carts($ctx, $groupname, $low_cart, $high_cart, $cart_type, $enforce_cart_range);
+  unless(defined $cnt) {
+    print STDERR "$errorstring\n";
+    return 1;
+  }
+  print int($cnt) . " rows affected\n";
+  return 0;
+}
+
+sub get_reports
+{
+  my ($ctx, $groupname) = @_;
+
+  my ($nownext, $traffic, $music) = RHRD::rddb::get_group_reports($ctx, $groupname);
+  unless(defined $nownext) {
+    print STDERR "$music\n";
+    return 1;
+  }
+  print "Now-Next: " . $nownext . ", Traffic: " . $traffic . ", Music: " . $music . "\n";
+  return 0;
+}
+
+sub set_reports
+{
+  my ($ctx, $groupname, $now_next, $traffic, $music) = @_;
+
+  my ($cnt, undef, $errorstring) = RHRD::rddb::set_group_reports($ctx, $groupname, $now_next, $traffic, $music);
+  unless(defined $cnt) {
+    print STDERR "$errorstring\n";
+    return 1;
+  }
+  print int($cnt) . " rows affected\n";
+
+  return 0;
+}
+
+
+my $num_args = $#ARGV + 1;
+if($num_args < 1) {
+  print_usage();
+  exit(1);
+}
+my $cmd = $ARGV[0];
+my $groupname = $ARGV[1];
+my $ret = 0;
+
+my ($ctx, $status, $errorstring) = RHRD::rddb::init();
+if(defined $ctx) {
+  if($cmd eq "list") {
+    if($num_args != 1) {
+      print_usage();
+      $ret = 1;
+    } else {
+      $ret = list($ctx);
+    }
+  }
+  elsif($cmd eq "check") {
+    if($num_args != 2) {
+      print_usage();
+      $ret = 1;
+    } else {
+      $ret = check($ctx, $groupname);
+    }
+  }
+  elsif($cmd eq "add") {
+    if($num_args < 2 || $num_args > 3) {
+      print_usage();
+      $ret = 1;
+    } else {
+      $ret = add($ctx, $groupname, $ARGV[2]);
+    }
+  }
+  elsif($cmd eq "remove") {
+    if($num_args != 2) {
+      print_usage();
+      $ret = 1;
+    } else {
+      $ret = remove($ctx, $groupname);
+    }
+  }
+  elsif($cmd eq "get-members") {
+    if($num_args != 2) {
+      print_usage();
+      $ret = 1;
+    } else {
+      $ret = get_members($ctx, $groupname);
+    }
+  }
+  elsif($cmd eq "add-member") {
+    if($num_args != 3) {
+      print_usage();
+      $ret = 1;
+    } else {
+      $ret = add_member($ctx, $groupname, $ARGV[2]);
+    }
+  }
+  elsif($cmd eq "remove-member") {
+    if($num_args != 3) {
+      print_usage();
+      $ret = 1;
+    } else {
+      $ret = remove_member($ctx, $groupname, $ARGV[2]);
+    }
+  }
+  elsif($cmd eq "is-member") {
+    if($num_args != 3) {
+      print_usage();
+      $ret = 1;
+    } else {
+      $ret = is_member($ctx, $groupname, $ARGV[2]);
+    }
+  }
+  elsif($cmd eq "get-carts") {
+    if($num_args != 2) {
+      print_usage();
+      $ret = 1;
+    } else {
+      $ret = get_carts($ctx, $groupname);
+    }
+  }
+  elsif($cmd eq "set-carts") {
+    if($num_args < 2 || $num_args > 6) {
+      print_usage();
+      $ret = 1;
+    } else {
+      $ret = set_carts($ctx, $groupname, $ARGV[2], $ARGV[3], $ARGV[4], $ARGV[5]);
+    }
+  }
+  elsif($cmd eq "get-reports") {
+    if($num_args != 2) {
+      print_usage();
+      $ret = 1;
+    } else {
+      $ret = get_reports($ctx, $groupname);
+    }
+  }
+  elsif($cmd eq "set-reports") {
+    if($num_args < 2 || $num_args > 5) {
+      print_usage();
+      $ret = 1;
+    } else {
+      $ret = set_reports($ctx, $groupname, $ARGV[2], $ARGV[3], $ARGV[4]);
+    }
+  }
+  else {
+    print_usage();
+    $ret = 1;
+  }
+
+  RHRD::rddb::destroy($ctx);
+} else {
+  print STDERR "$errorstring\n";
+  $ret = 1;
+}
+
+exit $ret;
diff --git a/utils/rhrd-sanity-check b/utils/rhrd-sanity-check
new file mode 100755
index 0000000..ced1d30
--- /dev/null
+++ b/utils/rhrd-sanity-check
@@ -0,0 +1,98 @@
+#!/usr/bin/perl -w
+#
+#  rhrdlibs
+#
+#  Copyright (C) 2015 Christian Pointner <equinox@helsinki.at>
+#
+#  This file is part of rhrdlibs.
+#
+#  rhrdlibs is free software: you can redistribute it and/or modify
+#  it under the terms of the GNU Affero General Public License as published by
+#  the Free Software Foundation, either version 3 of the License, or
+#  any later version.
+#
+#  rhrdlibs is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU Affero General Public License for more details.
+#
+#  You should have received a copy of the GNU Affero General Public License
+#  along with rhrdlibs. If not, see <http://www.gnu.org/licenses/>.
+#
+
+use strict;
+use lib "../lib/";
+use RHRD::rddb;
+
+# this is ridiculous but makes it a little harder to create/remove users...
+# if ($> != 0 ) {
+#   print STDERR "this must be run as root!\n";
+#   exit 1;
+# }
+
+sub print_usage
+{
+  print STDERR "Usage: rhrd-sanity-check\n";
+}
+
+my $num_args = $#ARGV + 1;
+if($num_args > 0) {
+  print_usage();
+  exit(1);
+}
+my $ret = 0;
+
+
+sub check_groups
+{
+  my ($ctx) = @_;
+
+  print "groups:\n";
+
+  my @groups = RHRD::rddb::list_groups($ctx);
+  if(!defined $groups[0] && defined $groups[1]) {
+    print STDERR "$groups[1]: $groups[2]";
+    return 1;
+  }
+  for my $group (@groups) {
+    next if($group eq $ctx->{'config'}{'specialgroups'}{'system'});
+    next if($group eq $ctx->{'config'}{'specialgroups'}{'shows'});
+    next if($group eq $ctx->{'config'}{'specialgroups'}{'allshows'});
+    next if($group eq $ctx->{'config'}{'specialgroups'}{'allpools'});
+    next if($group eq $ctx->{'config'}{'specialgroups'}{'alljingles'});
+    print " " . $group . "\n";
+  }
+  return 0;
+}
+
+sub check_logs
+{
+  my ($ctx) = @_;
+
+  print "logs:\n";
+  print "  check not yet implemtned!!\n";
+}
+
+sub check_dropboxes
+{
+  my ($ctx) = @_;
+
+  print "dropboxes:\n";
+  print "  check not yet implemtned!!\n";
+}
+
+my ($ctx, $status, $errorstring) = RHRD::rddb::init();
+if(defined $ctx) {
+  check_groups($ctx);
+  print "\n";
+  check_logs($ctx);
+  print "\n";
+  check_dropboxes($ctx);
+
+  RHRD::rddb::destroy($ctx);
+} else {
+  print STDERR "$errorstring\n";
+  $ret = 1;
+}
+
+exit $ret;
diff --git a/utils/rhrd-show b/utils/rhrd-show
new file mode 100755
index 0000000..0ad2426
--- /dev/null
+++ b/utils/rhrd-show
@@ -0,0 +1,326 @@
+#!/usr/bin/perl -w
+#
+#  rhrdlibs
+#
+#  Copyright (C) 2015 Christian Pointner <equinox@helsinki.at>
+#
+#  This file is part of rhrdlibs.
+#
+#  rhrdlibs is free software: you can redistribute it and/or modify
+#  it under the terms of the GNU Affero General Public License as published by
+#  the Free Software Foundation, either version 3 of the License, or
+#  any later version.
+#
+#  rhrdlibs is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU Affero General Public License for more details.
+#
+#  You should have received a copy of the GNU Affero General Public License
+#  along with rhrdlibs. If not, see <http://www.gnu.org/licenses/>.
+#
+
+use strict;
+use lib "../lib/";
+use RHRD::rddb;
+
+# this is ridiculous but makes it a little harder to create/remove users...
+# if ($> != 0 ) {
+#   print STDERR "this must be run as root!\n";
+#   exit 1;
+# }
+
+sub print_usage
+{
+  print STDERR "Usage: rd-show list\n" .
+               "       rd-show (show|remove) <show-id>\n" .
+               "       rd-show add <groupname> <name> <title> <num-carts> <rhythm> <dow> <starttime> <len>\n";
+}
+
+sub list
+{
+  my ($ctx) = @_;
+
+  my @shows = RHRD::rddb::list_shows($ctx);
+  if(!defined $shows[0] && defined $shows[1]) {
+    print STDERR "$shows[1]: $shows[2]";
+    return 1;
+  }
+  for my $href (@shows) {
+    print $href->{'ID'} . ": " . $href->{'TITLE'} . "\n";
+  }
+  return 0;
+}
+
+sub show
+{
+  my ($ctx, $show_id) = @_;
+
+  my @carts = RHRD::rddb::get_show_carts($ctx, $show_id);
+  if(!defined $carts[0] && defined $carts[1]) {
+    print STDERR "$carts[1]: $carts[2]\n";
+    return 1;
+  }
+  my ($title, undef, $status, $errorstring) = RHRD::rddb::get_show_title_and_log($ctx, $show_id);
+  unless (defined $title) {
+    print STDERR "$errorstring\n";
+    return 1;
+  }
+  print $title . ":\n";
+  for my $cart (@carts) {
+    print " > " . $cart . "\n";
+  }
+  return 0;
+}
+
+
+
+sub add__check_arguments
+{
+  my ($name, $title, $num_carts, $rhythm, $dow, $starttime, $len) = @_;
+
+  if($name !~ m/^[a-zA-Z0-9_]{1,10}$/) {
+    print STDERR "name '" . $name . "' contains illegal characters or is too long/short\n";
+    print STDERR "  only a-z, A-Z, 0-9 and _ are allowed and the length must be between 1 and 10\n";
+    return 1;
+  }
+
+  if($num_carts <= 0) {
+    print STDERR "num-carts '" . $num_carts . "' must be > 0\n";
+    return 1;
+  }
+
+  if($rhythm !~ m/^[01]{4}$/ || $rhythm eq '0000') {
+    print STDERR "rhythm '" . $rhythm . "' contains illegal characters or is too long/short\n";
+    print STDERR "  only 0 or 1 are allowed and, length must be exactly 4 and it must not be '0000'\n";
+    return 1;
+  }
+
+  if($dow < 1 || $dow > 7) {
+    print STDERR "dow '" . $dow . "' is out of range, must be between 1 and 7 (1=Monday, ..., 7=Sunday)\n";
+    return 1;
+  }
+
+  if($starttime !~ m/^[0-2][0-9][0-5][0-9]$/ || $starttime > 2359) {
+    print STDERR "starttime '" . $starttime . "' is not a valid time must be HHMM\n";
+    return 1;
+  }
+
+  if($len <= 0) {
+    print STDERR "len '" . $len . "' must be > 0\n";
+    return 1;
+  }
+
+  return 0;
+}
+
+sub add__get_show_carts
+{
+  my ($ctx, $groupname, $num_carts) = @_;
+
+  my ($result, $status, $errorstring) = RHRD::rddb::check_group($ctx, $groupname);
+  unless(defined $result) {
+    print STDERR $status . ": " . $errorstring . "\n";
+    return undef;
+  }
+
+  my $low_cart = 0;
+  if($result) {
+    print "   > using existing group '" . $groupname . "'\n";
+    $low_cart = add__get_free_group_carts($ctx, $groupname, $num_carts);
+  } else {
+    print "   > '" . $groupname . "' does not exist - creating it .. ";
+    $low_cart = add__create_group($ctx, $groupname);
+  }
+
+  return $low_cart;
+}
+
+sub add__create_group
+{
+  my ($ctx, $groupname) = @_;
+
+  my ($cnt, $status, $errorstring) = RHRD::rddb::add_group($ctx, $groupname);
+  unless(defined $cnt) {
+    print STDERR $status . ": " . $errorstring . "\n";
+    return undef;
+  }
+  print int($cnt) . " rows affected\n";
+
+  (my $low_cart, my $high_cart, $errorstring) = RHRD::rddb::get_shows_next_free_slot($ctx);
+  if(!$low_cart) {
+    print $high_cart . ": " . $errorstring . "\n";
+    return undef;
+  }
+  print "     using carts " . $low_cart . " - " . $high_cart . " for new group .. ";
+
+  ($cnt, $status, $errorstring) = RHRD::rddb::set_group_carts($ctx, $groupname, $low_cart, $high_cart, 1, 'Y');
+  unless(defined $cnt) {
+    print STDERR $status . ": " . $errorstring . "\n";
+    return undef;
+  }
+  print int($cnt) . " rows affected\n";
+
+  print "     enabling reports  .. ";
+  ($cnt, $status, $errorstring) = RHRD::rddb::set_group_reports($ctx, $groupname, 'Y', 'Y', 'Y');
+  unless(defined $cnt) {
+    print STDERR $status . ": " . $errorstring . "\n";
+    return undef;
+  }
+  print int($cnt) . " rows affected\n";
+
+  return $low_cart;
+}
+
+sub add__get_free_group_carts
+{
+  my ($ctx, $groupname, $num_carts) = @_;
+
+  my ($low_cart, $high_cart, $type, undef) = RHRD::rddb::get_group_carts($ctx, $groupname);
+  unless(defined $low_cart) {
+    print STDERR $high_cart . ": " . $type . "\n";
+    return undef;
+  }
+
+  my @dropboxes = RHRD::rddb::get_dropboxes($ctx, $ctx->{'config'}{'shows'}{'defaultuser'}, $groupname, 'S');
+  if(!defined $dropboxes[0]) {
+    if(defined $dropboxes[1]) {
+      print STDERR "$dropboxes[1]: $dropboxes[2]";
+      return undef;
+    }
+    return $low_cart;
+  }
+
+  my @carts = ();
+  for my $db (@dropboxes) {
+    my @show_carts = RHRD::rddb::get_show_carts($ctx, $db->{'SHOWID'});
+    if(!defined $show_carts[0] && defined $show_carts[1]) {
+      print STDERR "$show_carts[1]: $show_carts[2]\n";
+      return undef;
+    }
+    @carts = (@carts, @show_carts) if defined($show_carts[0])
+  }
+
+  @carts = sort(@carts);
+  for my $cart (@carts) {
+    last if(($low_cart + $num_carts - 1) < $cart);
+    $low_cart += 1;
+  }
+  if(($low_cart + $num_carts -1) > $high_cart) {
+    print STDERR "there are not enough free carts\n";
+    return undef;
+  }
+
+  return $low_cart;
+}
+
+sub add
+{
+  my ($ctx, $groupname, $name, $title, $num_carts, $rhythm, $dow, $starttime, $len) = @_;
+
+  my $ret = add__check_arguments($name, $title, $num_carts, $rhythm, $dow, $starttime, $len);
+  if($ret) {
+    return $ret;
+  }
+
+  print " * creating show: " . $title . " (" . $name . ") for group '" . $groupname . "'\n";
+
+  my $low_cart = add__get_show_carts($ctx, $groupname, $num_carts);
+  return 1 unless defined($low_cart);
+  my $high_cart = $low_cart + $num_carts - 1;
+  print " * will be using carts: " . $low_cart . " - " . $high_cart . "\n";
+
+  my ($result, $status, $errorstring) = RHRD::rddb::create_show_log($ctx, $name, $low_cart, $high_cart);
+  unless(defined $result) {
+    print STDERR $status . ": " . $errorstring . "\n";
+    return 1;
+  }
+  print " * created log with name: " . $name . "\n";
+
+  (my $show_id, $status, $errorstring) = RHRD::rddb::create_show_macro_cart($ctx, $name, $title);
+  unless(defined $result) {
+    print STDERR $status . ": " . $errorstring . "\n";
+    return 1;
+  }
+  print " * created macro cart -> new show-id = " . $show_id . "\n";
+
+  ($result, $status, $errorstring) = RHRD::rddb::create_show_dropbox($ctx, $groupname, $show_id, $rhythm, $dow, $starttime, $len);
+  unless(defined $result) {
+    print STDERR $status . ": " . $errorstring . "\n";
+    return 1;
+  }
+  print " * created dropbox for show .. " . $result . " rows affected\n";
+
+  print " * finished\n";
+
+  return 0;
+}
+
+sub remove
+{
+  my ($ctx, $show_id) = @_;
+
+  my @results = RHRD::rddb::remove_show($ctx, $show_id);
+  if(!defined $results[0] && defined $results[2]) {
+    print STDERR "$results[2]\n";
+    return 1;
+  }
+  for my $href (@results) {
+    print int($href->{cnt}) . " " . $href->{name} . " deleted\n";
+  }
+  return 0;
+}
+
+my $num_args = $#ARGV + 1;
+if($num_args < 1) {
+  print_usage();
+  exit(1);
+}
+my $cmd = $ARGV[0];
+my $ret = 0;
+
+my ($ctx, $status, $errorstring) = RHRD::rddb::init();
+if(defined $ctx) {
+  if($cmd eq "list") {
+    if($num_args != 1) {
+      print_usage();
+      $ret = 1;
+    } else {
+      $ret = list($ctx)
+    }
+  }
+  elsif($cmd eq "show") {
+    if($num_args != 2) {
+      print_usage();
+      $ret = 1;
+    } else {
+      $ret = show($ctx, $ARGV[1])
+    }
+  }
+  elsif($cmd eq "remove") {
+    if($num_args != 2) {
+      print_usage();
+      $ret = 1;
+    } else {
+      $ret = remove($ctx, $ARGV[1]);
+    }
+  }
+  elsif($cmd eq "add") {
+    if($num_args != 9) {
+      print_usage();
+      $ret = 1;
+    } else {
+      $ret = add($ctx, $ARGV[1], $ARGV[2], $ARGV[3], $ARGV[4], $ARGV[5], $ARGV[6], $ARGV[7], $ARGV[8]);
+    }
+  }
+  else {
+    print_usage();
+    $ret = 1;
+  }
+  RHRD::rddb::destroy($ctx);
+} else {
+  print STDERR "$errorstring\n";
+  $ret = 1;
+}
+
+exit $ret;
diff --git a/utils/rhrd-user b/utils/rhrd-user
new file mode 100755
index 0000000..8689cb4
--- /dev/null
+++ b/utils/rhrd-user
@@ -0,0 +1,145 @@
+#!/usr/bin/perl -w
+#
+#  rhrdlibs
+#
+#  Copyright (C) 2015 Christian Pointner <equinox@helsinki.at>
+#
+#  This file is part of rhrdlibs.
+#
+#  rhrdlibs is free software: you can redistribute it and/or modify
+#  it under the terms of the GNU Affero General Public License as published by
+#  the Free Software Foundation, either version 3 of the License, or
+#  any later version.
+#
+#  rhrdlibs is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU Affero General Public License for more details.
+#
+#  You should have received a copy of the GNU Affero General Public License
+#  along with rhrdlibs. If not, see <http://www.gnu.org/licenses/>.
+#
+
+use strict;
+use RHRD::rddb;
+use String::MkPasswd qw(mkpasswd);
+
+# this is ridiculous but makes it a little harder to create/remove users...
+if ($> != 0 ) {
+  print STDERR "this must be run as root!\n";
+  exit 1;
+}
+
+sub print_usage
+{
+  print STDERR "Usage: rd-user list\n" .
+               "       rd-user (check|remove) <username>\n" .
+               "       rd-user add <username> [ <fullname> ]\n";
+}
+
+sub list
+{
+  my ($ctx) = @_;
+
+  my @users = RHRD::rddb::list_users($ctx);
+  if(!defined $users[0] && defined $users[1]) {
+    print STDERR "$users[1]: $users[2]";
+    return 1;
+  }
+  for my $user (@users) {
+    print $user . "\n";
+  }
+  return 0;
+}
+
+sub check
+{
+  my ($ctx, $username) = @_;
+
+  my ($result, $status, $errorstring) = RHRD::rddb::check_user($ctx, $username);
+  print STDERR "$result, $status: $errorstring\n";
+  return $result;
+}
+
+sub add
+{
+  my ($ctx, $username, $fullname) = @_;
+
+  my $token = mkpasswd(-length => 16, -minnum => 3, -minupper => 3, -minspecial => 0);
+  my ($cnt, undef, $errorstring) = RHRD::rddb::add_user($ctx, $username, $token, $fullname);
+  unless(defined $cnt) {
+    print STDERR "$errorstring\n";
+    return 1;
+  }
+  print int($cnt) . " rows affected\n";
+  return 0;
+}
+
+sub remove
+{
+  my ($ctx, $username) = @_;
+
+  my @results = RHRD::rddb::remove_user($ctx, $username);
+  if(!defined $results[0] && defined $results[2]) {
+    print STDERR "$results[2]\n";
+    return 1;
+  }
+  for my $href (@results) {
+    print int($href->{cnt}) . " " . $href->{name} . " deleted\n";
+  }
+  return 0;
+}
+
+
+my $num_args = $#ARGV + 1;
+if($num_args < 1) {
+  print_usage();
+  exit(1);
+}
+my $cmd = $ARGV[0];
+my $username = $ARGV[1];
+my $ret = 0;
+
+my ($ctx, undef, $errorstring) = RHRD::rddb::init();
+if(defined $ctx) {
+  if($cmd eq "list") {
+    if($num_args != 1) {
+      print_usage();
+      $ret = 1;
+    } else {
+      $ret = list($ctx);
+    }
+  }
+  elsif($cmd eq "check") {
+    if($num_args != 2) {
+      print_usage();
+      $ret = 1;
+    } else {
+      $ret = check($ctx, $username);
+    }
+  } elsif($cmd eq "add") {
+    if($num_args < 2 || $num_args > 3) {
+      print_usage();
+      $ret = 1;
+    } else {
+      $ret = add($ctx, $username, $ARGV[2]);
+    }
+  } elsif($cmd eq "remove") {
+    if($num_args != 2) {
+      print_usage();
+      $ret = 1;
+    } else {
+      $ret = remove($ctx, $username);
+    }
+  } else {
+    print_usage();
+    $ret = 1;
+  }
+
+  RHRD::rddb::destroy($ctx);
+} else {
+  print STDERR "$errorstring\n";
+  $ret = 1;
+}
+
+exit $ret;
-- 
cgit v0.10.2