--- /dev/null
+<?php
+/**
+ * Delete records
+ *
+ * Copyright 2006-2008 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file LICENSE for license information (BSD). If you
+ * did not receive this file, see http://cvs.horde.org/co.php/merk/LICENSE.
+ *
+ * $Horde: beatnik/autogenerate.php,v 1.16 2009/07/14 00:25:28 mrubinsk Exp $
+ *
+ * @author Duck <duck@obala.net>
+ */
+
+define('BEATNIK_BASE', dirname(__FILE__));
+require_once BEATNIK_BASE . '/lib/base.php';
+require_once BEATNIK_BASE . '/lib/Forms/Autogenerate.php';
+
+$viewurl = Horde::applicationUrl('viewzone.php');
+
+$vars = Horde_Variables::getDefaultVariables();
+$form = new Autogenerate($vars);
+
+if ($form->validate($vars)) {
+ if (Horde_Util::getFormData('submitbutton') == _("Autogenerate")) {
+ $result = Beatnik::autogenerate($vars);
+ if (is_a($result, 'PEAR_Error')) {
+ $notification->push($zonedata, 'horde.error');
+ header('Location:' . Horde::applicationUrl('listzones.php'));
+ exit;
+ }
+ } else {
+ $notification->push(_("Autogeneration not performed"), 'horde.warning');
+ }
+
+ header('Location: ' . $viewurl);
+ exit;
+}
+
+$title = _("Autogenerate");
+require BEATNIK_BASE . '/templates/common-header.inc';
+require BEATNIK_BASE . '/templates/menu.inc';
+
+$form->renderActive(null, null, Horde::applicationUrl('autogenerate.php'), 'post');
+
+require $registry->get('templates', 'horde') . '/common-footer.inc';
--- /dev/null
+<?php
+/**
+ * $Horde: beatnik/commit.php,v 1.11 2009/07/03 10:05:29 duck Exp $
+ *
+ * Copyright 2006-2007 Ben Klang <ben@alkaloid.net>
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ */
+
+define('BEATNIK_BASE', dirname(__FILE__));
+require_once BEATNIK_BASE . '/lib/base.php';
+require_once BEATNIK_BASE . '/lib/Forms/EditRecord.php';
+
+$domains = array();
+if (Horde_Util::getGet('domain') == 'current') {
+ $url = Horde::applicationUrl('viewzone.php');
+ $domains[] = $_SESSION['beatnik']['curdomain'];
+} elseif (Horde_Util::getGet('domain') == 'all') {
+ $url = Horde::applicationUrl('listzones.php');
+ foreach (Beatnik::needCommit() as $domain) {
+ $domains[] = $beatnik_driver->getDomain($domain);
+ }
+}
+
+foreach ($domains as $domain) {
+ $_SESSION['beatnik']['curdomain'] = $domain;
+ $vars = new Horde_Variables;
+
+ $vars->set('rectype', 'soa');
+ foreach ($domain as $field => $value) {
+ $vars->set($field, $value);
+ }
+ $vars->set('serial', Beatnik::incrementSerial($domain['serial']));
+
+ $form = new EditRecord($vars);
+ $form->useToken(false);
+ $form->setSubmitted(true);
+ if ($form->validate($vars)) {
+ $form->getInfo($vars, $info);
+ $result = $beatnik_driver->saveRecord($info);
+
+ if (is_a($result, 'PEAR_Error')) {
+ $notification->push($result->getMessage() . ': ' . $result->getDebugInfo(), 'horde.error');
+ } else {
+ $notification->push(sprintf(_('Zone serial for %s incremented.'), $domain['zonename']), 'horde.success');
+ }
+ } else {
+ $notification->push(sprintf(_("Unable to construct valid SOA for %s. Not incrementing serial."), $domain['zonename']), 'horde.error');
+ }
+}
+
+header('Location: ' . $url);
+exit;
--- /dev/null
+autogenerate.php
+conf.php
+conf.bak.php
+prefs.php
--- /dev/null
+<?php
+/**
+ * Autogenerate template
+ *
+ * $Horde: beatnik/config/autogenerate.php.dist,v 1.5 2007/06/27 17:23:28 jan Exp $
+ *
+ * Copyright 2006-2007 Duck <duck@obala.net>
+ *
+ * NOTE: Template is an multidimensional array.
+ * The first level key define record types
+ * For each type you can specify the replacement behavior and how
+ * autogenerate will treat old records. 'all' deletes all records
+ * of the same type, 'match' deletes those which have the same hostname,
+ * and 'none' simply adds more records leaving everything existing in
+ * place.
+ * The 'records' element is an array of arrays of Beatnick::getRecFields()
+ * key => value pairs.
+ *
+ * EXAMPLE:
+ *
+ * $template['cname'][] = array('hostname' => 'www',
+ * 'pointer' => 'server1',
+ * 'ttl' => 3600);
+ * $template['mx'][] = array('pointer' => 'server2',
+ * 'pref' => 10);
+ *
+ * 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 Duck <duck@obala.net>
+ * @package Beatnik
+ */
+$templates['example'] = array(
+ 'description' => _("Example Template"),
+ 'types' => array(
+
+ // Example 'NS' records
+ 'ns' => array(
+ 'replace' => 'all', // Set to 'all' to remove all pre-existing
+ // NS records
+
+ 'records' => array( // Array of records to be created
+ array('hostname' => 'ns1', 'pointer' => '10.0.0.1' ),
+ array('hostname' => 'ns2', 'pointer' => '10.0.0.2' ),
+ ),
+ ),
+
+ // Example 'MX' record
+ 'mx' => array(
+ 'replace' => 'none', // Set to 'none' to leave all existing
+ // MX records alone
+ 'records' => array(
+ array('pointer' => 'mail', 'pref' => 10 ),
+ ),
+ ),
+
+
+ // Example 'A' record
+ 'a' => array(
+ 'replace' => 'match', // Set to 'match' to remove all records
+ // which share the same hostname
+ // (ie. 'www')
+
+ 'records' => array(
+ // Notice the trailing '.' on the A record for the
+ // domain itself. For all other records, use the short
+ // hostname and do not append a '.'
+ array('hostname' =>
+ $_SESSION['beatnik']['curdomain']['zonename'] . '.',
+ 'ipaddr' => '10.0.0.3',
+ ),
+
+ array('hostname' => 'www', 'ipaddr' => '10.0.0.3' ),
+ ),
+ ),
+ ),
+);
+
--- /dev/null
+<?xml version="1.0"?>
+<!-- $Horde: beatnik/config/conf.xml,v 1.5 2008/05/15 04:20:53 bklang Exp $ -->
+<configuration>
+ <configsection name="storage">
+ <configheader>Beatnik Storage</configheader>
+ <configswitch name="driver" desc="What backend should we use for storing DNS
+ records?">
+ <case name="pdnsgsql" desc="PowerDNS Generic SQL">
+ <configsection name="params">
+ <configsql switchname="driverconfig">
+ <configstring name="domains_table" desc="Table that holds the list of domains. [domains]" required="false" />
+ <configstring name="records_table" desc="Table that holds the list of domains. [records]" required="false" />
+ </configsql>
+ </configsection>
+ </case>
+ <case name="ldap2dns" desc="ldap2dns (LDAP)">
+ <configsection name="params">
+ <configstring name="hostspec" desc="The hostname of the LDAP
+ server">localhost</configstring>
+ <configstring name="basedn" desc="The base DN for the LDAP server"/>
+ <configstring name="binddn" required="false" desc="The DN used to bind to
+ the LDAP server"/>
+ <configstring name="password" required="false" desc="The password used to
+ bind to the LDAP server"/>
+ <configenum name="version" desc="LDAP Protocol Version">3
+ <values>3
+ <value desc="LDAPv2 (Deprecated)">2</value>
+ <value desc="LDAPv3">3</value>
+ </values>
+ </configenum>
+ <configstring name="dn" desc="The object search key"/>
+ <configswitch name="filter_type" desc="How to specify a filter for the
+ zone lists">objectclass
+ <case name="objectclass" desc="One or more objectclass filters">
+ <configlist name="objectclass" desc="The objectclass filter used to
+ search for zones. Can be a single objectclass or a list."/>dnszone
+ </case>
+ <case name="free" desc="A complete LDAP filter expression">
+ <configstring name="filter" desc="The LDAP RFC formatted filter used to
+ search for users."/>
+ </case>
+ </configswitch>
+ </configsection>
+ </case>
+ <case name="sql" desc="SQL">
+ <configsection name="params">
+ <configsql switchname="driverconfig">
+ </configsql>
+ </configsection>
+ </case>
+ </configswitch>
+ </configsection>
+ <configsection name="menu">
+ <configheader>Menu Settings</configheader>
+ <configmultienum name="apps" desc="Select any applications that should be
+ linked in Beatnik's menu">
+ <values>
+ <configspecial name="list-horde-apps" />
+ </values>
+ </configmultienum>
+ </configsection>
+</configuration>
--- /dev/null
+<?php
+/**
+ * $Horde: beatnik/config/prefs.php.dist,v 1.5 2008/03/07 17:53:34 bklang Exp $
+ *
+ * See horde/config/prefs.php for documentation on the structure of this file.
+ */
+
+$prefGroups['display'] = array(
+ 'column' => _("Options"),
+ 'label' => _("Display Preferences"),
+ 'desc' => _("Set default display parameters."),
+ 'members' => array('domain_groups', 'domains_perpage')
+);
+
+$prefGroups['defaults'] = array(
+ 'column' => _("Options"),
+ 'label' => _("Record Defaults"),
+ 'desc' => _("Set default record parameters."),
+ 'members' => array('default_ttl')
+);
+
+// user domain groups
+$_prefs['domain_groups'] = array(
+ 'value' => '',
+ 'locked' => false,
+ 'shared' => false,
+ 'type' => 'implicit'
+);
+
+// listing
+$_prefs['domains_perpage'] = array(
+ 'value' => 20,
+ 'locked' => false,
+ 'shared' => false,
+ 'type' => 'number',
+ 'desc' => _("How many domain to display per page.")
+);
+
+$_prefs['default_ttl'] = array(
+ 'value' => '86400',
+ 'locked' => false,
+ 'shared' => false,
+ 'type' => 'number',
+ 'desc' => _("Default Time-To-Live for new records.")
+);
--- /dev/null
+<?php
+/**
+ * Delete records
+ *
+ * Copyright 2006-2008 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file LICENSE for license information (BSD). If you
+ * did not receive this file, see http://cvs.horde.org/co.php/merk/LICENSE.
+ *
+ * $Horde: beatnik/delete.php,v 1.15 2009/07/03 10:05:29 duck Exp $
+ */
+
+define('BEATNIK_BASE', dirname(__FILE__));
+require_once BEATNIK_BASE . '/lib/base.php';
+require_once BEATNIK_BASE . '/lib/Forms/DeleteRecord.php';
+
+$vars = Horde_Variables::getDefaultVariables();
+list($type, $record) = $beatnik_driver->getRecord(Horde_Util::getFormData('id'));
+
+$form = new DeleteRecord($vars);
+
+if ($form->validate($vars)) {
+ $form->getInfo($vars, $info);
+ if (Horde_Util::getFormData('submitbutton') == _("Delete")) {
+ $result = $beatnik_driver->deleteRecord($info);
+ if (is_a($result, 'PEAR_Error')) {
+ $notification->push($result->getMessage() . ': ' . $result->getDebugInfo(), 'horde.error');
+ header('Location: ' . Horde_Util::addParameter(Horde::applicationUrl('viewzone.php'), $info));
+ } else {
+ $notification->push(_("Record deleted"), 'horde.success');
+ if ($info['rectype'] == 'soa') {
+ header('Location: ' . Horde::applicationUrl('listzones.php'));
+ } else {
+ header('Location: ' . Horde::applicationUrl('viewzone.php'));
+ }
+ }
+ } else {
+ $notification->push(_("Record not deleted"), 'horde.warning');
+ header('Location: ' . Horde_Util::addParameter(Horde::applicationUrl('viewzone.php'), $info));
+ }
+ exit;
+} elseif (!$form->isSubmitted() && $record) {
+ foreach ($record as $field => $value) {
+ $vars->set($field, $value);
+ }
+}
+
+
+$title = _("Delete");
+require BEATNIK_BASE . '/templates/common-header.inc';
+require BEATNIK_BASE . '/templates/menu.inc';
+
+$form->renderActive(null, null, Horde::applicationUrl('delete.php'), 'post');
+
+require $registry->get('templates', 'horde') . '/common-footer.inc';
--- /dev/null
+---
+0.1
+---
+
+[beatnik] Initial Release
--- /dev/null
+===========================
+ Beatnik Development Team
+===========================
+
+:Last update: $Date: 2007/04/22 04:50:38 $
+:Revision: $Revision: 1.6 $
+
+
+Core Developers
+===============
+Ben Klang <bklang@alkaloid.net>
+Duck <duck@obala.net>
+
+
+Drivers
+=======
+ldap2dns - Ben Klang <bklang@alkaloid.net>
+sql - Duck <duck@obala.net>
+
+
+Localization
+============
+Slovenian Duck <duck@obala.net>
+
+===================== ======================================================
+===================== ======================================================
+
+
+Contributions
+=============
+
+$Horde: beatnik/docs/CREDITS,v 1.6 2007/04/22 04:50:38 chuck Exp $
--- /dev/null
+=========================
+ Installing Beatnik 1.0
+=========================
+
+:Last update: $Date: 2007/06/19 09:56:38 $
+:Revision: $Revision: 1.4 $
+
+.. contents:: Contents
+.. section-numbering::
+
+This document contains instructions for installing the Beatnik ...
+
+For information on the capabilities and features of Beatnik, see the file
+README_ in the top-level directory of the Beatnik distribution.
+
+
+Obtaining Beatnik
+==================
+
+Beatnik can be obtained from the Horde website and FTP server, at
+
+ http://www.horde.org/beatnik/
+
+ ftp://ftp.horde.org/pub/beatnik/
+
+Or use the mirror closest to you:
+
+ http://www.horde.org/mirrors.php
+
+Bleeding-edge development versions of Beatnik are available via CVS; see the
+file `horde/docs/HACKING`_ in the Horde distribution, or the website
+http://www.horde.org/source/, for information on accessing the Horde CVS
+repository.
+
+
+Prerequisites
+=============
+
+To function properly, Beatnik **requires** the following:
+
+1. A working Horde installation.
+
+ Beatnik runs within the `Horde Application Framework`_, a set of common
+ tools for Web applications written in PHP. You must install Horde before
+ installing Beatnik.
+
+ .. Important:: Beatnik 1.0 requires version 3.0+ of the Horde Framework -
+ earlier versions of Horde will **not** work.
+
+ .. _`Horde Application Framework`: http://www.horde.org/horde/
+
+ The Horde Framework can be obtained from the Horde website and FTP server,
+ at
+
+ http://www.horde.org/horde/
+
+ ftp://ftp.horde.org/pub/horde/
+
+ Many of Beatnik's prerequisites are also Horde prerequisites.
+
+ .. Important:: Be sure to have completed all of the steps in the
+ `horde/docs/INSTALL`_ file for the Horde Framework before
+ installing Beatnik.
+
+2. The following PHP capabilities:
+
+ a. FOO support ``--with-foo`` [OPTIONAL]
+
+ Description of Foo and what it is used for.
+
+3. The following PEAR modules:
+ (See `horde/docs/INSTALL`_ for instructions on installing PEAR modules)
+
+ a. PEAR_Package x.x.x [OPTIONAL]
+
+ Beatnik uses the Foo_Bar class for...
+
+4. Something else.
+
+The following items are not required, but are strongly **recommended**:
+
+1. Yet something else.
+
+
+Installing Beatnik
+===================
+
+Beatnik is written in PHP, and must be installed in a web-accessible
+directory. The precise location of this directory will differ from system to
+system. Conventionally, Beatnik is installed directly underneath Horde in
+the web server's document tree.
+
+Since Beatnik is written in PHP, there is no compilation necessary; simply
+expand the distribution where you want it to reside and rename the root
+directory of the distribution to whatever you wish to appear in the URL. For
+example, with the Apache web server's default document root of
+``/usr/local/apache/htdocs``, you would type::
+
+ cd /usr/local/apache/htdocs/horde
+ tar zxvf /path/to/beatnik-x.y.z.tar.gz
+ mv beatnik-x.y.z beatnik
+
+and would then find Beatnik at the URL::
+
+ http://your-server/horde/beatnik/
+
+
+Configuring Beatnik
+====================
+
+1. Configuring Horde for Beatnik
+
+ a. Register the application
+
+ In ``horde/config/registry.php``, find the ``applications['beatnik']``
+ stanza. The default settings here should be okay, but you can change
+ them if desired. If you have changed the location of Beatnik relative
+ to Horde, either in the URL, in the filesystem or both, you must update
+ the ``fileroot`` and ``webroot`` settings to their correct values.
+
+2. Configuring Beatnik
+
+ To configure Beatnik, change to the ``config/`` directory of the installed
+ distribution, and make copies of all of the configuration ``dist`` files
+ without the ``dist`` suffix::
+
+ cd config/
+ for foo in *.dist; do cp $foo `basename $foo .dist`; done
+
+ Or on Windows::
+
+ copy *.dist *.
+
+ Documentation on the format and purpose of those files can be found in each
+ file. You may edit these files if you wish to customize Beatnik's
+ appearance and behavior. With one exception (``foo.php``) the defaults
+ will be correct for most sites.
+
+ You must login to Horde as a Horde Administrator to finish the
+ configuration of Beatnik. Use the Horde ``Administration`` menu item to
+ get to the administration page, and then click on the ``Configuration``
+ icon to get the configuration page. Select ``Beatnik Name`` from the
+ selection list of applications. Fill in or change any configuration values
+ as needed. When done click on ``Generate Beatnik Name Configuration`` to
+ generate the ``conf.php`` file. If your web server doesn't have write
+ permissions to the Beatnik configuration directory or file, it will not be
+ able to write the file. In this case, go back to ``Configuration`` and
+ choose one of the other methods to create the configuration file
+ ``beatnik/config/conf.php``.
+
+ Note for international users: Beatnik uses GNU gettext to provide local
+ translations of text displayed by applications; the translations are found
+ in the ``po/`` directory. If a translation is not yet available for your
+ locale (and you wish to create one), see the ``horde/po/README`` file, or
+ if you're having trouble using a provided translation, please see the
+ `horde/docs/TRANSLATIONS`_ file for instructions.
+
+3. More instructions, upgrading, securing, etc.
+
+4. Testing Beatnik
+
+ Once you have configured Beatnik, bring up the included test page in your
+ Web browser to ensure that all necessary prerequisites have been met. See
+ the `horde/docs/INSTALL`_ document for further details on Horde test
+ scripts. If you installed Beatnik as described above, the URL to the test
+ page would be::
+
+ http://your-server/horde/beatnik/test.php
+
+ The test script will also allow you to test...
+
+ Next, use Beatnik to.... Test at least the following:
+
+ - Foo
+ - Bar
+
+
+Known Problems
+==============
+
+...
+
+
+Obtaining Support
+=================
+
+If you encounter problems with Beatnik, help is available!
+
+The Horde Frequently Asked Questions List (FAQ), available on the Web at
+
+ http://www.horde.org/faq/
+
+The Horde Project runs a number of mailing lists, for individual applications
+and for issues relating to the project as a whole. Information, archives, and
+subscription information can be found at
+
+ http://www.horde.org/mail/
+
+Lastly, Horde developers, contributors and users may also be found on IRC,
+on the channel #horde on the Freenode Network (irc.freenode.net).
+
+Please keep in mind that Beatnik is free software written by volunteers.
+For information on reasonable support expectations, please read
+
+ http://www.horde.org/support.php
+
+Thanks for using Beatnik!
+
+The Beatnik team
+
+
+.. _README: ?f=README.html
+.. _`horde/docs/HACKING`: ../../horde/docs/?f=HACKING.html
+.. _`horde/docs/INSTALL`: ../../horde/docs/?f=INSTALL.html
+.. _`horde/docs/TRANSLATIONS`: ../../horde/docs/?f=TRANSLATIONS.html
--- /dev/null
+<?php
+/**
+ * Release focus. Possible values:
+ * 0 - N/A
+ * 1 - Initial freshmeat announcement
+ * 2 - Documentation
+ * 3 - Code cleanup
+ * 4 - Minor feature enhancements
+ * 5 - Major feature enhancements
+ * 6 - Minor bugfixes
+ * 7 - Major bugfixes
+ * 8 - Minor security fixes
+ * 9 - Major security fixes
+ */
+$this->notes['fm']['focus'] = 4;
+
+/* Mailing list release notes. */
+$this->notes['ml']['changes'] = <<<ML
+The Horde Team is pleased to announce the [first release candidate|final
+release] of the Skeleton Foo Bar Application version H3 (x.x).
+
+The Skeleton Foo Bar Application is a...
+
+[For alpha/beta releases:
+This is a preview version that should not be used on production systems. This
+version is considered feature complete but there might still be a few bugs.
+You should not use this preview version over existing production data.
+
+We encourage widespread testing and feedback via the mailing lists or our bug
+tracking system. Updated translations are very welcome, though some strings
+might still change before the final release.]
+
+[For release candidates:
+Barring any problems, this code will be released as Skeleton H3 (x.x).
+Testing is requested and comments are encouraged.
+Updated translations would also be great.]
+
+The major changes compared to the Skeleton version H3 (x.x) are:
+[or: Changes in this release:]
+ * ...
+ML;
+
+/* Freshmeat release notes. */
+$this->notes['fm']['changes'] = <<<FM
+FM;
+
+$this->notes['name'] = 'Skeleton';
+$this->notes['fm']['project'] = 'skeleton';
+$this->notes['fm']['branch'] = 'Default';
--- /dev/null
+================================
+ Beatnik Development TODO List
+================================
+$Horde: beatnik/docs/TODO,v 1.5 2007/04/12 01:46:42 bklang Exp $
+
+:Last update: $Date: 2007/04/12 01:46:42 $
+:Revision: $Revision: 1.5 $
+:Contact:
+
+
+* Create an api which can be used by XML-RPC where remote clients can
+ authenticate to horde and update their own DNS entries (subject to built-in
+ permissions scheme).
+
+* Allow sorting on arbitrary fields
+
+* Fix deleting entire domains
--- /dev/null
+<?php
+/**
+ * $Horde: beatnik/editrec.php,v 1.35 2009/07/03 10:05:29 duck Exp $
+ *
+ * Copyright 2005-2007 Ben Klang <ben@alkaloid.net>
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ */
+
+define('BEATNIK_BASE', dirname(__FILE__));
+require_once BEATNIK_BASE . '/lib/base.php';
+require_once BEATNIK_BASE . '/lib/Forms/EditRecord.php';
+
+$vars = Horde_Variables::getDefaultVariables();
+$url = Horde::applicationUrl('editrec.php');
+list($type, $record) = $beatnik_driver->getRecord(Horde_Util::getFormData('id'));
+
+$form = new EditRecord($vars);
+
+if ($form->validate($vars)) {
+ $form->getInfo($vars, $info);
+ $result = $beatnik_driver->saveRecord($info);
+
+ if (is_a($result, 'PEAR_Error')) {
+ $notification->push($result->getMessage() . ': ' . $result->getDebugInfo(), 'horde.error');
+ } else {
+ $notification->push('Record data saved.', 'horde.success');
+
+ // Check to see if this is a new domain
+ $edit = $vars->get('id');
+ if ($info['rectype'] == 'soa' && !$edit) {
+ // if added a soa redirect to the autogeneration page
+ $url = Horde_Util::addParameter(Horde::applicationUrl('autogenerate.php'),
+ array('rectype' => 'soa', 'curdomain' => $info['zonename']), false, false);
+ } else {
+ $url = Horde::applicationUrl('viewzone.php');
+ }
+ }
+
+ header('Location: ' . $url);
+ exit;
+
+} elseif (!$form->isSubmitted() && $record) {
+ foreach ($record as $field => $value) {
+ $vars->set($field, $value);
+ }
+}
+
+$title = $form->getTitle();
+require BEATNIK_TEMPLATES . '/common-header.inc';
+require BEATNIK_TEMPLATES . '/menu.inc';
+
+$form->renderActive(null, null, $url, 'post');
+
+require $registry->get('templates', 'horde') . '/common-footer.inc';
--- /dev/null
+<?php
+/**
+ * $Horde: beatnik/index.php,v 1.5 2008/08/22 08:53:50 duck Exp $
+ *
+ * Copyright 2005 Ben Klang <ben@alkaloid.net>
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ */
+
+define('BEATNIK_BASE', dirname(__FILE__));
+$beatnik_configured = (is_readable(BEATNIK_BASE . '/config/conf.php') &&
+ is_readable(BEATNIK_BASE . '/config/prefs.php'));
+
+if (!$beatnik_configured) {
+ require BEATNIK_BASE . '/../lib/Test.php';
+ Horde_Test::configFilesMissing('Beatnik', BEATNIK_BASE,
+ array('conf.php', 'prefs.php'));
+}
+
+require BEATNIK_BASE . '/listzones.php';
--- /dev/null
+
+var loading;function domainSubmit(clear)
+{if(document.menu.domainSelector[document.menu.domainSelector.selectedIndex].value!=''){if((loading==null)||(clear!=null)){loading=true;document.menu.submit();}}}
\ No newline at end of file
--- /dev/null
+// $Horde: beatnik/js/src/beatnik.js,v 1.3 2008/08/20 08:56:53 duck Exp $
+
+// Menu Domain submit
+var loading;
+function domainSubmit(clear)
+{
+ if (document.menu.domainSelector[document.menu.domainSelector.selectedIndex].value != '') {
+ if ((loading == null) || (clear != null)) {
+ loading = true;
+ document.menu.submit();
+ }
+ }
+}
+
--- /dev/null
+<?php
+/**
+ * Beatnik application API.
+ *
+ * @package Beatnik
+ */
+class Beatnik_Application extends Horde_Registry_Application
+{
+ public $version = 'H4 (1.0-git)';
+
+ /**
+ * Returns a list of available permissions.
+ *
+ * @return array An array describing all available permissions.
+ */
+ public function perms()
+ {
+ static $perms = array();
+
+ if (!empty($perms)) {
+ return $perms;
+ }
+
+ require_once dirname(__FILE__) . '/base.php';
+
+ $perms['title']['beatnik:domains'] = _("Domains");
+
+ // Run through every domain
+ foreach ($GLOBALS['beatnik_driver']->getDomains() as $domain) {
+ $perms['tree']['beatnik']['domains'][$domain['zonename']] = false;
+ $perms['title']['beatnik:domains:' . $domain['zonename']] = $domain['zonename'];
+ }
+
+ return $perms;
+ }
+
+ /**
+ * Generate the menu to use on the prefs page.
+ *
+ * @return Horde_Menu A Horde_Menu object.
+ */
+ public function prefsMenu()
+ {
+ return Beatnik::getMenu();
+ }
+}
--- /dev/null
+<?php
+/**
+ * Beatnik base class
+ *
+ * $Horde: beatnik/lib/Beatnik.php,v 1.53 2009/07/15 15:05:32 duck Exp $
+ *
+ * Copyright 2005-2007 Alkaloid Networks <http://www.alkaloid.net>
+ *
+ * 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 Ben Klang <ben@alkaloid.net>
+ * @package Beatnik
+ */
+class Beatnik {
+
+ /**
+ * Build Beatnik's list of menu items.
+ */
+ function getMenu($returnType = 'object')
+ {
+ // We are editing rather than adding if an ID was passed
+ $editing = Horde_Util::getFormData('id');
+ $editing = !empty($editing);
+
+ $hordeImgDir = $GLOBALS['registry']->getImageDir('horde');
+ $beatnikImgDir = $GLOBALS['registry']->getImageDir();
+ $menu = new Horde_Menu();
+
+ $menu->add(Horde::applicationUrl('listzones.php'), _('List Domains'), 'website.png', $hordeImgDir);
+ if (!empty($_SESSION['beatnik']['curdomain'])) {
+ $menu->add(Horde_Util::addParameter(Horde::applicationUrl('editrec.php'), 'curdomain', $_SESSION['beatnik']['curdomain']['zonename']), ($editing) ? _("Edit Record") : _("Add Record"), 'edit.png', $hordeImgDir);
+ } else {
+ $menu->add(Horde::applicationUrl('editrec.php?rectype=soa'), _("Add Zone"), 'edit.png', $hordeImgDir);
+ }
+
+ $url = Horde_Util::addParameter(Horde::selfUrl(true), array('expertmode' => 'toggle'));
+ $menu->add($url, _('Expert Mode'), 'hide_panel.png', $hordeImgDir, '', null, ($_SESSION['beatnik']['expertmode']) ? 'current' : '');
+
+ if (count(Beatnik::needCommit())) {
+ $url = Horde_Util::addParameter(Horde::applicationUrl('commit.php'), array('domain' => 'all'));
+ $menu->add($url, _('Commit All'), 'commit-all.png', $beatnikImgDir);
+ }
+
+ if ($returnType == 'object') {
+ return $menu;
+ } else {
+ return $menu->render();
+ }
+ }
+
+ /**
+ * Get possible records
+ *
+ * The keys of this array are the IDs of the record type. The values
+ * are a human friendly description of the record type.
+ */
+ function getRecTypes()
+ {
+ $records = array(
+ 'soa' => _("SOA (Start of Authority)"),
+ 'ns' => _("NS (Name Server)"),
+ 'a' => _("A (Address)"),
+ 'ptr' => _("PTR (Reverse DNS)"),
+ 'cname' => _("CNAME (Alias)"),
+ 'mx' => _("MX (Mail eXchange)"),
+ 'srv' => _("SRV (Service Record)"),
+ 'txt' => _("TXT (Text Record)"),
+ );
+
+ return array_merge($records, $GLOBALS['beatnik_driver']->getRecDriverTypes());
+ }
+
+ /**
+ */
+ function getRecFields($recordtype)
+ {
+ // Record Format:
+ // $recset is an array of fields. The field IDs are the keys.
+ // Each field is an array with the following keys:
+ // 'name': The short name of the field. This key is also used
+ // to reference the help system.
+ // 'description': Long description of the field
+ // 'type': Field type. Choose from any available from Horde_Form
+ // 'maxlength': Maximum field length. 0 is unlimited
+ // 'required': If true, the field will be required by the form
+ // 'infoset': one of 'basic' or 'advanced'. This is used to help keep
+ // the forms simple for non-power-users. If 'required' is true and
+ // 'infoset' is false then 'default' MUST be specified
+ // 'default': the default value of the field.
+ // 'index': Crude sort ordering. Lower means show higher in the group
+
+ // Attempt to return cached results.
+ static $recset = array();
+
+ if (isset($recset[$recordtype])) {
+ return $recset[$recordtype];
+ }
+ $recset[$recordtype] = array();
+
+ $recset[$recordtype]['id'] = array(
+ 'name' => _("UID"),
+ 'description' => _("Unique Identifier (Used as Record ID)"),
+ 'type' => 'hidden',
+ 'maxlength' => 0,
+ 'required' => false, // Empty for "new" entries
+ 'infoset' => 'basic',
+ 'index' => 0,
+ );
+
+ switch (strtolower($recordtype)) {
+ case 'soa':
+ $recset[$recordtype]['zonename'] = array(
+ 'name' => _("Domain Name"),
+ 'description' => _("Zone Domain Name"),
+ 'type' => 'text',
+ 'maxlength' => 0,
+ 'required' => true,
+ 'infoset' => 'basic',
+ 'index' => 1,
+ );
+ $recset[$recordtype]['zonens'] = array(
+ 'name' => _("Primary Nameserver"),
+ 'description' => _("Primary nameserver for this zone"),
+ 'type' => 'text',
+ 'maxlength' => 0,
+ 'required' => true,
+ 'infoset' => 'basic',
+ 'index' => 2,
+ );
+ $recset[$recordtype]['zonecontact'] = array(
+ 'name' => _("Zone Contact"),
+ 'description' => _("Contact e-mail address for this zone"),
+ 'type' => 'text',
+ 'maxlength' => 0,
+ 'required' => true,
+ 'infoset' => 'basic',
+ 'index' => 2,
+ );
+ $recset[$recordtype]['serial'] = array(
+ 'name' => _("Serial"),
+ 'description' => _("Zone Serial Number"),
+ 'type' => 'int',
+ 'default' => date('Ymd'). '00',
+ 'maxlength' => 0,
+ 'required' => false,
+ 'infoset' => 'advanced',
+ 'index' => 3,
+ );
+ $recset[$recordtype]['refresh'] = array(
+ 'name' => 'Refresh',
+ 'description' => _("Zone Refresh"),
+ 'type' => 'int',
+ 'maxlength' => 0,
+ 'required' => false,
+ 'infoset' => 'advanced',
+ 'index' => 4,
+ );
+ $recset[$recordtype]['retry'] = array(
+ 'name' => _("Retry"),
+ 'description' => _("Zone Retry"),
+ 'type' => 'int',
+ 'maxlength' => 0,
+ 'required' => false,
+ 'infoset' => 'advanced',
+ 'index' => 5,
+ );
+ $recset[$recordtype]['expire'] = array(
+ 'name' => _("Expiration"),
+ 'description' => _("Zone Expiry"),
+ 'type' => 'int',
+ 'maxlength' => 0,
+ 'required' => false,
+ 'infoset' => 'advanced',
+ 'index' => 6,
+ );
+ $recset[$recordtype]['minimum'] = array(
+ 'name' => _("Minimum"),
+ 'description' => _("Zone Minimum"),
+ 'type' => 'int',
+ 'maxlength' => 0,
+ 'required' => false,
+ 'infoset' => 'advanced',
+ 'index' => 7,
+ );
+ break;
+
+ case 'a':
+ $recset[$recordtype]['hostname'] = array(
+ 'name' => _("Hostname"),
+ 'description' => _("Short hostname for this record"),
+ 'type' => 'text',
+ 'maxlength' => 0,
+ 'required' => true,
+ 'infoset' => 'basic',
+ 'index' => 1,
+ );
+ $recset[$recordtype]['ipaddr'] = array(
+ 'name' => _("IP Address"),
+ 'description' => _("IPv4 Network Address"),
+ 'type' => 'ipaddress',
+ 'maxlength' => 0,
+ 'required' => true,
+ 'infoset' => 'basic',
+ 'index' => 2,
+ );
+ break;
+
+ case 'ptr':
+ $recset[$recordtype]['hostname'] = array(
+ 'name' => _("Hostname"),
+ 'description' => _("IP in Reverse notation (.in-addr.arpa)"),
+ 'type' => 'text',
+ 'maxlength' => 0,
+ 'required' => true,
+ 'infoset' => 'basic',
+ 'index' => 1,
+ );
+ $recset[$recordtype]['pointer'] = array(
+ 'name' => _("Hostname Target"),
+ 'description' => _("Hostname for Reverse DNS"),
+ 'type' => 'text',
+ 'maxlength' => 0,
+ 'required' => true,
+ 'infoset' => 'basic',
+ 'index' => 2,
+ );
+ break;
+
+ case 'mx':
+ $recset[$recordtype]['pointer'] = array(
+ 'name' => _("Hostname Target"),
+ 'description' => _("Hostname of Mail eXchanger"),
+ 'type' => 'text',
+ 'maxlength' => 0,
+ 'required' => true,
+ 'infoset' => 'basic',
+ 'index' => 1,
+ );
+ $recset[$recordtype]['pref'] = array(
+ 'name' => _("Preference"),
+ 'description' => _("MX Preference (lower is more preferred)"),
+ 'type' => 'int',
+ 'default' => 0,
+ 'maxlength' => 0,
+ 'required' => true,
+ 'infoset' => 'basic',
+ 'index' => 2,
+ );
+ break;
+
+ case 'cname':
+ $recset[$recordtype]['hostname'] = array(
+ 'name' => _("Hostname"),
+ 'description' => _("Short hostname for this record"),
+ 'type' => 'text',
+ 'maxlength' => 0,
+ 'required' => true,
+ 'infoset' => 'basic',
+ 'index' => 1,
+ );
+ $recset[$recordtype]['pointer'] = array(
+ 'name' => _("Hostname Target"),
+ 'description' => _("Hostname for CNAME alias"),
+ 'type' => 'text',
+ 'maxlength' => 0,
+ 'required' => true,
+ 'infoset' => 'basic',
+ 'index' => 2,
+ );
+ break;
+
+ case 'ns':
+ $recset[$recordtype]['hostname'] = array(
+ 'name' => _("Domain Name"),
+ 'description' => _("Short sub-domain for NS record (leave blank unless creating a subdomain)"),
+ 'type' => 'text',
+ 'maxlength' => 0,
+ 'required' => false,
+ // If we have a current domain name, use it for the default val
+ 'default' => @$GLOBALS['curdomain']['zonename'],
+ 'infoset' => 'basic',
+ 'index' => 1,
+ );
+ $recset[$recordtype]['pointer'] = array(
+ 'name' => _("Hostname Target"),
+ 'description' => _("Hostname of Authoritative Name Server"),
+ 'type' => 'text',
+ 'maxlength' => 0,
+ 'required' => true,
+ 'infoset' => 'basic',
+ 'index' => 2,
+ );
+ break;
+
+ case 'srv':
+ $recset[$recordtype]['hostname'] = array(
+ 'name' => _("Hostname"),
+ 'description' => _("Short hostname for this record"),
+ 'type' => 'text',
+ 'maxlength' => 0,
+ 'required' => true,
+ 'infoset' => 'basic',
+ 'index' => 1,
+ );
+ $recset[$recordtype]['pointer'] = array(
+ 'name' => _("Hostname Target"),
+ 'description' => _("Hostname for DNS Service Record"),
+ 'type' => 'text',
+ 'maxlength' => 0,
+ 'required' => true,
+ 'infoset' => 'basic',
+ 'index' => 2,
+ );
+ $recset[$recordtype]['priority'] = array(
+ 'name' => _("SRV Priority"),
+ 'description' => _("DNS Service Record Priority"),
+ 'type' => 'int',
+ 'default' => 0,
+ 'maxlength' => 0,
+ 'required' => true,
+ 'infoset' => 'basic',
+ 'index' => 3,
+ );
+ $recset[$recordtype]['weight'] = array(
+ 'name' => _("SRV Weight"),
+ 'description' => _("DNS Service Record Weight"),
+ 'type' => 'int',
+ 'default' => 0,
+ 'maxlength' => 0,
+ 'required' => true,
+ 'infoset' => 'basic',
+ 'index' => 4,
+ );
+ $recset[$recordtype]['port'] = array(
+ 'name' => _("SRV Port"),
+ 'description' => _("DNS Service Record Port Number"),
+ 'type' => 'int',
+ 'default' => 0,
+ 'maxlength' => 0,
+ 'required' => true,
+ 'infoset' => 'basic',
+ 'index' => 5,
+ );
+ break;
+
+ case 'txt':
+ $recset[$recordtype]['hostname'] = array(
+ 'name' => _("Hostname"),
+ 'description' => _("Short hostname for this record"),
+ 'type' => 'text',
+ 'maxlength' => 0,
+ 'required' => true,
+ 'infoset' => 'basic',
+ 'index' => 1,
+ );
+ $recset[$recordtype]['text'] = array(
+ 'name' => 'Text',
+ 'description' => _("String payload for DNS TXT"),
+ 'type' => 'text',
+ 'maxlength' => 256,
+ 'required' => true,
+ 'infoset' => 'basic',
+ 'index' => 2,
+ );
+ break;
+ }
+
+ $recset[$recordtype]['ttl'] = array(
+ 'name' => _("TTL"),
+ 'description' => _("Record Time-To-Live (seconds)"),
+ 'type' => 'int',
+ 'maxlength' => 0,
+ 'required' => false,
+ 'infoset' => 'advanced',
+ 'index' => 100,
+ 'default' => $GLOBALS['prefs']->getValue('default_ttl')
+ );
+
+ $recset[$recordtype] = array_merge($recset[$recordtype], $GLOBALS['beatnik_driver']->getRecDriverFields($recordtype));
+ uasort($recset[$recordtype], array('Beatnik', 'fieldSort'));
+
+ return $recset[$recordtype];
+ }
+
+ /**
+ * Check or set a flag to show that a domain has outstanding changes that
+ * need to be committed.
+ *
+ * @param optional string $domain Domain to check whether a commit is
+ * necessary
+ * @param optional boolean $needcommit true adds the domain to the list
+ * that needs committing; false removes
+ * the domain from the list
+ *
+ * @return mixed Array of domains needing committing if no arguments are
+ * passed.
+ * Boolean if only a $domain is passed: True if $domain has
+ * outstanding changes, false if not.
+ * Mixed if both $domain and $needcommit are passed. True
+ * on success, PEAR::Error on error.
+ */
+ function needCommit($domain = null, $needcommit = null)
+ {
+ // Make sure we have a valid array with which to work
+ if (!isset($_SESSION['beatnik']['needcommit'])) {
+ $_SESSION['beatnik']['needcommit'] = array();
+ }
+
+ if ($domain === null && $needcommit === null) {
+ // Return the stored list of domains needing changes committed.
+ return array_keys($_SESSION['beatnik']['needcommit']);
+ } elseif ($domain !== null && $needcommit === null) {
+ // Check if domain need committing
+ return isset($_SESSION['beatnik']['needcommit'][$domain]);
+ } elseif ($domain !== null && is_bool($needcommit)) {
+ // Flag domain for committing
+ if ($needcommit) {
+ if(!isset($_SESSION['beatnik']['needcommit'][$domain])) {
+ $_SESSION['beatnik']['needcommit'][$domain] = true;
+ }
+ } else {
+ if (isset($_SESSION['beatnik']['needcommit'][$domain])) {
+ unset($_SESSION['beatnik']['needcommit'][$domain]);
+ }
+ }
+ return true;
+ } else {
+ // Somebody sent something they should not have...
+ return PEAR::raiseError(_("Unable to determine if domain needs committing: invalid parameter."));
+ }
+ }
+
+ /**
+ * Checks for the given permissions for the current user on the given
+ * permissions node. Optionally check for the requested permssion for a
+ * given number of steps up the tree.
+ *
+ * @param string $permname Name of the permission to check
+ *
+ * @param optional int $permmask Bitfield of permissions to check for
+ *
+ * @param options int $numparents Check for the same permissions this
+ * many levels up the tree
+ *
+ * @return boolean True if the user has permission, False if not
+ */
+ function hasPermission($permname, $permmask = null, $numparents = 0)
+ {
+ if (Horde_Auth::isAdmin()) {
+ return true;
+ }
+
+ $perms = Perms::singleton();
+ if ($permmask === null) {
+ $permmask = PERMS_SHOW|PERMS_READ;
+ }
+
+ # Default deny all permissions
+ $user = 0;
+ $superadmin = 0;
+
+ $superadmin = $perms->hasPermission('beatnik:domains', Horde_Auth::getAuth(), $permmask);
+
+ while ($numparents >= 0) {
+ $tmpuser = $perms->hasPermission($permname, Horde_Auth::getAuth(), $permmask);
+
+ $user = $user | $tmpuser;
+ if ($numparents > 0) {
+ $pos = strrpos($permname, ':');
+ if ($pos) {
+ $permname = substr($permname, 0, $pos);
+ }
+ }
+ $numparents--;
+ }
+ return (($superadmin | $user) & $permmask);
+ }
+
+ /**
+ * Autogenerate a set of records from a template defined in
+ * config/autogenerate.php
+ *
+ * @param object $vars Horde_Variables object from Autogenerate form
+ *
+ * @return mixed true on success, PEAR::Error on failure
+ */
+ function autogenerate(&$vars)
+ {
+
+ require BEATNIK_BASE . '/config/autogenerate.php';
+ $template = $templates[$vars->get('template')];
+ $zonedata = $GLOBALS['beatnik_driver']->getRecords($_SESSION['beatnik']['curdomain']['zonename']);
+ if (is_a($zonedata, 'PEAR_Error')) {
+ return $zonedata;
+ }
+
+ foreach ($template['types'] as $rectype => $definitions) {
+ // Only attempt to delete records if the type is already defined
+ if (isset($zonedata[$rectype])) {
+ // Check for collisions and handle as requested
+ switch($definitions['replace']) {
+ case 'all':
+ foreach ($zonedata[$rectype] as $record) {
+ $result = $GLOBALS['beatnik_driver']->deleteRecord($record);
+ if (is_a($result, 'PEAR_Error')) {
+ $GLOBALS['notification']->push($result);
+ }
+ }
+ break;
+
+ case 'match':
+ foreach ($zonedata[$rectype] as $record) {
+ // Check every record in the template to see if the
+ // hostname matches
+ foreach ($definitions['records'] as $Trecord) {
+ if ($record['hostname'] == $Trecord['hostname']) {
+ $result = $GLOBALS['beatnik_driver']->deleteRecord($record);
+ if (is_a($result, 'PEAR_Error')) {
+ $GLOBALS['notification']->push($result);
+ }
+ }
+ }
+ }
+ break;
+
+ #case 'none':
+ #default:
+ }
+ }
+
+ $defaults = array('rectype' => $rectype,
+ 'zonename'=> $_SESSION['beatnik']['curdomain']['zonename']);
+ foreach ($definitions['records'] as $info) {
+ if ($GLOBALS['beatnik_driver']->recordExists($info, $rectype)) {
+ $GLOBALS['notification']->push(_("Skipping existing identical record"));
+ continue;
+ }
+ $result = $GLOBALS['beatnik_driver']->saveRecord(array_merge($defaults, $info));
+ if (is_a($result, 'PEAR_Error')) {
+ $GLOBALS['notification']->push($result->getMessage() . ': ' . $result->getDebugInfo(), 'horde.error');
+ } else {
+ $GLOBALS['notification']->push(sprintf(_('Record added: %s/%s'), $rectype, $info['hostname']), 'horde.success');
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Increments a domain serial number.
+ *
+ * @param int $serial Serial number to be incremented
+ *
+ * @return int Incremented serial number
+ */
+ function incrementSerial($serial)
+ {
+ // Create a serial number of the ad-hoc standard YYYYMMDDNN
+ // where YYYYMMDD is the year/month/day of the last update to this
+ // odmain and NN is an incrementer to handle multiple updates in a
+ // given day.
+ $newserial = (int) (date('Ymd') . '00');
+ if ($serial < $newserial) {
+ return $newserial;
+ } else {
+ return ++$serial;
+ }
+ }
+
+ /**
+ * Callback for usort to make field data print in a friendly order
+ *
+ * @param mixed $a First sort variable
+ * @param mixed $b Second sort variable
+ *
+ * @return int -1, 0, 1 based on relative sort order
+ */
+ function fieldSort($a, $b)
+ {
+ if ($a['index'] < $b['index']) {
+ return -1;
+ } elseif ($a['index'] > $b['index']) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * Beatnik_Driver:: defines an API implementing astorage backends for Beatnik.
+ *
+ * $Horde: beatnik/lib/Driver.php,v 1.21 2009/07/15 15:05:32 duck Exp $
+ *
+ * Copyright 2005-2007 Alkaloid Networks <http://www.alkaloid.net>
+ *
+ * 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 Ben Klang <ben@alkaloid.net>
+ * @version $Revision: 1.21 $
+ * @package Beatnik
+ */
+class Beatnik_Driver {
+
+ /**
+ * Hash containing connection parameters.
+ *
+ * @var array $_params
+ */
+ var $_params = array();
+
+ function Beatnik_Driver($params = array())
+ {
+ $this->_params = $params;
+ }
+
+ /**
+ * Get any record types available specifically in this driver.
+ *
+ * @return array Records available only to this driver
+ */
+ function getRecDriverTypes()
+ {
+ return array();
+ }
+
+
+ /**
+ * Get any fields available specifically in this driver by record type.
+ *
+ * @param string $type Record type for which fields should be returned
+ *
+ * @return array Fields specific to this driver
+ */
+ function getRecDriverFields($type) {
+
+ return array();
+ }
+
+ /**
+ * Gets domains from driver for which the user has the specified
+ * permission.
+ *
+ * @param int $perms Permissions filter for domain result set
+ *
+ * @return array Possibly empty array of domain information
+ */
+ function getDomains($perms = PERMS_SHOW)
+ {
+ $domains = $this->_getDomains();
+ if (is_a($domains, 'PEAR_Error')) {
+ $GLOBALS['notification']->push($domains->getMessage() . ': ' . $domains->getDebugInfo(), 'horde.warning');
+ return array();
+ }
+
+ if (!Horde_Auth::isAdmin() &&
+ !$GLOBALS['perms']->hasPermission('beatnik:domains', Horde_Auth::getAuth(), $perms)) {
+ foreach ($domains as $id => $domain) {
+ if (!$GLOBALS['perms']->hasPermission('beatnik:domains:' . $domain['zonename'], Horde_Auth::getAuth(), $perms)) {
+ unset($domains[$id]);
+ }
+ }
+ }
+
+ if (empty($domains)) {
+ $GLOBALS['notification']->push(_("You are not permitted to view any domains."), 'horde.warning');
+ return array();
+ }
+
+ // Sort the resulting list by domain name
+ // TODO: Allow sorting by other columns
+ require_once 'Horde/Array.php';
+ Horde_Array::arraySort($domains, 'zonename');
+
+ return $domains;
+ }
+
+ /**
+ * Return SOA for a single domain
+ *
+ * @param string $domain Domain for which to return SOA information
+ *
+ * @return mixed Array of SOA information for domain or PEAR_Error
+ * on failure.
+ */
+ function getDomain($domainname)
+ {
+ $domains = $this->getDomains(PERMS_SHOW | PERMS_READ);
+
+ foreach ($domains as $domain) {
+ if ($domain['zonename'] == $domainname) {
+ return $domain;
+ }
+ }
+ return PEAR::raiseError(sprintf(_("Unable to read requested domain %s"), $domainname));
+ }
+
+ /**
+ * Gets a specific record from the backend. This method may be overridden
+ * in specific backend drivers if there is a performance or other benefit
+ * for doing so.
+ *
+ * @return array Array of type and record information
+ */
+ function getRecord($id)
+ {
+ if ($id === null) {
+ return false;
+ }
+
+ $zonedata = $this->getRecords($_SESSION['beatnik']['curdomain']['zonename']);
+ // Search for the requested record id
+ foreach ($zonedata as $type => $records) {
+ foreach ($records as $record) {
+ if ($record['id'] == $id) {
+ // Found the record we're looking for
+ break;
+ }
+ $type = false;
+ $record = false;
+ }
+ if ($record) {
+ // Record found in nested loop. Break out of this one too.
+ break;
+ }
+ }
+
+ if (!$record) {
+ // We may be editing the SOA. See if it matches
+ $record = $this->getDomain($_SESSION['beatnik']['curdomain']['zonename']);
+ if ($record['id'] == $id) {
+ $type = 'soa';
+ } else {
+ $GLOBALS['notification']->push(_("Unable to locate requested record."), 'horde.error');
+ $type = false;
+ $record = false;
+ }
+ }
+
+ return array($type, $record);
+ }
+
+ /**
+ * Try to determinate if the autogenerated record
+ * already exits. This method may be overridden in the backend driver
+ * for performance or other reasons.
+ *
+ * @param array $record record to check
+ *
+ * @return boolean if records exits or or not
+ */
+ function recordExists($record, $rectype)
+ {
+ $zonedata = $this->getRecords($_SESSION['beatnik']['curdomain']['zonename']);
+ if (is_a($zonedata, 'PEAR_Error')) {
+ $notification->push($zonedata, 'horde.error');
+ header('Location:' . Horde::applicationUrl('listzones.php'));
+ exit;
+ }
+
+ if (isset($zonedata[$rectype])) {
+ foreach ($zonedata[$rectype] as $row) {
+ // Prune empty values from $row to aid in comparison
+ foreach ($row as $key => $value) {
+ if (empty($value)) {
+ unset($row[$key]);
+ }
+ }
+
+ $same_values = array_intersect_assoc($row, $record);
+ if (count($same_values) == count($record)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Saves a record fo the configured driver and checks/sets needCommit()
+ * Also first checks to ensure permission to save record is available.
+ *
+ * @param array $info Data to be passed to backend driver for storage
+ *
+ * @return mixed True on success, PEAR::Error on error
+ */
+ function saveRecord(&$info)
+ {
+ // Check to see if this is a new domain
+ if ($info['rectype'] == 'soa' && $info['zonename'] != $_SESSION['beatnik']['curdomain']['zonename']) {
+ // Make sure the user has permissions to add domains
+ if (!Beatnik::hasPermission('beatnik:domains', PERMS_EDIT)) {
+ return PEAR::raiseError(_('You do not have permission to create new domains.'));
+ }
+
+ // Create a dummy old domain for comparison purposes
+ $oldsoa['serial'] = 0;
+
+ } else {
+ $oldsoa =& $_SESSION['beatnik']['curdomain'];
+
+ // Check for permissions to edit the record in question
+ if ($info['rectype'] == 'soa') {
+ $node = 'beatnik:domains:' . $info['zonename'];
+ if (!Beatnik::hasPermission($node, PERMS_EDIT, 1)) {
+ return PEAR::raiseError(_('You do not have permssion to edit the SOA of this zone.'));
+ }
+ } else {
+ $node = 'beatnik:domains:' . $_SESSION['beatnik']['curdomain']['zonename'] . ':' . $info['id'];
+ if (!Beatnik::hasPermission($node, PERMS_EDIT, 2)) {
+ return PEAR::raiseError(_('You do not have permssion to edit this record.'));
+ }
+ }
+ }
+
+ // Save the changes to the backend
+ // FIXME: Modify saveRecord() to return the new (possibly changed) ID of the
+ // record and then use that ID to update permissions
+ $return = $this->_saveRecord($info);
+
+ $oldsoa =& $_SESSION['beatnik']['curdomain'];
+
+ if (is_a($return, 'PEAR_Error')) {
+ return $return;
+ } else {
+ if ($info['rectype'] == 'soa' &&
+ ($oldsoa['serial'] < $info['serial'])) {
+ // Clear the commit flag (if set)
+ Beatnik::needCommit($oldsoa['zonename'], false);
+ } else {
+ Beatnik::needCommit($oldsoa['zonename'], true);
+ }
+ }
+
+ // Check to see if an SOA was just added or updated.
+ // If so, make it the current domain.
+ if ($info['rectype'] == 'soa') {
+ $_SESSION['beatnik']['curdomain'] = $this->getDomain($info['zonename']);
+ }
+
+ return true;
+ }
+
+ /**
+ * Delete record from backend
+ *
+ * @access private
+ *
+ * @param array $info Reference to array of record information for deletion
+ *
+ * @return boolean true on success, PEAR::raiseError on error
+ */
+ function deleteRecord(&$info)
+ {
+ $return = $this->_deleteRecord($info);
+
+ $oldsoa =& $_SESSION['beatnik']['curdomain'];
+
+ if (is_a($return, 'PEAR_Error')) {
+ return $return;
+ } else {
+ // No need to commit if the whole zone is gone
+ if ($info['rectype'] != 'soa') {
+ Beatnik::needCommit($oldsoa['zonename'], true);
+ }
+ }
+ }
+
+ /**
+ * Attempts to return a concrete Beatnik_Driver instance based on
+ * $driver.
+ *
+ * @param string $driver The type of the concrete Beatnik_Driver subclass
+ * to return. The class name is based on the storage
+ * driver ($driver). The code is dynamically
+ * included.
+ *
+ * @param array $params (optional) A hash containing any additional
+ * configuration or connection parameters a
+ * subclass might need.
+ *
+ * @return mixed The newly created concrete Beatnik_Driver instance, or
+ * false on an error.
+ */
+ function factory($driver = null, $params = null)
+ {
+ if ($driver === null) {
+ $driver = $GLOBALS['conf']['storage']['driver'];
+ }
+
+ $driver = basename($driver);
+ if (empty($driver) || ($driver == 'none')) {
+ return new Horde_Lock();
+ }
+
+ if (is_null($params)) {
+ // Since we have more than one backend that uses SQL make sure
+ // all of them have a chance to inherit the site-wide config.
+ $sqldrivers = array('sql', 'pdnsgsql');
+ if (in_array($driver, $sqldrivers)) {
+ $params = Horde::getDriverConfig('storage', 'sql');
+ } else {
+ $params = Horde::getDriverConfig('storage', $driver);
+ }
+ }
+
+ require_once dirname(__FILE__) . '/Driver/' . $driver . '.php';
+ $class = 'Beatnik_Driver_' . $driver;
+ if (class_exists($class)) {
+ return new $class($params);
+ } else {
+ return PEAR::raiseError(_('Driver not found.'));
+ }
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * $Horde: beatnik/lib/Driver/ldap2dns.php,v 1.25 2008/03/11 08:57:59 duck Exp $
+ *
+ * Copyright 2005-2007 Alkaloid Networks <http://www.alkaloid.net>
+ *
+ * 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 Ben Klang <ben@alkaloid.net>
+ * @package Beatnik
+ */
+class Beatnik_Driver_ldap2dns extends Beatnik_Driver
+{
+ /**
+ * Handle for the current database connection.
+ * @var object LDAP $_LDAP
+ */
+ var $_LDAP;
+
+ /**
+ * Boolean indicating whether or not we're connected to the LDAP
+ * server.
+ * @var boolean $_connected
+ */
+ var $_connected = false;
+
+ /**
+ * Constructs a new Beatnik LDAP driver object.
+ *
+ * @param array $params A hash containing connection parameters.
+ */
+ function Beatnik_Driver_ldap2dns($params = array())
+ {
+ parent::Beatnik_Driver($params);
+ $this->_connect();
+ }
+
+ /**
+ * Get any record types available specifically in this driver.
+ *
+ * @return array Records available only to this driver
+ */
+ function getRecDriverTypes()
+ {
+ return array(
+ 'a+ptr' => 'A + PTR',
+ );
+ }
+
+ /**
+ * Get any fields available specifically in this driver by record type.
+ *
+ * @param string $type Record type for which fields should be returned
+ *
+ * @return array Fields specific to this driver
+ */
+ function getRecDriverFields($type) {
+ $recset = array();
+ switch($type) {
+ case 'a+ptr':
+ $recset['hostname'] = array(
+ 'name' => 'Hostname',
+ 'description' => 'Hostname',
+ 'type' => 'text',
+ 'maxlength' => 0,
+ 'required' => true,
+ 'infoset' => 'basic',
+ 'index' => 1,
+ );
+ $recset['cipaddr'] = array(
+ 'name' => 'IP Address',
+ 'description' => 'IP Address to be forward and reverse mapped',
+ 'type' => 'ipaddress',
+ 'maxlength' => 0,
+ 'required' => true,
+ 'infoset' => 'basic',
+ 'index' => 2,
+ );
+ break;
+ }
+
+ $recset['timestamp'] = array(
+ 'name' => 'Timestamp',
+ 'description' => '"Do Not Issue Before/After" Timestamp',
+ 'type' => 'int',
+ 'maxlength' => 0,
+ 'required' => false,
+ 'infoset' => 'advanced',
+ 'index' => 100,
+ );
+ $recset['location'] = array(
+ 'name' => 'Location',
+ 'description' => 'Location Restriction',
+ 'type' => 'text',
+ 'maxlength' => 2,
+ 'required' => false,
+ 'infoset' => 'advanced',
+ 'index' => 101,
+ );
+
+ return $recset;
+ }
+
+ /**
+ * Gets all zones for accessible to the user matching the filter
+ *
+ * @access private
+ *
+ * @return array Array with zone records numerically indexed
+ */
+ function _getDomains()
+ {
+ static $zonedata = array();
+ if (count($zonedata) > 0) {
+ # If at least one element is in the array then we should have valid
+ # cached data.
+ return $zonedata;
+ }
+
+ // Record format
+ // $zonedata =
+ // zone array ( # numerically indexed
+ // zonename => zone domain name
+ // serial => zone SOA serial number
+ // refresh => zone SOA refresh
+ // retry => zone SOA retry
+ // expire => zone SOA expiry
+ // minimum => zone SOA minimum
+ // admin => zone contact admin
+ // zonemaster => SOA master NS
+ // )
+
+ $res = ldap_list($this->_LDAP,
+ $this->_params['basedn'],
+ "(objectClass=dnszone)");
+
+ if ($res === false) {
+ return PEAR::raiseError("Unable to locate any DNS zones " .
+ "underneath ".$this->_params['basedn']);
+ }
+
+ $res = ldap_get_entries($this->_LDAP, $res);
+
+ if ($res === false) {
+ return PEAR::raiseError(sprintf(_("Unable to retrieve data from LDAP results: %s"), @ldap_error($this->_LDAP)));
+ }
+
+ $fields = Beatnik::getRecFields('soa');
+ $i = 0;
+ # FIXME: Add some way to handle missing zone data
+ # FIXME: Don't forget to remove error silencers (@whatever)
+ while ($i < $res['count']) {
+ $tmp = array();
+
+ foreach ($fields as $field => $fieldinfo) {
+ $key = strtolower($this->_getAttrByField($field));
+ if ($key === null) {
+ // This is not a field we are concerned with. Skip it
+ continue;
+ }
+ // Special case for 'dn' as it's not treated as an array
+ if ($key == 'dn') {
+ $val = @ldap_explode_dn($res[$i]['dn'], 1);
+ $tmp[$field] = $val[0];
+ continue;
+ }
+ @$tmp[$field] = $res[$i][$key][0];
+ }
+
+ # Push the zone on the stack
+ $zonedata[] = $tmp;
+
+ # Next zone, please
+ $i++;
+ }
+ return $zonedata;
+ }
+
+ /**
+ * Map LDAP Attributes to application record fields
+ *
+ * @access private
+ *
+ * @param $field string LDAP Attribute for which a record field should be
+ * returned
+ *
+ * @return string Application record field name
+ */
+ function _getAttrByField($field)
+ {
+ $field = strtolower($field);
+ $fields = array(
+ 'hostname' => 'dnsdomainname',
+ 'zonename' => 'dnszonename', # FIXME This will go away for ldap2dns 0.4.x
+ 'serial' => 'dnsserial',
+ 'refresh' => 'dnsrefresh',
+ 'retry' => 'dnsretry',
+ 'expire' => 'dnsexpire',
+ 'minimum' => 'dnsminimum',
+ 'zonecontact' => 'dnsadminmailbox',
+ 'zonens' => 'dnszonemaster',
+ 'ttl' => 'dnsttl',
+ 'timestamp' => 'dnstimestamp',
+ 'location' => 'dnslocation',
+ 'ipaddr' => 'dnsipaddr',
+ 'cipaddr' => 'dnscipaddr',
+ 'pointer' => 'dnscname',
+ 'pref' => 'dnspreference',
+ 'priority' => 'dnssrvpriority',
+ 'weight' => 'dnssrvweight',
+ 'port' => 'dnssrvport',
+ 'text' => 'dnscname', # FIXME THIS WILL CHANGE IN ldap2dns 0.5.0!!!
+ 'id' => 'dn',
+ );
+
+ if (!isset($fields[$field])) {
+ return null;
+ }
+
+ return $fields[$field];
+
+ }
+
+ /**
+ * Gets all records associated with the given zone
+ *
+ * @param string $domain Retrieve records for this domain
+ *
+ * @return array Array with zone records
+ */
+ function getRecords($domain)
+ {
+ $domain = $this->cleanFilterString($domain);
+ $dn = $this->_params['dn'].'='.$domain.','.$this->_params['basedn'];
+ $res = @ldap_list($this->_LDAP, $dn, '(objectClass=dnsrrset)');
+
+ if ($res === false) {
+ return PEAR::raiseError("Unable to locate any DNS data for $domain");
+ }
+
+ # FIXME Cache these results
+ $zonedata = array();
+ $res = @ldap_get_entries($this->_LDAP, $res);
+ if ($res === false) {
+ return PEAR::raiseError(sprintf(_("Internal error: %s"), @ldap_error($this->_LDAP)));
+ }
+
+ $i = 0;
+ while ($i < $res['count']) {
+ $rectype = $res[$i]['dnstype'][0];
+ // Special case for A+PTR records
+ if ($rectype == 'a' && isset($res[$i]['dnscipaddr'])) {
+ $rectype = 'a+ptr';
+ }
+ if (!isset($zonedata[$rectype])) {
+ # Initialize this type if it hasn't already been done
+ $zonedata[$rectype] = array();
+ }
+ $tmp = array();
+ foreach (Beatnik::getRecFields($rectype) as $field => $fielddata) {
+ $key = $this->_getAttrByField($field);
+ if ($key === null) {
+ // Not a key we care about
+ continue;
+ }
+ // Special case for 'dn' as it's not treated as an array
+ if ($key == 'dn') {
+ $val = @ldap_explode_dn($res[$i]['dn'], 1);
+ $tmp[$field] = $val[0];
+ continue;
+ }
+
+ // Only the first value is used. All other are ignored.
+ $tmp[$field] = @$res[$i][$key][0];
+ }
+ # Push the record on the stack
+ $zonedata[$rectype][] = $tmp;
+
+ # Next entry, please.
+ $i++;
+ }
+
+ return $zonedata;
+ }
+
+ /**
+ * Delete record from backend
+ *
+ * @access private
+ *
+ * @param array $info Reference to array of record information for deletion
+ *
+ * @return boolean true on success, PEAR::raiseError on error
+ */
+ function _deleteRecord(&$info)
+ {
+ // Ensure we have a record ID before continuing
+ if (!isset($info['id'])) {
+ return PEAR::raiseError(_("Unable to delete record: No record ID specified."));
+ }
+
+ // Attribute used to identify objects
+ $dnattr = $this->_params['dn'];
+
+ $suffix = $dnattr . '=' . $_SESSION['beatnik']['curdomain']['zonename'] . ',' . $this->_params['basedn'];
+ if ($info['rectype'] == 'soa') {
+ // FIXME: Add recursion
+ return PEAR::raiseError(_("Unsupported recursive delete."));
+
+ $domain = $this->cleanDNString($info['zonename']);
+ $dn = $suffix;
+ } else {
+ $domain = $this->cleanDNString($_SESSION['beatnik']['curdomain']['zonename']);
+ // Strip the array fluff and add the attribute
+ $dn = $dnattr . '=' . $this->cleanDNString($info['id']) . ',' . $suffix;
+ }
+
+ $res = @ldap_delete($this->_LDAP, $dn);
+ if ($res === false) {
+ return PEAR::raiseError(sprintf(_("Unable to delete record. Reason: %s"), @ldap_error($this->_LDAP)));
+ }
+ return true;
+ }
+
+ /**
+ * Saves a new or edited record to the DNS backend
+ *
+ * @access private
+ *
+ * @param array $info Array from Horde_Form with record data
+ *
+ * @return mixed The new or modified record ID on success;
+ * PEAR_Error on error
+ */
+ function _saveRecord($info)
+ {
+ // Make sure we have a valid record type
+ $rectype = strtolower($info['rectype']);
+ $rdata = false;
+ foreach (Beatnik::getRecTypes() as $rtype => $rdata) {
+ if ($rectype == $rtype) {
+ break;
+ }
+ $rdata = false;
+ }
+
+ if (!$rdata) {
+ return PEAR::raiseError(_("Invalid record type specified."));
+ }
+
+ $recfields = Beatnik::getRecFields($rectype);
+
+ $entry = array();
+
+ if ($rectype == 'a+ptr') {
+ // Special case for A+PTR Records
+ $entry['dnstype'] = 'a';
+ } else {
+ $entry['dnstype'] = $rectype;
+ }
+
+ $id = strtoupper($rectype);
+
+ // Apply each piece of submitted data to the new/updated object
+ foreach ($recfields as $field => $fdata) {
+ // Translate the key to an LDAP attribute
+ $key = $this->_getAttrByField($field);
+
+ if ($key === null || $key == 'dn') {
+ // Skip the DN or any other key we don't care about
+ continue;
+ }
+
+ if (!isset($info[$field]) && isset($fdata['default'])) {
+ // No value specified. Use the default
+ $val = $fdata['default'];
+ } else {
+ // Only populate the field if there is actual data
+ if (isset($info[$field]) && strlen($info[$field])) {
+ $entry[$key] = $info[$field];
+ } else {
+ // $info[$field] was possibly unset
+ $info[$field] = '';
+ // If the record previously had data, we have to send an
+ // empty array to remove the attribute. However, always
+ // sending an empty attribute causes PHP to return with
+ // "Protocol Error". Hence this somewhat expensive check:
+ if (isset($info['id'])) {
+ list($type, $record) = $this->getRecord($info['id']);
+ if ($record && isset($record[$field])) {
+ $entry[$key] = array();
+ }
+ }
+ }
+ }
+
+ if (!isset($entry[$key]) && $fdata['required']) {
+ // No value available but required field
+ return PEAR::raiseError(sprintf(_("Missing required field %s to save record."), $fdata['name']));
+ }
+
+ // Construct an ID for this object as a tuple of its data.
+ // This guarantees uniqueness.
+ $id .= '-'.$this->cleanDNString($info[$field]);
+ }
+
+ // Create and populate the DN
+ $key = $this->_params['dn'];
+ $dn = '';
+ // Special case for SOA records.
+ if ($rectype == 'soa') {
+ $domain = $this->cleanDNString($info['zonename']);
+ $entry[$key] = $domain;
+ $id = $domain;
+ $dn = $key.'='.$domain;
+ $suffix = $this->_params['basedn'];
+ } else {
+ // Everything else gets full id for DN
+ $id = $this->cleanDNString($id);
+ $entry[$key] = $id;
+ $dn = $key.'='.$id;
+ // The domain is held in the session
+ $domain = $this->cleanDNString($_SESSION['beatnik']['curdomain']['zonename']);
+ // Prepare the DN suffix
+ $suffix = $key.'='.$domain.','.$this->_params['basedn'];
+ }
+
+ // Check to see if this is a modification
+ if (isset($info['id'])) {
+ // Get the base name of the old object
+ $oldRDN = $key . '=' . $this->cleanDNString($info['id']);
+ if ($dn != $oldRDN) {
+ // We have an old DN but it doesn't match the new DN.
+ // Need to rename the old object
+ if ($rectype == 'soa') {
+ return PEAR::raiseError(_("Unsupported operation: cannot rename a domain."));
+ }
+ $res = @ldap_rename($this->_LDAP, $oldRDN . ',' . $suffix,
+ $dn, $suffix, true);
+ if ($res === false) {
+ return PEAR::raiseError(sprintf(_("Unable to rename old object. Reason: %s"), @ldap_error($this->_LDAP)));
+ }
+ }
+
+ // Finish appending the DN suffix information
+ $dn .= ',' . $suffix;
+
+ // Modify the existing record
+ $res = @ldap_mod_replace($this->_LDAP, $dn, $entry);
+ if ($res === false) {
+ return PEAR::raiseError(sprintf(_("Unable to modify record. Reason: %s"), @ldap_error($this->_LDAP)));
+ }
+
+ } else {
+ // Must be a new record
+ // Append the suffix to the DN to make it fully qualified
+ $dn .= ',' . $suffix;
+ // Create the necessary objectClass definitions
+ $entry['objectclass'] = array();
+ $entry['objectclass'][] = 'top';
+ $entry['objectclass'][] = 'dnszone';
+ if ($rectype != 'soa') {
+ // An objectclass to hold the non-SOA record information
+ $entry['objectclass'][] = 'dnsrrset';
+ }
+ $res = @ldap_add($this->_LDAP, $dn, $entry);
+ if ($res === false) {
+ return PEAR::raiseError(sprintf(_("Unable to add record to LDAP. Reason: %s"), @ldap_error($this->_LDAP)));
+ }
+ }
+
+ return $id;
+ }
+
+ function cleanFilterString($string) {
+ return preg_replace(
+ array('/\*/', '/\(/', '/\)/', '/\x00/'),
+ array('\2a', '\28', '\29', '\00'),
+ $string
+ );
+ }
+
+ function cleanDNString($string) {
+ return preg_replace(
+ array('/=/', '/,/', '/\+/'),
+ array('-', '~', ''),
+ $string);
+ }
+
+ /**
+ * Attempts to open a connection to the LDAP server.
+ *
+ * @access private
+ *
+ * @return boolean True on success; exits (Horde::fatal()) on error.
+ *
+ * @access private
+ */
+ function _connect()
+ {
+ if (!$this->_connected) {
+ Horde::assertDriverConfig($this->_params, 'storage',
+ array('hostspec', 'basedn', 'binddn', 'password', 'dn'));
+
+ $port = (isset($this->_params['port'])) ?
+ $this->_params['port'] : 389;
+
+ $this->_LDAP = ldap_connect($this->_params['hostspec'], $port);
+ if (!$this->_LDAP) {
+ Horde::fatal("Unable to connect to LDAP server $hostname on $port", __FILE__, __LINE__);
+ }
+ $res = ldap_set_option($this->_LDAP, LDAP_OPT_PROTOCOL_VERSION, $this->_params['version']);
+ if ($res === false) {
+ return PEAR::raiseError("Unable to set LDAP protocol version");
+ }
+ $res = ldap_bind($this->_LDAP, $this->_params['binddn'], $this->_params['password']);
+ if ($res === false) {
+ return PEAR::raiseError("Unable to bind to the LDAP server. Check authentication credentials.");
+ }
+
+ $this->_connected = true;
+ }
+ return true;
+ }
+}
--- /dev/null
+<?php
+/**
+ * The Beatnik_Driver_sql class implements a SQL driver for managing DNS records
+ * in the PowerDNS generic SQL driver. The PowerDNS generic SQL driver aims to
+ * support MySQL, PostgreSQL, SQLite and Oracle. This driver attempts to do the
+ * same as long as the default queries are used.
+ *
+ * $Horde: beatnik/lib/Driver/pdnsgsql.php,v 1.4 2009/07/03 10:05:30 duck Exp $
+ *
+ * Copyright 2008 The Horde Project <http://www.horde.org>
+ *
+ * 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 Ben Klang <ben@alkaloid.net>
+ * @package Beatnik
+ */
+
+class Beatnik_Driver_pdnsgsql extends Beatnik_Driver
+{
+ /**
+ * Hash containing connection parameters.
+ *
+ * @var array
+ */
+ var $_params = array();
+
+ /**
+ * Handle for the current database connection.
+ *
+ * @var DB
+ */
+ var $_db;
+
+ /**
+ * Handle for the current database connection, used for writing. Defaults
+ * to the same handle as $_db if a separate write database is not required.
+ *
+ * @var DB
+ */
+ var $_write_db;
+
+ /**
+ * Boolean indicating whether or not we're connected to the SQL server.
+ *
+ * @var boolean
+ */
+ var $_connected = false;
+
+ /**
+ * Constructs a new Beatnik DB driver object.
+ *
+ * @param array $params A hash containing connection parameters.
+ */
+ function Beatnik_Driver_pdnsgsql($params = array())
+ {
+ parent::Beatnik_Driver($params);
+ }
+
+ /**
+ * Gets all zones
+ *
+ * @access private
+ *
+ * @return array Array with zone records numerically indexed
+ */
+ function _getDomains()
+ {
+ if (is_a(($result = $this->_connect()), 'PEAR_Error')) {
+ Horde::logMessage($result, __FILE__, __LINE__, PEAR_LOG_ERR);
+ return PEAR::raiseError(_("Internal database error. Details have been logged for the administrator."));
+ }
+
+ $query = 'SELECT d.id, d.name AS name, r.content AS content, ' .
+ 'r.ttl AS ttl FROM ' . $this->_params['domains_table'] .
+ ' AS d JOIN ' . $this->_params['records_table'] . ' AS r ON ' .
+ 'r.domain_id = d.id WHERE r.type = \'SOA\'';
+ Horde::logMessage('SQL Query by Beatnik_Driver_pdnsgsql::_getDomains(): ' . $query, __FILE__, __LINE__, PEAR_LOG_DEBUG);
+
+ $domainlist = $this->_db->getAll($query, null, DB_FETCHMODE_ASSOC);
+ if (is_a($domainlist, 'PEAR_Error')) {
+ Horde::logMessage($domainlist, __FILE__, __LINE__, PEAR_LOG_ERR);
+ return array();
+ }
+
+ $results = array();
+ foreach ($domainlist as $info) {
+ $soa = explode(' ', $info['content']);
+ if (count($soa) != 7) {
+ Horde::logMessage(sprintf('Invalid SOA found for %s, skipping.', $info['name']), __FILE__, __LINE__, PEAR_LOG_WARNING);
+ continue;
+ }
+
+ $d = array();
+ $d['id'] = $info['id'];
+ $d['zonename'] = $info['name'];
+ $d['zonemaster'] = $d['zonens'] = $soa[0];
+ $d['admin'] = $d['zonecontact'] = $soa[1];
+ $d['serial'] = $soa[2];
+ $d['refresh'] = $soa[3];
+ $d['retry'] = $soa[4];
+ $d['expire'] = $soa[5];
+ $d['minimum'] = $soa[6];
+ $results[] = $d;
+ }
+
+ return $results;
+ }
+
+ /**
+ * Return SOA for a single domain
+ *
+ * @param string $domain Domain for which to return SOA information
+ *
+ * @return array Domain SOA
+ */
+ function getDomain($domainname)
+ {
+ if (is_a(($result = $this->_connect()), 'PEAR_Error')) {
+ Horde::logMessage($result, __FILE__, __LINE__, PEAR_LOG_ERR);
+ return PEAR::raiseError(_("Internal database error. Details have been logged for the administrator."));
+ }
+
+ $query = 'SELECT d.id AS id, d.name AS name, r.content AS content, ' .
+ 'r.ttl AS ttl FROM ' . $this->_params['domains_table'] .
+ ' AS d JOIN ' . $this->_params['records_table'] . ' AS r ON ' .
+ 'r.domain_id = d.id WHERE r.type = \'SOA\' AND d.name = ?';
+ $values = array($domainname);
+ Horde::logMessage('SQL Query by Beatnik_Driver_pdnsgsql::getDomain(): ' . $query, __FILE__, __LINE__, PEAR_LOG_DEBUG);
+
+ $result = $this->_db->getAll($query, $values, DB_FETCHMODE_ASSOC);
+ if (is_a($result, 'PEAR_Error')) {
+ Horde::logMessage($result, __FILE__, __LINE__, PEAR_LOG_ERR);
+ return PEAR::raiseError(_("An error occurred while searching the database. Details have been logged for the administrator."), __FILE__, __LINE__, PEAR_LOG_ERR);
+ }
+
+ if (count($result) != 1) {
+ return PEAR::raiseError(_("Too many domains matched that name. Contact your administrator."));
+ }
+
+ $info = $result[0];
+
+ $soa = explode(' ', $info['content']);
+ if (count($soa) != 7) {
+ Horde::logMessage(sprintf('Invalid SOA found for %s, skipping.', $info['name']), __FILE__, __LINE__, PEAR_LOG_WARN);
+ return PEAR::raiseError(_("Corrupt SOA found for zone. Contact your administrator."), __FILE__, __LINE__, PEAR_LOG_ERR);
+ }
+
+ $ret = array();
+ $ret['id'] = $info['id'];
+ $ret['zonename'] = $info['name'];
+ $ret['zonemaster'] = $soa[0];
+ $ret['admin'] = $soa[1];
+ $ret['serial'] = $soa[2];
+ $ret['refresh'] = $soa[3];
+ $ret['retry'] = $soa[4];
+ $ret['expire'] = $soa[5];
+ $ret['minimum'] = $soa[6];
+
+ return $ret;
+ }
+
+ /**
+ * Gets all records associated with the given zone
+ *
+ * @param string $domain Retrieve records for this domain
+ *
+ * @return array Array with zone records
+ */
+ function getRecords($domain)
+ {
+ if (is_a(($result = $this->_connect()), 'PEAR_Error')) {
+ Horde::logMessage($result, __FILE__, __LINE__, PEAR_LOG_ERR);
+ return PEAR::raiseError(_("Internal database error. Details have been logged for the administrator."));
+ }
+
+ $zonedata = array();
+
+ $query = 'SELECT d.id AS domain_id, r.id AS id, d.name AS domain, ' .
+ 'r.name AS name, r.type AS type, r.content AS content, ' .
+ 'r.ttl AS ttl, r.prio AS prio FROM ' .
+ $this->_params['domains_table'] . ' AS d JOIN ' .
+ $this->_params['records_table'] . ' AS r ON ' .
+ 'd.id = r.domain_id AND d.name = ?';
+ $values = array($domain);
+
+ Horde::logMessage('SQL Query by Beatnik_Driver_pdnsgsql::getRecords(): ' . $query, __FILE__, __LINE__, PEAR_LOG_DEBUG);
+ $result = $this->_db->getAll($query, $values, DB_FETCHMODE_ASSOC);
+ if (is_a($result, 'PEAR_Error')) {
+ Horde::logMessage($result, __FILE__, __LINE__, PEAR_LOG_ERR);
+ return PEAR::raiseError(_("An error occurred while searching the database. Details have been logged for the administrator."), __FILE__, __LINE__, PEAR_LOG_ERR);
+ }
+
+ foreach ($result as $rec) {
+ $type = strtolower($rec['type']);
+ if (!isset($zonedata[$type])) {
+ $zonedata[$type] = array();
+ }
+
+ $tmp = array();
+ $tmp['id'] = $rec['id'];
+ $tmp['ttl'] = $rec['ttl'];
+ switch($type) {
+ case 'soa':
+ $soa = explode(' ', $rec['content']);
+ if (count($soa) != 7) {
+ Horde::logMessage(sprintf('Invalid SOA found for %s, skipping.', $info['name']), __FILE__, __LINE__, PEAR_LOG_WARNING);
+ }
+
+ $tmp['zonename'] = $rec['name'];
+ $tmp['zonens'] = $soa[0];
+ $tmp['zonecontact'] = $soa[1];
+ $tmp['serial'] = $soa[2];
+ $tmp['refresh'] = $soa[3];
+ $tmp['retry'] = $soa[4];
+ $tmp['expire'] = $soa[5];
+ $tmp['minimum'] = $soa[6];
+ break;
+
+ case 'a':
+ $tmp['hostname'] = $rec['name'];
+ $tmp['ipaddr'] = $rec['content'];
+ break;
+
+ case 'ptr':
+ $tmp['hostname'] = $rec['name'];
+ $tmp['pointer'] = $rec['content'];
+ break;
+
+ case 'mx':
+ $tmp['pointer'] = $rec['content'];
+ $tmp['pref'] = $rec['prio'];
+ break;
+
+ case 'cname':
+ $tmp['hostname'] = $rec['name'];
+ $tmp['pointer'] = $rec['content'];
+ break;
+
+ case 'ns':
+ $tmp['hostname'] = $rec['name'];
+ $tmp['pointer'] = $rec['content'];
+ break;
+
+ case 'srv':
+ $srv = preg_split('/\s+/', trim($rec['content']));
+ if (count($srv) != 3) {
+ Horde::logMessage(sprintf('Invalid SRV data found for %s, skipping.', $rec['name']), __FILE__, __LINE__, PEAR_LOG_WARNING);
+ continue;
+ }
+ $tmp['hostname'] = $rec['name'];
+ $tmp['weight'] = $srv[0];
+ $tmp['port'] = $srv[1];
+ $tmp['pointer'] = $srv[2];
+ $tmp['priority'] = $rec['prio'];
+ break;
+
+ case 'txt':
+ $tmp['hostname'] = $rec['name'];
+ $tmp['text'] = $rec['content'];
+ break;
+ }
+
+ $zonedata[$type][] = $tmp;
+ }
+
+ return $zonedata;
+ }
+
+ /**
+ * Saves a new or edited record to the DNS backend
+ *
+ * @access private
+ *
+ * @param array $info Array of record data
+ *
+ * @return boolean true on success, PEAR::raiseError on error
+ */
+ function _saveRecord($info)
+ {
+ if (is_a(($result = $this->_connect()), 'PEAR_Error')) {
+ Horde::logMessage($result, __FILE__, __LINE__, PEAR_LOG_ERR);
+ return PEAR::raiseError(_("Internal database error. Details have been logged for the administrator."));
+ }
+
+ $change_date = time();
+ $domain_id = $_SESSION['beatnik']['curdomain']['id'];
+
+ switch($info['rectype']) {
+ case 'soa':
+ if (empty($info['refresh'])) {
+ // 24 hours
+ $info['refresh'] = 86400;
+ }
+ if (empty($info['retry'])) {
+ // 2 hours
+ $info['retry'] = 7200;
+ }
+ if (empty($info['expire'])) {
+ // 1000 hours
+ $info['expire'] = 3600000;
+ }
+ if (empty($info['minimum'])) {
+ // 2 days
+ $info['miniumum'] = 172800;
+ }
+
+ $name = $info['zonename'];
+ $type = 'SOA';
+ $content = $info['zonens'] . ' ' . $info['zonecontact'] . ' ' .
+ $info['serial'] . ' ' . $info['refresh'] . ' ' .
+ $info['retry'] . ' ' . $info['expire'] . ' ' .
+ $info['minimum'];
+ $ttl = $info['ttl'];
+ $prio = null;
+ break;
+
+ case 'a':
+ $name = $info['hostname'];
+ $type = 'A';
+ $content = $info['ipaddr'];
+ $ttl = $info['ttl'];
+ $prio = null;
+ break;
+
+ case 'ptr':
+ $name = $info['hostname'];
+ $type = 'PTR';
+ $content = $info['pointer'];
+ $ttl = $info['ttl'];
+ $prio = null;
+ break;
+
+ case 'mx':
+ $name = $_SESSION['beatnik']['curdomain']['zonename'];
+ $type = 'MX';
+ $content = $info['pointer'];
+ $ttl = $info['ttl'];
+ $prio = $info['pref'];
+ break;
+
+ case 'cname':
+ $name = $info['hostname'];
+ $type = 'CNAME';
+ $content = $info['pointer'];
+ $ttl = $info['ttl'];
+ $prio = null;
+ break;
+
+ case 'ns':
+ $name = $info['hostname'];
+ $type = 'NS';
+ $content = $info['pointer'];
+ $ttl = $info['ttl'];
+ $prio = null;
+ break;
+
+ case 'srv':
+ $name = $info['hostname'];
+ $type = 'SRV';
+ $content = $info['weight'] . ' ' . $info['port'] . ' ' .
+ $info['pointer'];
+ $ttl = $info['ttl'];
+ $prio = $info['priority'];
+ break;
+
+ case 'txt':
+ $name = $info['hostname'];
+ $type = 'TXT';
+ $content = $info['text'];
+ $ttl = $info['ttl'];
+ $prio = null;
+ break;
+ }
+
+ if (!empty($info['id'])) {
+ $query = 'UPDATE ' . $this->_params['records_table'] . ' SET ' .
+ 'name = ?, type = ?, content = ?, ttl = ?, ' .
+ 'prio = ' . (empty($prio) ? 'NULL' : $prio) . ', ' .
+ 'change_date = ? WHERE id = ?';
+ $values = array($name, $type, $content, $ttl);
+ if (!empty($prio)) {
+ $values[] = $prio;
+ }
+ $values[] = $change_date;
+ $values[] = $info['id'];
+ } else {
+ $query = 'INSERT INTO ' . $this->_params['records_table'] . ' ' .
+ '(domain_id, name, type, content, ttl, prio, ' .
+ 'change_date) VALUES (?, ?, ?, ?, ?, ' .
+ (empty($prio) ? 'NULL' : '?') . ', ?)';
+ $values = array($domain_id, $name, $type, $content, $ttl);
+ if (!empty($prio)) {
+ $values[] = $prio;
+ }
+ $values[] = $change_date;
+ }
+
+ Horde::logMessage('SQL Query by Beatnik_Driver_pdnsgsql::_saveRecord(): ' . $query, __FILE__, __LINE__, PEAR_LOG_DEBUG);
+ $result = $this->_write_db->query($query, $values);
+ if (is_a($result, 'PEAR_Error')) {
+ return $result;
+ }
+
+ return true;
+ }
+
+ /**
+ * Delete record from backend
+ *
+ * @access private
+ *
+ * @param array $data Reference to array of record data to be deleted
+ *
+ * @return boolean true on success, PEAR::Error on error
+ */
+ function _deleteRecord($data)
+ {
+ if (is_a(($result = $this->_connect()), 'PEAR_Error')) {
+ Horde::logMessage($result, __FILE__, __LINE__, PEAR_LOG_ERR);
+ return PEAR::raiseError(_("Internal database error. Details have been logged for the administrator."));
+ }
+
+ return PEAR::raiseError(_("Not implemented."));
+ }
+
+ /**
+ * Attempts to open a persistent connection to the SQL server.
+ *
+ * @access private
+ *
+ * @return boolean True on success; exits (Horde::fatal()) on error.
+ */
+ function _connect()
+ {
+ if ($this->_connected) {
+ return true;
+ }
+
+ $result = Horde_Util::assertDriverConfig($this->_params, array('phptype'),
+ 'PowerDNS Generic SQL',
+ array('driver' => 'pdnsgsql'));
+ if (is_a($result, 'PEAR_Error')) {
+ Horde::logMessage($result, __FILE__, __LINE__, PEAR_LOG_ERR);
+ return $result;
+ }
+
+ if (!isset($this->_params['domains_table'])) {
+ $this->_params['domains_table'] = 'domains';
+ }
+ if (!isset($this->_params['records_table'])) {
+ $this->_params['records_table'] = 'records';
+ }
+
+ /* Connect to the SQL server using the supplied parameters. */
+ require_once 'DB.php';
+ $this->_write_db = &DB::connect($this->_params,
+ array('persistent' => !empty($this->_params['persistent'])));
+ if (is_a($this->_write_db, 'PEAR_Error')) {
+ Horde::fatal($this->_write_db, __FILE__, __LINE__);
+ }
+
+ // Set DB portability options.
+ switch ($this->_write_db->phptype) {
+ case 'mssql':
+ $this->_write_db->setOption('portability', DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_ERRORS | DB_PORTABILITY_RTRIM);
+ break;
+ default:
+ $this->_write_db->setOption('portability', DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_ERRORS);
+ }
+
+ /* Check if we need to set up the read DB connection seperately. */
+ if (!empty($this->_params['splitread'])) {
+ $params = array_merge($this->_params, $this->_params['read']);
+ $this->_db = &DB::connect($params,
+ array('persistent' => !empty($params['persistent'])));
+ if (is_a($this->_db, 'PEAR_Error')) {
+ Horde::fatal($this->_db, __FILE__, __LINE__);
+ }
+
+ // Set DB portability options.
+ switch ($this->_db->phptype) {
+ case 'mssql':
+ $this->_db->setOption('portability', DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_ERRORS | DB_PORTABILITY_RTRIM);
+ break;
+ default:
+ $this->_db->setOption('portability', DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_ERRORS);
+ }
+
+ } else {
+ /* Default to the same DB handle for the writer too. */
+ $this->_db =& $this->_write_db;
+ }
+
+ $this->_connected = true;
+
+ return true;
+ }
+
+ /**
+ * Disconnects from the SQL server and cleans up the connection.
+ *
+ * @access private
+ *
+ * @return boolean True on success, false on failure.
+ */
+ function _disconnect()
+ {
+ if ($this->_connected) {
+ $this->_connected = false;
+ $this->_db->disconnect();
+ $this->_write_db->disconnect();
+ }
+
+ return true;
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * $Horde: beatnik/lib/Driver/sql.php,v 1.21 2008/08/20 08:56:53 duck Exp $
+ *
+ * Copyright 2006-2008 The Horde Project (http://www.horde.org/)
+ *
+ * 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 Duck <duck@obala.net>
+ * @package Beatnik
+ */
+
+class Beatnik_Driver_sql extends Beatnik_Driver
+{
+ /**
+ * Hash containing connection parameters.
+ *
+ * @var array
+ */
+ var $_params = array();
+
+ /**
+ * Handle for the current database connection.
+ *
+ * @var DB
+ */
+ var $_db;
+
+ /**
+ * Handle for the current database connection, used for writing. Defaults
+ * to the same handle as $_db if a separate write database is not required.
+ *
+ * @var DB
+ */
+ var $_write_db;
+
+ /**
+ * Boolean indicating whether or not we're connected to the SQL server.
+ *
+ * @var boolean
+ */
+ var $_connected = false;
+
+ /**
+ * Constructs a new Beatnik DB driver object.
+ *
+ * @param array $params A hash containing connection parameters.
+ */
+ function Beatnik_Driver_sql($params = array())
+ {
+ parent::Beatnik_Driver($params);
+ $this->_connect();
+ }
+
+ /**
+ * Get any record types available specifically in this driver.
+ *
+ * @return array Records available only to this driver
+ */
+ function getRecDriverTypes()
+ {
+ return array();
+ }
+
+
+ /**
+ * Get any fields available specifically in this driver by record type.
+ *
+ * @param string $type Record type for which fields should be returned
+ *
+ * @return array Fields specific to this driver
+ */
+ function getRecDriverFields($type) {
+
+ return array();
+ }
+
+ /**
+ * Gets all zones
+ *
+ * @access private
+ *
+ * @return array Array with zone records numerically indexed
+ */
+ function _getDomains()
+ {
+ $query = 'SELECT * FROM beatnik_soa ORDER BY zonename';
+ return $this->_db->getAll($query, null, DB_FETCHMODE_ASSOC);
+ }
+
+ /**
+ * Return SOA for a single domain
+ *
+ * @param string $domain Domain for which to return SOA information
+ *
+ * @return array Domain SOA
+ */
+ function getDomain($domainname)
+ {
+ $query = 'SELECT * FROM beatnik_soa WHERE zonename = ? ORDER BY zonename';
+ return $this->_db->getRow($query, array($domainname), DB_FETCHMODE_ASSOC);
+ }
+
+ /**
+ * Gets all records associated with the given zone
+ *
+ * @param string $domain Retrieve records for this domain
+ *
+ * @return array Array with zone records
+ */
+ function getRecords($domain)
+ {
+ $zonedata = array();
+ $params = array($domain);
+
+ foreach (array_keys(Beatnik::getRecTypes()) as $type) {
+ if ($type == 'soa') {
+ continue;
+ }
+ if ($type == 'mx') {
+ $order = 'pointer';
+ } else {
+ $order = 'hostname';
+ }
+
+ $query = 'SELECT * FROM beatnik_' . $type . ' WHERE zonename = ? ORDER BY ' . $order . ' ASC';
+ $result = $this->_db->getAll($query, $params, DB_FETCHMODE_ASSOC);
+ if (is_a($result, 'PEAR_Error') || empty($result)) {
+ continue;
+ }
+
+ $zonedata[$type] = $result;
+ }
+
+ return $zonedata;
+ }
+
+ /**
+ * Saves a new or edited record to the DNS backend
+ *
+ * @access private
+ *
+ * @param array $info Array of record data
+ *
+ * @return boolean true on success, PEAR::raiseError on error
+ */
+ function _saveRecord($info)
+ {
+ $fields = array_keys(Beatnik::getRecFields($info['rectype']));
+ $params = array();
+ foreach ($fields as $i => $key) {
+ if (!isset($info[$key])) {
+ unset($fields[$i]);
+ continue;
+ }
+ $params[$key] = $info[$key];
+ }
+
+ if (isset($params['id']) && $params['id']) {
+ unset($params['id'], $fields[0]);
+ $query = 'UPDATE beatnik_' . $info['rectype'] . ' SET ';
+ foreach ($fields as $key) {
+ $query .= $key . ' = ?, ';
+ $params[$key] = $info[$key];
+ }
+ $query = substr($query, 0, -2) . ' WHERE id = ?';
+ $params['id'] = $info['id'];
+ } else {
+ unset($params['id'], $fields[0]);
+ if ($info['rectype'] != 'soa') {
+ $fields[] = 'zonename';
+ $params['zonename'] = $_SESSION['beatnik']['curdomain']['zonename'];
+ }
+ $query = 'INSERT INTO beatnik_' . $info['rectype'] . ' (' . implode(', ', $fields) . ') ' .
+ ' VALUES (' . substr(str_repeat('?, ', sizeof($params)), 0, -2) . ')';
+ }
+
+ return $this->_write_db->query($query, $params);
+ }
+
+ /**
+ * Delete record from backend
+ *
+ * @access private
+ *
+ * @param array $data Reference to array of record data to be deleted
+ *
+ * @return boolean true on success, PEAR::Error on error
+ */
+ function _deleteRecord($data)
+ {
+ // delete just one record
+ if ($data['rectype'] != 'soa') {
+ return $this->_write_db->query('DELETE FROM beatnik_' . $data['rectype'] . ' WHERE id = ?', array($data['id']));
+ }
+
+ // delete all subrecords
+ $params = array($data['curdomain']);
+ foreach (array_keys(Beatnik::getRecTypes()) as $type) {
+ if ($type == 'soa') {
+ continue;
+ }
+ $result = $this->_write_db->query('DELETE FROM beatnik_' . $type . ' WHERE zonename = ?', $params);
+ if (is_a($result, 'PEAR_Error')) {
+ return $result;
+ }
+ }
+
+ // we are cuccesfull so, delete even soa
+ return $this->_write_db->query('DELETE FROM beatnik_soa WHERE zonename = ?', $params);
+ }
+
+ /**
+ * Attempts to open a persistent connection to the SQL server.
+ *
+ * @access private
+ *
+ * @return boolean True on success; exits (Horde::fatal()) on error.
+ */
+ function _connect()
+ {
+ if ($this->_connected) {
+ return true;
+ }
+
+ Horde::assertDriverConfig($this->_params, 'storage',
+ array('phptype', 'charset'));
+
+ if (!isset($this->_params['database'])) {
+ $this->_params['database'] = '';
+ }
+ if (!isset($this->_params['username'])) {
+ $this->_params['username'] = '';
+ }
+ if (!isset($this->_params['hostspec'])) {
+ $this->_params['hostspec'] = '';
+ }
+
+ /* Connect to the SQL server using the supplied parameters. */
+ require_once 'DB.php';
+ $this->_write_db = &DB::connect($this->_params,
+ array('persistent' => !empty($this->_params['persistent'])));
+ if (is_a($this->_write_db, 'PEAR_Error')) {
+ Horde::fatal($this->_write_db, __FILE__, __LINE__);
+ }
+
+ // Set DB portability options.
+ switch ($this->_write_db->phptype) {
+ case 'mssql':
+ $this->_write_db->setOption('portability', DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_ERRORS | DB_PORTABILITY_RTRIM);
+ break;
+ default:
+ $this->_write_db->setOption('portability', DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_ERRORS);
+ }
+
+ /* Check if we need to set up the read DB connection seperately. */
+ if (!empty($this->_params['splitread'])) {
+ $params = array_merge($this->_params, $this->_params['read']);
+ $this->_db = &DB::connect($params,
+ array('persistent' => !empty($params['persistent'])));
+ if (is_a($this->_db, 'PEAR_Error')) {
+ Horde::fatal($this->_db, __FILE__, __LINE__);
+ }
+
+ // Set DB portability options.
+ switch ($this->_db->phptype) {
+ case 'mssql':
+ $this->_db->setOption('portability', DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_ERRORS | DB_PORTABILITY_RTRIM);
+ break;
+ default:
+ $this->_db->setOption('portability', DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_ERRORS);
+ }
+
+ } else {
+ /* Default to the same DB handle for the writer too. */
+ $this->_db =& $this->_write_db;
+ }
+
+ $this->_connected = true;
+
+ return true;
+ }
+}
--- /dev/null
+<?php
+/**
+ * $Horde: beatnik/lib/Forms/Autogenerate.php,v 1.6 2009/07/03 10:05:30 duck Exp $
+ *
+ * Copyright 2006-2007 Alkaloid Networks <http://www.alkaloid.net>
+ *
+ * See the enclosed file LICENSE for license information (GPL). If you
+ * did not receive this file, see http://www.horde.org/licenses/gpl.php.
+ *
+ * @author Ben Klang <ben@alkaloid.net>
+ * @package Beatnik
+ */
+class Autogenerate extends Horde_Form
+{
+ /**
+ */
+ function Autogenerate(&$vars)
+ {
+ require BEATNIK_BASE . '/config/autogenerate.php';
+
+ parent::Horde_Form($vars, _("Choose a template for autogenerating the records:"), 'autogenerate');
+ $this->setButtons(array(_("Autogenerate"), _("Cancel")));
+
+ // Create an array of template => description for the enum
+ $template_keys = array_keys($templates);
+ foreach ($template_keys as $template) {
+ $t[$template] = $templates[$template]['description'];
+ }
+ $this->addVariable(_("Template"), 'template', 'enum', true, false, null, array($t, true));
+
+ return true;
+ }
+}
--- /dev/null
+<?php
+/**
+ * $Horde: beatnik/lib/Forms/DeleteRecord.php,v 1.5 2009/07/03 10:05:30 duck Exp $
+ *
+ * Copyright 2005-2007 Alkaloid Networks <http://www.alkaloid.net>
+ *
+ * See the enclosed file LICENSE for license information (GPL). If you
+ * did not receive this file, see http://www.horde.org/licenses/gpl.php.
+ *
+ * @author Ben Klang <ben@alkaloid.net>
+ * @package Beatnik
+ */
+class DeleteRecord extends Horde_Form
+{
+ /**
+ */
+ function DeleteRecord(&$vars)
+ {
+ parent::Horde_Form($vars, _("Are you sure you want to delete this record?"));
+
+ $rectype = $vars->get('rectype');
+ $types = Beatnik::getRecTypes();
+
+ $this->addHidden('', 'id', 'text', $vars->get('id'));
+ $this->addHidden('', 'curdomain', 'text', $vars->get('curdomain'));
+ $this->addHidden('', 'rectype', 'text', $vars->get('rectype'));
+ $this->addVariable(_("Type"), 'rectype', 'text', false, true);
+
+ $recset = Beatnik::getRecFields($rectype);
+ foreach ($recset as $field => $fdata) {
+ if ($fdata['type'] != 'hidden' && ($fdata['infoset'] == 'basic' || $_SESSION['beatnik']['expertmode'])) {
+ $this->addVariable(_($fdata['description']), $field, $fdata['type'], false, true);
+ }
+
+ }
+
+ $this->setButtons(array(_("Delete"), _("Cancel")));
+
+ return true;
+ }
+}
--- /dev/null
+<?php
+/**
+ * $Horde: beatnik/lib/Forms/EditRecord.php,v 1.8 2009/07/03 10:05:30 duck Exp $
+ *
+ * Copyright 2005-2007 Alkaloid Networks <http://www.alkaloid.net>
+ *
+ * See the enclosed file LICENSE for license information (GPL). If you
+ * did not receive this file, see http://www.horde.org/licenses/gpl.php.
+ *
+ * @author Ben Klang <ben@alkaloid.net>
+ * @package Beatnik
+ */
+class EditRecord extends Horde_Form
+{
+ /**
+ */
+ function EditRecord(&$vars)
+ {
+ $isnew = !$vars->exists('id');
+ $rectype = $vars->get('rectype');
+ $recset = Beatnik::getRecFields($rectype);
+ if ($isnew) {
+ // Pre-load the field defaults on a new record
+ foreach ($recset as $field => $fdata) {
+ if (isset($fdata['default'])) {
+ $vars->set($field, $fdata['default']);
+ }
+ }
+ }
+
+ parent::Horde_Form($vars, $isnew ? _("Add DNS Record") : _("Edit DNS Record"));
+
+ $types = Beatnik::getRecTypes();
+ if (empty($_SESSION['beatnik']['curdomain'])) {
+ // Without an active domain, limit the form to creating a new zone.
+ $types = array('soa' => _('SOA (Start of Authority)'));
+ }
+ $action = &Horde_Form_Action::factory('reload');
+ $select = &$this->addVariable(_("Record Type"), 'rectype', 'enum', true,
+ false, null, array($types, true));
+ $select->setAction($action);
+ $select->setOption('trackchange', true);
+
+ // Do not show record-specific fields until a record type is chosen
+ if (!$rectype) {
+ return true;
+ }
+
+ foreach ($recset as $field => $fdata) {
+ if ($fdata['type'] == 'hidden' || ($fdata['infoset'] != 'basic' &&
+ !$_SESSION['beatnik']['expertmode'])) {
+ $this->addHidden(_($fdata['description']), $field, 'text',
+ $fdata['required']);
+ } else {
+ $this->addVariable(_($fdata['description']), $field,
+ $fdata['type'], $fdata['required']);
+ }
+
+ }
+
+ return true;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Beatnik base inclusion file.
+ *
+ * $Horde: beatnik/lib/base.php,v 1.31 2009/09/15 09:20:03 duck Exp $
+ *
+ * Copyright 2005-2007 Alkaloid Networks <http://www.alkaloid.net>
+ *
+ * This file brings in all of the dependencies that every Beatnik
+ * script will need and sets up objects that all scripts use.
+ *
+ * @author Ben Klang <ben@alkaloid.net>
+ * @package Beatnik
+ */
+
+// Check for a prior definition of HORDE_BASE (perhaps by an
+// auto_prepend_file definition for site customization).
+if (!defined('HORDE_BASE')) {
+ define('HORDE_BASE', dirname(__FILE__) . '/../..');
+}
+// Load the Horde Framework core, and set up inclusion paths.
+require_once HORDE_BASE . '/lib/core.php';
+
+// Registry.
+$registry = Horde_Registry::singleton();
+
+try {
+ $registry->pushApp('beatnik', array('check_perms' => (Horde_Util::nonInputVar('beatnik_authentication') != 'none')));
+} catch (Horde_Exception $e) {
+ if ($e->getCode() == Horde_Registry::PERMISSION_DENIED) {
+ Horde_Auth::authenticateFailure('beatnik', $e);
+ }
+ Horde::fatal($e, __FILE__, __LINE__, false);
+}
+
+$conf = &$GLOBALS['conf'];
+define('BEATNIK_TEMPLATES', $registry->get('templates'));
+
+// Find the base file path of Beatnik.
+if (!defined('BEATNIK_BASE')) {
+ define('BEATNIK_BASE', dirname(__FILE__) . '/..');
+}
+
+// Notification system.
+$notification = Horde_Notification::singleton();
+$notification->attach('status');
+
+// Beatnik base libraries.
+require_once BEATNIK_BASE . '/lib/Beatnik.php';
+require_once BEATNIK_BASE . '/lib/Driver.php';
+
+$GLOBALS['beatnik_driver'] = Beatnik_Driver::factory();
+if (is_a($GLOBALS['beatnik_driver'], 'PEAR_Error')) {
+ Horde::fatal($GLOBALS['beatnik_driver'], __FILE__, __LINE__);
+}
+
+// Get a list of domains to work with
+$domains = $GLOBALS['beatnik_driver']->getDomains();
+
+// Jump to new domain
+if (Horde_Util::getFormData('curdomain') !== null && !empty($domains)) {
+ $domain = $GLOBALS['beatnik_driver']->getDomain(Horde_Util::getFormData('curdomain'));
+ if (is_a($domain, 'PEAR_Error')) {
+ $notification->push($domain->getMessage() . ': ' . $domain->getDebugInfo(), 'horde.error');
+ $domain = $domains[0];
+ }
+
+ $_SESSION['beatnik']['curdomain'] = $domain;
+}
+
+// Determine if the user should see basic or advanced options
+if (!isset($_SESSION['beatnik']['expertmode'])) {
+ $_SESSION['beatnik']['expertmode'] = false;
+} elseif (Horde_Util::getFormData('expertmode') == 'toggle') {
+ if ($_SESSION['beatnik']['expertmode']) {
+ $notification->push(_('Expert Mode off'), 'horde.message');
+ $_SESSION['beatnik']['expertmode'] = false;
+ } else {
+ $notification->push(_('Expert Mode ON'), 'horde.warning');
+ $_SESSION['beatnik']['expertmode'] = true;
+ }
+}
+
+// Initialize the page marker
+if (!isset($_SESSION['beatnik']['curpage'])) {
+ $_SESSION['beatnik']['curpage'] = 0;
+}
+
+// Start output compression.
+if (!Horde_Util::nonInputVar('no_compress')) {
+ Horde::compressOutput();
+}
+
--- /dev/null
+<?php define('BEATNIK_VERSION', 'H4 (1.0-cvs)') ?>
--- /dev/null
+<?php
+/**
+ * $Horde: beatnik/listzones.php,v 1.25 2009/07/14 00:25:28 mrubinsk Exp $
+ *
+ * Copyright 2005-2007 Ben Klang <ben@alkaloid.net>
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ */
+
+require_once dirname(__FILE__) . '/lib/base.php';
+require_once 'Horde/Prefs/CategoryManager.php';
+
+// Unset the current domain since we are generating a zone list
+$_SESSION['beatnik']['curdomain'] = null;
+
+// Set up categories
+$cManager = new Prefs_CategoryManager();
+$categories = $cManager->get();
+$colors = $cManager->colors();
+$fgcolors = $cManager->fgColors();
+
+// Page results
+// Check for and store the current page in the session
+$page = Horde_Util::getGet('page', $_SESSION['beatnik']['curpage']);
+$_SESSION['beatnik']['curpage'] = $page;
+
+// Create the Pager UI
+$pager_vars = Horde_Variables::getDefaultVariables();
+$pager_vars->set('page', $page);
+$perpage = $prefs->getValue('domains_perpage');
+$pager = new Horde_UI_Pager('page', $pager_vars,
+ array('num' => count($domains),
+ 'url' => 'listzones.php',
+ 'page_count' => 10,
+ 'perpage' => $perpage));
+
+// Limit the domain list to the current page
+$domains = array_slice($domains, $page*$perpage, $perpage);
+
+$img_dir = $registry->getImageDir('horde');
+
+// Hide fields that the user does not want to see
+$fields = Beatnik::getRecFields('soa');
+foreach ($fields as $field_id => $field) {
+ if ($field['type'] == 'hidden' ||
+ ($field['infoset'] != 'basic' && !$_SESSION['beatnik']['expertmode'])) {
+ unset($fields[$field_id]);
+ }
+}
+
+// Add javascript navigation and striping
+Horde::addScriptFile('beatnik.js');
+Horde::addScriptFile('stripe.js', 'horde', true);
+
+// Initialization complete. Render the page.
+require BEATNIK_TEMPLATES . '/common-header.inc';
+require BEATNIK_TEMPLATES . '/menu.inc';
+
+require BEATNIK_TEMPLATES . '/listzones/header.inc';
+foreach ($domains as $domain) {
+ $autourl = Horde_Util::addParameter(Horde::applicationUrl('autogenerate.php'), array('rectype' => 'soa', 'curdomain' => $domain['zonename']));
+ $deleteurl = Horde_Util::addParameter(Horde::applicationUrl('delete.php'), array('rectype' => 'soa', 'curdomain' => $domain['zonename']));
+ $viewurl = Horde_Util::addParameter(Horde::applicationUrl('viewzone.php'), 'curdomain', $domain['zonename']);
+ $editurl = Horde_Util::addParameter(Horde::applicationUrl('editrec.php'), array('curdomain' => $domain['zonename'], 'id' => $domain['id'], 'rectype' => 'soa'));
+ require BEATNIK_TEMPLATES . '/listzones/row.inc';
+}
+require BEATNIK_TEMPLATES . '/listzones/footer.inc';
+
+require $registry->get('templates', 'horde') . '/common-footer.inc';
--- /dev/null
+<?xml version='1.0'?>
+<!-- $Horde: beatnik/locale/en_US/help.xml,v 1.2 2006/07/02 03:25:06 bklang Exp $ -->
+<help>
+
+<entry id="beatnik-overview">
+ <title>Beatnik Overview</title>
+
+ <heading>What is Beatnik?</heading>
+ <para>Beatnik manages DNS records in a convenient web interface.</para>
+</entry>
+
+<entry id="record-types">
+ <title>Record Types</title>
+</entry>
+
+<entry id="record-fields">
+ <title>Record Fields</title>
+
+ <heading>Timestamp</heading>
+ <para>This field is available only with the "ldap2dns" backend.</para>
+
+ <para>The Timestamp field provides tell the DNS server "Do Not Issue Before"
+ or "Do Not Issue After" a particular time. If the "ttl" field is
+ nonzero or omitted, "timestamp" indicates a starting time for the record
+ to be valid. If "ttl" is 0 the timestamp is an ending time, after which
+ the record will no longer be served. <a href="http://cr.yp.to">tinydns
+ </a> will automatically adjust the ttl so that the record should not be
+ cached for more than a few seconds beyond the expiry.
+ </para>
+
+ <para>The format of the record is the number of seconds since midnight of
+ January 1st, 1970 expressed in TAI64, a 16 character hexadecimal string.
+ See
+ <a href="http://cr.yp.to/libtai/tai64.html#tai64">
+ http://cr.yp.to/libtai/tai64.html#tai64
+ </a> for more information on TAI64.
+ </para>
+</entry>
+
+</help>
--- /dev/null
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR Horde Project
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: dev@lists.horde.org\n"
+"POT-Creation-Date: 2009-07-06 10:53+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: scripts/export_config.php:139
+msgid "-h, --help Show this help"
+msgstr ""
+
+#: scripts/export_config.php:141
+msgid "-p, --password[=password] Horde login password"
+msgstr ""
+
+#: scripts/export_config.php:143
+msgid "-r, --rpc[=http://example.com/horde/rpc.php] Remote url"
+msgstr ""
+
+#: scripts/export_config.php:142
+msgid "-t, --type[=type] Export format"
+msgstr ""
+
+#: scripts/export_config.php:140
+msgid "-u, --username[=username] Horde login username"
+msgstr ""
+
+#: lib/Beatnik.php:63
+msgid "A (Address)"
+msgstr ""
+
+#: templates/listzones/header.inc:45 templates/view/header.inc:43
+msgid "Actions"
+msgstr ""
+
+#: lib/Forms/EditRecord.php:31
+msgid "Add DNS Record"
+msgstr ""
+
+#: lib/Beatnik.php:32
+msgid "Add Record"
+msgstr ""
+
+#: lib/Beatnik.php:34
+msgid "Add Zone"
+msgstr ""
+
+#: lib/Driver/pdnsgsql.php:134 lib/Driver/pdnsgsql.php:191
+msgid ""
+"An error occurred while searching the database. Details have been logged "
+"for the administrator."
+msgstr ""
+
+#: lib/Forms/DeleteRecord.php:19
+msgid "Are you sure you want to delete this record?"
+msgstr ""
+
+#: autogenerate.php:25 autogenerate.php:40 templates/listzones/row.inc:16
+#: lib/Forms/Autogenerate.php:22
+msgid "Autogenerate"
+msgstr ""
+
+#: autogenerate.php:33
+msgid "Autogeneration not performed"
+msgstr ""
+
+#: lib/Beatnik.php:65
+msgid "CNAME (Alias)"
+msgstr ""
+
+#: lib/Forms/DeleteRecord.php:37 lib/Forms/Autogenerate.php:22
+msgid "Cancel"
+msgstr ""
+
+#: lib/Forms/Autogenerate.php:21
+msgid "Choose a template for autogenerating the records:"
+msgstr ""
+
+#: lib/Beatnik.php:42
+msgid "Commit All"
+msgstr ""
+
+#: templates/view/header.inc:13
+msgid "Commit Changes"
+msgstr ""
+
+#: lib/Beatnik.php:133
+msgid "Contact e-mail address for this zone"
+msgstr ""
+
+#: lib/Driver/pdnsgsql.php:146
+msgid "Corrupt SOA found for zone. Contact your administrator."
+msgstr ""
+
+#: scripts/export_config.php:44
+msgid "Couldn't read command-line options."
+msgstr ""
+
+#: lib/Beatnik.php:337
+msgid "DNS Service Record Port Number"
+msgstr ""
+
+#: lib/Beatnik.php:317
+msgid "DNS Service Record Priority"
+msgstr ""
+
+#: lib/Beatnik.php:327
+msgid "DNS Service Record Weight"
+msgstr ""
+
+#: config/prefs.php.dist:44
+msgid "Default Time-To-Live for new records."
+msgstr ""
+
+#: delete.php:24 delete.php:49 templates/listzones/row.inc:18
+#: templates/view/record.inc:18 templates/view/header.inc:25
+#: lib/Forms/DeleteRecord.php:37
+msgid "Delete"
+msgstr ""
+
+#: config/prefs.php.dist:10
+msgid "Display Preferences"
+msgstr ""
+
+#: templates/listzones/header.inc:15
+msgid "Domain Categories"
+msgstr ""
+
+#: lib/Beatnik.php:114 lib/Beatnik.php:275
+msgid "Domain Name"
+msgstr ""
+
+#: lib/api.php:46
+msgid "Domains"
+msgstr ""
+
+#: lib/Driver.php:326
+msgid "Driver not found."
+msgstr ""
+
+#: templates/listzones/row.inc:20 templates/view/record.inc:16
+#: templates/view/header.inc:23
+msgid "Edit"
+msgstr ""
+
+#: lib/Forms/EditRecord.php:31
+msgid "Edit DNS Record"
+msgstr ""
+
+#: lib/Beatnik.php:32
+msgid "Edit Record"
+msgstr ""
+
+#: templates/listzones/header.inc:20
+msgid "Edit categories and colors"
+msgstr ""
+
+#: templates/listzones/header.inc:19
+msgid "Edit domain groups and colors"
+msgstr ""
+
+#: config/autogenerate.php.dist:34
+msgid "Example Template"
+msgstr ""
+
+#: lib/Beatnik.php:38
+msgid "Expert Mode"
+msgstr ""
+
+#: lib/base.php:76
+msgid "Expert Mode ON"
+msgstr ""
+
+#: lib/base.php:73
+msgid "Expert Mode off"
+msgstr ""
+
+#: lib/Beatnik.php:169
+msgid "Expiration"
+msgstr ""
+
+#: scripts/export_config.php:117
+msgid "Have noting to do."
+msgstr ""
+
+#: lib/Beatnik.php:190 lib/Beatnik.php:211 lib/Beatnik.php:254
+#: lib/Beatnik.php:298 lib/Beatnik.php:349
+msgid "Hostname"
+msgstr ""
+
+#: lib/Beatnik.php:220 lib/Beatnik.php:232 lib/Beatnik.php:263
+#: lib/Beatnik.php:286 lib/Beatnik.php:307
+msgid "Hostname Target"
+msgstr ""
+
+#: lib/Beatnik.php:264
+msgid "Hostname for CNAME alias"
+msgstr ""
+
+#: lib/Beatnik.php:308
+msgid "Hostname for DNS Service Record"
+msgstr ""
+
+#: lib/Beatnik.php:221
+msgid "Hostname for Reverse DNS"
+msgstr ""
+
+#: lib/Beatnik.php:287
+msgid "Hostname of Authoritative Name Server"
+msgstr ""
+
+#: lib/Beatnik.php:233
+msgid "Hostname of Mail eXchanger"
+msgstr ""
+
+#: config/prefs.php.dist:36
+msgid "How many domain to display per page."
+msgstr ""
+
+#: lib/Beatnik.php:199
+msgid "IP Address"
+msgstr ""
+
+#: lib/Beatnik.php:212
+msgid "IP in Reverse notation (.in-addr.arpa)"
+msgstr ""
+
+#: lib/Beatnik.php:200
+msgid "IPv4 Network Address"
+msgstr ""
+
+#: lib/Driver/pdnsgsql.php:71 lib/Driver/pdnsgsql.php:121
+#: lib/Driver/pdnsgsql.php:174 lib/Driver/pdnsgsql.php:283
+#: lib/Driver/pdnsgsql.php:421
+msgid ""
+"Internal database error. Details have been logged for the administrator."
+msgstr ""
+
+#: lib/Driver/ldap2dns.php:246
+#, php-format
+msgid "Internal error: %s"
+msgstr ""
+
+#: lib/Driver/ldap2dns.php:349
+msgid "Invalid record type specified."
+msgstr ""
+
+#: lib/Beatnik.php:30
+msgid "List Domains"
+msgstr ""
+
+#: scripts/export_config.php:109
+#, php-format
+msgid "Logged in successfully as \"%s\"."
+msgstr ""
+
+#: scripts/export_config.php:105
+msgid "Login is incorrect."
+msgstr ""
+
+#: lib/Beatnik.php:66
+msgid "MX (Mail eXchange)"
+msgstr ""
+
+#: lib/Beatnik.php:242
+msgid "MX Preference (lower is more preferred)"
+msgstr ""
+
+#: scripts/export_config.php:137
+msgid ""
+"Mandatory arguments to long options are mandatory for short options too."
+msgstr ""
+
+#: lib/Beatnik.php:178
+msgid "Minimum"
+msgstr ""
+
+#: lib/Driver/ldap2dns.php:400
+#, php-format
+msgid "Missing required field %s to save record."
+msgstr ""
+
+#: lib/Beatnik.php:62
+msgid "NS (Name Server)"
+msgstr ""
+
+#: lib/Driver/pdnsgsql.php:424
+msgid "Not implemented."
+msgstr ""
+
+#: config/prefs.php.dist:9 config/prefs.php.dist:16
+msgid "Options"
+msgstr ""
+
+#: lib/Beatnik.php:64
+msgid "PTR (Reverse DNS)"
+msgstr ""
+
+#: lib/Beatnik.php:241
+msgid "Preference"
+msgstr ""
+
+#: lib/Beatnik.php:123
+msgid "Primary Nameserver"
+msgstr ""
+
+#: lib/Beatnik.php:124
+msgid "Primary nameserver for this zone"
+msgstr ""
+
+#: config/prefs.php.dist:17
+msgid "Record Defaults"
+msgstr ""
+
+#: lib/Beatnik.php:371
+msgid "Record Time-To-Live (seconds)"
+msgstr ""
+
+#: lib/Forms/EditRecord.php:39
+msgid "Record Type"
+msgstr ""
+
+#: lib/Beatnik.php:543
+#, php-format
+msgid "Record added: %s/%s"
+msgstr ""
+
+#: delete.php:30
+msgid "Record deleted"
+msgstr ""
+
+#: delete.php:38
+msgid "Record not deleted"
+msgstr ""
+
+#: lib/Beatnik.php:160
+msgid "Retry"
+msgstr ""
+
+#: lib/Beatnik.php:61 lib/Forms/EditRecord.php:36
+msgid "SOA (Start of Authority)"
+msgstr ""
+
+#: lib/Beatnik.php:67
+msgid "SRV (Service Record)"
+msgstr ""
+
+#: lib/Beatnik.php:336
+msgid "SRV Port"
+msgstr ""
+
+#: lib/Beatnik.php:316
+msgid "SRV Priority"
+msgstr ""
+
+#: lib/Beatnik.php:326
+msgid "SRV Weight"
+msgstr ""
+
+#: templates/menu.inc:17
+msgid "Select Domain"
+msgstr ""
+
+#: templates/menu.inc:11 templates/menu.inc:18
+msgid "Select _Domain"
+msgstr ""
+
+#: lib/Beatnik.php:141
+msgid "Serial"
+msgstr ""
+
+#: config/prefs.php.dist:11
+msgid "Set default display parameters."
+msgstr ""
+
+#: config/prefs.php.dist:18
+msgid "Set default record parameters."
+msgstr ""
+
+#: lib/Beatnik.php:191 lib/Beatnik.php:255 lib/Beatnik.php:299
+#: lib/Beatnik.php:350
+msgid "Short hostname for this record"
+msgstr ""
+
+#: lib/Beatnik.php:276
+msgid ""
+"Short sub-domain for NS record (leave blank unless creating a subdomain)"
+msgstr ""
+
+#: lib/Beatnik.php:536
+msgid "Skipping existing identical record"
+msgstr ""
+
+#: lib/Beatnik.php:359
+msgid "String payload for DNS TXT"
+msgstr ""
+
+#: lib/Beatnik.php:370
+msgid "TTL"
+msgstr ""
+
+#: lib/Beatnik.php:68
+msgid "TXT (Text Record)"
+msgstr ""
+
+#: lib/Forms/Autogenerate.php:29
+msgid "Template"
+msgstr ""
+
+#: lib/Driver/pdnsgsql.php:138
+msgid "Too many domains matched that name. Contact your administrator."
+msgstr ""
+
+#: templates/view/header.inc:44 lib/Forms/DeleteRecord.php:27
+msgid "Type"
+msgstr ""
+
+#: lib/Beatnik.php:102
+msgid "UID"
+msgstr ""
+
+#: lib/Driver/ldap2dns.php:469
+#, php-format
+msgid "Unable to add record to LDAP. Reason: %s"
+msgstr ""
+
+#: commit.php:49
+#, php-format
+msgid "Unable to construct valid SOA for %s. Not incrementing serial."
+msgstr ""
+
+#: lib/Driver/ldap2dns.php:321
+#, php-format
+msgid "Unable to delete record. Reason: %s"
+msgstr ""
+
+#: lib/Driver/ldap2dns.php:300
+msgid "Unable to delete record: No record ID specified."
+msgstr ""
+
+#: lib/Beatnik.php:430
+msgid "Unable to determine if domain needs committing: invalid parameter."
+msgstr ""
+
+#: lib/Driver.php:147
+msgid "Unable to locate requested record."
+msgstr ""
+
+#: lib/Driver/ldap2dns.php:452
+#, php-format
+msgid "Unable to modify record. Reason: %s"
+msgstr ""
+
+#: lib/Driver.php:108
+#, php-format
+msgid "Unable to read requested domain %s"
+msgstr ""
+
+#: lib/Driver/ldap2dns.php:442
+#, php-format
+msgid "Unable to rename old object. Reason: %s"
+msgstr ""
+
+#: lib/Driver/ldap2dns.php:146
+#, php-format
+msgid "Unable to retrieve data from LDAP results: %s"
+msgstr ""
+
+#: lib/Beatnik.php:103
+msgid "Unique Identifier (Used as Record ID)"
+msgstr ""
+
+#: lib/Driver/ldap2dns.php:437
+msgid "Unsupported operation: cannot rename a domain."
+msgstr ""
+
+#: lib/Driver/ldap2dns.php:309
+msgid "Unsupported recursive delete."
+msgstr ""
+
+#: scripts/export_config.php:135
+#, php-format
+msgid "Usage: %s [OPTIONS]..."
+msgstr ""
+
+#: lib/Driver.php:79
+msgid "You are not permitted to view any domains."
+msgstr ""
+
+#: lib/Driver.php:207
+msgid "You do not have permission to create new domains."
+msgstr ""
+
+#: lib/Driver.php:220
+msgid "You do not have permssion to edit the SOA of this zone."
+msgstr ""
+
+#: lib/Driver.php:225
+msgid "You do not have permssion to edit this record."
+msgstr ""
+
+#: templates/common-header.inc:15
+#, php-format
+msgid "You have uncommitted changes in %s."
+msgstr ""
+
+#: lib/Beatnik.php:132
+msgid "Zone Contact"
+msgstr ""
+
+#: lib/Beatnik.php:115
+msgid "Zone Domain Name"
+msgstr ""
+
+#: lib/Beatnik.php:170
+msgid "Zone Expiry"
+msgstr ""
+
+#: lib/Beatnik.php:179
+msgid "Zone Minimum"
+msgstr ""
+
+#: lib/Beatnik.php:152
+msgid "Zone Refresh"
+msgstr ""
+
+#: lib/Beatnik.php:161
+msgid "Zone Retry"
+msgstr ""
+
+#: lib/Beatnik.php:142
+msgid "Zone Serial Number"
+msgstr ""
+
+#: commit.php:46
+#, php-format
+msgid "Zone serial for %s incremented."
+msgstr ""
--- /dev/null
+# Slovenian translations for Beatnik packaga
+# Slovenski prevod Beatnik paketa
+# Copyright (C) 2006 Horde Project
+# This file is distributed under the same license as the horde package.
+# Automatically generated, 2006.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: dev@lists.horde.org\n"
+"POT-Creation-Date: 2006-09-13 12:27+0200\n"
+"PO-Revision-Date: 2006-04-30 10:32+0100\n"
+"Last-Translator: duck@obala.net\n"
+"Language-Team: sl_SI <duck@obala.net>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: scripts/commands.php:133 scripts/tinydns.php:167 scripts/apache.php:142
+#: scripts/unixhosts.php:123
+msgid "-h, --help Show this help"
+msgstr ""
+
+#: scripts/commands.php:135 scripts/tinydns.php:169 scripts/apache.php:144
+#: scripts/unixhosts.php:125
+msgid "-p, --password[=password] Horde login password"
+msgstr ""
+
+#: scripts/commands.php:134 scripts/tinydns.php:168 scripts/apache.php:143
+#: scripts/unixhosts.php:124
+msgid "-u, --username[=username] Horde login username"
+msgstr ""
+
+#: lib/Beatnik.php:61
+msgid "A (Address)"
+msgstr "A (naslov)"
+
+#: templates/listzones/header.inc:44 templates/view/header.inc:45
+msgid "Actions"
+msgstr "Ukazi"
+
+#: lib/Forms/EditRecord.php:22
+msgid "Add DNS Record"
+msgstr "Dodaj DNS zapis"
+
+#: lib/Beatnik.php:33
+msgid "Add Record"
+msgstr "Dodaj zapis"
+
+#: lib/Forms/DeleteRecord.php:22
+msgid "Are you sure you want to delete this record?"
+msgstr "Resnično želite izbrisati ta zapis?"
+
+#: autogenerate.php:28 autogenerate.php:43 templates/listzones/row.inc:16
+#: lib/Forms/Autogenerate.php:28
+msgid "Autogenerate"
+msgstr "Samodejno tvorjenje"
+
+#: autogenerate.php:36
+msgid "Autogeneration not performed"
+msgstr "Samodejno tvorjenje ni bilo izvršeno"
+
+#: lib/Beatnik.php:63
+msgid "CNAME (Alias)"
+msgstr ""
+
+#: lib/Forms/DeleteRecord.php:40 lib/Forms/Autogenerate.php:28
+msgid "Cancel"
+msgstr "Prekliči"
+
+#: lib/Forms/Autogenerate.php:27
+msgid "Choose a template for autogenerating the records:"
+msgstr "Izberite šablono za samodejno tvorjenje zapisov"
+
+#: lib/Beatnik.php:40
+msgid "Commit All"
+msgstr "Izvrši vse"
+
+#: templates/view/header.inc:13
+msgid "Commit Changes"
+msgstr "Izvrši spremembe"
+
+#: lib/Beatnik.php:131
+msgid "Contact e-mail address for this zone"
+msgstr "Kontaktni email za to zono"
+
+#: scripts/commands.php:47 scripts/tinydns.php:50 scripts/apache.php:47
+#: scripts/unixhosts.php:47
+msgid "Couldn't read command-line options."
+msgstr ""
+
+#: lib/Beatnik.php:335
+msgid "DNS Service Record Port Number"
+msgstr ""
+
+#: lib/Beatnik.php:315
+msgid "DNS Service Record Priority"
+msgstr ""
+
+#: lib/Beatnik.php:325
+msgid "DNS Service Record Weight"
+msgstr ""
+
+#: delete.php:29 delete.php:54 templates/listzones/row.inc:18
+#: templates/view/record.inc:18 templates/view/header.inc:25
+#: lib/Forms/DeleteRecord.php:40
+msgid "Delete"
+msgstr "Izbriši"
+
+#: config/prefs.php.dist:10
+msgid "Display details"
+msgstr "Podrobnosti prikazovanja"
+
+#: config/prefs.php.dist:9
+msgid "Display listings"
+msgstr "Nastavitve izpisovanja"
+
+#: templates/listzones/header.inc:15
+msgid "Domain Categories"
+msgstr "Kategorije domen"
+
+#: lib/Beatnik.php:112 lib/Beatnik.php:273
+msgid "Domain Name"
+msgstr "Ime domene"
+
+#: lib/api.php:45
+msgid "Domains"
+msgstr "Domene"
+
+#: templates/listzones/row.inc:20 templates/view/record.inc:16
+#: templates/view/header.inc:23
+msgid "Edit"
+msgstr "Uredi"
+
+#: lib/Forms/EditRecord.php:22
+msgid "Edit DNS Record"
+msgstr "Uredi DNS zapis"
+
+#: lib/Beatnik.php:33
+msgid "Edit Record"
+msgstr "Uredi zapis"
+
+#: templates/listzones/header.inc:20
+msgid "Edit categories and colors"
+msgstr "Uredi kategorije in barve"
+
+#: templates/listzones/header.inc:19
+msgid "Edit domain groups and colors"
+msgstr "Uredi grupe in barve"
+
+#: config/autogenerate.php.dist:34
+msgid "Example Template"
+msgstr "Primer šablone"
+
+#: lib/Beatnik.php:36
+msgid "Expert Mode"
+msgstr "Napredni način"
+
+#: lib/base.php:79
+msgid "Expert Mode ON"
+msgstr "Napredni način je bil vklopljen"
+
+#: lib/base.php:76
+msgid "Expert Mode off"
+msgstr "Napredni način ke bil izklopljen"
+
+#: lib/Beatnik.php:167
+msgid "Expiration"
+msgstr "Poteče"
+
+#: lib/Beatnik.php:188 lib/Beatnik.php:209 lib/Beatnik.php:252
+#: lib/Beatnik.php:296 lib/Beatnik.php:347
+msgid "Hostname"
+msgstr ""
+
+#: lib/Beatnik.php:218 lib/Beatnik.php:230 lib/Beatnik.php:261
+#: lib/Beatnik.php:284 lib/Beatnik.php:305
+msgid "Hostname Target"
+msgstr ""
+
+#: lib/Beatnik.php:262
+msgid "Hostname for CNAME alias"
+msgstr ""
+
+#: lib/Beatnik.php:306
+msgid "Hostname for DNS Service Record"
+msgstr ""
+
+#: lib/Beatnik.php:219
+msgid "Hostname for Reverse DNS"
+msgstr ""
+
+#: lib/Beatnik.php:285
+msgid "Hostname of Authoritative Name Server"
+msgstr ""
+
+#: lib/Beatnik.php:231
+msgid "Hostname of Mail eXchanger"
+msgstr ""
+
+#: config/prefs.php.dist:28
+msgid "How many domain to display per page."
+msgstr "Koliko domen naj prikažem na stran?"
+
+#: lib/Beatnik.php:197
+msgid "IP Address"
+msgstr "IP naslov"
+
+#: lib/Beatnik.php:210
+msgid "IP in Reverse notation (.in-addr.arpa)"
+msgstr ""
+
+#: lib/Beatnik.php:198
+msgid "IPv4 Network Address"
+msgstr ""
+
+#: lib/Driver/ldap2dns.php:267
+#, php-format
+msgid "Internal error: %s"
+msgstr "Interna napaka: %s"
+
+#: lib/Driver/ldap2dns.php:370
+msgid "Invalid record type specified."
+msgstr "Podan je bil neveljavni način zapisa."
+
+#: lib/Beatnik.php:32
+msgid "List Domains"
+msgstr "Spisek domen"
+
+#: scripts/commands.php:87 scripts/tinydns.php:90 scripts/apache.php:87
+#: scripts/unixhosts.php:87
+#, php-format
+msgid "Logged in successfully as \"%s\"."
+msgstr ""
+
+#: scripts/commands.php:83 scripts/tinydns.php:86 scripts/apache.php:83
+#: scripts/unixhosts.php:83
+msgid "Login is incorrect."
+msgstr ""
+
+#: lib/Beatnik.php:64
+msgid "MX (Mail eXchange)"
+msgstr ""
+
+#: lib/Beatnik.php:240
+msgid "MX Preference (lower is more preferred)"
+msgstr ""
+
+#: scripts/commands.php:131 scripts/tinydns.php:165 scripts/apache.php:140
+#: scripts/unixhosts.php:121
+msgid ""
+"Mandatory arguments to long options are mandatory for short options too."
+msgstr ""
+
+#: lib/Beatnik.php:176
+msgid "Minimum"
+msgstr "Najmanj"
+
+#: lib/Driver/ldap2dns.php:425
+#, php-format
+msgid "Missing required field %s to save record."
+msgstr "Ne morem shraniti zapisa saj manjka zahtevano polje %s."
+
+#: lib/Beatnik.php:60
+msgid "NS (Name Server)"
+msgstr ""
+
+#: lib/Beatnik.php:62
+msgid "PTR (Reverse DNS)"
+msgstr ""
+
+#: lib/Beatnik.php:239
+msgid "Preference"
+msgstr ""
+
+#: lib/Beatnik.php:121
+msgid "Primary Nameserver"
+msgstr ""
+
+#: lib/Beatnik.php:122
+msgid "Primary nameserver for this zone"
+msgstr ""
+
+#: lib/Beatnik.php:369
+msgid "Record Time-To-Live (seconds)"
+msgstr ""
+
+#: lib/Forms/EditRecord.php:28
+msgid "Record Type"
+msgstr "Tip zapisa"
+
+#: lib/Beatnik.php:532
+msgid "Record added"
+msgstr "Zapis je bil dodan"
+
+#: delete.php:35
+msgid "Record deleted"
+msgstr "Zapis je bil izbrisan"
+
+#: delete.php:43
+msgid "Record not deleted"
+msgstr "Zapis ni bil izbrisan"
+
+#: lib/Beatnik.php:158
+msgid "Retry"
+msgstr "Poskusi znova"
+
+#: lib/Beatnik.php:59
+msgid "SOA (Start of Authority)"
+msgstr ""
+
+#: lib/Beatnik.php:65
+msgid "SRV (Service Record)"
+msgstr ""
+
+#: lib/Beatnik.php:334
+msgid "SRV Port"
+msgstr ""
+
+#: lib/Beatnik.php:314
+msgid "SRV Priority"
+msgstr ""
+
+#: lib/Beatnik.php:324
+msgid "SRV Weight"
+msgstr ""
+
+#: templates/menu.inc:17
+msgid "Select Domain"
+msgstr "Izberi domeno"
+
+#: templates/menu.inc:11 templates/menu.inc:18
+msgid "Select _Domain"
+msgstr "Izberi Domeno"
+
+#: lib/Beatnik.php:139
+msgid "Serial"
+msgstr "Serijska št."
+
+#: config/prefs.php.dist:11
+msgid "Set default display parameters."
+msgstr "Nastavite prenstavljene parameterje prikaza."
+
+#: lib/Beatnik.php:189 lib/Beatnik.php:253 lib/Beatnik.php:297
+#: lib/Beatnik.php:348
+msgid "Short hostname for this record"
+msgstr ""
+
+#: lib/Beatnik.php:274
+msgid "Short sub-domain for NS record"
+msgstr ""
+
+#: lib/Beatnik.php:525
+msgid "Skipping existing identical record"
+msgstr "Preskoži že obstoječe zapise"
+
+#: lib/Beatnik.php:357
+msgid "String payload for DNS TXT"
+msgstr ""
+
+#: lib/Beatnik.php:368
+msgid "TTL"
+msgstr ""
+
+#: lib/Beatnik.php:66
+msgid "TXT (Text Record)"
+msgstr ""
+
+#: lib/Forms/Autogenerate.php:35
+msgid "Template"
+msgstr "Šablona"
+
+#: templates/view/header.inc:46 lib/Forms/DeleteRecord.php:30
+msgid "Type"
+msgstr "Tip"
+
+#: lib/Beatnik.php:100
+msgid "UUID"
+msgstr ""
+
+#: lib/Driver/ldap2dns.php:488
+#, php-format
+msgid "Unable to add record to LDAP. Reason: %s"
+msgstr "Ne morem dodati zapisa v LDAP: %s"
+
+#: commit.php:51
+#, php-format
+msgid "Unable to construct valid SOA for %s. Not incrementing serial."
+msgstr ""
+
+#: lib/Driver/ldap2dns.php:342
+#, php-format
+msgid "Unable to delete record. Reason: %s"
+msgstr "Nemorem dodati zapisa: %s"
+
+#: lib/Driver/ldap2dns.php:321
+msgid "Unable to delete record: No record ID specified."
+msgstr "Ne morem izbrisati zapisa. Niste podatli IDja."
+
+#: lib/Beatnik.php:427
+msgid "Unable to determine if domain needs committing: invalid parameter."
+msgstr ""
+
+#: lib/Driver.php:100
+msgid "Unable to locate requested record."
+msgstr "Ne morem najti izbranega zapisa"
+
+#: lib/Driver/ldap2dns.php:479
+#, php-format
+msgid "Unable to modify record. Reason: %s"
+msgstr "Ne morem ažurirati zapisa: %s"
+
+#: lib/Driver/ldap2dns.php:198
+#, php-format
+msgid "Unable to read requested domain %s"
+msgstr "Ne morem prebrati zahtevane domene %s"
+
+#: lib/Driver/ldap2dns.php:469
+#, php-format
+msgid "Unable to rename old object. Reason: %s"
+msgstr "Ne preimenovati starega objekta: %s"
+
+#: lib/Driver/ldap2dns.php:148
+#, php-format
+msgid "Unable to retrieve data from LDAP results: %s"
+msgstr "Ne morem prebrati podatkov: %s"
+
+#: lib/Beatnik.php:101
+msgid "Universally Unique Identifier (Used as Record ID)"
+msgstr ""
+
+#: lib/Driver/ldap2dns.php:464
+msgid "Unsupported operation: cannot rename a domain."
+msgstr "Nepodprti ukaz: ne morem preimenovati domene."
+
+#: lib/Driver/ldap2dns.php:330
+msgid "Unsupported recursive delete."
+msgstr "Nepodarti rekurzivni izbris."
+
+#: scripts/commands.php:129 scripts/tinydns.php:163 scripts/apache.php:138
+#: scripts/unixhosts.php:119
+#, php-format
+msgid "Usage: %s [OPTIONS]..."
+msgstr ""
+
+#: lib/Driver.php:57
+msgid "You are not permitted to view any domains."
+msgstr "Nimate pravic za pregled katerekoli domene."
+
+#: lib/Driver.php:164
+msgid "You do not have permission to create new domains."
+msgstr "Nimate pravic za tvorjenje novih domenskih zapisov."
+
+#: lib/Driver.php:177
+msgid "You do not have permssion to edit the SOA of this zone."
+msgstr "Nimate pravic za urejanje novih domenskih zapisov."
+
+#: lib/Driver.php:182
+msgid "You do not have permssion to edit this record."
+msgstr "Nimate pravic za tvorjenje urejanje tega zapisa."
+
+#: templates/common-header.inc:15
+#, php-format
+msgid "You have uncommitted changes in %s."
+msgstr "Preklicali ste spremembe za %s."
+
+#: lib/Beatnik.php:130
+msgid "Zone Contact"
+msgstr "Kontakt"
+
+#: lib/Beatnik.php:113
+msgid "Zone Domain Name"
+msgstr "Ime domene"
+
+#: lib/Beatnik.php:168
+msgid "Zone Expiry"
+msgstr "Poteče"
+
+#: lib/Beatnik.php:177
+msgid "Zone Minimum"
+msgstr ""
+
+#: lib/Beatnik.php:150
+msgid "Zone Refresh"
+msgstr "Osvežitev"
+
+#: lib/Beatnik.php:159
+msgid "Zone Retry"
+msgstr ""
+
+#: lib/Beatnik.php:140
+msgid "Zone Serial Number"
+msgstr "Serijska številka"
+
+#: commit.php:48
+#, php-format
+msgid "Zone serial for %s incremented."
+msgstr ""
+
+#: lib/Forms/EditRecord.php:39 lib/Forms/EditRecord.php:41
+#: lib/Forms/DeleteRecord.php:35
+msgid "description"
+msgstr "opis"
--- /dev/null
+<?php
+/**
+ * Helper for creating mass config files
+ *
+ * NOTE You should change the creation section to swit your needs
+ *
+ * USE:
+ * php ./export_config.php --type=TYPE --username=USR --password=PASS --url=URL > hosts
+ *
+ * $Horde: beatnik/scripts/export_config.php,v 1.2 2009/07/15 15:05:33 duck Exp $
+ *
+ * Copyright 2008 The Horde Project (http://www.horde.org/)
+ *
+ * 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 Duck <duck@obala.net>
+ * @package Beatnik
+ */
+
+define('AUTH_HANDLER', true);
+define('HORDE_BASE', dirname(__FILE__) . '/../../');
+define('BEATNIK_BASE', HORDE_BASE . '/beatnik');
+
+// 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.
+Horde_CLI::init();
+$cli = &Horde_CLI::singleton();
+
+// We accept the user name on the command-line.
+require_once 'Console/Getopt.php';
+$ret = Console_Getopt::getopt(Console_Getopt::readPHPArgv(), 'h:u:p:t:r',
+ array('help', 'username=', 'password=', 'type=', 'rpc='));
+
+if (is_a($ret, 'PEAR_Error')) {
+ $error = _("Couldn't read command-line options.");
+ Horde::logMessage($error, __FILE__, __LINE__, PEAR_LOG_DEBUG);
+ $cli->fatal($error);
+}
+
+// Show help and exit if no arguments were set.
+list($opts, $args) = $ret;
+if (!$opts) {
+ showHelp();
+ exit;
+}
+
+foreach ($opts as $opt) {
+ list($optName, $optValue) = $opt;
+ switch ($optName) {
+ case 'u':
+ case '--username':
+ $username = $optValue;
+ break;
+
+ case 'p':
+ case '--password':
+ $password = $optValue;
+ break;
+
+ case 't':
+ case '--type':
+ $type = $optValue;
+ break;
+
+ case 'r':
+ case '--rpc':
+ $rpc = $optValue;
+ break;
+
+ case 'h':
+ case '--help':
+ showHelp();
+ exit;
+ }
+}
+
+// We will fetch data from RPC
+if (!empty($rpc)) {
+
+ require_once 'Horde/RPC.php';
+ $domains = Horde_RPC::request('xmlrpc', $rpc,
+ 'dns.getDomains',
+ array(),
+ array('user' => $username,
+ 'pass' => $password));
+ if (is_a($result, 'PEAR_Error')) {
+ $cli->fatal($domains);
+ }
+
+// Login to horde if username & password are set and load module.
+} elseif (!empty($username) && !empty($password)) {
+
+ require_once HORDE_BASE . '/lib/base.php';
+ $auth = &Horde_Auth::singleton($conf['auth']['driver']);
+ if (!$auth->authenticate($username, array('password' => $password))) {
+ $error = _("Login is incorrect.");
+ Horde::logMessage($error, __FILE__, __LINE__, PEAR_LOG_ERR);
+ $cli->fatal($error);
+ } else {
+ $msg = sprintf(_("Logged in successfully as \"%s\"."), $username);
+ Horde::logMessage($msg, __FILE__, __LINE__, PEAR_LOG_DEBUG);
+ $cli->message($msg, 'cli.success');
+ }
+
+ require_once BEATNIK_BASE . '/lib/base.php';
+
+} else {
+ $msg = _("Have noting to do.");
+ $cli->fatal($msg);
+}
+
+// Steps
+if (empty($type)) {
+ $type = 'tinydns';
+}
+$function = '_' . $type;
+echo $function();
+
+/**
+ * Show the command line arguments that the script accepts.
+ */
+function showHelp()
+{
+ global $cli;
+
+ $cli->writeln(sprintf(_("Usage: %s [OPTIONS]..."), basename(__FILE__)));
+ $cli->writeln();
+ $cli->writeln(_("Mandatory arguments to long options are mandatory for short options too."));
+ $cli->writeln();
+ $cli->writeln(_("-h, --help Show this help"));
+ $cli->writeln(_("-u, --username[=username] Horde login username"));
+ $cli->writeln(_("-p, --password[=password] Horde login password"));
+ $cli->writeln(_("-t, --type[=type] Export format"));
+ $cli->writeln(_("-r, --rpc[=http://example.com/horde/rpc.php] Remote url"));
+ $cli->writeln();
+}
+
+/**
+ * Get domain records
+ */
+function _getRecords($domain)
+{
+ if (empty($GLOBALS['rpc'])) {
+ $result = $GLOBALS['beatnik_driver']->getRecords($domain);
+ } else {
+ $result = Horde_RPC::request('xmlrpc', $GLOBALS['rpc'],
+ 'dns.getRecords',
+ array($domain),
+ array('user' => $GLOBALS['username'],
+ 'pass' => $GLOBALS['password']));
+ }
+
+ if (is_a($result, 'PEAR_Error')) {
+ $GLOBALS['cli']->fatal($result);
+ } else {
+ return $result;
+ }
+}
+
+/**
+ * Generate unix hosts file
+ */
+function _hosts()
+{
+ $c = "# Generated with beatnik on " . date('Y-m-d h:i:s') . " by " . $GLOBALS['username'] . "\n\n";
+ foreach ($GLOBALS['domains'] as $domain) {
+
+ $zonename = $domain['zonename'];
+ $tld = substr($zonename, strrpos($zonename, '.')+1);
+ $domain = substr($zonename, 0, strrpos($zonename, '.'));
+
+ foreach ($zonedata['cname'] as $id => $values) {
+ extract($values);
+ if (!empty($hostname)) {
+ $hostname .= '.';
+ }
+ $c .= "$pointer $hostname.$domain.$tld\n";
+ }
+ }
+
+ return $c;
+}
+
+/**
+ * Generate bash script
+ */
+function _bash()
+{
+ $c = "# Generated with beatnik on " . date('Y-m-d h:i:s') . " by " . $GLOBALS['username'] . "\n\n";
+ foreach ($GLOBALS['domains'] as $domain) {
+
+ $zonename = $domain['zonename'];
+ $tld = substr($zonename, strrpos($zonename, '.')+1);
+ $domain = substr($zonename, 0, strrpos($zonename, '.'));
+
+ $c .= "useradd $zonename" . "_$tld -d /var/www/$zonename" . "_$tld -s /bin/false" . "\n";
+ $c .= "mkdir /var/www/$zonename" . "_$tld/" . "\n";
+ $c .= "chown -R $zonename" . "_$tld:apache /var/www/$zonename" . "_$tld/" . "\n";
+
+ foreach ($zonedata['cname'] as $id => $values) {
+ extract($values);
+ if (empty($hostname)) {
+ // use empty hostname as alias for www
+ $c .= "ln -s /var/www/$zonename" . "_$tld/$zonename.$tld " .
+ "/var/www/$zonename" . "_$tld/$hostname.$zonename.$tld" . "\n";
+ continue;
+ }
+
+ $c .= "mkdir /var/www/$zonename" . "_$tld/$hostname.$zonename.$tld" . "\n";
+ $c .= "mkdir /var/tmp/www/$hostname.$zonename.$tld" . "\n";
+ $c .= "mkdir /var/log/apache2/$hostname.$zonename.$tld" . "\n";
+ }
+ }
+
+ return $c;
+}
+
+/**
+ * Generate apache host defs
+ */
+function _apache()
+{
+ $c = "# Generated with beatnik on " . date('Y-m-d h:i:s') . " by " . $GLOBALS['username'] . "\n\n";
+ foreach ($GLOBALS['domains'] as $domain) {
+ // Get default data and skip if no cnames
+ $zonedata = _getRecords($domain['zonename']);
+ if (!isset($zonedata['cname'])) {
+ continue;
+ }
+
+ // data
+ $zonename = $domain['zonename'];
+ $tld = substr($zonename, strrpos($zonename, '.')+1);
+ $domain = substr($zonename, 0, strrpos($zonename, '.'));
+ foreach ($zonedata['cname'] as $id => $values) {
+
+ extract($values);
+ if (empty($hostname)) {
+ continue; // use empty hostname as alias for www
+ }
+
+ $c .= "\n";
+ $c .= "<VirtualHost $hostname.$zonename:80>\n";
+ $c .= " DocumentRoot /var/www/$domain" . "_$tld/$hostname.$zonename\n";
+ $c .= " ServerName $hostname.$zonename\n";
+ if ($hostname == 'www') {
+ $c .= " ServerAlias $zonename\n";
+ }
+ $c .= " ErrorLog logs/$hostname.$zonename/error_log\n";
+ $c .= " TransferLog logs/$hostname.$zonename/access_log\n";
+ $c .= " php_admin_value upload_tmp_dir \"/var/tmp/www/$hostname.$zonename\"\n";
+ $c .= " php_admin_value open_basedir \".:/usr/lib/php:/var/tmp/www/$hostname.$zonename:/var/www/$domain" . "_$tld/$hostname.$zonename\"\n";
+ $c .= "</VirtualHost>\n";
+ }
+ }
+
+ return $c;
+}
+
+/**
+ * Generate tinydns defs
+ */
+function _tinydns()
+{
+ $c = "# Generated with beatnik on " . date('Y-m-d h:i:s') . " by " . $GLOBALS['username'] . "\n\n";
+ foreach ($GLOBALS['domains'] as $domain) {
+ // Get zone data
+ $zonedata = _getRecords($domain['zonename']);
+ $c .= '# ' . $domain['zonename'] . "\n";
+
+ // default SOA, NS
+ $c .= '.' . $domain['zonename'] . ':' . gethostbyname($domain['zonens']) . ':' . $domain['zonens'] . ':' . $domain['ttl'] . "\n";
+
+ // NS records
+ if (isset($zonedata['ns'])) {
+ foreach ($zonedata['ns'] as $id => $values) {
+ $c .= '.' . $domain['zonename'] . ':'. gethostbyname($values['pointer']) . ':' . $values['pointer'] . ':' . $values['ttl'] . "\n";
+ }
+ }
+
+ // MX records
+ if (isset($zonedata['mx'])) {
+ foreach ($zonedata['mx'] as $id => $values) {
+ $c .= '@' . $domain['zonename'] . ':'. gethostbyname($values['pointer']) . ':' . $values['pointer'] . ':' . $values['pref'] . ':' . $values['ttl'] . "\n";
+ }
+ }
+
+ // PTR records
+ if (isset($zonedata['ptr'])) {
+ foreach ($zonedata['ptr'] as $id => $values) {
+ $c .= '=';
+ $c .= $values['hostname'] . '.' . $domain['zonename'] . ':' . $values['pointer'] . ':' . $values['ttl'] . "\n";
+ }
+ }
+
+ // A records
+ if (isset($zonedata['a'])) {
+ foreach ($zonedata['a'] as $id => $values) {
+ $c .= '+';
+ if ($values['hostname']) {
+ $c .= $values['hostname'] . '.';
+ }
+ $c .= $domain['zonename'] . ':' . $values['ipaddr'] . ':' . $values['ttl'] . "\n";
+ }
+ }
+
+ // CNAME records
+ if (isset($zonedata['cname'])) {
+ foreach ($zonedata['cname'] as $id => $values) {
+ $c .= 'C';
+ if ($values['hostname']) {
+ $c .= $values['hostname'] . '.';
+ }
+ $c .= $domain['zonename'] . ':' . $values['pointer'] . ':' . $values['ttl'] . "\n";
+ }
+ }
+
+ $c .= "\n";
+ }
+
+ return $c;
+}
--- /dev/null
+--
+-- $Horde: beatnik/scripts/sql/beatnik.mysql.php,v 1.5 2006/08/13 18:52:47 duck Exp $
+--
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `beatnik_a`
+--
+
+CREATE TABLE `beatnik_a` (
+ `id` int(10) unsigned NOT NULL auto_increment,
+ `zonename` varchar(255) NOT NULL,
+ `hostname` varchar(255) NOT NULL,
+ `ipaddr` varchar(255) NOT NULL,
+ `ttl` varchar(255) default NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `beatnik_cname`
+--
+
+CREATE TABLE `beatnik_cname` (
+ `id` int(10) unsigned NOT NULL auto_increment,
+ `zonename` varchar(255) NOT NULL,
+ `hostname` varchar(255) NOT NULL,
+ `pointer` varchar(255) NOT NULL,
+ `ttl` varchar(255) default NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `beatnik_mx`
+--
+
+CREATE TABLE `beatnik_mx` (
+ `id` int(10) unsigned NOT NULL auto_increment,
+ `zonename` varchar(255) NOT NULL,
+ `pointer` varchar(255) NOT NULL,
+ `pref` varchar(255) NOT NULL,
+ `ttl` varchar(255) default NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `beatnik_ns`
+--
+
+CREATE TABLE `beatnik_ns` (
+ `id` int(10) unsigned NOT NULL auto_increment,
+ `zonename` varchar(255) NOT NULL,
+ `hostname` varchar(255) default NULL,
+ `pointer` varchar(255) default '',
+ `ttl` varchar(255) default NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `beatnik_ptr`
+--
+
+CREATE TABLE `beatnik_ptr` (
+ `id` int(10) unsigned NOT NULL auto_increment,
+ `zonename` varchar(255) NOT NULL,
+ `hostname` varchar(255) NOT NULL,
+ `pointer` varchar(255) NOT NULL,
+ `ttl` varchar(255) default NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `beatnik_soa`
+--
+
+CREATE TABLE `beatnik_soa` (
+ `id` int(10) unsigned NOT NULL auto_increment,
+ `zonename` varchar(255) NOT NULL,
+ `zonens` varchar(255) NOT NULL,
+ `zonecontact` varchar(255) default NULL,
+ `serial` varchar(255) default NULL,
+ `refresh` int(10) unsigned default NULL,
+ `retry` int(10) unsigned default NULL,
+ `expire` varchar(255) default NULL,
+ `minimum` varchar(255) default NULL,
+ `ttl` int(11) NOT NULL default '3600',
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `zonename` (`zonename`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 PACK_KEYS=1;
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `beatnik_srv`
+--
+
+CREATE TABLE `beatnik_srv` (
+ `id` int(10) unsigned NOT NULL auto_increment,
+ `zonename` varchar(255) NOT NULL,
+ `hostname` varchar(255) NOT NULL,
+ `pointer` varchar(255) NOT NULL,
+ `priority` varchar(255) NOT NULL,
+ `weight` varchar(255) NOT NULL,
+ `port` varchar(255) NOT NULL,
+ `ttl` varchar(255) default NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `beatnik_txt`
+--
+
+CREATE TABLE `beatnik_txt` (
+ `id` int(10) unsigned NOT NULL auto_increment,
+ `zonename` varchar(255) NOT NULL,
+ `hostname` varchar(255) NOT NULL,
+ `text` varchar(255) NOT NULL,
+ `ttl` varchar(255) default NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
--- /dev/null
+<?php
+/**
+ * $Horde: beatnik/templates/common-header.inc,v 1.9 2009/09/15 09:20:03 duck Exp $
+ *
+ * Copyright 2005-2007 Ben Klang <ben@alkaloid.net>
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ */
+
+// This check has to come after the page has finished all work in case the
+// status has changed due to a now-completed edit.
+if (count(Beatnik::needCommit())) {
+ foreach(Beatnik::needCommit() as $domain) {
+ $notification->push(sprintf(_("You have uncommitted changes in %s."), $domain));
+ }
+}
+?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "DTD/xhtml1-transitional.dtd">
+<!-- Beatnik Copyright 2005-2007, Ben Klang <ben@alkaloid.net> -->
+<!-- Horde Project: http://www.horde.org/ -->
+<!-- Beatnik: http://projects.alkaloid.net/ -->
+<!-- Horde Licenses: http://www.horde.org/licenses/ -->
+<?php echo !empty($language) ? '<html lang="' . strtr($language, '_', '-') . '">' : '<html>' ?>
+<head>
+<?php
+
+$page_title = $registry->get('name');
+if (!empty($title)) $page_title .= ' :: ' . $title;
+if (!empty($refresh_time) && ($refresh_time > 0) && !empty($refresh_url)) {
+ echo "<meta http-equiv=\"refresh\" content=\"$refresh_time;url=$refresh_url\">\n";
+}
+
+Horde::includeScriptFiles();
+
+?>
+<title><?php echo htmlspecialchars($page_title) ?></title>
+<link href="<?php echo $GLOBALS['registry']->getImageDir()?>/favicon.ico" rel="SHORTCUT ICON" />
+<?php echo Horde::includeStylesheetFiles(); ?>
+</head>
+<body<?php if ($bc = Horde_Util::nonInputVar('bodyClass')) echo ' class="' . $bc . '"' ?><?php if ($bi = Horde_Util::nonInputVar('bodyId')) echo ' id="' . $bi . '"'; ?>>
--- /dev/null
+<?php
+/**
+ * $Horde: beatnik/templates/listzones/footer.inc,v 1.6 2008/08/22 09:00:22 duck Exp $
+ *
+ * Copyright 2005-2007 Ben Klang <ben@alkaloid.net>
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ */
+?>
+</tbody>
+</table>
+<?php echo $pager->render(); ?>
--- /dev/null
+<?php
+/**
+ * $Horde: beatnik/templates/listzones/header.inc,v 1.13 2009/07/15 15:05:33 duck Exp $
+ *
+ * Copyright 2005-2007 Ben Klang <ben@alkaloid.net>
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ *
+ */
+?>
+<div class="box" style="float: right;">
+<p>
+<?php
+echo _("Domain Categories") . ' ';
+if (Horde_Auth::getAuth() && (!$prefs->isLocked('categories') || !$prefs->isLocked('category_colors'))) {
+ $categoryUrl = Horde_Util::addParameter(Horde::url($registry->get('webroot', 'horde') . '/services/prefs.php'),
+ array('app' => 'horde', 'group' => 'categories'));
+ echo Horde::link($categoryUrl, _("Edit domain groups and colors"), 'widget', '_blank') .
+ Horde::img('colorpicker.png', _("Edit categories and colors"), array('align' => 'absmiddle'), $registry->getImageDir('horde')) . '</a>';
+}
+?>
+</p>
+<p>
+<ul>
+ <?php
+ foreach ($categories as $category) {
+ $color = isset($colors[$category]) ? $colors[$category] : '#FFFFFF';
+ $fgcolor = isset($fgcolors[$category]) ? $fgcolors[$category] : '#000000';
+ ?>
+ <li style="background-color:<?php echo htmlspecialchars($color) ?>; color:<?php echo $fgcolor ?>">
+ <input type="checkbox" id="dgroup-<?php echo $category; ?>" onclick="javascript:groupToggle('<?php echo $category; ?>');" />
+ <?php echo $category; ?>
+ </li>
+ <?php
+ }
+ ?>
+</ul>
+</p>
+</div>
+
+<table class="striped">
+<thead>
+<tr>
+<th><?php echo _("Actions")?></th>
+<?php
+foreach ($fields as $field) {
+ echo '<th>' . $field['name'] . '</th>';
+}
+?>
+</tr>
+</thead>
+<tbody>
+
--- /dev/null
+<?php
+/**
+ * $Horde: beatnik/templates/listzones/row.inc,v 1.11 2007/06/27 17:23:31 jan Exp $
+ *
+ * Copyright 2005-2007 Ben Klang <ben@alkaloid.net>
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ *
+ */
+?>
+<tr>
+<td>
+ <?php
+ echo Horde::link($autourl) .
+ Horde::img('devel.png', _("Autogenerate"), '', $img_dir) . '</a> ' .
+ Horde::link($deleteurl) .
+ Horde::img('delete.png', _("Delete"), '', $img_dir) . '</a> ' .
+ Horde::link($editurl) .
+ Horde::img('edit.png', _("Edit"), '', $img_dir) . '</a>';
+ ?>
+</td>
+<?php
+foreach ($fields as $key => $field) {
+ if ($key == 'zonename') {
+ echo '<td>' . Horde::link($viewurl) . $domain['zonename'] . '</a></td>';
+ } else {
+ echo '<td>' . $domain[$key] . '</td>';
+ }
+}
+?>
+</tr>
--- /dev/null
+<?php
+/*
+ * $Horde: beatnik/templates/menu.inc,v 1.18 2009/07/15 15:08:27 duck Exp $
+ *
+ * Copyright 2005-2007 Ben Klang <ben@alkaloid.net>
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ */
+
+$accesskey = $prefs->getValue('widget_accesskey') ? Horde::getAccessKey(_("Select _Domain")) : '';
+$menu_view = $prefs->getValue('menu_view');
+?>
+<div id="menu">
+<span style="float:right">
+<?php
+ $link = Horde::link('#', _("Select Domain"), '', '', 'domainSubmit(true); return false;');
+ sprintf('<ul><li>%s%s<br />%s</a></li></ul>', $link, Horde::img('tree/folderopen.png', '', '', $registry->getImageDir('horde')), ($menu_view != 'icon') ? Horde::highlightAccessKey(_("Select _Domain"), $accesskey) : '');
+?>
+</span>
+<span style="float:right">
+ <form action="<?php echo Horde::applicationUrl('viewzone.php') ?>" method="get" name="menu">
+ <?php Horde_Util::pformInput(); ?>
+ <label for="domain" accesskey="<?php echo $accesskey ?>">
+ <select id="domainSelector" name="curdomain"
+ onchange="domainSubmit()">
+ <?php
+ foreach ($domains as $domain) {
+ echo '<option value="' . $domain['zonename'] . '"';
+ if ($domain['zonename'] == $_SESSION['beatnik']['curdomain']['zonename']) {
+ echo " selected";
+ }
+ echo '>' . $domain['zonename'] . "</option>\n";
+ }
+ ?>
+ </select>
+ </label>
+ </form>
+</span>
+<?php echo Beatnik::getMenu('string') ?>
+</div>
+<?php $GLOBALS['notification']->notify(array('listeners' => 'status')) ?>
--- /dev/null
+<?php
+/**
+ * $Horde: beatnik/templates/view/footer.inc,v 1.4 2008/08/22 09:00:23 duck Exp $
+ *
+ * Copyright 2005-2007 Ben Klang <ben@alkaloid.net>
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ */
+?>
+</tbody>
+</table>
--- /dev/null
+<?php
+/**
+ * $Horde: beatnik/templates/view/header.inc,v 1.14 2009/07/03 10:05:31 duck Exp $
+ *
+ * Copyright 2005-2007 Ben Klang <ben@alkaloid.net>
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ */
+
+if (Beatnik::needCommit($_SESSION['beatnik']['curdomain']['zonename'])) {
+ $commit = Horde_Util::addParameter(Horde::applicationUrl('commit.php'), array('domain' => 'current'));
+ echo Horde::link($commit, _('Commit Changes'), 'button') . _('Commit Changes') . '</a><br /><br />';
+}
+?>
+
+<div class="header">
+<?php
+$params = array('id' => $_SESSION['beatnik']['curdomain']['id'],
+ 'rectype' => 'soa');
+echo $_SESSION['beatnik']['curdomain']['zonename'] . ' '
+ . Horde::link(Horde_Util::addParameter($edit, $params))
+ . Horde::img('edit.png', _("Edit"), '', $img_dir) . '</a> '
+ . Horde::link(Horde_Util::addParameter($delete, $params))
+ . Horde::img('delete.png', _("Delete"), '', $img_dir) . '</a></td>';
+?>
+</div>
+
+<?php
+if ($_SESSION['beatnik']['expertmode']) {
+ echo '<table class="striped">' . "\n";
+ foreach (Beatnik::getRecFields('soa') as $key => $value) {
+ if (isset($_SESSION['beatnik']['curdomain'][$key])) {
+ echo '<tr><td>' . $value['name'] . '</td><td>' . $_SESSION['beatnik']['curdomain'][$key] . '</td></tr>' . "\n";
+ }
+ }
+ echo '</table><br />' . "\n";
+}
+?>
+<table class="striped">
+<thead>
+<tr>
+ <th><?php echo _("Actions")?></th>
+ <th><?php echo _("Type") ?></th>
+ <?php
+ foreach ($fields as $field => $fdata) {
+ if ((($fdata['infoset'] == 'basic') || $_SESSION['beatnik']['expertmode']) && $fdata['type'] != 'hidden') {
+ echo '<th>' . $fdata['name'] . '</th>' . "\n";
+ }
+ }
+ ?>
+</tr>
+</thead>
+<tbody>
--- /dev/null
+<?php
+/**
+ * $Horde: beatnik/templates/view/record.inc,v 1.13 2009/07/03 10:05:31 duck Exp $
+ *
+ * Copyright 2005-2007 Ben Klang <ben@alkaloid.net>
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ */
+
+foreach ($zonedata[$type] as $record) {
+
+ $params = array('id' => $record['id'], 'rectype' => $type);
+ echo '<tr>' . "\n";
+ echo '<td>' . Horde::link(Horde_Util::addParameter($edit, $params))
+ . Horde::img('edit.png', _("Edit"), '', $img_dir) . '</a> '
+ . Horde::link(Horde_Util::addParameter($delete, $params))
+ . Horde::img('delete.png', _("Delete"), '', $img_dir) . '</a></td>';
+ echo '<td>' . $rectypes[$type] . '</td>';
+
+ foreach ($fields as $field => $fdata) {
+
+ if ((($fdata['infoset'] != 'basic') && !$_SESSION['beatnik']['expertmode']) || $fdata['type'] == 'hidden') {
+ continue;
+ }
+
+ echo '<td>' . "\n";
+
+ if (!isset($record[$field])) {
+ continue;
+ }
+
+ if (is_array($record[$field])) {
+ foreach ($record[$field] as $entry) {
+ echo $entry;
+ }
+ } else {
+ echo $record[$field];
+ }
+
+ echo '</td>' . "\n";
+ }
+
+ echo '</tr>' . "\n";
+}
--- /dev/null
+/**
+ * $Horde: beatnik/themes/screen.css,v 1.5 2006/12/18 05:56:52 chuck Exp $
+ */
+
+.zoneData {
+ border: 1px solid #000;
+ padding: 2px;
+}
+
+.soa {
+ border: 1px solid #111;
+ padding: 2px;
+ font-size: 120%
+}
--- /dev/null
+<?php
+/**
+ * $Horde: beatnik/viewzone.php,v 1.21 2009/07/03 10:05:29 duck Exp $
+ *
+ * Copyright 2005-2007 Ben Klang <ben@alkaloid.net>
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ */
+
+define('BEATNIK_BASE', dirname(__FILE__));
+require_once BEATNIK_BASE . '/lib/base.php';
+require_once BEATNIK_BASE . '/lib/Beatnik.php';
+
+$zonedata = $beatnik_driver->getRecords($_SESSION['beatnik']['curdomain']['zonename']);
+if (is_a($zonedata, 'PEAR_Error')) {
+ $notification->push($zonedata, 'horde.error');
+ header('Location:' . Horde::applicationUrl('listzones.php'));
+ exit;
+}
+
+$title = $_SESSION['beatnik']['curdomain']['zonename'];
+Horde::addScriptFile('stripe.js', 'horde', true);
+require BEATNIK_TEMPLATES . '/common-header.inc';
+require BEATNIK_TEMPLATES . '/menu.inc';
+
+// Get a list of all the fields for all record typess we'll be processing
+$fields = array();
+foreach ($zonedata as $type => $data) {
+ $fields = array_merge($fields, Beatnik::getRecFields($type));
+}
+
+// Remove fields that should not be shown
+foreach ($fields as $field_id => $field) {
+ if ($field['type'] == 'hidden' ||
+ ($field['infoset'] != 'basic' && !$_SESSION['beatnik']['expertmode'])) {
+ unset($field[$field_id]);
+ }
+}
+
+$img_dir = $registry->getImageDir('horde');
+$delete = Horde_Util::addParameter(Horde::applicationUrl('delete.php'), 'curdomain', $_SESSION['beatnik']['curdomain']['zonename']);
+$edit = Horde_Util::addParameter(Horde::applicationUrl('editrec.php'), 'curdomain', $_SESSION['beatnik']['curdomain']['zonename']);
+$rectypes = Beatnik::getRecTypes();
+
+require BEATNIK_TEMPLATES . '/view/header.inc';
+foreach ($rectypes as $type => $typedescr) {
+ if (!isset($zonedata[$type])) {
+ continue;
+ }
+ require BEATNIK_TEMPLATES . '/view/record.inc';
+}
+require BEATNIK_TEMPLATES . '/view/footer.inc';
+
+
+require $registry->get('templates', 'horde') . '/common-footer.inc';