--- /dev/null
+<?php
+
+class Koward_ApplicationController extends Horde_Controller_Base
+{
+ protected function _initializeApplication()
+ {
+ $this->koward = Koward_Koward::singleton();
+
+ $this->types = array_keys($this->koward->objects);
+ if (empty($this->types)) {
+ throw new KowardException('No object types have been configured!');
+ }
+
+ $this->menu = $this->getMenu();
+
+ $this->theme = isset($this->koward->conf['koward']['theme']) ? $this->koward->conf['koward']['theme'] : 'koward';
+ }
+
+ /**
+ * Builds Koward's list of menu items.
+ */
+ public function getMenu()
+ {
+ global $registry;
+
+ require_once 'Horde/Menu.php';
+ $menu = new Menu();
+
+ $menu->add($this->urlFor(array('controller' => 'object', 'action' => 'listall')),
+ _("_Objects"), 'user.png', $registry->getImageDir('horde'));
+ $menu->add($this->urlFor(array('controller' => 'object', 'action' => 'edit')),
+ _("_Add"), 'plus.png', $registry->getImageDir('horde'));
+ $menu->add(Horde::applicationUrl('search'), _("_Search"), 'search.png', $registry->getImageDir('horde'));
+ $menu->add(Horde::applicationUrl('Queries'), _("_Queries"), 'query.png', $registry->getImageDir('koward'));
+ $menu->add($this->urlFor(array('controller' => 'check', 'action' => 'show')),
+ _("_Test"), 'problem.png', $registry->getImageDir('horde'));
+
+ return $menu;
+ }
+}
--- /dev/null
+<?php
+/**
+ * @package Koward
+ */
+
+// @TODO Clean up
+require_once dirname(__FILE__) . '/ApplicationController.php';
+
+/**
+ * @package Koward
+ */
+class CheckController extends Koward_ApplicationController
+{
+
+ protected function _initializeApplication()
+ {
+ parent::_initializeApplication();
+
+ $this->suite = Koward_Test_AllTests::suite();
+ }
+
+ public function show()
+ {
+ $this->list = array();
+
+ $this->list[0] = Horde::link(
+ $this->urlFor(array('controller' => 'check',
+ 'action' => 'run',
+ 'id' => 'all')),
+ _("All tests")) . _("All tests") . '</a>';
+
+ $this->list[1] = '';
+
+ for ($i = 0; $i < $this->suite->count(); $i++) {
+ $class_name = $this->suite->testAt($i)->getName();
+ $this->list[$i + 2] = Horde::link(
+ $this->urlFor(array('controller' => 'check',
+ 'action' => 'run',
+ 'id' => $i + 1)),
+ $class_name) . $class_name . '</a>';
+ }
+ }
+
+ public function run()
+ {
+
+ if ($this->params['id'] == 'all') {
+ $this->test = $this->suite;
+ } else {
+ $id = (int) $this->params['id'];
+ if (!empty($id)) {
+ $this->test = $this->suite->testAt($id - 1);
+ } else {
+ $this->test = null;
+ $this->koward->notification->push(_("You selected no test!"));
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+<?php
+/**
+ * @package Koward
+ */
+
+// @TODO Clean up
+require_once dirname(__FILE__) . '/ApplicationController.php';
+
+/**
+ * @package Koward
+ */
+class IndexController extends Koward_ApplicationController
+{
+ protected $welcome;
+
+ public function index()
+ {
+ $this->title = _("Index");
+ $this->welcome = _("Welcome to the Koward administration interface");
+ }
+}
\ No newline at end of file
--- /dev/null
+<?php
+/**
+ * @package Koward
+ */
+
+// @TODO Clean up
+require_once dirname(__FILE__) . '/ApplicationController.php';
+
+/**
+ * @package Koward
+ */
+class ObjectController extends Koward_ApplicationController
+{
+
+ public function listall()
+ {
+ require_once 'Horde/UI/Tabs.php';
+ require_once 'Horde/Variables.php';
+ require_once 'Horde/Util.php';
+
+ $this->object_type = $this->params->get('id', $this->types[0]);
+
+ if (isset($this->koward->objects[$this->object_type])) {
+ $this->attributes = $this->koward->objects[$this->object_type]['attributes'];
+ $params = array('attributes' => array_keys($this->attributes));
+ $this->objectlist = $this->koward->server->listHash($this->object_type,
+ $params);
+ foreach ($this->objectlist as $uid => $info) {
+ $this->objectlist[$uid]['edit_url'] = Horde::link(
+ $this->urlFor(array('controller' => 'object',
+ 'action' => 'edit',
+ 'id' => $uid)),
+ _("Edit")) . Horde::img('edit.png', _("Edit"), '',
+ $GLOBALS['registry']->getImageDir('horde'))
+ . '</a>';
+ $this->objectlist[$uid]['delete_url'] = Horde::link(
+ $this->urlFor(array('controller' => 'object',
+ 'action' => 'delete',
+ 'id' => $uid)),
+ _("Delete")) . Horde::img('delete.png', _("Delete"), '',
+ $GLOBALS['registry']->getImageDir('horde'))
+ . '</a>';
+ $this->objectlist[$uid]['view_url'] = Horde::link(
+ $this->urlFor(array('controller' => 'object',
+ 'action' => 'view',
+ 'id' => $uid)), _("View"));
+ }
+ } else {
+ $this->objectlist = 'Unkown object type.';
+ }
+ $this->tabs = new Horde_UI_Tabs(null, Variables::getDefaultVariables());
+ foreach ($this->koward->objects as $key => $configuration) {
+ $this->tabs->addTab($configuration['list_label'],
+ $this->urlFor(array('controller' => 'object',
+ 'action' => 'listall',
+ 'id' => $key)),
+ $key);
+ }
+
+ $this->render();
+ }
+
+ public function delete()
+ {
+ try {
+ if (empty($this->params->id)) {
+ $this->koward->notification->push(_("The object that should be deleted has not been specified."),
+ 'horde.error');
+ } else {
+ $this->object = $this->koward->getObject($this->params->id);
+ if (empty($this->params->submit)) {
+ $this->token = $this->koward->getRequestToken('object.delete');
+ } else {
+ $this->koward->checkRequestToken('object.delete', $this->params->token);
+ $this->object->delete();
+ $this->koward->notification->push(sprintf(_("Successfully deleted the object \"%s\""),
+ $this->params->id),
+ 'horde.message');
+ header('Location: ' . $this->urlFor(array('controller' => 'object',
+ 'action' => 'listall',
+ 'id' => get_class($this->object))));
+ exit;
+ }
+ }
+ } catch (Exception $e) {
+ $this->koward->notification->push($e->getMessage(), 'horde.error');
+ }
+
+ $this->render();
+ }
+
+ public function view()
+ {
+ try {
+ if (empty($this->params->id)) {
+ $this->koward->notification->push(_("The object that should be viewed has not been specified."),
+ 'horde.error');
+ } else {
+ $this->object = $this->koward->getObject($this->params->id);
+
+ require_once 'Horde/Variables.php';
+ $this->vars = Variables::getDefaultVariables();
+ $this->form = new Koward_Form_Object($this->vars, $this->object,
+ array('title' => _("View object")));
+ }
+ } catch (Exception $e) {
+ $this->koward->notification->push($e->getMessage(), 'horde.error');
+ }
+
+ $this->render();
+ }
+
+ public function edit()
+ {
+ try {
+ if (empty($this->params->id)) {
+ $this->object = null;
+ } else {
+ $this->object = $this->koward->getObject($this->params->id);
+ }
+
+ require_once 'Horde/Variables.php';
+ $this->vars = Variables::getDefaultVariables();
+ $this->form = new Koward_Form_Object($this->vars, $this->object);
+
+ if ($this->form->validate()) {
+ $object = $this->form->execute();
+
+ header('Location: ' . $this->urlFor(array('controller' => 'object',
+ 'action' => 'view',
+ 'id' => $object->get(Horde_Koward_Server_Object::ATTRIBUTE_UID))));
+ exit;
+ }
+ } catch (Exception $e) {
+ $this->koward->notification->push($e->getMessage(), 'horde.error');
+ }
+
+ $this->post = $this->urlFor(array('controller' => 'object',
+ 'action' => 'edit',
+ 'id' => $this->params->id));
+
+ $this->render();
+ }
+}
\ No newline at end of file
--- /dev/null
+<?= $this->renderPartial('header'); ?>
+<?= $this->renderPartial('menu'); ?>
+
+<?php
+if (!empty($this->test)) {
+ ob_start();
+ $listener = new Koward_Test_Renderer();
+ PHPUnit_TextUI_TestRunner::run($this->test, array('listeners' => array($listener)));
+ echo ob_get_clean();
+}
\ No newline at end of file
--- /dev/null
+<?= $this->renderPartial('header'); ?>
+<?= $this->renderPartial('menu'); ?>
+
+<?php
+
+foreach ($this->list as $test) {
+ echo $test;
+ echo '<br/>';
+}
\ No newline at end of file
--- /dev/null
+<?= $this->renderPartial('header'); ?>
+<?= $this->renderPartial('menu'); ?>
+
+<div class="contenttext">
+ <h1><?= $this->welcome ?></h1>
+</div>
--- /dev/null
+<?= $this->renderPartial('header'); ?>
+<?= $this->renderPartial('menu'); ?>
+
+<?php
+$this->form->renderActive(new Horde_Form_Renderer(), $vars, 'modify', 'post');
+
--- /dev/null
+<?= $this->renderPartial('header'); ?>
+<?= $this->renderPartial('menu'); ?>
--- /dev/null
+<?= $this->renderPartial('header'); ?>
+<?= $this->renderPartial('menu'); ?>
+<?= $this->form->renderActive(new Horde_Form_Renderer(), $this->vars,
+ $this->post, 'post'); ?>
\ No newline at end of file
--- /dev/null
+<?= $this->renderPartial('header'); ?>
+<?= $this->renderPartial('menu'); ?>
+
+<?= $this->tabs->render($this->object_type); ?>
+
+<table cellspacing="0" width="100%" class="linedRow">
+ <thead>
+ <tr>
+ <th class="item" width="1%"><?php echo Horde::img('edit.png', _("Edit"), '', $GLOBALS['registry']->getImageDir('horde')) ?></th>
+ <th class="item" width="1%"><?php echo Horde::img('delete.png', _("Delete"), '', $GLOBALS['registry']->getImageDir('horde')) ?></th>
+ <?php foreach ($this->attributes as $attribute => $info): ?>
+ <th class="item leftAlign" width="<?php echo $info['width'] ?>%" nowrap="nowrap"><?= $info['title'] ?></th>
+ <?php endforeach; ?>
+ </tr>
+ </thead>
+ <tbody>
+ <?php foreach ($this->objectlist as $dn => $info): ?>
+ <tr>
+ <td>
+ <?= $info['edit_url'] ?>
+ </td>
+ <td>
+ <?= $info['delete_url'] ?>
+ </td>
+ <?php foreach ($this->attributes as $attribute => $ainfo): ?>
+ <td>
+ <?php if (!empty($ainfo['link_view'])): ?>
+ <?= $info['view_url'] . $this->escape($info[$attribute]) . '</a>'; ?>
+ <?php else: ?>
+ <?= $this->escape($info[$attribute]) ?>
+ <?php endif; ?>
+ </td>
+ <?php endforeach; ?>
+ </tr>
+ <?php endforeach; ?>
+ </tbody>
+</table>
--- /dev/null
+<?= $this->renderPartial('header'); ?>
+<?= $this->renderPartial('menu'); ?>
+<?= $this->form->renderInactive(new Horde_Form_Renderer(), $this->vars); ?>
\ No newline at end of file
--- /dev/null
+<?php
+if (isset($language)) {
+ header('Content-type: text/html; charset=' . NLS::getCharset());
+ header('Vary: Accept-Language');
+}
+?>
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--
+Koward - The Kolab warden
+
+Copyright
+
+2004 - 2009 Klarälvdalens Datakonsult AB
+2009 The Horde Project
+
+Koward is under the GPL. GNU Public License: http://www.fsf.org/copyleft/gpl.html -->
+
+<?php echo !empty($language) ? '<html lang="' . strtr($language, '_', '-') . '">' : '<html>' ?>
+<head>
+<?php
+
+global $registry;
+
+$page_title = $registry->get('name');
+$page_title .= !empty($this->title) ? ' :: ' . $this->title : '';
+
+Horde::includeScriptFiles();
+?>
+<title><?php echo htmlspecialchars($page_title) ?></title>
+<link href="<?php echo $GLOBALS['registry']->getImageDir()?>/favicon.ico" rel="SHORTCUT ICON" />
+
+<?php echo Horde::stylesheetLink('koward', empty($this->print_view) ? $this->theme : 'print') ?>
+
+</head>
+
+<body>
--- /dev/null
+<div id="menu">
+ <?= $this->menu->render(); ?>
+</div>
+<?php $this->koward->notification->notify(array('listeners' => 'status')) ?>
+
--- /dev/null
+<?php
+
+define('AUTH_HANDLER', true);
+
+$options = array(
+ new Horde_Argv_Option('-n', '--not-defined', array('type' => 'int')),
+);
+$parser = new Horde_Argv_Parser(array('optionList' => $options));
+list($opts, $tags) = $parser->parseArgs();
+
+if (!$opts->not_defined) {
+ throw new InvalidArgumentException('');
+}
+
+exit(0);
--- /dev/null
+<?php
+
+$attributes['givenName'] = array(
+ 'label' => _("First Name"),
+ 'type' => 'text',
+ 'required' => true,
+ 'params' => array('regex' => '', 'size' => 40, 'maxlength' => 255)
+);
+$attributes['sn'] = array(
+ 'label' => _("Last Name"),
+ 'type' => 'text',
+ 'required' => true,
+ 'params' => array('regex' => '', 'size' => 40, 'maxlength' => 255)
+);
+$attributes['mail'] = array(
+ 'label' => _("Mail address"),
+ 'type' => 'text',
+ 'required' => true,
+ 'params' => array('regex' => '', 'size' => 40, 'maxlength' => 255)
+);
+$attributes['uid'] = array(
+ 'label' => _("User ID"),
+ 'type' => 'text',
+ 'required' => true,
+ 'params' => array('regex' => '', 'size' => 40, 'maxlength' => 255)
+);
--- /dev/null
+<?php
+
+$conf['koward']['theme'] = 'silver';
--- /dev/null
+<?php
+
+$objects['Horde_Kolab_Server_Object'] = array(
+ 'label' => _("Object"),
+ 'list_label' => _("Objects"),
+ 'attributes' => array(
+ 'id' => array(
+ 'title' => _("Object id"),
+ 'width' => 80,
+ 'link_view'=> true,
+ ),
+ ),
+);
+
+$objects['Horde_Kolab_Server_Object_user'] = array(
+ 'label' => _("User"),
+ 'list_label' => _("Users"),
+ 'attributes' => array(
+ 'sn' => array(
+ 'title' => _("Last name"),
+ 'width' => 20,
+ ),
+ 'givenName' => array(
+ 'title' => _("First name"),
+ 'width' => 20,
+ ),
+ 'mail' => array(
+ 'title' => _("E-mail"),
+ 'width' => 20,
+ 'link_view'=> true,
+ ),
+ 'uid' => array(
+ 'title' => _("User ID"),
+ 'width' => 20,
+ ),
+ ),
+);
+
+$objects['Horde_Kolab_Server_Object_administrator'] = array(
+ 'label' => _("Administrator"),
+ 'list_label' => _("Administrators"),
+ 'attributes' => array(
+ ),
+);
--- /dev/null
+<?php
+
+$mapper->connect('index', array('controller' => 'index'));
+$mapper->connect('index.php', array('controller' => 'index'));
+
+$mapper->connect('check/:action/:id', array('controller' => 'check', 'action' => 'show'));
+$mapper->connect(':controller/:action/:id', array('controller' => 'object'));
+
+// Local route overrides
+if (file_exists(dirname(__FILE__) . '/routes.local.php')) {
+ include dirname(__FILE__) . '/routes.local.php';
+}
--- /dev/null
+Can we have mixed CLI and html views? If we can, will these be in a library install location?
+
+How to add translations?
+
+How to install via PEAR?
--- /dev/null
+<?php
+/**
+ * An application for managing a Kolab server.
+ *
+ * PHP version 5
+ *
+ * @category Kolab
+ * @package Koward_Server
+ * @author Gunnar Wrobel <wrobel@pardus.de>
+ * @license http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @link http://pear.horde.org/index.php?package=Koward_Server
+ */
+
+/**
+ * This class provides the standard error class for the Koward application.
+ *
+ * Copyright 2009 The Horde Project (http://www.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.
+ *
+ * @category Kolab
+ * @package Koward_Server
+ * @author Gunnar Wrobel <wrobel@pardus.de>
+ * @license http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @link http://pear.horde.org/index.php?package=Koward_Server
+ */
+class Koward_Exception extends Exception
+{
+}
--- /dev/null
+<?php
+/**
+ * @package Koward
+ */
+
+/**
+ * @package Koward
+ */
+class Koward_Form_Object extends Horde_Form {
+
+ /**
+ * The link to the application driver.
+ *
+ * @var Koward_Koward
+ */
+ protected $koward;
+
+ public function __construct(&$vars, &$object, $params = array())
+ {
+ $this->koward = &Koward_Koward::singleton();
+
+ $this->object = &$object;
+
+ parent::Horde_Form($vars);
+
+ if (empty($this->object)) {
+ $title = _("Add Object");
+ $this->setButtons(_("Add"));
+
+ foreach ($this->koward->objects as $key => $config) {
+ $options[$key] = $config['label'];
+ }
+
+ $v = &$this->addVariable(_("Choose an object type"), 'type', 'enum', true, false, null, array($options, true));
+ $action = Horde_Form_Action::factory('submit');
+ $v->setAction($action);
+ $v->setOption('trackchange', true);
+ if (is_null($vars->get('formname')) &&
+ $vars->get($v->getVarName()) != $vars->get('__old_' . $v->getVarName())) {
+ $this->koward->notification->push(sprintf(_("Selected object type \"%s\"."), $object_conf[$vars->get('type')]['label']), 'horde.message');
+ }
+ } else {
+ $title = _("Edit Object");
+ $type = get_class($this->object);
+ if (!$this->isSubmitted()) {
+ $vars->set('type', $type);
+ $keys = array_keys($this->koward->objects[$type]['attributes']);
+ $vars->set('object', $this->object->toHash($keys));
+ $this->setButtons(_("Edit"));
+ }
+ }
+
+ if (isset($params['title'])) {
+ $title = $params['title'];
+ }
+
+ $this->setTitle($title);
+
+ $type = $vars->get('type');
+ if (isset($type)) {
+ $this->_addFields($this->koward->objects[$type]);
+ }
+ }
+
+ /**
+ * Set up the Horde_Form fields for the attributes of this object type.
+ */
+ function _addFields($config)
+ {
+ // Now run through and add the form variables.
+ $fields = isset($config['attributes']) ? $config['attributes'] : array();
+ $tabs = isset($config['tabs']) ? $config['tabs'] : array('' => $fields);
+
+ foreach ($tabs as $tab => $tab_fields) {
+ if (!empty($tab)) {
+ $this->setSection($tab, $tab);
+ }
+ foreach ($tab_fields as $key => $field) {
+ if (!in_array($key, array_keys($fields)) ||
+ !isset($this->koward->attributes[$key])) {
+ continue;
+ }
+
+ $attribute = $this->koward->attributes[$key];
+ $params = isset($attribute['params']) ? $attribute['params'] : array();
+ $desc = isset($attribute['desc']) ? $attribute['desc'] : null;
+
+ $readonly = isset($attribute['readonly']) ? $attribute['readonly'] : null;
+ $v = &$this->addVariable($attribute['label'], 'object[' . $key . ']', $attribute['type'], $attribute['required'], $readonly, $desc, $params);
+ }
+
+ if (isset($attribute['default'])) {
+ $v->setDefault($attribute['default']);
+ }
+ }
+ }
+
+ function &execute()
+ {
+ $this->getInfo($this->_vars, $info);
+ if (isset($info['object'])) {
+ if (empty($this->object)) {
+ if (isset($info['type'])) {
+ $object = $this->koward->server->add(array_merge(array('type' => $info['type']),
+ $info['object']));
+ $this->koward->notification->push(_("Successfully added the object."),
+ 'horde.message');
+ return $object;
+ }
+ } else {
+ $this->object->save($info['object']);
+ $this->koward->notification->push(_("Successfully updated the object."),
+ 'horde.message');
+ return $this->object;
+ }
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * Copyright 2009 The Horde Project (http://www.horde.org/)
+ *
+ * @author Gunnar Wrobel <p@rdus.de>
+ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
+ * @category Kolab
+ * @package Koward
+ */
+
+class Koward_Koward {
+
+ /**
+ * The singleton instance.
+ *
+ * @var Koward_Koward
+ */
+ static protected $instance = null;
+
+ public $objectconf;
+
+ public function __construct()
+ {
+ require_once 'Horde/Notification.php';
+ require_once 'Horde/Registry.php';
+
+ $this->notification = Notification::singleton();
+ $this->registry = Registry::singleton();
+
+ $result = $this->registry->pushApp('koward', false);
+ if ($result instanceOf PEAR_Error) {
+ $this->notification->push($result);
+ }
+
+ $this->conf = Horde::loadConfiguration('conf.php', 'conf');
+ $this->objects = Horde::loadConfiguration('objects.php', 'objects');
+ $this->attributes = Horde::loadConfiguration('attributes.php', 'attributes');
+ $this->server = Horde_Kolab_Server::singleton();
+ }
+
+ /**
+ * Get a token for protecting a form.
+ *
+ * @param string $seed TODO
+ *
+ * @return TODO
+ */
+ static public function getRequestToken($seed)
+ {
+ $token = Horde_Token::generateId($seed);
+ $_SESSION['horde_form_secrets'][$token] = time();
+ return $token;
+ }
+
+ /**
+ * Check if a token for a form is valid.
+ *
+ * @param string $seed TODO
+ * @param string $token TODO
+ *
+ * @throws Horde_Exception
+ */
+ static public function checkRequestToken($seed, $token)
+ {
+ if (empty($_SESSION['horde_form_secrets'][$token])) {
+ throw new Horde_Exception(_("We cannot verify that this request was really sent by you. It could be a malicious request. If you intended to perform this action, you can retry it now."));
+ }
+
+ if ($_SESSION['horde_form_secrets'][$token] + $GLOBALS['conf']['server']['token_lifetime'] < time()) {
+ throw new Horde_Exception(sprintf(_("This request cannot be completed because the link you followed or the form you submitted was only valid for %d minutes. Please try again now."), round($GLOBALS['conf']['server']['token_lifetime'] / 60)));
+ }
+ }
+
+ public function getObject($uid)
+ {
+ return $this->server->fetch($uid);
+ }
+
+ static public function singleton()
+ {
+ if (!isset(self::$instance)) {
+ self::$instance = new Koward_Koward();
+ }
+
+ return self::$instance;
+ }
+}
\ No newline at end of file
--- /dev/null
+<?php
+/**
+ * Base for PHPUnit scenarios.
+ *
+ * PHP version 5
+ *
+ * @category Kolab
+ * @package Koward
+ * @author Gunnar Wrobel <wrobel@pardus.de>
+ * @license http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @link http://pear.horde.org/index.php?package=Koward
+ */
+
+/**
+ * Base for PHPUnit scenarios.
+ *
+ * Copyright 2009 The Horde Project (http://www.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.
+ *
+ * @category Kolab
+ * @package Koward
+ * @author Gunnar Wrobel <wrobel@pardus.de>
+ * @license http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @link http://pear.horde.org/index.php?package=Koward
+ */
+class Koward_Test extends Horde_Kolab_Test_Storage
+{
+ /**
+ * Prepare the configuration.
+ *
+ * @return NULL
+ */
+ public function prepareConfiguration()
+ {
+ $fh = fopen(HORDE_BASE . '/config/conf.php', 'w');
+ $data = <<<EOD
+\$conf['use_ssl'] = 2;
+\$conf['server']['name'] = \$_SERVER['SERVER_NAME'];
+\$conf['server']['port'] = \$_SERVER['SERVER_PORT'];
+\$conf['debug_level'] = E_ALL;
+\$conf['umask'] = 077;
+\$conf['compress_pages'] = true;
+\$conf['menu']['always'] = false;
+\$conf['portal']['fixed_blocks'] = array();
+\$conf['imsp']['enabled'] = false;
+
+/** Additional config variables required for a clean Horde setup */
+\$conf['session']['use_only_cookies'] = false;
+\$conf['session']['timeout'] = 0;
+\$conf['cookie']['path'] = '/';
+\$conf['cookie']['domain'] = \$_SERVER['SERVER_NAME'];
+\$conf['use_ssl'] = false;
+\$conf['session']['cache_limiter'] = 'nocache';
+\$conf['session']['name'] = 'Horde';
+\$conf['log']['enabled'] = false;
+\$conf['prefs']['driver'] = 'session';
+\$conf['auth']['driver'] = 'kolab';
+\$conf['share']['driver'] = 'kolab';
+\$conf['server']['token_lifetime'] = 3600;
+\$conf['debug_level'] = E_ALL;
+
+/** Make the share driver happy */
+\$conf['kolab']['enabled'] = true;
+
+/** Ensure we still use the LDAP test driver */
+\$conf['kolab']['server']['driver'] = 'test';
+
+/** Ensure that we do not trigger on folder update */
+\$conf['kolab']['no_triggering'] = true;
+
+/** Storage location for the free/busy system */
+\$conf['fb']['cache_dir'] = '/tmp';
+\$conf['kolab']['freebusy']['server'] = 'https://fb.example.org/freebusy';
+
+/** Setup the virtual file system for Kolab */
+\$conf['vfs']['params']['all_folders'] = true;
+\$conf['vfs']['type'] = 'kolab';
+
+\$conf['kolab']['ldap']['phpdn'] = null;
+\$conf['fb']['use_acls'] = true;
+EOD;
+ fwrite($fh, "<?php\n" . $data);
+ fclose($fh);
+ }
+
+ /**
+ * Prepare the registry.
+ *
+ * @return NULL
+ */
+ public function prepareRegistry()
+ {
+ $fh = fopen(HORDE_BASE . '/config/registry.php', 'w');
+ $data = <<<EOD
+\$this->applications['horde'] = array(
+ 'fileroot' => dirname(__FILE__) . '/..',
+ 'webroot' => '/',
+ 'initial_page' => 'login.php',
+ 'name' => _("Horde"),
+ 'status' => 'active',
+ 'templates' => dirname(__FILE__) . '/../templates',
+ 'provides' => 'horde',
+);
+
+\$this->applications['koward'] = array(
+ 'fileroot' => KOWARD_BASE,
+ 'webroot' => \$this->applications['horde']['webroot'] . '/koward',
+ 'name' => _("Koward"),
+ 'status' => 'active',
+ 'initial_page' => 'index.php',
+);
+EOD;
+ fwrite($fh, "<?php\n" . $data);
+ fclose($fh);
+ if (!file_exists(HORDE_BASE . '/config/registry.d')) {
+ mkdir(HORDE_BASE . '/config/registry.d');
+ }
+ }
+
+ /**
+ * Handle a "given" step.
+ *
+ * @param array &$world Joined "world" of variables.
+ * @param string $action The description of the step.
+ * @param array $arguments Additional arguments to the step.
+ *
+ * @return mixed The outcome of the step.
+ */
+ public function runGiven(&$world, $action, $arguments)
+ {
+ switch($action) {
+ default:
+ return parent::runGiven($world, $action, $arguments);
+ }
+ }
+
+ /**
+ * Handle a "when" step.
+ *
+ * @param array &$world Joined "world" of variables.
+ * @param string $action The description of the step.
+ * @param array $arguments Additional arguments to the step.
+ *
+ * @return mixed The outcome of the step.
+ */
+ public function runWhen(&$world, $action, $arguments)
+ {
+ switch($action) {
+ default:
+ return parent::runWhen($world, $action, $arguments);
+ }
+ }
+
+ /**
+ * Handle a "then" step.
+ *
+ * @param array &$world Joined "world" of variables.
+ * @param string $action The description of the step.
+ * @param array $arguments Additional arguments to the step.
+ *
+ * @return mixed The outcome of the step.
+ */
+ public function runThen(&$world, $action, $arguments)
+ {
+ switch($action) {
+ default:
+ return parent::runThen($world, $action, $arguments);
+ }
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * All server tests for the Kolab server.
+ *
+ * PHP version 5
+ *
+ * @category Kolab
+ * @package Koward
+ * @author Gunnar Wrobel <wrobel@pardus.de>
+ * @license http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @link http://pear.horde.org/index.php?package=Kolab_Server
+ */
+
+/**
+ * The Autoloader allows us to omit "require/include" statements.
+ */
+require_once 'Horde/Autoloader.php';
+
+/**
+ * Combine the tests for this package.
+ *
+ * Copyright 2007-2009 The Horde Project (http://www.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.
+ *
+ * @category Kolab
+ * @package Kolab_Server
+ * @author Gunnar Wrobel <wrobel@pardus.de>
+ * @license http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @link http://pear.horde.org/index.php?package=Kolab_Server
+ */
+class Koward_Test_AllTests
+{
+
+ /**
+ * Main entry point for running the suite.
+ *
+ * @return NULL
+ */
+ public static function main()
+ {
+ PHPUnit_TextUI_TestRunner::run(self::suite());
+ }
+
+ /**
+ * Collect the unit tests of this directory into a new suite.
+ *
+ * @return PHPUnit_Framework_TestSuite The test suite.
+ */
+ public static function suite()
+ {
+ // Catch strict standards
+ // FIXME: This does not work yet, as we still have a number of
+ // static methods in basic Horde libraries that are not
+ // declared as such.
+ //error_reporting(E_ALL | E_STRICT);
+
+ $suite = new PHPUnit_Framework_TestSuite('Kolab server test suite');
+
+ $basedir = dirname(__FILE__);
+ $baseregexp = preg_quote($basedir . DIRECTORY_SEPARATOR, '/');
+
+ foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($basedir)) as $file) {
+ if ($file->isFile() && preg_match('/Test.php$/', $file->getFilename())) {
+ $pathname = $file->getPathname();
+ require $pathname;
+
+ $class = str_replace(DIRECTORY_SEPARATOR, '_',
+ preg_replace("/^$baseregexp(.*)\.php/", '\\1', $pathname));
+ $suite->addTestSuite('Koward_Test_' . $class);
+ }
+ }
+
+ return $suite;
+ }
+
+}
--- /dev/null
+<?php
+
+class Koward_Test_Renderer extends PHPUnit_Extensions_Story_ResultPrinter_HTML
+{
+ /**
+ * Constructor.
+ *
+ * @param mixed $out
+ * @throws InvalidArgumentException
+ */
+ public function __construct($out = NULL)
+ {
+ parent::__construct($out);
+
+ $this->templatePath = sprintf(
+ '%s%sTemplate%s',
+
+ dirname(__FILE__),
+ DIRECTORY_SEPARATOR,
+ DIRECTORY_SEPARATOR
+ );
+ }
+
+ /**
+ * @param string $buffer
+ */
+ public function write($buffer)
+ {
+ if ($this->out !== NULL) {
+ fwrite($this->out, $buffer);
+
+ if ($this->autoFlush) {
+ $this->incrementalFlush();
+ }
+ } else {
+
+ print $buffer;
+
+ if ($this->autoFlush) {
+ $this->incrementalFlush();
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+<?php
+/**
+ * Test the user object.
+ *
+ * PHP version 5
+ *
+ * @category Kolab
+ * @package Koward
+ * @author Gunnar Wrobel <wrobel@pardus.de>
+ * @license http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @link http://pear.horde.org/index.php?package=Koward
+ */
+
+/**
+ * Test the user object.
+ *
+ * Copyright 2009 The Horde Project (http://www.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.
+ *
+ * @category Kolab
+ * @package Koward
+ * @author Gunnar Wrobel <wrobel@pardus.de>
+ * @license http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @link http://pear.horde.org/index.php?package=Koward
+ */
+class Koward_Test_Server_UserTest extends Horde_Kolab_Test_Server {
+
+ /**
+ * Test listing users if there are no users.
+ *
+ * @scenario
+ *
+ * @return NULL
+ */
+ public function listingUsersOnEmptyServer()
+ {
+ $this->given('the current Kolab server')
+ ->when('listing all users')
+ ->then('the list is an empty array');
+ }
+}
--- /dev/null
+ <tr>
+ <td>
+ <p class="{scenarioStatus}" onclick="showHide('{id}', this)">[+] {name}</p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <table border="0" width="100%" class="{scenarioStatus} scenarioStepsTable" id="stepContainer{id}">
+{steps}
+ </table>
+ </td>
+ </tr>
+
--- /dev/null
+ <tr>
+ <td>
+ <p class="header">{name}</p>
+ </td>
+ </tr>
+
--- /dev/null
+ <style type ="text/css">
+ .scenarioSuccess { color: green; }
+ .scenario { color: black; }
+ .scenarioFailed { color: red; }
+ .scenarioSkipped { color: teal; }
+ .scenarioIncomplete { color: gray; }
+ .scenarioStepsTable { margin-left: 10px; display: none; }
+ .stepName { }
+ </style>
+
+ <script type="text/javascript">
+ function showHide(nodeId, linkObj)
+ {
+ var subObj = document.getElementById('stepContainer' + nodeId);
+
+ if (linkObj.innerHTML.indexOf('+')>0) {
+ linkObj.innerHTML = linkObj.innerHTML.replace('+','-');
+ subObj.style.display='block';
+ subObj.style.width = '100%';
+ } else {
+ linkObj.innerHTML = linkObj.innerHTML.replace('-','+');
+ subObj.style.display='none';
+ }
+ }
+ </script>
+
+ <table border="0" width="100%" style="margin: 20 px">
+{scenarios}
+ <tr>
+ <td>
+ <p style="margin-top: 20px;" id="Summary" onclick="showHide('Summary', this)">[+] Summary:</p>
+ <div style="margin-left: 10px; display:none" id="stepContainerSummary">
+ <table border="0">
+ <tr>
+ <td width="250" class="scenarioSuccess">Successful scenarios:</td>
+ <td class="scenarioSuccessValue">{successfulScenarios}</td>
+ </tr>
+ <tr>
+ <td class="scenarioFailed">Failed scenarios:</td>
+ <td class="scenarioFailedValue">{failedScenarios}</td>
+ </tr>
+ <tr>
+ <td class="scenarioSkipped">Skipped scenarios:</td>
+ <td class="scenarioSkippedValue">{skippedScenarios}</td>
+ </tr>
+ <tr>
+ <td class="scenarioIncomplete">Incomplete scenarios:</td>
+ <td class="scenarioIncompleteValue">{incompleteScenarios}</td>
+ </tr>
+ </table>
+ </div>
+ </td>
+ </tr>
+ </table>
--- /dev/null
+ <tr>
+ <td width="60">{text}</td>
+ <td class="stepName">{action}</td>
+ <td> </td>
+ </tr>
+
--- /dev/null
+<?php
+/**
+ * All tests for the Koward application.
+ *
+ * PHP version 5
+ *
+ * @category Kolab
+ * @package Koward
+ * @author Gunnar Wrobel <wrobel@pardus.de>
+ * @license http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @link http://pear.horde.org/index.php?package=Koward
+ */
+
+if (!defined('PHPUnit_MAIN_METHOD')) {
+ define('PHPUnit_MAIN_METHOD', 'Koward_AllTests::main');
+}
+
+/**
+ * Initialize testing for this application.
+ */
+require_once 'TestInit.php';
+
+/**
+ * Combine the tests for this package.
+ *
+ * Copyright 2007-2009 The Horde Project (http://www.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.
+ *
+ * @category Kolab
+ * @package Koward
+ * @author Gunnar Wrobel <wrobel@pardus.de>
+ * @license http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @link http://pear.horde.org/index.php?package=Koward
+ */
+class Koward_AllTests
+{
+ /**
+ * Main entry point for running the suite.
+ *
+ * @return NULL
+ */
+ public static function main()
+ {
+ PHPUnit_TextUI_TestRunner::run(self::suite());
+ }
+
+ /**
+ * Collect the unit tests of this directory into a new suite.
+ *
+ * @return PHPUnit_Framework_TestSuite The test suite.
+ */
+ public static function suite()
+ {
+ // Catch strict standards
+ error_reporting(E_ALL | E_STRICT);
+
+ // Build the suite
+ $suite = new PHPUnit_Framework_TestSuite('Koward');
+
+ $basedir = dirname(__FILE__);
+ $baseregexp = preg_quote($basedir . DIRECTORY_SEPARATOR, '/');
+
+ foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($basedir)) as $file) {
+ if ($file->isFile() && preg_match('/Test.php$/', $file->getFilename())) {
+ $pathname = $file->getPathname();
+ require $pathname;
+
+ $class = str_replace(DIRECTORY_SEPARATOR, '_',
+ preg_replace("/^$baseregexp(.*)\.php/", '\\1', $pathname));
+ $suite->addTestSuite('Koward_' . $class);
+ }
+ }
+
+ return $suite;
+ }
+
+}
+
+if (PHPUnit_MAIN_METHOD == 'Koward_AllTests::main') {
+ Koward_AllTests::main();
+}
--- /dev/null
+<?php
+/**
+ * Test the user object.
+ *
+ * PHP version 5
+ *
+ * @category Kolab
+ * @package Koward
+ * @author Gunnar Wrobel <wrobel@pardus.de>
+ * @license http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @link http://pear.horde.org/index.php?package=Koward
+ */
+
+/**
+ * Initialize testing for this application.
+ */
+require_once 'TestInit.php';
+
+/**
+ * Test the user object.
+ *
+ * Copyright 2009 The Horde Project (http://www.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.
+ *
+ * @category Kolab
+ * @package Koward
+ * @author Gunnar Wrobel <wrobel@pardus.de>
+ * @license http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @link http://pear.horde.org/index.php?package=Koward
+ */
+class Koward_KowardTest extends Koward_Test
+{
+ /**
+ * Set up testing.
+ *
+ * @return NULL
+ */
+ protected function setUp()
+ {
+ $world = $this->prepareBasicSetup();
+
+ $this->koward = Koward_Koward::singleton();
+ }
+
+ /**
+ * Verify that the Koward object ist initialized correctly.
+ *
+ * @return NULL
+ */
+ public function testSetup()
+ {
+ $this->assertType('Horde_Kolab_Server', $this->koward->server);
+ }
+
+ /**
+ * Verify that we can fetch objects from the Kolab server.
+ *
+ * @return NULL
+ */
+ public function testFetching()
+ {
+ $this->assertType('Horde_Kolab_Server_Object', $this->koward->getObject('cn=Gunnar Wrobel,dc=example,dc=org'));
+ }
+
+ /**
+ * Verify token processing mechanisms.
+ *
+ * @return NULL
+ */
+ public function testToken()
+ {
+ // Get the token.
+ $token = $this->koward->getRequestToken('test');
+ // Checking it should be fine.
+ $this->koward->checkRequestToken('test', $token);
+ // Now we set the token to a value that will be considered a timeout.
+ $_SESSION['horde_form_secrets'][$token] = time() - 100000;
+ try {
+ $this->koward->checkRequestToken('test', $token);
+ $this->fail('The rquest token is still valid which was not expected.');
+ } catch (Horde_Exception $e) {
+ $this->assertContains(_("This request cannot be completed because the link you followed or the form you submitted was only valid for"), $e->getMessage());
+ }
+ // Now we remove the token
+ unset($_SESSION['horde_form_secrets'][$token]);
+ try {
+ $this->koward->checkRequestToken('test', $token);
+ $this->fail('The rquest token is still valid which was not expected.');
+ } catch (Horde_Exception $e) {
+ $this->assertEquals(_("We cannot verify that this request was really sent by you. It could be a malicious request. If you intended to perform this action, you can retry it now."), $e->getMessage());
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * Initialize testing for this application.
+ *
+ * PHP version 5
+ *
+ * @category Kolab
+ * @package Koward
+ * @author Gunnar Wrobel <wrobel@pardus.de>
+ * @license http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @link http://pear.horde.org/index.php?package=Koward
+ */
+
+/**
+ * The Autoloader allows us to omit "require/include" statements.
+ */
+require_once 'Horde/Autoloader.php';
+
+if (!defined('KOWARD_BASE')) {
+ define('KOWARD_BASE', dirname(__FILE__) . '/../');
+}
+
+/* Set up the application class and controller loading */
+Horde_Autoloader::addClassPattern('/^Koward_/', KOWARD_BASE . '/lib/');
+Horde_Autoloader::addClassPattern('/^Koward_/', KOWARD_BASE . '/app/controllers/');
--- /dev/null
+/*
+ Local variables:
+ buffer-file-coding-system: utf-8
+ End:
+*/
+body {
+ color: black;
+ background-color: #F8FCF8;
+ font-family: verdana,arial,helvetica,sans-serif;
+ font-size: 95%;
+ border: 0;
+ margin: 0;
+}
+a, a:visited {
+ font-family: verdana,arial,helvetica,sans-serif;
+}
+
+a { color: #001155; }
+a:hover { color: #113399; }
+
+#page {
+ background-repeat: no-repeat;
+ background-position: top right;
+}
+
+#topbar {
+ display:block;
+ background-color: #B0BCD0;
+ height: 70px;
+ clear: both;
+}
+#toplogo {
+ display:block;
+ background-image: url(pics/kolab_logo.png);
+ background-color: #B0BCD0;
+ width: 245px;
+ height: 70px;
+ margin-left: 1em;
+ margin-top: 0.4em;
+ float: left;
+}
+#toptitle {
+ display:block;
+ text-align: right;
+ font-size: 200%;
+ padding-right: 1em;
+ padding-top: 0.5em;
+}
+#topuserinfo {
+ display:block;
+ background-color: #B0BCD0;
+ font-size: 80%;
+ padding: 0.1em;
+ border-bottom: solid 1px black;
+ text-align: right;
+}
+#topmenu {
+ background-color: #B0BCD0;
+ font-size: 90%;
+ border-bottom: solid 1px black;
+}
+#submenu {
+ background-color: #EEEEEE;
+ border-bottom: solid 1px black;
+ font-size: 90%;
+}
+
+.topmenuitem {
+ background-color: #B0BCD0;
+ border-right: solid 1px black;
+ padding-left: 0.5em;
+ padding-right: 0.5em;
+ margin: 0px;
+}
+.topmenuitemselected {
+ background-color: #EEEEEE;
+ border-right: solid 1px black;
+ padding-left: 0.5em;
+ padding-right: 0.5em;
+ margin: 0px;
+ border-bottom: solid 1px #EEEEEE;
+}
+.submenuitem {
+}
+.submenuitemselected {
+}
+.alphagroupitem {
+}
+.alphagroupitemselected {
+ font-weight:bold
+}
+#logout {
+ color: red;
+}
+#maintitle {
+ font-size: 200%;
+}
+#maincontent {
+ display:block;
+ padding: 1em;
+ margin: 1em;
+}
+#errorcontent {
+ display:block;
+ padding: 0.2em;
+ margin: 1em;
+ text-align: left;
+ color: red;
+ background-color: #EEEEEE;
+ border: solid 1px black;
+}
+#errorheader {
+ display:block;
+ text-align: left;
+ color: black;
+ background-color: #EEEEEE;
+ font-size: 150%;
+}
+#messagecontent {
+ display:block;
+ padding: 0.2em;
+ margin: 1em;
+ text-align: left;
+ color: green;
+ background-color: #EEEEEE;
+ border: solid 1px black;
+}
+#messageheader {
+ display:block;
+ text-align: left;
+ color: black;
+ background-color: #EEEEEE;
+ font-size: 150%;
+}
+.contenttext {
+ margin: 10px;
+}
+.contenttable {
+ width: 100%;
+ background-color: black;
+ border: 0px;
+}
+.contentroweven {
+ background-color: #C0CDE0;
+ margin: 0px;
+}
+.contentrowodd {
+ background-color: #D0DDF0;
+ margin: 0px;
+}
+.contentcell {
+ font-size: 90%;
+ padding: .1em .5em .1em .5em;
+ margin: 0px;
+/* text-align: center; */
+}
+.actioncell {
+ font-size: 90%;
+ padding: .1em .5em .1em .5em;
+ width: 10%;
+ margin: 0px;
+ text-align: center;
+}
+.contentform {
+ /*float: left;*/
+ padding: .1em .5em .1em .5em;
+ background-color: #EEEEEE;
+ border: solid 1px black;
+}
+.contentformtable {
+ font-size: 90%;
+}
+.langcombo {
+ font-size: 80%;
+}
+
+#validators {
+ text-align: right;
+}
+
+th {
+ background-color: #EEEEEE;
+ border: 0px;
+}
+
+.ctrl {
+ background-color: #E0E3E0;
+ border: solid 1px black;
+ padding: .2em .5em .2em .5em;
+}
+
+.required_asterisk {
+ color: red;
+ font-size: 80%;
+ text-align: right;
+}
+
+label {
+ cursor: pointer;
+}
+
+.align_center {
+ text-align: center;
+}
+
+.align_right {
+ text-align: right;
+}
+
+.align_left {
+ text-align: left;
+}