steffen: server/kolab-horde-fbview/kolab-horde-fbview/fbview/scripts .cvsignore, NONE, 1.1 .htaccess, NONE, 1.1 SCRIPTS, NONE, 1.1 compare_revisions.sh, NONE, 1.1 create-symlinks.php, NONE, 1.1 crond, NONE, 1.1 get_ISO3166.php, NONE, 1.1 get_login.php, NONE, 1.1 horde-rsync.sh, NONE, 1.1 http_login_refer.php, NONE, 1.1 make-release-conf.php.dist, NONE, 1.1 make-release.php, NONE, 1.1 make-snaps.php, NONE, 1.1 merge.php, NONE, 1.1 migrate_categories.php, NONE, 1.1 migrate_links.php, NONE, 1.1 migrate_user_categories.php, NONE, 1.1 package.dtd, NONE, 1.1 remove_prefs.php, NONE, 1.1 rename_category.php, NONE, 1.1 set_perms.sh, NONE, 1.1 setup.php, NONE, 1.1 temp-cleanup.cron, NONE, 1.1 update_horde.sh, NONE, 1.1

cvs at intevation.de cvs at intevation.de
Mon Oct 31 12:43:33 CET 2005


Author: steffen

Update of /kolabrepository/server/kolab-horde-fbview/kolab-horde-fbview/fbview/scripts
In directory doto:/tmp/cvs-serv18388/kolab-horde-fbview/kolab-horde-fbview/fbview/scripts

Added Files:
	.cvsignore .htaccess SCRIPTS compare_revisions.sh 
	create-symlinks.php crond get_ISO3166.php get_login.php 
	horde-rsync.sh http_login_refer.php make-release-conf.php.dist 
	make-release.php make-snaps.php merge.php 
	migrate_categories.php migrate_links.php 
	migrate_user_categories.php package.dtd remove_prefs.php 
	rename_category.php set_perms.sh setup.php temp-cleanup.cron 
	update_horde.sh 
Log Message:
Fbview in separate package

--- NEW FILE: .cvsignore ---
make-release-conf.php
--- NEW FILE: .htaccess ---
Deny from all

--- NEW FILE: SCRIPTS ---
Horde Utility Scripts                                        scripts/SCRIPTS
=--------------------------------------------------------------------------=

Introduction
~~~~~~~~~~~~
This directory contains various utility scripts for the Horde
distribution.  They are here for your convenience.


Script Index
~~~~~~~~~~~~
compare_revisions.sh
    Compares different CVS revisions of the same file.

create-symlinks.php
    Creates symbolic links necessary for developers to work
    directly on the files in the framework module without needing
    to install the changed packages.

crond
    tbd

horde-rsync.sh
    Performs a checkout of the latest Horde cvs sources using
    rsync.

http_login_refer.php
    tbd

make-snaps.php
    tbd

make-tarball.pl
    Builds distribution tarballs for Horde and Horde modules.

merge.php
    Merges commits from a commit message into the CVS tree of
    the current directory.

migrate_categories.php
    Migrates old categories to the new horde_category_attributes table.

migrate_links.php
    Migrates old Horde_Links to the horde_category_attributes table.

package.dtd
    The PEAR package description.

rpc-test.php
    Provides tests for the RPC client against several (including our own)
    RPC servers.

set_perms.sh
    Sets file ownership and permissions on the Horde tree for
    high security.

setup.php
    The main Horde setup script which allows for a step by step setup
    or reconfiguration of a Horde installation.

temp-cleanup.cron
    An example cron job shell script which will clean up any
    temporary files which may get stranded by Horde users in the
    web server's temporary directory.

update_horde.sh
    Facilitates the updating and/or installation of horde
    and its applications.

mime_mapping/
    This script converts an Apache-style mime.types file into
    a mime.mapping.php driver file suitable for use with Horde.
    It is useful for syncing Apache updates to their MIME types
    with Horde.


Database Scripts
~~~~~~~~~~~~~~~~
Database table schemas and associated utility scripts are located in the
db/ subdirectory.


LDAP Schemas
~~~~~~~~~~~~
LDAP schemas are located in the ldap/ subdirectory.

--- NEW FILE: compare_revisions.sh ---
#!/bin/sh
#
# Script to compare revisions and ignore files that should be different, and
# differences in revision numbers.
# Syntax: ./compare_revisions.sh FIRST_FOLDER SECOND_FOLDER ['ADDITIONAL PARAMETERS']

diff -r -I "\$Horde" -I "\$Revision" -I "\$Date" --exclude version.php --exclude CHANGES --exclude CREDITS --exclude '*.po' --exclude '*.pot' --exclude locale --exclude CVS --exclude '.#*' --exclude '*~' --exclude '*.bak' $3 $4 $5 $6 $7 $8 $9 $1 $2 | grep -v "config/.*\.php "

--- NEW FILE: create-symlinks.php ---
#!/usr/bin/php
<?php

// Find the base file path of Horde.
@define('HORDE_BASE', dirname(__FILE__) . '/..');

// Configuration.
// Enter directories without trailing slashes.

// The directory with the CVS checkout.
$srcDir = HORDE_BASE . '/framework';

// The directory where the softlinks are created.
// This is also the directory which you should put in your include path
// after creating the links.
$destDir = HORDE_BASE . '/libs';

/**
 * This script creates softlinks to the library files you retrieved from
 * the CVS "framework" module.
 *
 * It creates the same directory structure the packages would have if they
 * were installed with "pear install package.xml".
 * For creating this structure it uses the information given in the
 * package.xml files inside each package directory.
 *
 * $Horde: horde/scripts/create-symlinks.php,v 1.10 2004/02/14 02:00:17 chuck Exp $
 *
 * Copyright 2002 Wolfram Kriesing <wolfram at kriesing.de>
 * Copyright 2003-2004 Jan Schneider <jan at horde.org>
 *
 * See the enclosed file COPYING for license information (LGPL). If you
 * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
 *
 * @author Wolfram Kriesing <wolfram at kriesing.de>
 * @author Jan Schneider <jan at horde.org>
 * @version $Revision: 1.1 $
 * @since Horde 3.0
 */

// Do CLI checks and environment setup first.
require_once $srcDir . '/CLI/CLI.php';

// Make sure no one runs this from the web.
if (!Horde_CLI::runningFromCLI()) {
    exit("Must be run from the command line\n");
}

// Load the CLI environment - make sure there's no time limit, init
// some variables, etc.
Horde_CLI::init();

require_once 'Tree/Tree.php';

$copy = false;
if (isset($argv)) {
    while ($arg = array_shift($argv)) {
        if ($arg == '--copy') {
            $copy = true;
        } elseif (strstr($arg, '--src')) {
            list(,$srcDir) = explode('=', $arg);
        } elseif (strstr($arg, '--dest')) {
            list(,$destDir) = explode('=', $arg);
        }
    }
 }

$linker = &new Linker($copy);
if ($handle = opendir($srcDir)) {
    while ($file = readdir($handle)) {
        if ($file != '.' &&
            $file != '..' &&
            $file != 'CVS' &&
            is_dir("$srcDir/$file")) {
            $linker->process("$srcDir/$file", $destDir);
        }
    }
    closedir($handle);
 }

echo "\n";

//  possible xml-structs
//  <filelist>
//      <dir name="/" baseinstalldir="XML">
//          <file role="php">Parser.php</file>
//          <file role="php" name="RSS.php" />
//      </dir>
//  </filelist>
//
//  <filelist>
//      <file role="php" baseinstalldir="/">DB.php</file>
//      <dir name="DB">
//          <file role="php">common.php</file>
//      </dir>
//  </filelist>
class Linker {

    var $_srcDir;

    var $_baseInstallDir;

    var $_fileroles = array('php');

    var $_role;

    var $_copy;

    function Linker($copy = false)
    {
        $this->_copy = $copy;
    }

    function process($srcDir, $destDir)
    {
        $this->_srcDir = $srcDir;
        $packageFile = $this->_srcDir . '/package.xml';
        $cli = &Horde_CLI::singleton();

        if (!is_file($packageFile)) {
            $cli->message('No package.xml in ' . $this->_srcDir, 'cli.warning');
            return false;
        }

        $tree = Tree::setupMemory('XML', $packageFile);
        $tree->setup();

        // read package name
        $packageName = trim($tree->getElementContent('/package/name', 'cdata'));
        $cli->writeln("Processing package $packageName.");

        // look for filelist in '/package/release/filelist'
        $filelist = $tree->getElementByPath('/package/release/filelist');

        if ($filelist) {
            // do this better, make the tree class work case insensitive
            $baseInstallDir = $filelist['child']['attributes']['baseinstalldir'];

            $this->_baseInstallDir = $destDir;
            if ($baseInstallDir != '/') {
                $this->_baseInstallDir .= '/' . $baseInstallDir;
            }

            if (!is_dir($this->_baseInstallDir)) {
                require_once 'System.php';
                System::mkdir('-p ' . $this->_baseInstallDir);
            }

            $this->_handleFilelistTag($filelist);
        } else {
            $cli->message('No filelist tag found inside: ' . $packageFile, 'cli.warning');
        }
    }

    function _handleFilelistTag($element, $curDir = '')
    {
        foreach ($element['children'] as $child) {
            switch ($child['name']) {
            case 'file':
                $this->_handleFileTag($child, $curDir);
                break;
            case 'dir':
                $this->_handleDirTag($child, $curDir);
                break;
            default:
                $cli = &Horde_CLI::singleton();
                $cli->message('Got no handler for tag: ' . $child['name'], 'cli-warning');
                break;
            }
        }

    }

    function _handleDirTag($element, $curDir)
    {
        if ($element['attributes']['name'] != '/') {
            if (substr($curDir, -1) != '/') {
                $curDir = $curDir . '/';
            }
            $curDir = $curDir . $element['attributes']['name'];
        }

        if (!empty($element['attributes']['role'])) {
            $this->_role = $element['attributes']['role'];
        }

        if (!is_dir($this->_baseInstallDir . $curDir)) {
            require_once 'System.php';
            System::mkdir('-p ' . $this->_baseInstallDir . $curDir);
        }

        $this->_handleFilelistTag($element, $curDir);
    }

    function _handleFileTag($element, $dir)
    {
        if (!empty($element['attributes']['role'])) {
            $this->_role = $element['attributes']['role'];
        }

        if (!in_array($this->_role, $this->_fileroles)) {
            return;
        }

        if (!empty($element['attributes']['name'])) {
            $filename = $element['attributes']['name'];
        } else {
            $filename = $element['cdata'];
        }
        $filename = trim($filename);

        if ($this->_copy) {
            $cmd = "cp {$this->_srcDir}$dir/$filename {$this->_baseInstallDir}$dir/$filename";
        } else {
            $cmd = "ln -sf {$this->_srcDir}$dir/$filename {$this->_baseInstallDir}$dir/$filename";
        }
        exec($cmd);
    }

}

--- NEW FILE: crond ---
#!/usr/local/bin/php
<?php
/**
 * $Horde: horde/scripts/crond,v 1.4 2004/04/07 14:43:44 chuck Exp $
 *
 * Copyright 2003-2004 Charles J. Hagenbuch <chuck at horde.org>
 *
 * See the enclosed file COPYING for license information (LGPL).  If you
 * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
 */

define('HORDE_BASE', dirname(__FILE__) . '/..');
require_once HORDE_BASE . '/lib/CLI.php';
require_once 'Horde/Scheduler.php';

// Make sure no one runs this from the web.
if (!Horde_CLI::runningFromCLI()) {
    exit("Must be run from the command line\n");
}

// Load the CLI environment - make sure there's no time limit, init
// some variables, etc.
Horde_CLI::init();

// Get an instance of the cron scheduler.
$daemon = &Horde_Scheduler::singleton('cron');

// Now add some cron jobs to do, or add parsing to read a config file.
// $daemon->addTask('ls', '0,5,10,15,20,30,40 * * * *');

// Start the daemon going.
$daemon->run();

--- NEW FILE: get_ISO3166.php ---
#!/usr/local/bin/php
<?php
/**
 * This is a script to fetch the current ISO-3166 country definitions and
 * update Horde's country list file in horde/lib/NLS/countries.php in an
 * interactive way.
 *
 * The source for the country list is the International Organization for
 * Standardization (http://iso.org).
 *
 * $Horde: horde/scripts/get_ISO3166.php,v 1.4 2004/04/07 14:43:44 chuck Exp $
 *
 * Copyright 2004 Marko Djukic <marko at oblo.com>
 *
 * See the enclosed file COPYING for license information (GPL). If you did not
 * receive this file, see http://www.fsf.org/copyleft/gpl.html.
 *
 * @author  Marko Djukic <marko at oblo.com>
 * @version $Revision: 1.1 $
 * @since   Horde 3.0
 *
 * @todo  Would be good to expand this to fetch also ISO-3166-2 lists from
 *        somewhere for lists of countries' regions/states.
 */

define('HORDE_BASE', dirname(__FILE__) . '/..');
require_once HORDE_BASE . '/lib/core.php';

/* Location on ISO website where to fetch the updates from. */
$url = 'http://www.iso.org/iso/en/prods-services/iso3166ma/02iso-3166-code-lists/list-en1-semic.txt';
define('HORDE_BASE', dirname(__FILE__) . '/..');
$countries = &Countries::singleton($url);

/* Update Horde's file. */
$updated = $countries->update();
if ($updated == false) {
    /* Nothing found to update. */
    $countries->cli->writeln(_("Nothing to update. Exiting."));
    exit;
}
/* Save the new file. */
$countries->save();
exit;

class Countries {

    var $old_data = array();
    var $new_data = array();
    var $cli;
    var $_url;

    /**
     * Constructor
     */
    function Countries($url)
    {
        $this->_url = $url;

        require_once 'Horde/CLI.php';
        $this->cli = &new Horde_CLI();

        $this->old_data = $this->_loadOld();
        $this->new_data = $this->_loadNew();
    }

    function &factory($url)
    {
        return $ret = &new Countries($url);
    }

    function &singleton($url)
    {
        static $instance;

        if (!isset($instance)) {
            require_once 'Horde/CLI.php';
            if (!Horde_CLI::runningFromCLI()) {
                exit("Must be run from the command line\n");
            }
            Horde_CLI::init();
            $instance = &Countries::factory($url);
        }

        return $instance;
    }

    function update()
    {
        $accept_all = false;
        $updated = false;
        foreach ($this->new_data as $code => $name) {
            if ($accept_all == true) {
                /* Auto accept activated just select all auto names. */
                $this->new_data[$code] = $this->_newName($name);
            } elseif (isset($this->old_data[$code]) &&
                      strtolower($this->old_data[$code]) == strtolower($name)) {
                /* Old name matches new name so assume no changes. */
                $this->new_data[$code] = $this->old_data[$code];
            } else {
                $new_name = $this->_newName($name);
                if (isset($this->old_data[$code])) {
                    /* There is an existing old name, show the two versions. */
                    $old = $this->cli->red($this->old_data[$code]);
                    $this->cli->writeln(sprintf(_("Old name: %s"), $old));
                    $new = $this->cli->green($new_name);
                    $this->cli->writeln(sprintf(_("New name: %s"), $new));
                }
                /* Prompt for a new country name. */
                $accept = $this->cli->prompt(sprintf(_("New country name '%s', convert to: '%s'?"), $name, $new_name), array('y' => _("Yes"), 'n' => _("No"), 'a' => _("Accept All")));
                if ($accept == 'n') {
                    /* User does not accept auto name, ask for input. */
                    $new_name = $this->cli->prompt(_("Enter the new name: "), true);
                } elseif ($accept == 'a') {
                    /* User asked to accept all, flag it. */
                    $accept_all = true;
                }
                $updated = true;
                $this->new_data[$code] = $new_name;
            }
        }
        return $updated;
    }

    function save()
    {
        $filename = HORDE_BASE . '/lib/NLS/countries.php';
        $old_file = file($filename);
        $new_file = '';
        foreach ($old_file as $key => $line) {
            $new_file .= $line;
            if ($line == "\$countries = array(\n") {
                break;
            }
        }
        $new_data = array();
        foreach ($this->new_data as $code => $name) {
            $new_data[] = sprintf('    \'%s\' => _("%s")', $code, $name);
        }
        $new_file .= implode(", \n", $new_data) . ');';

        /* Save the new file. */
        if (!$fp = @fopen($filename, 'w')) {
            $this->cli->fatal(sprintf(_("Cannot open file %s."), $filename));
        }

        if (!fwrite($fp, $new_file)) {
            $this->cli->fatal(sprintf(_("Cannot write file %s."), $filename));
        }
        fclose($fp);
        $this->cli->writeln(_("Success, saved new country data."));
    }

    function &_loadOld()
    {
        require_once HORDE_BASE . '/lib/NLS/countries.php';
        return $countries;
    }

    function &_loadNew()
    {
        $new_file = Countries::_readURL($this->_url);
        if (is_a($new_file, 'PEAR_Error')) {
            $this->cli->fatal(sprintf(_("Cannot read source for country data. %s"), $new_file->getMessage()));
        }

        $lines = explode("\r\n", $new_file);
        $new_data = array();
        foreach ($lines as $line) {
            if (!preg_match('/^(.*?);(\w\w)$/', $line, $matches)) {
                continue;
            }
            $new_data[$matches[2]] = $matches[1];
        }
        return $new_data;
    }

    function _readURL()
    {
        $options['method'] = 'GET';
        $options['timeout'] = 5;
        $options['allowRedirects'] = true;

        require_once 'HTTP/Request.php';
        $http = &new HTTP_Request($this->_url, $options);
        @$http->sendRequest();
        if ($http->getResponseCode() != 200) {
            return PEAR::raiseError(sprintf(_("Could not open %s."), $this->_url));
        }

        return $http->getResponseBody();
    }

    function _newName($name)
    {
        $no_caps = array('AND', 'OF', 'THE');
        $parts = explode(' ', $name);
        foreach ($parts as $key => $part) {
            if (in_array($part, $no_caps)) {
                $part = strtolower($part);
            } else {
                $part = preg_replace('/(\w)(\w*(\'S)?)/e', "$1 . strtolower('$2')", $part);
            }
            $parts[$key] = $part;
        }
        return implode(' ', $parts);
    }

}

--- NEW FILE: get_login.php ---
<?php
/**
 * $Horde: horde/scripts/get_login.php,v 1.2 2004/05/25 20:38:32 chuck Exp $
 *
 * Copyright 2004 Joel Vandal <jvandal at infoteck.qc.ca>
 *
 * See the enclosed file COPYING for license information (LGPL). If you
 * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
 */

@define('AUTH_HANDLER', true);
@define('HORDE_BASE', dirname(__FILE__));
require_once HORDE_BASE . '/lib/base.php';

$auth = &Auth::singleton($conf['auth']['driver']);

// Check for GET auth.
if (empty($_GET['user']) || !$auth->authenticate($_GET['user'], array('password' => $_GET['pass']))) {
    header('Location: ' . Horde::applicationUrl('login.php?logout_reason=logout'));
    exit;
}

header('Location: ' . Horde::applicationUrl('index.php'));

--- NEW FILE: horde-rsync.sh ---
#!/bin/sh
#
#  $Horde: horde/scripts/horde-rsync.sh,v 2.11 2001/12/03 07:50:24 jon Exp $
#
#  This script performs a checkout from the horde CVS tree at horde.org
#
#  [ Edit the following values to suit your local environment ]

# The path to the basedirectory for your horde checkout                        
BASEDIR="${HOME}/horde"

# The path to your CVSROOT:
export CVSROOT="${BASEDIR}/rsync"

# The path in which to put the retrieved Horde files:
HORDE_DIR="${BASEDIR}/cvs"

# The absolute path to your rsync binary:
export RSYNC="/usr/local/bin/rsync"

# The absolute path to your cvs binary:
export CVSCOMMAND="/usr/bin/cvs"

# The modules which you'd like to retrieve:
DEFAULT_MODULE_LIST="imp kronolith turba jonah babel nag troll whups"

# The default label from which to checkout
DEFAULT_LABEL=HEAD

# The default type of action that should be done
DEFAULT_ACTION=update


#  -[ NOTHING ELSE SHOULD NEED TO BE EDITED BELOW THIS LINE ]-

# Arguments that you wish to pass on to cvs
#CVS_ARGS="-q"

# Arguments that you wish to pass on to rsync
RSYNC_ARGS="-av --delete"

# The rsync server/repository from which to "checkout"
RSYNC_DIR="rsync.horde.org::horde-cvs/"

# Make sure that the CVSROOT and HORDE_DIR directories exist
mkdir -p "$CVSROOT" "$HORDE_DIR"

# Some useful vars
MYNAME=`basename $0`
CWD=`pwd`

while [ $# -gt 0 ]; do
    case "${1}" in
        --with-modules=*)
            # Set the comma module list
            COMMA_MODULES=$(echo $1 | sed 's|.*=||')
            # Transform this to the module list
            MODULE_LIST="$(echo $COMMA_MODULES | tr ',' ' ')"
            shift
            ;;
        --type=*)
            # Set the type of action
            ACTION=$(echo $1 | sed 's|.*=||')
            shift
            ;;
        --label=*)
            # Set the label from which to checkout
            LABEL=$(echo $1 | sed 's|.*=||')
            shift
            ;;
        --h*|-h*)
            echo "Usage: $MYNAME {--with-modules=[module[,module]*]|--type=[checkout|update]|--label=[\"\"|[label]]" 1>&2
            exit 2
            ;;
    esac
done

# Check if all the needed vars have been set
MODULE_LIST="${MODULE_LIST:-$DEFAULT_MODULE_LIST}"
COMMA_MODULES=${COMMA_MODULES:-$(echo $DEFAULT_MODULE_LIST | tr ' ' ',')}
ACTION=${ACTION:-$DEFAULT_ACTION}
LABEL=${LABEL:-$DEFAULT_LABEL}

# Append the action to the cvs arguments
CVS_ARGS="${CVS_ARGS} -d $CVSROOT ${ACTION}"

# Buildup the list of to-be excluded files
RSYNC_EXCLUDES="CVSROOT/config*"

RSYNC_EXCLUDE=""
for exclude in $RSYNC_EXCLUDES ; do
    RSYNC_EXCLUDE="${RSYNC_EXCLUDE} --exclude=${exclude}"
done

# Sync up our repository with the main repository
echo "rsync'ing with $RSYNC_DIR..."

$RSYNC $RSYNC_EXCLUDE $RSYNC_ARGS $RSYNC_DIR $CVSROOT

# Checkout the main Horde module
cd `dirname $HORDE_DIR`

echo "Doing $CVS_ACTION from $LABEL in main Horde module..."

$CVSCOMMAND $CVS_ARGS -r $LABEL horde
cd $HORDE_DIR

# Check out each of the other modules specified
for MODULE in $MODULE_LIST; do
    echo "Doing $ACTION from $LABEL in $MODULE module..."
    echo $CVSCOMMAND $CVS_ARGS -r $LABEL $MODULE
    $CVSCOMMAND $CVS_ARGS -r $LABEL $MODULE
done

# Put the user back where they came from
cd $CWD

--- NEW FILE: http_login_refer.php ---
<?php
/**
 * $Horde: horde/scripts/http_login_refer.php,v 1.3 2004/01/01 15:16:54 jan Exp $
 *
 * Copyright 1999-2004 Charles J. Hagenbuch <chuck at horde.org>
 * Copyright 1999-2004 Jon Parise <jon at horde.org>
 *
 * See the enclosed file COPYING for license information (LGPL). If you
 * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
 */

require_once '../lib/base.php';

$auth = &Auth::singleton($conf['auth']['driver']);

// Check for HTTP auth.
if (empty($_SERVER['PHP_AUTH_USER']) ||
    empty($_SERVER['PHP_AUTH_PW']) ||
    !$auth->authenticate($_SERVER['PHP_AUTH_USER'],
                         array('password' => $_SERVER['PHP_AUTH_PW']))) {

    header('WWW-Authenticate: Basic realm="' . $auth->getParam('realm') . '"');
    header('HTTP/1.0 401 Unauthorized');
    exit('Forbidden');
}

if ($url = Util::getFormData('url')) {
    header('Location: ' . $url);
} else {
    header('Location: ' . Horde::applicationUrl('login.php'));
}

--- NEW FILE: make-release-conf.php.dist ---
<?php
/**
 * Configuration for the make-release.php script.
 *
 * $Horde: horde/scripts/make-release-conf.php.dist,v 1.4 2004/02/15 13:32:50 jan Exp $
 */

/* Username for horde.org.
 * Make sure you belong to the "horde" group there. */
$this->options['horde']['user'] = '';

/* From: address for announcements. */
$this->options['ml']['from'] = '';

/* Username for freshmeat.net.
 * Make sure you are a project admin there for the modules 
 * you want to release. */
$this->options['fm']['user'] = '';

/* Password for freshmeat.net. */
$this->options['fm']['password'] = '';

/* Local MD5 command. */
$this->options['md5'] = '/usr/bin/md5sum';

/* Configuration for local MTA. */
$this->options['mailer']['type'] = 'sendmail';
$this->options['mailer']['params'] = array();

--- NEW FILE: make-release.php ---
#!/usr/bin/php
<?php
/**
 * Copyright 1999 Mike Hardy
 * Copyright 2004 Jan Schneider <jan at horde.org>
 *
 * Licensed under GPL, please see the file COPYING for details on licensing.
 *
 * $Horde: horde/scripts/make-release.php,v 1.17 2004/04/07 14:43:44 chuck Exp $
 *
 * This is a short script to make an "official" Horde or application release
 *
 * This script relies on a few things.
 *
 * 1) The file containing the version string is:
 *         <module>/lib/version.php
 * 2) The tag to use in the source is:
 *         <module>_<major>_<minor>_<patch>[_<text>]
 * 3) The directory the source should be packaged from is:
 *         <module>-<major>.<minor>.<patch>[-<text>]
 * 4) The version to put into the version file in CVS when done is:
 *         <major>.<minor>.<patch+1>-cvs unless there was [-<text>],
 *         then just <major>.<minor>.<patch>-cvs
 * 5) It expects the version file's version line to look like this:
 *        <?php define('<MODULE>_VERSION', '<version>') ?>
 * 6) It expects that you have CVS all set up in the shell you're using.
 *         This includes all of the password stuff...
 * 7) The changelog file is:
 *         <module>/docs/CHANGES
 * 8) The release notes are in:
 *         <module>/docs/RELEASE_NOTES
 */

require 'Horde/Util.php';
require 'Horde/RPC.php';
require 'Horde/MIME/Message.php';

// Create a class instance
$tarball = &new Tarball();

// Get all the arguments from the command-line
$tarball->getArguments();

// Make sure they are sane
$tarball->checkArguments();

// Do testing (development only)
$tarball->test();

// Check for running as root, set umask, etc.
$tarball->checkSetSystem();

// Set all of the version strings we're going to need for tags, source, etc
$tarball->setVersionStrings();

// Check out the source we're going to release
$tarball->checkOutTag($tarball->options['branch'], $tarball->directoryName);

// Check out the framework module if necessary
$tarball->checkOutFramework($tarball->options['branch'], $tarball->directoryName);

// Update the version file with the release version
$tarball->updateVersionFile($tarball->directoryName, $tarball->sourceVersionString);

// Tag the source in the release directory with the correct versioned tag
$tarball->tagSource();

// Get version number of CHANGES file
$tarball->saveChangelog();

// Clean up all the non-tarball-bound directories so the package is clean
$tarball->cleanDirectories($tarball->directoryName);

if ($tarball->oldVersion) {

    // Check out the next-lowest-patch-level
    $tarball->checkOutTag($tarball->oldTagVersionString, $tarball->oldDirectoryName);

    // Get version number of CHANGES file
    $tarball->saveChangelog(true);

}

// If we have a lower patch-level on this tree, make a diff
if ($tarball->makeDiff) {

    // Clean all the non-tarball-bound directories out of it
    $tarball->cleanDirectories($tarball->oldDirectoryName);

    // Make a diff of the two cleaned releasable directories now
    $tarball->diff();

}

if ($tarball->oldVersion) {

    // Clean the directory out
    $tarball->deleteDirectory($tarball->oldDirectoryName);

}

// Make the tarball now
$tarball->makeTarball();

// Clean all the old directories out
$tarball->deleteDirectory($tarball->directoryName);

// Put tarball up on the server
$tarball->upload();

// Check the new source out again so we can change the string post-tarball
$tarball->checkOutTag($tarball->options['branch'], $tarball->directoryName);
$tarball->updateVersionFile($tarball->directoryName, $tarball->newSourceVersionString);
$tarball->updateSentinel();

// Clean this directory up now
$tarball->deleteDirectory($tarball->directoryName);

// Announce release on mailing lists and freshmeat.
$tarball->announce();

// Should be all done
exit;


/***************************************************************
*
*  There's no algorithmic logic below here, just implementation
*
***************************************************************/

class Tarball {

    /**
     * Default options.
     * @var array $options
     */
    var $options = array('test' => false,
                         'nocommit' => false, 
                         'noftp' => false, 
                         'noannounce' => false);

    /**
     * Version number of release.
     * @var string $sourceVersionString
     */
    var $sourceVersionString;

    /**
     * Version number of previous release.
     * @var string $oldVersionString
     */
    var $oldSourceVersionString;

    /**
     * Version number of next release.
     * @var string $newSourceVersionString
     */
    var $newSourceVersionString;

    /**
     * CVS tag of release.
     * @var string $tagVersionString
     */
    var $tagVersionString;

    /**
     * CVS tag of previous release.
     * @var string $oldTagVersionString
     */
    var $oldTagVersionString;

    /**
     * Revision number of CHANGES file.
     * @var string $changelogVersion
     */
    var $changelogVersion;

    /**
     * Revision number of previous CHANGES file.
     * @var string $changelogVersion
     */
    var $oldChangelogVersion;

    /**
     * Directory name of unpacked tarball.
     * @var string $directoryName
     */
    var $directoryName;

    /**
     * Directory name of unpacked previous tarball.
     * @var string $oldDirectoryName
     */
    var $oldDirectoryName;

    /**
     * Filename of the tarball.
     * @var string $tarballName
     */
    var $tarballName;

    /**
     * MD5 sum of the tarball.
     * @var string $tarballMD5
     */
    var $tarballMD5;

    /**
     * Whether or not to create a patch file.
     * @var boolean $makeDiff
     */
    var $makeDiff = false;

    /**
     * Whether or not we have an old version to compare against.
     * @var boolean $oldVersion
     */
    var $oldVersion = false;

    /**
     * Filename of the gzip'ed patch file (without .gz extension).
     * @var string $patchName;
     */
    var $patchName;

    /**
     * MD5 sum of the patch file.
     * @var string $patchMD5
     */
    var $patchMD5;

    /**
     * Whether or not this is a final release version.
     * @var boolean $latest
     */
    var $latest = true;

    // Load the configuration
    function Tarball()
    {
        require dirname(__FILE__) . '/make-release-conf.php';
        $cvsroot = getenv('CVSROOT');
        if (empty($cvsroot)) {
            putenv('CVSROOT=:ext:' . $this->options['horde']['user'] . '@cvs.horde.org:/repository');
        }
    }


    // Delete the directory given as an argument
    function deleteDirectory($directory)
    {
        print "Deleting directory $directory\n";
        system("rm -rf $directory");
    }


    // tar and gzip the directory given as an argument
    function makeTarball()
    {
        print "Setting owner/group to 0/0\n";
        system("chown -R 0:0 $this->directoryName");

        print "Making tarball\n";
        $this->tarballName = $this->directoryName . '.tar.gz';
        if (file_exists($this->tarballName)) {
            unlink($this->tarballName);
        }
        system("tar -zcf $this->tarballName $this->directoryName");
        exec($this->options['md5'] . ' ' . $this->tarballName, $this->tarballMD5);
    }


    // Label all of the source here with the new label given as an argument
    function tagSource()
    {
        if (!$this->options['nocommit']) {
            print "Tagging source in $this->directoryName with tag {$this->tagVersionString}\n";
            system("cd {$this->directoryName};cvs tag -F $this->tagVersionString > /dev/null 2>&1");
        } else {
            print "NOT tagging source in $this->directoryName (would have been tag {$this->tagVersionString})\n";
        }
    }


    // Make a diff of the two directories given as arguments
    function diff()
    {
        $this->patchName = 'patch-' . $this->options['module'] . '-' . $this->oldSourceVersionString . '-' . $this->sourceVersionString;
        print "Making diff between $this->oldDirectoryName and $this->directoryName\n";
        system("diff -uNr $this->oldDirectoryName $this->directoryName > $this->patchName");
        system("gzip -9f $this->patchName");
        exec($this->options['md5'] . ' ' . $this->patchName . '.gz', $this->patchMD5);
    }


    // Change the version file for the module in the directory specified to the version specified
    function updateVersionFile($directory, $version_string)
    {
        $module = $this->options['module'];
        $all_caps_module = strtoupper($module);
        print "Updating version file for $module\n";

        // construct the filenames
        $filename_only = 'version.php';
        $filename = $directory . '/lib/' . $filename_only;
        $newfilename = $filename . '.new';

        $oldfp = fopen($filename, 'r');
        $newfp = fopen($newfilename, 'w');
        while ($line = fgets($oldfp)) {
            if (strstr($line, 'VERSION')) {
                fwrite($newfp, "<?php define('{$all_caps_module}_VERSION', '$version_string') ?>\n");
            } else {
                fwrite($newfp, $line);
            }
        }
        fclose($oldfp);
        fclose($newfp);

        system("mv -f $newfilename $filename");
        if (!$this->options['nocommit']) {
            system("cd $directory/lib/; cvs commit -f -m \"Tarball script: building new $module release - $version_string\" $filename_only > /dev/null 2>&1");
        }
    }


    // Update the CHANGES file with the new version number
    function updateSentinel()
    {
        $module = $this->options['module'];
        $all_caps_module = strtoupper($module);
        print "Updating sentinel file for $module\n";

        // construct the filenames
        $filename_only = 'CHANGES';
        $filename = $this->directoryName . '/docs/' . $filename_only;
        $newfilename = $filename . '.new';

        $version = 'v' . substr($this->newSourceVersionString, 0, strpos($this->newSourceVersionString, '-'));

        $oldfp = fopen($filename, 'r');
        $newfp = fopen($newfilename, 'w');
        fwrite($newfp, str_repeat('-', strlen($version)) . "\n$version\n" .
               str_repeat('-', strlen($version)) . "\n\n\n");
        while ($line = fgets($oldfp)) {
            fwrite($newfp, $line);
        }
        fclose($oldfp);
        fclose($newfp);

        system("mv -f $newfilename $filename");
        if (!$this->options['nocommit']) {
            system("cd {$this->directoryName}/docs/; cvs commit -f -m \"Tarball script: building new $module release - {$this->newSourceVersionString}\" $filename_only > /dev/null 2>&1");
        }
    }


    // get and save the revision number of the CHANGES file
    function saveChangelog($old = false)
    {
        if ($old) {
            $directory = $this->oldDirectoryName;
        } else {
            $directory = $this->directoryName;
            @include "./$directory/docs/RELEASE_NOTES";
        }
        exec("cd $directory/docs/; cvs status CHANGES", $output);
        foreach ($output as $line) {
            if (preg_match('/Repository revision:\s+([\d.]+)/', $line, $matches)) {
                if ($old) {
                    $this->oldChangelogVersion = $matches[1];
                } else {
                    $this->changelogVersion = $matches[1];
                }
                break;
            }
        }
    }


    // work through the source directory given, cleaning things up by removing
    // directories and files we don't want in the tarball
    function cleanDirectories($directory)
    {
        print "Cleaning source tree\n";
        $directories = explode("\n", `find $directory -type d \\( -name CVS -o -name packaging \\) -print | sort -r`);
        foreach ($directories as $dir) {
            system("rm -rf $dir");
        }
        $cvsignores = explode("\n", `find $directory -name .cvsignore -print`);
        foreach ($cvsignores as $file) {
            if (!empty($file)) {
                unlink($file);
            }
        }
    }


    // Check out the tag we've been given to work with and move it to the directory name given
    function checkOutTag($mod_version, $directory)
    {
        $module = $this->options['module'];

        // Use CVS to check the source out
        if ($mod_version == 'HEAD') {
            print "Checking out HEAD for $module\n";
            system("cvs co -P $module > /dev/null 2>&1");
        } elseif ($mod_version == 'IMP_2_2_7') {
            print "Checking out tag $mod_version for $module (by date)\n";
            system("cvs co -P -rSTABLE_2_2 -D'2001-11-11' $module > /dev/null 2>&1");
            system("cd $module/lib/; cvs up -r1.1.2.13 version.php > /dev/null 2>&1");
        } else {
            print "Checking out tag $mod_version for $module\n";
            system("cvs co -P -r$mod_version $module > /dev/null 2>&1");
        }

        // Move the source into the directory specified
        print "Moving $module to $directory\n";
        if (@is_dir($directory)) {
            system("rm -rf $directory");
        }
        system("mv -f $module $directory");
    }


    // Checkout and install framework
    function checkOutFramework($mod_version, $directory)
    {
        if ($this->options['module'] == 'horde' &&
            ($mod_version == 'HEAD' || strstr($mod_version, 'FRAMEWORK'))) {
            if ($mod_version == 'HEAD') {
                print "Checking out HEAD for framework\n";
            } else {
                print "Checking out tag $mod_version for framework\n";
            }
            system("cd $directory; cvs co -P -r$mod_version framework > /dev/null 2>&1; cd ..");
            print "Installing framework packages\n";
            $dir = dirname(__FILE__);
            system("php $dir/create-symlinks.php --copy --src=$directory/framework --dest=$directory/lib; rm -r $directory/framework");

            print "Setting HORDE_LIBS\n";
            $filename = $directory . '/lib/core.php';
            $newfilename = $filename . '.new';
            $oldfp = fopen($filename, 'r');
            $newfp = fopen($newfilename, 'w');
            while ($line = fgets($oldfp)) {
                fwrite($newfp, str_replace('define(\'HORDE_LIBS\', \'\')', 'define(\'HORDE_LIBS\', dirname(__FILE__) . \'/\')', $line));
            }
            fclose($oldfp);
            fclose($newfp);
            system("mv -f $newfilename $filename");
        }
    }


    // Upload tarball to the FTP server
    function upload()
    {
        $module = $this->options['module'];
        $user = $this->options['horde']['user'];
        $cmd = "chmod 664 /horde/ftp/$module/$this->tarballName;";
        if ($this->makeDiff) {
            $cmd .= " chmod 664 /horde/ftp/$module/patches/$this->patchName.gz;";
        }
        if ($this->latest) {
            $cmd .= " ln -sf $this->tarballName /horde/ftp/$module/$module-latest.tar.gz;";
        }

        if (!$this->options['noftp']) {
            print "Uploading $this->tarballName to $user at dev.horde.org:/horde/ftp/$module/\n";
            system("scp $this->tarballName $user at dev.horde.org:/horde/ftp/$module/");
            if ($this->makeDiff) {
                print "Uploading $this->patchName.gz to $user at dev.horde.org:/horde/ftp/$module/patches/\n";
                system("scp $this->patchName.gz $user at dev.horde.org:/horde/ftp/$module/patches/");
            }
            print "Executing $cmd\n";
            system("ssh -l $user dev.horde.org '$cmd'");
        } else {
            print "NOT uploading $this->tarballName to dev.horde.org:/horde/ftp/$module/\n";
            if ($this->makeDiff) {
                print "NOT uploading $this->patchName.gz to $user at dev.horde.org:/horde/ftp/$module/patches/\n";
            }
            print "NOT executing $cmd\n";
        }
    }


    // check if freshmeat announcement was successful.
    function _fmVerify($fm)
    {
        if (is_a($fm, 'PEAR_Error')) {
            print $fm->getMessage() . "\n";
            return false;
        } elseif (!is_array($fm)) {
            var_dump($fm);
            return false;
        }
        return true;
    }


    // announce release to mailing lists and freshmeat.
    function announce()
    {
        $module = $this->options['module'];
        if (!isset($this->notes)) {
            print "NOT announcing release, RELEASE_NOTES missing.\n";
            return;
        }
        if (!empty($this->options['noannounce'])) {
            print "NOT announcing release on freshmeat.net\n";
        } else {
            print "Announcing release on freshmeat.net\n";
        }
        $fm = Horde_RPC::request(
            'xmlrpc',
            'http://freshmeat.net/xmlrpc/',
            'login',
            array('username' => $this->options['fm']['user'],
                  'password' => $this->options['fm']['password']));
        $announcement = array('SID' => $fm['SID'],
                              'project_name' => $this->notes['fm']['project'],
                              'branch_name' => $this->notes['fm']['branch'],
                              'version' => $this->sourceVersionString,
                              'changes' => $this->notes['fm']['changes'],
                              'release_focus' => (int)$this->notes['fm']['focus'],
                              'url_changelog' => ($this->oldVersion ? "http://cvs.horde.org/diff.php/$module/docs/CHANGES?r1={$this->oldChangelogVersion}&r2={$this->changelogVersion}&ty=h" : ''),
                              'url_tgz' => "ftp://ftp.horde.org/pub/$module/{$this->tarballName}");
        if ($this->_fmVerify($fm)) {
            if (!empty($this->options['noannounce'])) {
                print "Announcement data:\n";
                print_r($announcement);
            } else {
                $fm = Horde_RPC::request(
                    'xmlrpc',
                    'http://freshmeat.net/xmlrpc/',
                    'publish_release',
                    $announcement);
                $this->_fmVerify($fm);
            }
        }

        $ml = $module;
        if ($ml == 'accounts' || $ml == 'forwards' ||
            $ml == 'passwd' || $ml == 'vacation') {
            $ml = 'sork';
        }
        $to = "announce at lists.horde.org, $ml at lists.horde.org";
        if (!$this->latest) {
            $to .= ', i18n at lists.horde.org';
        }

        if (!empty($this->options['noannounce'])) {
            print "NOT announcing release on $to\n";
        } else {
            print "Announcing release to $to\n";
        }

        // Building headers
        $subject = $this->notes['name'] . ' ' . $this->sourceVersionString;
        if ($this->latest) {
            $subject .= ' (final)';
        }
        $headers = array('From' => $this->options['ml']['from'],
                         'To' => $to,
                         'Subject' => $subject);

        // Building message text
        $body = $this->notes['ml']['changes'];
        if ($this->oldVersion) {
            $body .= "\n\n" .
                sprintf('The full list of changes (from version %s) can be viewed here:', $this->oldSourceVersionString) .
                "\n\n" .
                sprintf('http://cvs.horde.org/diff.php/%s/docs/CHANGES?r1=%s&r2=%s&ty=h', $module, $this->oldChangelogVersion, $this->changelogVersion);
        }
        $body .= "\n\n" .
            sprintf('The %s %s distribution is available from the following locations:', $this->notes['name'], $this->sourceVersionString) .
            "\n\n" .
            sprintf('    ftp://ftp.horde.org/pub/%s/%s', $module, $this->tarballName) . "\n" .
            sprintf('    http://ftp.horde.org/pub/%s/%s', $module, $this->tarballName);
        if ($this->makeDiff) {
            $body .= "\n\n" .
                sprintf('Patches against version %s are available at:', $this->oldSourceVersionString) .
                "\n\n" .
                sprintf('    ftp://ftp.horde.org/pub/%s/patches/%s.gz', $module, $this->patchName) . "\n" .
                sprintf('    http://ftp.horde.org/pub/%s/patches/%s.gz', $module, $this->patchName);
        }
        $body .= "\n\n" .
            'Or, for quicker access, download from your nearest mirror:' .
            "\n\n" .
            '    http://www.horde.org/mirrors.php' .
            "\n\n" .
            'MD5 sums for the packages are as follows:' .
            "\n\n" .
            '    ' . $this->tarballMD5[0] . "\n" .
            '    ' . $this->patchMD5[0] .
            "\n\n" .
            'Have fun!' .
            "\n\n" .
            'The Horde Team.';

        if (!empty($this->options['noannounce'])) {
            print "Message headers:\n";
            print_r($headers);
            print "Message body:\n$body\n";
            return;
        }

        // Building and sending message
        $message = &new MIME_Message('lists.horde.org');
        $part = &new MIME_Part('text/plain',
                               $body,
                               'iso-8859-1');
        $message->addPart($part);
        $headers = $message->encode($headers, 'iso-8859-1');

        $msg = $message->toString();
        if (substr($msg, -1) != "\n") {
            $msg .= "\n";
        }

        require_once 'Mail.php';
        $mailer = &Mail::factory($this->options['mailer']['type'], $this->options['mailer']['params']);
        $result = $mailer->send(MIME::encodeAddress($to), $headers, $msg);
        if (is_a($result, 'PEAR_Error')) {
            print $result->getMessage() . "\n";
        }
    }


    // Do testing (development only)
    function test()
    {
        if (!$this->options['test']) {
            return;
        }

        print "options['version']={$this->options['version']}\n";
        print "options['oldversion']={$this->options['oldversion']}\n";
        print "options['module']={$this->options['module']}\n";

        $this->setVersionStrings();

        print "makeDiff={$this->makeDiff}\n";
        print "oldVersion={$this->oldVersion}\n";
        print "directoryName={$this->directoryName}\n";
        if ($this->oldVersion) {
            print "oldDirectoryName={$this->oldDirectoryName}\n";
        }
        print "tagVersionString={$this->tagVersionString}\n";
        if ($this->oldVersion) {
            print "oldTagVersionString={$this->oldTagVersionString}\n";
        }
        print "sourceVersionString={$this->sourceVersionString}\n";
        if ($this->oldVersion) {
            print "oldSourceVersionString={$this->oldSourceVersionString}\n";
        }
        print "newSourceVersionString={$this->newSourceVersionString}\n";
        exit(0);
    }


    // Set the version strings to use given the arguments
    function setVersionStrings() {
        $ver = explode('.', $this->options['version']);
        if (preg_match('/(\d+)\-(.*)/', $ver[count($ver) - 1], $matches)) {
            $ver[count($ver) - 1] = $matches[1];
            $plus = $matches[2];
        }
        if (count($ver) > 2 && $ver[count($ver) - 1] == '0') {
            die("version {$this->options['version']} should not have the trailing 3rd-level .0\n");
        }
        
        // check if --oldversion is empty or 0
        if (!empty($this->options['oldversion'])) {
            $this->oldVersion = true;
        }
        $oldver = explode('.', $this->options['oldversion']);

        // set the string to use as the tag name in CVS
        $this->tagVersionString = strtoupper($this->options['module'] . '_' . implode('_', $ver));
        if (isset($plus)) {
            $this->tagVersionString .= '_' . $plus;
        }

        // create patches only if not a major version change
        if ($ver[0] == $oldver[0]) {
            $this->makeDiff = true;
        }

        // is this really a production release?
        if (isset($plus) && !preg_match('/^pl\d/', $plus)) {
            $this->latest = false;
            $this->makeDiff = false;
        }

        // set the string to insert into the source version file
        $this->sourceVersionString = implode('.', $ver);
        if (isset($plus)) {
            $this->sourceVersionString .= '-' . $plus;
        }

        // set the string to be used for the directory to package from
        $this->directoryName = $this->options['module'] . '-' . $this->sourceVersionString;

        if ($this->oldVersion) {
            $this->oldSourceVersionString = implode('.', $oldver);
            $this->oldTagVersionString = strtoupper($this->options['module'] . '_' . implode('_', $oldver));
            $this->oldDirectoryName = $this->options['module'] . '-' . $this->oldSourceVersionString;
        }

        // set the name of the string to put into the source version file when done
        if (!isset($plus)) {
            while (count($ver) < 3) {
                array_push($ver, '0');
            }
            $ver[count($ver) - 1] += 1;
        }
        $this->newSourceVersionString = implode('.', $ver) . '-cvs';
    }


    // Get all of the command-line arguments from the user
    function getArguments() {
        global $argv;

        // Parse the command-line arguments
        foreach ($argv as $arg) {
            // Skip script name
            if (basename($arg) == basename(__FILE__)) {
                continue;
            }

            // Check to see if they gave us a module
            if (preg_match('/--module=(.*)/', $arg, $matches)) {
                $this->options['module'] = $matches[1];

            // Check to see if they tell us the version of the tarball to make
            } elseif (preg_match('/--version=(.*)/', $arg, $matches)) {
                $this->options['version']= $matches[1];

            // Check to see if they tell us the last release version
            } elseif (preg_match('/--oldversion=(.*)/', $arg, $matches)) {
                $this->options['oldversion']= $matches[1];

            // Check to see if they tell us which branch to work with
            } elseif (preg_match('/--branch=(.*)/', $arg, $matches)) {
                $this->options['branch']= $matches[1];

            // Check to see if they tell us not to commit or tag
            } elseif (strstr($arg, '--nocommit')) {
                $this->options['nocommit']= true;

            // Check to see if they tell us not to upload
            } elseif (strstr($arg, '--noftp')) {
                $this->options['noftp']= true;

            // Check to see if they tell us not to announce
            } elseif (strstr($arg, '--noannounce')) {
                $this->options['noannounce']= true;

            // Check to see if they tell us to test (for development only)
            } elseif (strstr($arg, '--test')) {
                $this->options['test']= true;
                // safety first
                $this->options['nocommit'] = true;
                $this->options['noftp'] = true;
                $this->options['noannounce'] = true;

            // We have no idea what this is
            } else {
                $this->print_usage('You have used unknown arguments: ' . $arg);
                exit;
            }
        }
    }


    // Check the command-line arguments and set some internal defaults
    function checkArguments() {
        // Make sure that we have a module defined
        if (!isset($this->options['module'])) {
            $this->print_usage('You must define which module to package.');
            exit;
        }

        // Let's make sure that there are valid version strings in here...
        if (!isset($this->options['version'])) {
            $this->print_usage('You must define which version to package.');
            exit;
        }
        if (!preg_match('/\d+\.\d+.*/', $this->options['version'])) {
            $this->print_usage('Incorrect version string.');
            exit;
        }
        if (!isset($this->options['oldversion'])) {
            $this->print_usage('You must define last release\'s version.');
            exit;
        }
        if (!preg_match('/\d+(\.\d+.*)?/', $this->options['oldversion'])) {
            $this->print_usage('Incorrect old version string.');
            exit;
        }

        // Make sure we have a horde.org user
        if (empty($this->options['horde']['user'])) {
            $this->print_usage('You must define a horde.org user.');
            exit;
        }

        // If there is no branch defined, we're using the tip revisions.
        // These releases are always developmental, and should use the HEAD "branch" name.
        if (!isset($this->options['branch'])) {
            $this->options['branch'] = 'HEAD';
        }
    }


    // Check the command-line arguments and set some internal defaults
    function checkSetSystem() {

        // Set umask
        umask(022);

        // Make sure we're running as root (so we can chown/chmod)
        if (posix_getuid() != 0) {
            die('This script must run be as root');
        }

    }


    // Show people how to use the damned thing
    function print_usage($message) {

        print "\n***  ERROR: $message  ***\n";

        print <<<USAGE

make-tarball.php: Horde release generator.

   This script takes as arguments the module to make a release of, the
   version of the release, and the branch:

      ./make-tarball.php --module=<name> --version=xx.yy[.zz[-<string>]]
                         --oldversion=xx[.yy[.zz[-<string>]]]
                         [--branch=<branchname>] [--nocommit] [--noftp]

   If you omit the branch, it will implicitly work with the HEAD branch.
   If you release a new major version use the --oldversion=0 option.
   Use the --nocommit option to do a test build (without touching the CVS
   repository). Use the --noftp option to not upload any files on the FTP
   server. Use the --noannounce option to not send any release announcements.

   Some examples would be:

   To make a new development release of Horde:
      ./make-tarball.php --module=horde --version=2.1-dev --oldversion=2.0

   To make a new stable release of IMP:
      ./make-tarball.php --module=imp --version=3.0 --oldversion=2.3.7 \
        --branch=RELENG_3

   To make a brand new alpha relase of Luxor:
      ./make-tarball.php --module=luxor --version=1.0-alpha1 --oldversion=0

USAGE;
    }

}

--- NEW FILE: make-snaps.php ---
#!/usr/local/bin/php -f
<?php
// $Horde: horde/scripts/make-snaps.php,v 1.17 2004/03/12 15:18:58 chuck Exp $

$modules = array('accounts',
                 'agora',
                 'ansel',
                 'babel',
                 'chora',
                 'forwards',
                 'framework',
                 'genie',
                 'giapeto',
                 'gollem',
                 'hermes',
                 'horde',
                 'HordeConduit',
                 'imapproxy',
                 'imp',
                 'ingo',
                 'jeta',
                 'jonah',
                 'juno',
                 'klutz',
                 'kronolith',
                 'luxor',
                 'midas',
                 'mimp',
                 'mnemo',
                 'mottle',
                 'nag',
                 'nic',
                 'odin',
                 'orator',
                 'passwd',
                 'rakim',
                 'sam',
                 'scry',
                 'skeleton',
                 'swoosh',
                 'thor',
                 'trean',
                 'troll',
                 'turba',
                 'ulaform',
                 'vacation',
                 'vilma',
                 'whups',
                 'whupsey',
                 'wicked');

$stable = array('accounts'  => 'RELENG_2',
                'chora'     => 'RELENG_1',
                'forwards'  => 'RELENG_2',
                'horde'     => 'RELENG_2',
                'imp'       => 'RELENG_3',
                'ingo'      => 'RELENG_1',
                'klutz'     => 'RELENG_1',
                'kronolith' => 'RELENG_1',
                'mnemo'     => 'RELENG_1',
                'nag'       => 'RELENG_1',
                'passwd'    => 'RELENG_2',
                'turba'     => 'RELENG_1',
                'vacation'  => 'RELENG_2');

$dir = date('Y-m-d');
if (!is_dir($dir)) {
    mkdir($dir);
}

exportCVS();
makeTarballs();
cleanup();
prune(7);

// Update latest/ symlink.
system("ln -sfh $dir latest");


/**
 * Functions
 */
function exportCVS()
{
    global $dir, $modules, $stable;

    foreach ($modules as $module) {
        system("cd $dir; cvs -Q export -r HEAD $module > /dev/null");
        if (array_key_exists($module, $stable)) {
            system("cd $dir; cvs -Q export -r $stable[$module] -d ${module}-RELENG $module");
        }
    }
}

function makeTarballs()
{
    global $dir, $modules, $stable;

    foreach ($modules as $module) {
        system("cd $dir; tar -zcf ${module}-HEAD-${dir}.tar.gz $module");
        if (array_key_exists($module, $stable)) {
            system("cd $dir; tar -zcf ${module}-RELENG-${dir}.tar.gz ${module}-RELENG");
        }
    }
}

function cleanup()
{
    global $dir, $modules;

    foreach ($modules as $module) {
        system("rm -rf $dir/$module");
        system("rm -rf $dir/${module}-RELENG");
    }
}

function prune($keep)
{
    if ($cwd = opendir(getcwd())) {
        $dirs = array();

        # Build a list of all the YYYY-MM-DD directories in this directory.
        while (false !== ($entry = readdir($cwd))) {
            if (is_dir($entry) && preg_match('/^\d+\-\d+\-\d+/', $entry)) {
                array_push($dirs, $entry);
            }
        }
        closedir($cwd);

        # Reverse-sort the list and remove the number of directories that we
        # want to keep (which will be the first $keep number of elements).
        rsort($dirs);
        $dirs = array_slice($dirs, $keep);

        # Prune (recursively delete) the rest of the directories in the list.
        foreach ($dirs as $dir) {
            system("rm -rf $dir");
        }
    }
}

--- NEW FILE: merge.php ---
#!/usr/local/bin/php -q
<?php
/**
$Horde: horde/scripts/merge.php,v 1.3 2002/11/10 20:52:19 chuck Exp $

A small script that takes lines of a commit message like:

  2.485     +26 -5     imp/compose.php
  1.503     +2 -0      imp/docs/CHANGES
  2.159     +25 -12    imp/templates/compose/compose.inc
  2.55      +28 -3     imp/templates/compose/javascript.inc

from the standard input and merges these commits into the
appropriate files of the current directory.
Mainly for merging changes in HEAD to the RELENG tree.
*/

@set_time_limit(0);
ob_implicit_flush(true);
ini_set('track_errors', true);
ini_set('implicit_flush', true);
ini_set('html_errors', false);
ini_set('magic_quotes_runtime', false);

$lines = file('php://stdin');
foreach ($lines as $line) {
    $tok = preg_split('/\s+/', $line, -1, PREG_SPLIT_NO_EMPTY);
    if (count($tok) != 4) {
        print "Unknown line format:\n" . $line . "\n";
        continue;
    }
    $new_version = explode('.', $tok[0]);
    $old_version = $new_version;
    $old_version[count($old_version) - 1]--;
    $cmd = sprintf('cvs up -kk -j %s -j %s %s' . "\n",
                   implode('.', $old_version), implode('.', $new_version), str_replace('horde/', '', $tok[3]));
    print $cmd;
    system($cmd . ' 2>&1');
    print "\n";
}

--- NEW FILE: migrate_categories.php ---
#!/usr/local/bin/php
<?php
/**
 * $Horde: horde/scripts/migrate_categories.php,v 1.10 2004/04/07 14:43:44 chuck Exp $
 *
 * This is a script to migrate old categories to the new
 * horde_category_attributes table. You MUST create that table before
 * running this script. Right now, this will migrate the following
 * kinds of categories:
 *
 * - Groups
 * - All Shares (horde.share.*)
 *
 * All other categories currently still use the category_data field.
 */

/**
 ** Set this to true if you want DB inserts done.
 **/
$live = false;

/**
 ** Kinds of categories to convert.
 **/
$groups = true;
$shares = true;


// No auth.
@define('AUTH_HANDLER', true);

// Find the base file path of Horde.
@define('HORDE_BASE', dirname(__FILE__) . '/..');

// Do CLI checks and environment setup first.
require_once HORDE_BASE . '/lib/core.php';
require_once 'Horde/CLI.php';

// Make sure no one runs this from the web.
if (!Horde_CLI::runningFromCLI()) {
    exit("Must be run from the command line\n");
}

// Load the CLI environment - make sure there's no time limit, init
// some variables, etc.
Horde_CLI::init();

require_once HORDE_BASE . '/lib/base.php';
require_once 'Horde/DataTree.php';
require_once 'Horde/Group.php';
require_once 'Horde/Share.php';

// Groups.
if ($groups) {
    $category = &DataTree::factory('sql');
    $db = &$category->_db;
    
    $ids = $db->getAssoc('SELECT category_id, category_name FROM horde_categories WHERE group_uid = \'horde.groups\'');
    $category->_params['group'] = 'horde.groups';
    $category->_load();
    foreach ($ids as $id => $name) {
        $categoryOb = &new DataTreeObject_Group($name);
        $categoryOb->data = $category->getCategoryData($id);
        if ($live) {
            $result = $category->updateData($categoryOb);
            if (is_a($result, 'PEAR_Error')) {
                var_dump($result);
                exit;
            }
        }
    }
}


// Shares.
if ($shares) {
    $category = &DataTree::factory('sql');
    $db = &$category->_db;

    $ids = $db->getAssoc('SELECT category_id, category_name, group_uid FROM horde_categories WHERE group_uid LIKE \'horde.shares.%\'');
    foreach ($ids as $id => $row) {
        $category = DataTree::factory('sql');
        $category->_params['group'] = $row[1];
        $category->_load();
        $categoryOb = &new DataTreeObject_Share($row[0]);
        $categoryOb->data = $category->getCategoryData($id);
        if ($live) {
            $result = $category->updateData($categoryOb);
            if (is_a($result, 'PEAR_Error')) {
                var_dump($result);
                exit;
            }
        }
    }
}

--- NEW FILE: migrate_links.php ---
#!/usr/bin/php -q
<?php
/**
 * $Horde: horde/scripts/migrate_links.php,v 1.5 2004/04/07 14:43:44 chuck Exp $
 *
 * This is a script to migrate old Horde_Links to the 
 * horde_category_attributes table. 
 *
 * Note that this script currently only migrates whups links (modules, tickets)
 * to the new categories structure.
 *
 */

// Find the base file path of Horde.
@define('HORDE_BASE', dirname(__FILE__) . '/..');

// Do CLI checks and environment setup first.
require_once HORDE_BASE . '/lib/core.php';
require_once 'Horde/CLI.php';

// Make sure no one runs this from the web.
if (!Horde_CLI::runningFromCLI()) {
    exit("Must be run from the command line\n");
}

// Load the CLI environment - make sure there's no time limit, init
// some variables, etc.
Horde_CLI::init();

require_once HORDE_BASE . '/lib/base.php';
require_once 'Horde/DataTree.php';
require_once 'Horde/Links.php';

$category = &DataTree::factory('sql');
$db = &$category->_db;

$links = &Horde_Links::singleton('horde');

$old_links = $db->getAll('SELECT link_id, link_type, link_from_provider, link_from_parameter, 
                                 link_to_provider, link_to_parameter
                          FROM horde_links');
$category->_params['group'] = 'horde.links';
$category->_load();
foreach ($old_links as $id => $params) {
    $link_id = $params[0];
    $link_type = $params[1];
    $link_from_provider = $params[2];
    $link_from_parameter = @unserialize($params[3]);
    $link_to_provider = $params[4];
    $link_to_parameter = @unserialize($params[5]);

    // workaround for Whups client data previously saved with provider 'contacts'
    // now standardise these as 'clients'
    if (strstr($link_type, 'client') && $link_to_provider == 'contacts') {
        $link_to_provider = 'clients';
    }

    // now build the new attributes structure (NOTE: only Whups links are currently fully implemented here)
    if ($link_from_provider == 'tickets') {
        if (!empty($link_from_parameter['module_id'])) {
            $link_from_parameter = array('from_key' => 'module_id', 
                                         'from_value' => $link_from_parameter['module_id']);
        } elseif (!empty($link_from_parameter['ticket_id'])) {
            $link_from_parameter = array('from_key' => 'ticket_id', 
                                         'from_value' => $link_from_parameter['ticket_id']);
        }
    }

    if ($link_to_provider == 'clients') {
        $link_to_parameter = array('source' => $link_to_parameter['source'], 
                                   'to_value' => $link_to_parameter['id']);
    }

    $link_data = array('from_params' => $link_from_parameter, 
                       'to_params' => $link_to_parameter, 
                       'link_params' => array('link_type' => $link_type, 
                                              'from_application' => $link_from_provider, 
                                              'to_application' => $link_to_provider));

    $status = $links->addLink($link_data);

    if (is_a($status, 'PEAR_Error')) {
        var_dump($status);
        exit;
    }

}

echo "Links successfully migrated\n";



--- NEW FILE: migrate_user_categories.php ---
#!/usr/bin/php -q
<?php
/**
 * $Horde: horde/scripts/migrate_user_categories.php,v 1.4 2004/05/27 11:59:39 jan Exp $
 *
 * A script to update users preferences to combine their categories
 * and category colors from Genie, Kronolith, Mnemo, and Nag into the
 * new Horde-wide preferences. Expects to be given a list of users on
 * STDIN, one username per line, to convert. Usernames need to match
 * the values stored in the preferences backend.
 */

// Find the base file path of Horde.
@define('AUTH_HANDLER', true);
@define('HORDE_BASE', dirname(__FILE__) . '/..');

// Do CLI checks and environment setup first.
require_once HORDE_BASE . '/lib/core.php';
require_once 'Horde/CLI.php';

// Make sure no one runs this from the web.
if (!Horde_CLI::runningFromCLI()) {
    exit("Must be run from the command line\n");
}

// Load the CLI environment - make sure there's no time limit, init
// some variables, etc.
Horde_CLI::init();

require_once HORDE_BASE . '/lib/base.php';
require_once 'Horde/Prefs/CategoryManager.php';
$cli = &Horde_CLI::singleton();
$auth = &Auth::singleton($conf['auth']['driver']);
$cManager = &new Prefs_CategoryManager();
$apps = $registry->listApps(array('hidden', 'notoolbar', 'active', 'admin'));

// Read in the list of usernames on STDIN.
$users = array();
while ($line = fgets(STDIN, 4096)) {
    $line = trim($line);
    if (!empty($line)) {
        $users[] = $line;
    }
}

// Loop through users and convert prefs for Genie, Mnemo, Nag, and
// Kronolith.
foreach ($users as $user) {
    echo 'Migrating prefs for ' . $cli->bold($user);

    // Set $user as the current user.
    $auth->setAuth($user, array(), '');

    // Fetch current categories and colors.
    $colors = $cManager->colors();

    // Genie.
    if (in_array('genie', $apps)) {
        echo ' . genie';
    	$result = $registry->pushApp('genie', false);
    	if (!is_a($result, 'PEAR_Error')) {
    	    $g_categories = listCategories('wish_categories');
    	    foreach ($g_categories as $category) {
    		$cManager->add($category);
    	    }
    	}
    }

    // Mnemo.
    if (in_array('mnemo', $apps)) {
        echo ' . mnemo';
    	$result = $registry->pushApp('mnemo', false);
    	if (!is_a($result, 'PEAR_Error')) {
    	    $m_categories = listCategories('memo_categories');
    	    $m_colors = listColors('memo_colors');
    	    foreach ($m_categories as $key => $category) {
    		if (isset($m_colors[$key])) {
    		    $colors[$category] = $m_colors[$key];
    		}
    		$cManager->add($category);
    	    }
    	}
    }

    // Nag.
    if (in_array('nag', $apps)) {
        echo ' . nag';
    	$result = $registry->pushApp('nag', false);
    	if (!is_a($result, 'PEAR_Error')) {
    	    $n_categories = listCategories('task_categories');
    	    foreach ($n_categories as $category) {
    		$cManager->add($category);
    	    }
    	}
    }

    // Kronolith.
    if (in_array('kronolith', $apps)) {
        echo ' . kronolith';
    	$result = $registry->pushApp('kronolith', false);
    	if (!is_a($result, 'PEAR_Error')) {
    	    $k_categories = listCategories('event_categories');
    	    $k_colors = listColors('event_colors');
    	    foreach ($k_categories as $key => $category) {
    		if (isset($k_colors[$key])) {
    		    $colors[$category] = $k_colors[$key];
    		}
    		$cManager->add($category);
    	    }
    	}
    }

    $cManager->setColors($colors);
    $prefs->store();
    $cli->writeln();
}

$cli->writeln();
$cli->writeln($cli->green('DONE'));
exit;

function listCategories($prefname)
{
    global $prefs;

    $string = $prefs->getValue($prefname);
    if (empty($string)) {
        return array();
    }

    $cats = explode('|', $string);
    foreach ($cats as $cat) {
        list($key, $val) = explode(':', $cat);
        $categories[$key] = $val;
    }

    return $categories;
}

function listColors($prefname)
{
    global $prefs;

    $string = $prefs->getValue($prefname);
    $cols = explode('|', $string);
    $colors = array();
    foreach ($cols as $col) {
        list($key, $val) = explode(':', $col);
        $colors[$key] = $val;
    }

    return $colors;
}

--- NEW FILE: package.dtd ---
<!--
     $Id: package.dtd,v 1.1 2005/10/31 11:43:31 steffen Exp $

     This is the PEAR package description, version 1.0b3.
     It should be used with the informal public identifier:

         "-//PHP Group//DTD PEAR Package 1.1//EN//XML"

     Copyright (c) 1997-2003 The PHP Group

     This source file is subject to version 2.02 of the PHP license,
     that is bundled with this package in the file LICENSE, and is
     available at through the world-wide-web at
     http://www.php.net/license/2_02.txt.
     If you did not receive a copy of the PHP license and are unable to
     obtain it through the world-wide-web, please send a note to
     license at php.net so we can mail you a copy immediately.

     Authors:
         Stig S. Bakken <ssb at fast.no>
         Tomas V.V.Cox <cox at idecnet.com>

     DTD Revision: 1.1

  -->

<!ENTITY % FileRoles     "(php|ext|test|doc|data|src|script)">
<!ENTITY % DepTypes      "(pkg|ext|php|prog|ldlib|ltlib|os|websrv|sapi)">
<!ENTITY % DepRels       "(has|not|eq|lt|le|gt|ge)">
<!ENTITY % ProvideTypes  "(ext|prog|class|function|feature|api)">

<!ELEMENT package (name,summary,description,license?,maintainers,release,changelog?)>
<!ATTLIST package
    type        (source|binary|empty) "empty"
    version     CDATA                 #REQUIRED>

<!ELEMENT name (#PCDATA)>

<!ELEMENT summary (#PCDATA)>

<!ELEMENT description (#PCDATA)>

<!ELEMENT maintainers (maintainer)+>

<!ELEMENT maintainer (user,role,name,email)>

<!ELEMENT user (#PCDATA)>

<!ELEMENT role (#PCDATA)>

<!ELEMENT email (#PCDATA)>

<!ELEMENT changelog (release)*>

<!ELEMENT release (license?,version,state,date,notes,filelist?,provides*,deps?)>

<!ELEMENT license (#PCDATA)>

<!ELEMENT version (#PCDATA)>

<!ELEMENT state (#PCDATA)>

<!ELEMENT date (#PCDATA)>

<!ELEMENT notes (#PCDATA)>

<!ELEMENT filelist (dir|file|libfile)+>

<!ELEMENT dir (dir|file|libfile)*>
<!ATTLIST dir
    name           CDATA              #REQUIRED
    role           %FileRoles;        "php"
    baseinstalldir CDATA              #IMPLIED>

<!ELEMENT file (replace)*>
<!ATTLIST file
    name           CDATA              #REQUIRED
    role           %FileRoles;        "php"
    debug          (na|on|off)        "na"
    threaded       (na|on|off)        "na"
    format         CDATA              #IMPLIED
    md5sum         CDATA              #IMPLIED
    install-as     CDATA              #IMPLIED
    platform       CDATA              #IMPLIED
    baseinstalldir CDATA              #IMPLIED>

<!ELEMENT replace EMPTY>
<!ATTLIST replace
    from           CDATA              #REQUIRED
    to             CDATA              #REQUIRED
    type           CDATA              #REQUIRED>

<!ELEMENT libfile (libname|sources|includes|libadd)*>

<!ELEMENT libname (#PCDATA)>

<!ELEMENT sources (#PCDATA)>

<!ELEMENT libadd (#PCDATA)>

<!ELEMENT deps (dep)*>

<!ELEMENT dep (#PCDATA)>
<!ATTLIST dep
    type      %DepTypes;      #REQUIRED
    rel       %DepRels;       #IMPLIED
    version   CDATA           #IMPLIED
    optional  (yes|no)        "no">

<!ELEMENT provides EMPTY>
<!ATTLIST provides
    type      %ProvideTypes;  #REQUIRED
    name      CDATA           #REQUIRED
    extends   CDATA           #IMPLIED>

--- NEW FILE: remove_prefs.php ---
#!/usr/local/bin/php
<?php
/**
 * $Horde: horde/scripts/remove_prefs.php,v 1.3 2004/04/07 14:43:44 chuck Exp $
 *
 * This script removes a pref from users' settings. Helps when a setting is
 * to be moved from locked = false, to locked = true and there have already
 * been prefs set by the users.
 */

/**
 ** Set this to true if you want DB modifications done.
 **/
$live = false;

// No auth.
@define('AUTH_HANDLER', true);

// Find the base file path of Horde.
@define('HORDE_BASE', dirname(__FILE__) . '/..');

// Do CLI checks and environment setup first.
require_once HORDE_BASE . '/lib/core.php';
require_once 'Horde/CLI.php';

// Make sure no one runs this from the web.
if (!Horde_CLI::runningFromCLI()) {
    exit("Must be run from the command line\n");
}

// Load the CLI environment - make sure there's no time limit, init
// some variables, etc.
Horde_CLI::init();
$cli = &new Horde_CLI();

require_once HORDE_BASE . '/lib/base.php';
require_once 'Horde/DataTree.php';
require_once 'Horde/Group.php';
require_once 'Horde/Share.php';

/* Make sure there's no compression. */
ob_end_clean();


$scope = $cli->prompt(_("Enter value for pref_scope:"));
$name = $cli->prompt(_("Enter value for pref_name:"));

/* Open the database. */
$db = &DB::connect($conf['sql']);
if (is_a($db, 'PEAR_Error')) {
   var_dump($db); exit;
}

if ($live) {
    $sql = sprintf('DELETE FROM horde_prefs WHERE pref_scope = %s AND pref_name = %s',
                   $db->quote($scope),
                   $db->quote($name));
    $result = $db->getAll($sql);
    if (is_a($result, 'PEAR_Error')) {
        var_dump($result);
    } elseif (empty($result)) {
        $cli->writeln(sprintf(_("No preference '%s' found in scope '%s'."), $name, $scope));
    } else {
        $cli->writeln(sprintf(_("Preferences '%s' deleted in scope '%s'."), $name, $scope));
    }
} else {
    $sql = sprintf('SELECT * FROM horde_prefs WHERE pref_scope = %s AND pref_name = %s',
                   $db->quote($scope),
                   $db->quote($name));
    $result = $db->getAll($sql);
    if (empty($result)) {
        $cli->writeln(sprintf(_("No preference '%s' found in scope '%s'."), $name, $scope));
    } else {
        var_dump($result);
    }
}

--- NEW FILE: rename_category.php ---
#!/usr/local/bin/php
<?php
/**
 * $Horde: horde/scripts/rename_category.php,v 1.6 2004/04/07 14:43:44 chuck Exp $
 *
 * Copyright 2004 Jan Schneider <jan at horde.org>
 *
 * See the enclosed file COPYING for license information (LGPL).  If you
 * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
 */

/* Change this variable to false. */
$live = false;

/* Configure your table names here, these are the default values. */
$category['table'] = 'horde_categories';
$category['table_attributes'] = 'horde_category_attributes';
$datatree['table'] = 'horde_datatree';
$datatree['table_attributes'] = 'horde_datatree_attributes';

/* 
 * Nothing to see below this line. 
 */

@define('AUTH_HANDLER', true);
@define('HORDE_BASE', dirname(__FILE__) . '/..');

// Do CLI checks and environment setup first.
require_once HORDE_BASE . '/lib/core.php';
require_once 'Horde/CLI.php';

// Make sure no one runs this from the web.
if (!Horde_CLI::runningFromCLI()) {
    exit("Must be run from the command line\n");
}

// Load the CLI environment - make sure there's no time limit, init
// some variables, etc.
Horde_CLI::init();

require_once HORDE_BASE . '/lib/base.php';

if (!$live) {
    echo "TEST MODE. No data will be changed.\nChange the \$live setting in this script to apply the changes.\n\n";
}

// DB setup for the category table.
$params = Horde::getDriverConfig('datatree', 'sql');
if (!isset($params['password'])) {
    $params['password'] = '';
}
$dbh = &DB::connect($params);

// Get the current max id.
$max = $dbh->getOne('SELECT MAX(category_id) FROM ' . $category['table']);
if (is_a($max, 'PEAR_Error')) {
    echo "Fatal error: ", $max->getMessage(), "\n";
    exit(1);
}

// Make sure the sequence is at least that high.
if ($live) {
    echo "Setting DataTree sequence to $max.\n";
    while ($dbh->nextId($datatree['table']) < $max);
} else {
    echo "NOT setting DataTree sequence to $max.\n";
}

// Get the old values...
$result = $dbh->query('SELECT category_id, group_uid, user_uid, category_name, category_parents, category_order, category_data, category_serialized, category_updated from ' . $category['table']);
if (is_a($result, 'PEAR_Error')) {
    var_dump($result);
    exit(1);
}

// ...and stuff them into the new table.
$sth = $dbh->prepare('INSERT INTO ' . $datatree['table'] . ' (datatree_id, group_uid, user_uid, datatree_name, datatree_parents, datatree_order, datatree_data, datatree_serialized, datatree_updated) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)');
$count = 0;
while ($row = $result->fetchRow()) {
    if ($live) {
        $exec_result = $dbh->execute($sth, $row);
        if (is_a($exec_result, 'PEAR_Error')) {
            echo "Error \"", $exec_result->getMessage(), "\" while copying rows to horde_datatree table (does it exist?)\n";
            exit(1);
        }
    }
    $count++;
}
if ($live) {
    echo "Copied $count row(s) from {$category['table']} to {$datatree['table']}.\n";
} else {
    echo "NOT copied $count row(s) from {$category['table']} to {$datatree['table']}.\n";
}

// Get the old attribute values...
$result = $dbh->query('SELECT * from ' . $category['table_attributes']);
if (is_a($result, 'PEAR_Error')) {
    var_dump($result);
    exit(1);
}

// ...and stuff them into the new table.
$sth = $dbh->prepare('INSERT INTO ' . $datatree['table_attributes'] . ' (datatree_id, attribute_name, attribute_key, attribute_value) VALUES (?, ?, ?, ?)');
$count = 0;
while ($row = $result->fetchRow()) {
    if ($live) {
        $exec_result = $dbh->execute($sth, $row);
        if (is_a($exec_result, 'PEAR_Error')) {
            echo "Fatal error: ", $exec_result->getMessage(), "\n";
            exit(1);
        }
    }
    $count++;
}
if ($live) {
    echo "Copied $count row(s) from {$category['table_attributes']} to {$datatree['table_attributes']}.\n\n";
    echo "You can now delete the {$category['table']} and {$category['table_attributes']} tables.\n";
} else {
    echo "NOT copied $count row(s) from {$category['table_attributes']} to {$datatree['table_attributes']}.\n";
}

--- NEW FILE: set_perms.sh ---
#!/bin/sh
#
# set_perms.sh - Jon Parise <jon at csh.rit.edu>
#
# $Horde: horde/scripts/set_perms.sh,v 1.7 2001/04/15 01:55:32 chuck Exp $

# "Dangerous" PHP scripts
#
DANGEROUS_FILES="test.php"

# Default non-web server user who will own the tree.
#
OWNER=root

# Introductory text
#
cat << EOF

This script will set the permissions on your Horde
tree so that the files will be accessible by the web
server.

You can cancel this script at any time using Ctrl-C.

EOF

# Verify that we're at the top of the Horde tree.
#
pwd
echo
echo -n "Is this directory the top of your Horde installation? [y,N] "
read RESPONSE 
if [ "$RESPONSE" != "y" -a "$RESPONSE" != "Y" ]; then
    echo
    echo -n "Enter your Horde directory: "
    read DIR  
	if [ "x$DIR" = "x" ]; then
		echo "Exiting..."
		exit
	else
    	cd $DIR
	fi
fi
echo

# Get the web server's group.
#
echo -n "Under what group does the web process run? [nobody] "
read WEB_GROUP
if [ "x$WEB_GROUP" = "x" ]; then
    WEB_GROUP="nobody" 
fi

# Ask before proceeding.
#
echo
echo -n "Proceed with changing ownership and permissions? [y,N] "
read RESPONSE 
if [ "$RESPONSE" != 'y' -a "$RESPONSE" != 'Y' ]; then
    echo "Exiting..."
    exit
fi

# Set the user and group ownership recursively.
#
echo
echo -n "Setting ownership recursively... "
chown -R $OWNER .
chgrp -R $WEB_GROUP .
echo "done."

# Set the permissions on files (0640) and directories (0750).
#
echo -n "Setting permissions recursively... "
find . -type f -exec chmod 0640 {} \;
find . -type d -exec chmod 0750 {} \;
echo "done."

# Disable any "dangerous" PHP scripts in the distribution (0000).
#
echo -n "Disabling potentially \"dangerous\" PHP scripts... "
for FILE in $DANGEROUS_FILES; do
	if [ -f $FILE ]; then
		chmod 0000 $FILE
	fi
done
echo "done."

# Say good-bye.
#
echo
echo "If you received any errors, you may not have sufficient access"
echo "to change file ownership and permissions."
echo

--- NEW FILE: setup.php ---
#!/usr/local/bin/php
<?php
/**
 * The main Horde setup script which allows for a step by step setup
 * or reconfiguration of a Horde installation.
 *
 * $Horde: horde/scripts/setup.php,v 1.21 2004/05/20 15:13:01 jan Exp $
 *
 * Copyright 2003-2004 Marko Djukic <marko at oblo.com>
 * Copyright 2003-2004 Charles J. Hagenbuch <chuck at horde.org>
 *
 * See the enclosed file COPYING for license information (LGPL).  If you
 * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
 *
 * @author  Marko Djukic <marko at oblo.com>
 * @author  Charles J. Hagenbuch <chuck at horde.org>
 * @version $Revision: 1.1 $
 * @since   Horde 3.0
 */

define('AUTH_HANDLER', true);
define('HORDE_BASE', dirname(__FILE__) . '/..');
require_once HORDE_BASE . '/lib/core.php';

$setup = &Setup::singleton();
if (!$setup->check('registry')) {
    $setup->log(_("No Horde registry file."), 'warning');
    $setup->makeRegistry();
} else {
    $setup->log(_("Horde registry file is available."), 'message');
}

/* Horde base libraries. */
$session_control = 'none';
require_once HORDE_BASE . '/lib/base.php';
require_once 'Horde/Form.php';
require_once 'Horde/Config.php';
require_once 'Horde/Variables.php';

if (!$setup->check('domxml')) {
    $this->fatal(_("You need the DOM XML PHP extension to run setup."));
} else {
    $setup->log(_("DOM XML extension is available."), 'message');
}

do {
} while ($setup->appConfig($setup->check('appconf')) != true);


$setup->log(_("Setup completed. Thank you for using Horde!"), 'success');
exit;


/**
 * The Setup:: class provides a set of functions to set up a Horde
 * installation.
 *
 * $Horde: horde/scripts/setup.php,v 1.21 2004/05/20 15:13:01 jan Exp $
 *
 * Copyright 2003-2004 Marko Djukic <marko at oblo.com>
 *
 * See the enclosed file COPYING for license information (LGPL). If you
 * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
 *
 * @author  Marko Djukic <marko at oblo.com>
 * @version $Revision: 1.1 $
 * @since   Horde 3.0
 * @package Horde_Setup
 */
class Setup {

    /**
     * Constructor
     */
    function Setup()
    {
    }

    function &factory($interface)
    {
        $class = 'Setup_' . $interface;
        if (class_exists($class)) {
            return $ret = &new $class();
        } else {
            exit(sprintf(_("Setup is not available through the %s interface."), $interface));
        }
    }

    function &singleton()
    {
        static $instance;

        if (!isset($instance)) {
            require_once 'Horde/CLI.php';
            if (Horde_CLI::runningFromCLI()) {
                $interface = 'cli';
            } else {
                $interface = 'web';
            }
            $instance = &Setup::factory($interface);
        }
        
        return $instance;
    }

    function check($target)
    {
        switch ($target) {
        case 'registry':
            /* We need to have the Horde registry file available. */
            return file_exists(HORDE_BASE . '/config/registry.php');

        case 'domxml':
            /* We need the domxml PHP extension to continue with the setup. */
            return Util::extensionExists('domxml');

        case 'appconf':
            /* Check which apps have a conf.php file. */
            global $registry;
            $apps = $registry->listApps(array('hidden', 'notoolbar', 'active'));
            $all_configured = true;
            foreach ($apps as $app) {
                if (!file_exists($registry->getParam('fileroot', $app))) {
                    $this->log(sprintf(_("Bad file root for %s in registry. Set 'inactive' if not installed."), $app), 'warning');
                } elseif (!file_exists($registry->getParam('fileroot', $app) . '/config/conf.php')) {
                    $all_configured = false;
                    $this->log(sprintf(_("No configuration file (conf.php) for %s."), $app), 'warning');
                } else {
                    $this->log(sprintf(_("Found the configuration file for %s."), $app), 'message');
                }
            }
            return $all_configured;
        }
    }

}


/**
 * The Setup_cli:: class provides a CLI interface to the Horde setup
 * script.
 *
 * $Horde: horde/scripts/setup.php,v 1.21 2004/05/20 15:13:01 jan Exp $
 *
 * Copyright 2003-2004 Marko Djukic <marko at oblo.com>
 *
 * See the enclosed file COPYING for license information (LGPL).  If you
 * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
 *
 * @author  Marko Djukic <marko at oblo.com>
 * @version $Revision: 1.1 $
 * @since   Horde 3.0
 * @package Horde_Setup
 */
class Setup_cli extends Setup {

    var $cli = null;

    /**
     * Constructs a new Setup object using the CLI interface.
     */
    function Setup_cli()
    {
        parent::Setup();

        require_once 'Horde/CLI.php';
        $this->cli = &new Horde_CLI();

    }

    function log($message, $type = 'message')
    {
        /* Wrap the messages with an indent, neater screen display. */
        $message = wordwrap($message, 69, "\n           ");
        $this->cli->message($message, 'cli.' . $type);
    }

    function makeRegistry()
    {
        $file     = HORDE_BASE . '/config/registry.php';
        $distfile = $file . '.dist';

        if (file_exists($distfile)) {
           $create_registry = $this->cli->prompt(_("Create a Horde registry from default now?"), array('y' => _("Yes"), 'n' => _("No")));
        } else {
            $this->cli->fatal(sprintf(_("The default Horde Registry file '%s' is not available, check your installation."), $distfile));
        }

        if ($create_registry == 'y') {
            if (!copy($file . '.dist', $file)) {
                $this->cli->fatal(sprintf(_("Copying '%1$s.dist' to '%1$s' failed. Check your installation."), $file));
            }
            $this->log(_("Registry created."), 'success');
        } else {
            $this->cli->fatal(sprintf(_("You need the Horde registry file to continue setup and to use Horde."), $file));
        }
    }

    function appConfig($is_config_ok)
    {
        if ($is_config_ok) {
            $run_config = $this->cli->prompt(_("All the installed applications seem to be configured, reconfigure any app?"), array('y' => _("Yes"), 'n' => _("No")));
            if ($run_config == 'n') {
                return true;
            }
        }

        global $registry;

        $applist = $registry->listApps(array('hidden', 'notoolbar', 'active'));
        sort($applist);
        $apps = array(0 => _("All applications"));
        foreach ($applist as $app) {
            if (@file_exists($registry->getParam('fileroot', $app) . '/config/conf.xml')) {
                array_push($apps, $app);
            }
        }
        $apps = $apps + array('x' => 'exit');
        $app_choice = $this->cli->prompt(_("Which app do you wish to reconfigure?"), $apps);
        if ($app_choice == 'x') {
            return true;
        }

        if ($app_choice > 0) {
            $apps = array($apps[$app_choice]);
        } else {
            $apps = array_slice($apps, 1, count($apps) - 2);
        }
        $vars = Variables::getDefaultVariables();
        foreach ($apps as $app) {
            $config = &new Horde_Config($app);
            $php = $config->generatePHPConfig($vars);
            $fp = @fopen($registry->getParam('fileroot', $app) . '/config/conf.php', 'w');
            if ($fp) {
                fwrite($fp, String::convertCharset($php, NLS::getCharset(), 'iso-8859-1'));
                fclose($fp);
                $this->log(sprintf(_("Wrote configuration file '%s'."), $registry->getParam('fileroot', $app) . '/config/conf.php'), 'success');
            } else {
                $this->log(sprintf(_("Can not write configuration file '%s'."), $registry->getParam('fileroot', $app) . '/config/conf.php'), 'error');
            }
        }

    }

}

--- NEW FILE: temp-cleanup.cron ---
#!/bin/sh

# This is an example cron job shell script which will clean up any
# temporary files which may get stranded by Horde users in the
# webserver's temporary directory.
#
# You may have to change /tmp to another location depending on your
# configuration.  Other modifications may also be required.
#
# This script is provided as-is and is to be used at your own risk. 
# Horde and the authors accept no responsibility for any damages or
# loses caused by this script whether indirect, incidental, or
# consequential,  whether or not such damages could be forseen.
#
# How to use this script will depend on your system.  For some systems,
# it is as simply as putting this file in the /etc/cron.daily directory.
# For others, more or different setup will be required.  See the
# documentation for your systems job scheduler for more information.
#

# The location of PHP's temporary directory
TMP_DIR=/tmp


# MSWord attachments (generated by the MSword viewer)
for MSWORD_FILE in `find $TMP_DIR -type f -name msword\* -ctime +2 `; do
	rm -f $MSWORD_FILE
done

# IMP attachments
for IMP_FILE in `find $TMP_DIR -type f -name impatt\* -ctime +2 `; do
	rm -f $IMP_FILE
done

# Klutz temporary files
for KLUTZ_FILE in `find $TMP_DIR -type f -name Klutz\* -ctime +2 `; do
	rm -f $KLUTZ_FILE
done

# Spell checking temporary files
for SPELL_FILE in `find $TMP_DIR -type f -name spell\* -ctime +2 `; do
	rm -f $SPELL_FILE
done

# VFS temporary files
for IMP_FILE in `find $TMP_DIR -type f -name vfs\* -ctime +2 `; do
	rm -f $IMP_FILE
done

--- NEW FILE: update_horde.sh ---
#!/bin/sh
# $Horde: horde/scripts/update_horde.sh,v 1.2 2002/07/08 23:46:42 chuck Exp $
#
# update_horde.sh - Marcus I. Ryan <marcus at riboflavin.net>
#
# I wrote this script for me, so there isn't really much documentation.
# I'll explain the few things that come to mind:
#
# Summary: This script facilitates the updating and/or installation of horde
# and its applications.
# * Create a temporary directory to hold a new install
# * Make a patch file of the various *.dist files and their non-dist versions
# * Copy the existing install or download fresh from CVS
# * Apply the patch made earlier
# * Make a backup of the existing install
# * Make the new download the current install
#
# Options/Variables:
# NUM_SLASHES - Since I'm too lazy to code a better way, this is the number
#               of slashes to remove from the path to make the patch work
#               relative to the temporary directory.
# NUM_BACKUPS - How many backups do we want to keep?
# WEBDIR      - The actual install directory (this is the live version)
# BACKUPDIR   - Where do we want to keep the backups
# TMPDIR      - Where do we build the new version to install
# RELEASES    - A list of the various "releases" we've defined
# <rel>_dir   - The name of the "horde" dir (usually horde) for release <rel>
# <rel>_ver   - A list of the various CVS distributions for realease <ver>
#               and the CVS branches to download.  See examples.
#
# WARNING: I do not currently have it set up to check if a patch fails 
#          completely.  This is not usually a problem, but if a *.dist file
#          is drastically updated it has been known to cause problems.
#          If you use this script, please keep an eye out for this.  That
#          said, I updated both my installs (release and head) with it
#          over 50 times before I finally had a problem.

trim () {
  echo $@
}

######## CONFIGURATION ########

### MISC. OPTIONS ###
NUM_SLASHES=4
NUM_BACKUPS=5

### DIRECTORIES ###
WEBDIR=/usr/local/www
BACKUPDIR=/usr/local/src
TMPDIR=/usr/local/src

### RELEASES ###
RELEASES="release head"

# For each release, we need _dir and _ver settings

#This is the "array" of applications and versions to get
release_dir=horde
release_ver="
        horde-RELENG_2
	imp-RELENG_3
	turba-RELENG_1
	kronolith-RELENG_1
	nag-RELENG_1
	mnemo-RELENG_1
"
release_ver=`trim ${release_ver}`

head_dir=horde.head
head_ver="
        horde-HEAD
	imp-HEAD
	turba-HEAD
	gollem-HEAD
	kronolith-HEAD
	jonah-HEAD
	troll-HEAD
	nag-HEAD
	nic-HEAD
        mnemo-HEAD
	passwd-HEAD
	sam-HEAD
"
head_ver=`trim ${head_ver}`

######## MAIN CODE ########

APPVER=$head_ver
HORDEDIR=$head_dir

# check to see if any command line args are specified
for arg in $*
do
  name=${arg%%=*}
  name=${name##--}
  value=${arg##*=}
  if [ "$name" = "release" ]; then
    APPVER=`eval echo '$'$value'_ver'`
    HORDEDIR=`eval echo '$'$value'_dir'`
    if [ "$APPVER" = "" -o "$HORDEDIR" = "" ]; then
      echo "ERROR: No settings for release $value"
    fi
    continue
  fi
  echo "Unknown option $arg ('$name' = '$value')"
  exit 1
done

echo "Verifying distribution list"
if [ ! "${APPVER%%[- ]*}" = "horde" ]; then
  echo "  horde MUST be the first item in the APPVER list!"
  exit 1
fi

echo "Determining temporary directory..."
EXISTS=`ls -d ${TMPDIR}/${HORDEDIR}.TMP.[0-9]* | head -1`
TMPDIR="${TMPDIR}/${HORDEDIR}.TMP.$$"

if [ ! -z ${EXISTS} ]; then
  echo "  Found an existing (aborted?) update of horde (${EXISTS})."
  read -p "  Should I use it? [Yes]" USE_EXISTING
  case ${USE_EXISTING} in
  [Nn]|[Nn][Oo])
    read -p "  Should I delete ${EXISTS}? [Yes]" DELETE_EXISTING
    case ${DELETE_EXISTING} in
    [Nn]|[Nn][Oo])
      echo "    Not deleting ${EXISTS}"
      ;;
    *)
      echo "    Deleting ${EXISTS}"
      rm -rf ${EXISTS}
      ;;
    esac
    ;;
  *)
    TMPDIR=${EXISTS}
    ;;
  esac
  unset USE_EXISTING
fi
if [ -e ${TMPDIR} ]; then
  echo "  Using ${TMPDIR}"
else
  echo "  Creating new directory ${TMPDIR}"
  mkdir ${TMPDIR}
  if [ ! -e ${TMPDIR} ]; then
    echo "ERROR: Couldn't create ${TMPDIR}"
    exit 1
  fi
fi

echo "Creating config patch file from existing horde"
if [ -e ${TMPDIR}/update.patch ]; then
  read -p "  This directory includes a patch. Use it? [Yes]" USE_EXISTING
  case ${USE_EXISTING} in
  [Nn]|[Nn][Oo])
    echo "  Clearing existing update.patch"
    rm -f ${TMPDIR}/update.patch || exit 1
    ;;
  esac
  unset USE_EXISTING
fi
if [ ! -e ${TMPDIR}/update.patch ]; then
  if [ ! -e ${WEBDIR}/${HORDEDIR} ]; then
    echo "  No existing horde distribution found.  Can't create patch."
  else
    read -p "  Do you want to create a patch from the existing install? [Yes]" MAKE_PATCH
    case ${MAKE_PATCH} in
    [Nn]|[Nn][Oo])
      echo "  Not creating a patch"
      ;;
    *)
      echo "  Creating patch...this could take a bit..."
      find ${WEBDIR}/${HORDEDIR} -type f -name \*.dist -print \
       | perl -ne 's/\.dist[\r\n]*//; print "$_.dist\n$_\n";' \
       | xargs -n 2 diff -u > ${TMPDIR}/update.patch
      ;;
    esac
    unset MAKE_PATCH
  fi
fi

if [ -e "${WEBDIR}/${HORDEDIR}" ]; then
  read -p "Do you want to fetch new (N) or update (U)? [U] " FETCH_NEW
else
  FETCH_NEW=new
fi

case ${FETCH_NEW} in
  [Nn]|[Nn][Ee][Ww])
    for APP in ${APPVER}
    {
      app=${APP%%-*}
      rel=${APP##*-}
      if [ ${app} = ${APP} ]; then
        echo "  No release specified...assuming HEAD"
        rel=HEAD
      fi

      case ${app} in
        horde)
          APPDIR=${TMPDIR}
          EXISTDIR="${TMPDIR}/${HORDEDIR}"
          ;;
        *)
          APPDIR=${TMPDIR}/${HORDEDIR}
          EXISTDIR="${TMPDIR}/${HORDEDIR}/${app}"
          ;;
      esac

      if [ -e $EXISTDIR ]; then
        case ${REGET} in
        [Aa]|[Aa][Ll][Ll])
          echo "  Removing existing ${APPDIR}/${app}...";
          rm -rf ${APPDIR}/${app}
          echo "  Retrieving ${app} $rel..."
          cd ${APPDIR}
          cvs -Q -z3 -d :pserver:cvsread at anoncvs.horde.org:/repository co \
           -r $rel ${app}
          ;;
        [Nn][Oo][Nn][Ee])
          REGET="NONE"
          echo "  Using existing ${APPDIR}/${app}"
          ;;
        *)
          echo "  ${app} exists. Should I get ${app} anyway?"
          if [ "${app}" = "horde" ]; then
            echo "  NOTE: regetting horde does not clear out any existing files"
          fi
          read -p "   [Y]es/[N]o/[A]ll/None (default None): " REGET
          case ${REGET} in
          [Yy]|[Yy][Ee][Ss]|[Aa]|[Aa][Ll][Ll])
            echo "  Removing existing ${APPDIR}/${app}...";
            rm -rf ${APPDIR}/${app}
            echo "  Retrieving ${app} $rel..."
            cd ${APPDIR}
            cvs -Q -z3 -d :pserver:cvsread at anoncvs.horde.org:/repository co \
             -r $rel ${app}
            ;;
          [Nn]|[Nn][Oo])
            echo "  Using existing ${APPDIR}/${app}"
            ;;
          *)
            echo "  Using existing ${APPDIR}/${app}"
            REGET=NONE
            ;;
          esac
          ;;
        esac
      else
        echo -n "  Retrieving ${app} $rel..."
        cd ${APPDIR}
        cvs -Q -z3 -d :pserver:cvsread at anoncvs.horde.org:/repository co \
         -r $rel ${app}
	echo "done"
      fi
      if [ "$app" = "horde" -a "$HORDEDIR" != "horde" ]; then
	echo "  Moving ${TMPDIR}/horde to ${TMPDIR}/${HORDEDIR}"
        mv ${TMPDIR}/horde ${TMPDIR}/${HORDEDIR}
      fi
    }
    ;;
  *)
    mkdir ${TMPDIR}/${HORDEDIR}
    cp -Rpf ${WEBDIR}/${HORDEDIR}/* ${TMPDIR}/${HORDEDIR}
    cd ${TMPDIR}/${HORDEDIR}
    cvs update -PdC
    ;;
esac

echo "Putting default config files in place..."
if [ -e ${TMPDIR}/${HORDEDIR}/config/conf.php ]; then
  echo "  I have found some configuration files already in place."
  echo "  If you are updating an existing installation this is normal."
  echo "  NOTE: If some have been copied and others not, horde will be broken."
  read -p "   Should I copy .dist files anyway? [Yes] " USE_EXISTING
  #The phrasing of the question means USE_EXISTING from the read is backwards
  # but it seems better to confuse the programmer than the user...
  case ${USE_EXISTING} in
   [Nn]|[Nn][Oo])
    USE_EXISTING=YES
    ;;
  *)
    USE_EXISTING=NO
    ;;
  esac
fi
if [ "${USE_EXISTING:=NO}" = "NO" ]; then
  echo "  Copying *.dist files..."
  find ${TMPDIR}/${HORDEDIR} -type f -name \*.dist -print \
   | perl -ne 'print "$_"; s/\.dist//; print "$_"' \
   | xargs -n 2 cp
fi

echo "Applying patch..."
echo "  Clearing out any old reject files..."
find ${TMPDIR} -name \*.rej -type f -exec rm {} \; -print

if [ ! -e ${TMPDIR}/update.patch ]; then
  echo "  I can't seem to find the patch file ${TMPDIR}/update.patch!"
  read -p "  Do you want me to load all config files in $EDITOR? [No]" EDIT
  case ${EDIT} in
  [Yy]|[Yy][Ee][Ss])
    find ${TMPDIR}/${HORDEDIR} -type f -name \*.dist \
     | perl -ne 's/\.dist[\r\n]*//; print "$_\n";' \
     | xargs -n 2 echo $EDITOR > ${TMPDIR}/edit.sh
    sh ${TMPDIR}/edit.sh
    rm ${TMPDIR}/edit.sh
    ;;
  *)
    echo "  WARNING: You need to change the config files later!"
    ;;
  esac
else
  if [ "${USE_EXISTING}" = "YES" ]; then
    echo "  We kept the modified configuration files."
    read -p "  Should we still apply the patch? [No] " PATCH
    case ${PATCH} in
    [Yy]|[Yy][Ee][Ss])
      PATCH=YES
      ;;
    *)
      PATCH=NO
      ;;
    esac
  fi

  if [ "${PATCH:=YES}" = "YES" ]; then
    echo "  running patch"
    cd ${TMPDIR}
    if [ `patch -f -p${NUM_SLASHES} -s < ${TMPDIR}/update.patch` ]; then
      echo "  Patch applied successfully"
    else
      find ${TMPDIR}/${HORDEDIR} -type f -name \*.rej \
       | perl -ne 's/\.rej[\r\n]*//; print "$_.rej\n$_\n"; ' \
       | xargs -n 2 echo $EDITOR > ${TMPDIR}/edit.sh
      sh ${TMPDIR}/edit.sh
      rm ${TMPDIR}/edit.sh
    fi
  fi
fi

read -p "Are you ready to put the new CVS into production? [Yes]" PROD
case ${PROD} in
[Nn]|[Nn][Oo])
  echo "${TMPDIR} has not been put in production."
  ;;
*)
  if [ -e ${WEBDIR}/${HORDEDIR} ]; then
    i=1
    while [ ${i} != ${NUM_BACKUPS} ]
    do
      if [ ! -e ${BACKUPDIR}/${HORDEDIR}.${i} ]; then
        break;
      fi
      i=$((${i}+1))
    done

    if [ ${i} = ${NUM_BACKUPS} ] && [ -e ${BACKUPDIR}/${HORDEDIR}.${i} ]; then
      echo "  Removing oldest backup directory (${BACKUPDIR}/${HORDEDIR}.${i})"
      rm -rf ${BACKUPDIR}/${HORDEDIR}.${i} || exit 1
    fi

    while [ ${i} != 1 ]
    do
      echo "  Moving ${BACKUPDIR}/${HORDEDIR}.$((${i}-1)) to ${BACKUPDIR}/${HORDEDIR}.${i}"
      mv ${BACKUPDIR}/${HORDEDIR}.$((${i}-1)) ${BACKUPDIR}/${HORDEDIR}.${i} || exit 1
      i=$((${i}-1))
    done

    echo "  Moving ${WEBDIR}/${HORDEDIR} to ${BACKUPDIR}/${HORDEDIR}.1"
    mv ${WEBDIR}/${HORDEDIR} ${BACKUPDIR}/${HORDEDIR}.1 || exit 1

    echo "  Moving ${TMPDIR}/${HORDEDIR} ${WEBDIR}/${HORDEDIR}"
    mv ${TMPDIR}/${HORDEDIR} ${WEBDIR}/${HORDEDIR} || exit 1

    echo "  Removing ${TMPDIR}"
    rm -rf ${TMPDIR}

    echo "New CVS horde is now in production!"
  else
    echo "${WEBDIR}/${HORDEDIR} does not exist.  Copying ${TMPDIR}/${HORDEDIR} to ${WEBDIR}/${HORDEDIR}"
    cp ${TMPDIR}/${HORDEDIR} ${WEBDIR}/${HORDEDIR}
  fi
  ;;
esac





More information about the commits mailing list