inc/record.inc.php
author rejo
Tue, 10 Jul 2007 21:24:06 +0000
changeset 37 b785e54690ce
parent 36 4ec5ab29f634
child 40 ee5300058c9d
permissions -rwxr-xr-x
[feladat @ 84] Bugfix. The function zone_count() now also counts zones an owner has only partial access to, not just those zones the owner has full access to. This fixes just the count, the zones a user has partial access to are not (yet!) shown in the "list zones" page. Bugfix. In the zone listing the "edit" button is now show for users with access level 1. Untill now they were presented an overview of the zones they could change, but there was no link for them to actually edit the zone. Bugfix. Some of the buttons in the "edit zone" interface that are of no use to a user with access level 1 have been hidden. Bugfix. Make sure a user with access level 1 with only partial access to a zone cannot add new records to that zone. Only the zone owner should be able to add new record. Bugfix. If a user with access level 1 edits a record in a zone he has only partial access to, an error was shown because of call to a non- existing function in the PEAR:MDB2. This bug was most likely introduced while migrating from PEAR:DB to PEAR:MDB2. Bugfix. A user with access level 1 was able to delete all records of a zone he has only partial access to. Some additional checks have been added. Bugfix. If a user with accees level 1 has partial access to one or more zones starting with a certain character, but did not own at least one entire zone starting with the same character, the character wasn't clickable in the "list zone" page. Interface. If no record or zone id is given for delete_record.php or delete_domain.php, don't just die but echo a nice message. The i18n files have not yet been updated to reflect this change. Interface. If no master IP is given in delete_supermaster.php, don't just die but echo a nice message. The i18n files have not yet been updated to reflect this change. [All fixes by Peter Beernink.]

<?


// Filename: record.inc.php
// Startdate: 26-10-2002
// This file is ought to edit the records in the database.
// Records are domains aswell, they also belong here.
// All database functions are associative.
// use nextID first to get a new id. Then insert it into the database.
// do not rely on auto_increment (see above).
// use dns.inc.php for validation functions.
//
// $Id: record.inc.php,v 1.21 2003/05/10 20:21:01 azurazu Exp $
//


function update_soa_serial($domain_id)
{
    global $db;
	/*
	 * THIS CODE ISNT TESTED THROUGH MUCH YET!
	 * !!!!!!! BETACODE !!!!!!!!!!
	 * Code committed by DeViCeD, Thanks a lot!
	 * Heavily hax0red by Trancer/azurazu
	 *
	 * First we have to check, wheather current searial number 
	 * was already updated on the other nameservers.
	 * If field 'notified_serial' is NULL, then I guess domain is
	 * NATIVE and we don't have any secondary nameservers for this domain.
	 * NOTICE: Serial number *will* be RFC1912 compilant after update 
	 * NOTICE: This function will allow only 100 DNS zone transfers ;-)
	 * YYYYMMDDnn
	 */

	$sqlq = "SELECT `notified_serial` FROM `domains` WHERE `id` = '".$domain_id."'";
	$notified_serial = $db->queryOne($sqlq);

	$sqlq = "SELECT `content` FROM `records` WHERE `type` = 'SOA' AND `domain_id` = '".$domain_id."'";
	$content = $db->queryOne($sqlq);
    $need_to_update = false;
	
	// Getting the serial field.
	$soa = explode(" ", $content);
	
	if(empty($notified_serial))
    {
        // Ok native replication, so we have to update.
        $need_to_update = true;
    }
    elseif($notified_serial >= $soa[2])
    {
        $need_to_update = true;
    }
    elseif(strlen($soa[2]) != 10)
    {
        $need_to_update = true;
    }
    else
    {
        $need_to_update = false;
    }
    if($need_to_update)
    {
        // Ok so we have to update it seems.
        $current_serial = $soa[2];
        
		/*
		 * What we need here (for RFC1912) is YEAR, MONTH and DAY
		 * so let's get it ...
		 */
		$new_serial = date('Ymd'); // we will add revision number later

		if(strncmp($new_serial, $current_serial, 8) === 0)
		{
            /*
             * Ok, so we already made updates tonight
             * let's just increase the revision number
             */				
            $revision_number = (int) substr($current_serial, -2);
            if ($revision_number == 99) return false; // ok, we cannot update anymore tonight
            ++$revision_number;
            // here it is ... same date, new revision
            $new_serial .= str_pad($revision_number, 2, "0", STR_PAD_LEFT);	
		}
 		else
		{
            /*
			 * Current serial is not RFC1912 compilant, so let's make a new one
			 */
 			$new_serial .= '00';
		}
        $soa[2] = $new_serial; // change serial in SOA array
		$new_soa = "";		
		// build new soa and update SQL after that
		for ($i = 0; $i < count($soa); $i++) 
		{	
			$new_soa .= $soa[$i] . " "; 
		}
		$sqlq = "UPDATE `records` SET `content` = '".$new_soa."' WHERE `domain_id` = '".$domain_id."' AND `type` = 'SOA' LIMIT 1";
		$db->Query($sqlq);
		return true;
	}
}  

/*
 * Edit a record.
 * This function validates it if correct it inserts it into the database.
 * return values: true if succesful.
 */
function edit_record($recordid, $zoneid, $name, $type, $content, $ttl, $prio)
{
	global $db;
  	if($content == "")
  	{
  		error(ERR_RECORD_EMPTY_CONTENT);
  	}
  	// Edits the given record (validates specific stuff first)
	if (!xs(recid_to_domid($recordid)))
	{
		error(ERR_RECORD_ACCESS_DENIED);
	}
	if (is_numeric($zoneid))
	{
		validate_input($zoneid, $type, $content, $name, $prio, $ttl);
                $change = time();
                $db->query("UPDATE records set name='$name', type='$type', content='$content', ttl='$ttl', prio='$prio', change_date='$change' WHERE id=$recordid");
		
		/*
		 * Added by DeViCeD - Update SOA Serial number
		 * There should be more checks
		 */
		if ($type != 'SOA')
		{
			update_soa_serial($zoneid);
		}
		return true;
	}
	else
	{
		error(sprintf(ERR_INV_ARGC, "edit_record", "no zoneid given"));
	}

}


/*
 * Adds a record.
 * This function validates it if correct it inserts it into the database.
 * return values: true if succesful.
 */
function add_record($zoneid, $name, $type, $content, $ttl, $prio)
{

	global $db;
	if (!xs($zoneid))
	{
		error(ERR_RECORD_ACCESS_DENIED);
	}
	if (is_numeric($zoneid))
	{
		// Check the user input.
		validate_input($zoneid, $type, $content, $name, $prio, $ttl);

		// Generate new timestamp for the daemon
		$change = time();
		
		// Execute query.
		$db->query("INSERT INTO records (domain_id, name, type, content, ttl, prio, change_date) VALUES ($zoneid, '$name', '$type', '$content', $ttl, '$prio', $change)");
		if ($type != 'SOA')
		{
			update_soa_serial($zoneid);
		}
		return true;
	}
	else
	{
		error(sprintf(ERR_INV_ARG, "add_record"));
	}
}


function add_supermaster($master_ip, $ns_name, $account)
{
        global $db;
        if (!is_valid_ip($master_ip) && !is_valid_ip6($master_ip))
        {
                error(sprintf(ERR_INV_ARGC, "add_supermaster", "No or no valid ipv4 or ipv6 address given."));
        }
        if (!is_valid_hostname($ns_name))
        {
                error(ERR_DNS_HOSTNAME);
        }
	if (!validate_account($account))
	{
		error(sprintf(ERR_INV_ARGC, "add_supermaster", "given account name is invalid (alpha chars only)"));
	}
        if (supermaster_exists($master_ip))
        {
                error(sprintf(ERR_INV_ARGC, "add_supermaster", "supermaster already exists"));
        }
        else
        {
                $db->query("INSERT INTO supermasters VALUES ('$master_ip', '$ns_name', '$account')");
                return true;
        }
}

function delete_supermaster($master_ip)
{
        global $db;
        if (!level(5))
        {
                error(ERR_LEVEL_5);
        }
        if (is_valid_ip($master_ip) || is_valid_ip6($master_ip))
        {
                $db->query("DELETE FROM supermasters WHERE ip = '$master_ip'");
                return true;
        }
        else
        {
                error(sprintf(ERR_INV_ARGC, "delete_supermaster", "No or no valid ipv4 or ipv6 address given."));
        }
}

function get_supermaster_info_from_ip($master_ip)
{
	global $db;
        if (!level(5))
        {
                error(ERR_LEVEL_5);
        }
        if (is_valid_ip($master_ip) || is_valid_ip6($master_ip))
	{
	        $result = $db->queryRow("SELECT ip,nameserver,account FROM supermasters WHERE ip = '$master_ip'");

		$ret = array(
		"master_ip"	=>              $result["ip"],
		"ns_name"	=>              $result["nameserver"],
		"account"	=>              $result["account"]
		);

		return $ret;	
	}
        else
	{
                error(sprintf(ERR_INV_ARGC, "get_supermaster_info_from_ip", "No or no valid ipv4 or ipv6 address given."));
        }
}


/*
 * Delete a record by a given id.
 * return values: true, this function is always succesful.
 */
function delete_record($id)
{
	global $db;

	// Check if the user has access.
	if (!xs(recid_to_domid($id)))
	{
		error(ERR_RECORD_ACCESS_DENIED);
	}

	// Retrieve the type of record to see if we can actually remove it.
	$recordtype = get_recordtype_from_id($id);

	// If the record type is NS and the user tries to delete it while ALLOW_NS_EDIT is set to 0
	// OR
	// check if the name of the record isnt the domain name (if so it should delete all records)
	// OR
	// check if we are dealing with a SOA field (same story as NS)
	if (($recordtype == "NS" && $GLOBALS["ALLOW_NS_EDIT"] != 1 && (get_name_from_record_id($id) == get_domain_name_from_id(recid_to_domid($id)))) || ($recordtype == "SOA" && $GLOBALS["ALLOW_SOA_EDIT"] != 1))
	{
		error(sprintf(ERR_RECORD_DELETE_TYPE_DENIED, $recordtype));

	}
	if (is_numeric($id))
	{
	    $did = recid_to_domid($id);
		$db->query('DELETE FROM records WHERE id=' . $id . ' LIMIT 1');
		if ($type != 'SOA')
		{
			update_soa_serial($did);
		}
        // $id doesnt exist in database anymore so its deleted or just not there which means "true"	
		return true;
	}
	else
	{
		error(sprintf(ERR_INV_ARG, "delete_record"));
	}
}


/*
 * Add a domain to the database.
 * A domain is name obligatory, so is an owner.
 * return values: true when succesful.
 * Empty means templates dont have to be applied.
 * --------------------------------------------------------------------------
 * This functions eats a template and by that it inserts various records.
 * first we start checking if something in an arpa record
 * remember to request nextID's from the database to be able to insert record.
 * if anything is invalid the function will error
 */
function add_domain($domain, $owner, $webip, $mailip, $empty, $type, $slave_master)
{

	global $db;

	if (!level(5))
	{
		error(ERR_LEVEL_5);
	}

	// If domain, owner and mailip are given
	// OR
	// empty is given and owner and domain
	// OR
	// the domain is an arpa record and owner is given
	// OR
	// the type is slave, domain, owner and slave_master are given
	// THAN
	// Continue this function
	if (($domain && $owner && $webip && $mailip) || ($empty && $owner && $domain) || (eregi('in-addr.arpa', $domain) && $owner) || $type=="SLAVE" && $domain && $owner && $slave_master)
	{
                // First insert zone into domain table
                $db->query("INSERT INTO domains (name, type) VALUES ('$domain', '$type')");

                // Determine id of insert zone (in other words, find domain_id)
                $iddomain = $db->lastInsertId('domains', 'id');
                if (PEAR::isError($iddomain)) {
                        die($id->getMessage());
                }

                // Second, insert into zones tables
                $db->query("INSERT INTO zones (domain_id, owner) VALUES ('$iddomain', $owner)");

		if ($type == "SLAVE")
		{
			$db->query("UPDATE domains SET master = '$slave_master' WHERE id = '$iddomain';");
			
			// Done
			return true;
		}
		else
		{
			// Generate new timestamp. We need this one anyhow.
			$now = time();

			if ($empty && $iddomain)
			{
				// If we come into this if statement we dont want to apply templates.
				// Retrieve configuration settings.
				$ns1 = $GLOBALS["NS1"];
				$hm  = $GLOBALS["HOSTMASTER"];
				$ttl = $GLOBALS["DEFAULT_TTL"];

				// Build and execute query
				$sql = "INSERT INTO records (domain_id, name, content, type, ttl, prio, change_date) VALUES ('$iddomain', '$domain', '$ns1 $hm 1', 'SOA', $ttl, '', '$now')";
				$db->query($sql);

				// Done
				return true;
			}
			elseif ($iddomain)
			{
				// If we are here we want to apply templates.
				global $template;

				// Iterate over the template and apply it for each field.
				foreach ($template as $r)
				{
					// Same type of if statement as previous.
					if ((eregi('in-addr.arpa', $domain) && ($r["type"] == "NS" || $r["type"] == "SOA")) || (!eregi('in-addr.arpa', $domain)))
					{
						// Parse the template.
						$name     = parse_template_value($r["name"], $domain, $webip, $mailip);
						$type     = $r["type"];
						$content  = parse_template_value($r["content"], $domain, $webip, $mailip);
						$ttl      = $r["ttl"];
						$prio     = $r["prio"];

						// If no ttl is given, use the default.
						if (!$ttl)
						{
							$ttl = $GLOBALS["DEFAULT_TTL"];
						}

						$sql = "INSERT INTO records (domain_id, name, content, type, ttl, prio, change_date) VALUES ('$iddomain', '$name','$content','$type','$ttl','$prio','$now')";
						$db->query($sql);
					}
				}
				// All done.
				return true;
			 }
			 else
			 {
				error(sprintf(ERR_INV_ARGC, "add_domain", "could not create zone"));
			 }
		}
	}
	else
	{
		error(sprintf(ERR_INV_ARG, "add_domain"));
	}
}


/*
 * Deletes a domain by a given id.
 * Function always succeeds. If the field is not found in the database, thats what we want anyway.
 */
function delete_domain($id)
{
	global $db;

	if (!level(5))
	{
		error(ERR_LEVEL_5);
	}

	// See if the ID is numeric.
	if (is_numeric($id))
	{
		$db->query("DELETE FROM zones WHERE domain_id=$id");
		$db->query("DELETE FROM domains WHERE id=$id");
		$db->query("DELETE FROM records WHERE domain_id=$id");
		// Nothing in the database. If the delete deleted 0 records it means the id is just not there.
		// therefore the is no need to check the affectedRows values.
		return true;
	}
	else
	{
		error(sprintf(ERR_INV_ARGC, "delete_domain", "id must be a number"));
	}
}


/*
 * Gets the id of the domain by a given record id.
 * return values: the domain id that was requested.
 */
function recid_to_domid($id)
{
	global $db;
	if (is_numeric($id))
	{
		$result = $db->query("SELECT domain_id FROM records WHERE id=$id");
		$r = $result->fetchRow();
		return $r["domain_id"];
	}
	else
	{
		error(sprintf(ERR_INV_ARGC, "recid_to_domid", "id must be a number"));
	}
}


/*
 * Sorts a zone by records.
 * return values: the sorted zone.
 */
function sort_zone($records)
{
	$ar_so = array();
	$ar_ns = array();
	$ar_mx = array();
	$ar_mb = array();
	$ar_ur = array();
	$ar_ov = array();
	foreach ($records as $c)
	{
		switch(strtoupper($c['type']))
		{
			case "SOA":
				$ar_so[] = $c;
				break;
			case "NS":
				$ar_ns[] = $c;
				break;
			case "MX":
				$ar_mx[] = $c;
				break;
			case "MBOXFW":
				$ar_mb[] = $c;
				break;
			case "URL":
				$ar_ur[] = $c;
				break;
			default:
				$ar_ov[] = $c;
				break;
		}
	}

	$res = array_merge($ar_so, $ar_ns, $ar_mx, $ar_mb, $ar_ur, $ar_ov);

	if (count($records) == count($res))
	{
		$records = $res;
	}
	else
	{
		error(sprintf(ERR_INV_ARGC, "sort_zone", "records sorting failed!"));
	}
	return $records;
}


/*
 * Change owner of a domain.
 * Function should actually be in users.inc.php. But its more of a record modification than a user modification
 * return values: true when succesful.
 */
function add_owner($domain, $newowner)
{
	global $db;

	if (!level(5))
	{
		error(ERR_LEVEL_5);
	}

	if (is_numeric($domain) && is_numeric($newowner) && is_valid_user($newowner))
	{
		if($db->queryOne("SELECT COUNT(id) FROM zones WHERE owner=$newowner AND domain_id=$domain") == 0)
		{
			$db->query("INSERT INTO zones (domain_id, owner) VALUES($domain, $newowner)");
		}
		return true;
	}
	else
	{
		error(sprintf(ERR_INV_ARGC, "change_owner", "$domain / $newowner"));
	}
}


function delete_owner($domain, $owner)
{
	global $db;
	if($db->queryOne("SELECT COUNT(id) FROM zones WHERE owner=$owner AND domain_id=$domain") != 0)
	{
		$db->query("DELETE FROM zones WHERE owner=$owner AND domain_id=$domain");
	}
	return true;
}

/*
 * Retrieves all supported dns record types
 * This function might be deprecated.
 * return values: array of types in string form.
 */
function get_record_types()
{
	global $rtypes;
	return $rtypes;
}


/*
 * Retrieve all records by a given type and domain id.
 * Example: get all records that are of type A from domain id 1
 * return values: a DB class result object
 */
function get_records_by_type_from_domid($type, $recid)
{
	global $rtypes;
	global $db;

	// Does this type exist?
	if(!in_array(strtoupper($type), $rtypes))
	{
		error(sprintf(ERR_INV_ARGC, "get_records_from_type", "this is not a supported record"));
	}

	// Get the domain id.
	$domid = recid_to_domid($recid);

	$result = $db->query("select id, type from records where domain_id=$recid and type='$type'");
	return $result;
}


/*
 * Retrieves the type of a record from a given id.
 * return values: the type of the record (one of the records types in $rtypes assumable).
 */
function get_recordtype_from_id($id)
{
	global $db;
	if (is_numeric($id))
	{
		$result = $db->query("SELECT type FROM records WHERE id=$id");
		$r = $result->fetchRow();
		return $r["type"];
	}
	else
	{
		error(sprintf(ERR_INV_ARG, "get_recordtype_from_id"));
	}
}


/*
 * Retrieves the name (e.g. bla.test.com) of a record by a given id.
 * return values: the name associated with the id.
 */
function get_name_from_record_id($id)
{
	global $db;
	if (is_numeric($id))
	{
		$result = $db->query("SELECT name FROM records WHERE id=$id");
		$r = $result->fetchRow();
		return $r["name"];
	}
	else
	{
		error(sprintf(ERR_INV_ARG, "get_name_from_record_id"));
	}
}


/*
 * Get all the domains from a database of which the user is the owner.
 * return values: an array with the id of the domain and its name.
 */
function get_domains_from_userid($id)
{
	global $db;
	if (is_numeric($id))
	{
		$result = $db->query("SELECT domains.id AS domain_id, domains.name AS name FROM domains LEFT JOIN zones ON domains.id=zones.domain_id WHERE owner=$id");

		$ret = array();

		// Put all the information in a big array.
		while ($r = $result->fetchRow())
		{
			$ret[] = array(
			"id"            =>              $r["domain_id"],
			"name"          =>              $r["name"]
			);
		}
		return $ret;
	}
	else
	{
		error(sprintf(ERR_INV_ARGC, "get_domains_from_userid", "This is not a valid userid: $id"));
	}
}


/*
 * Get domain name from a given id
 * return values: the name of the domain associated with the id.
 */
function get_domain_name_from_id($id)
{
	global $db;
	if (!xs($id))
	{
		error(ERR_RECORD_ACCESS_DENIED);
	}
	if (is_numeric($id))
	{
		$result = $db->query("SELECT name FROM domains WHERE id=$id");
		if ($result->numRows() == 1)
		{
 			$r = $result->fetchRow();
 			return $r["name"];
		}
		else
		{
	 		error(sprintf(ERR_INV_ARGC, "get_domain_name_from_id", "more than one domain found?! whaaa! BAD! BAD! Contact admin!"));
		}
	}
	else
	{
		error(sprintf(ERR_INV_ARGC, "get_domain_name_from_id", "Not a valid domainid: $id"));
	}
}


/*
 * Get information about a domain name from a given domain id.
 * the function looks up the domainname, the owner of the domain and the number of records in it.
 * return values: an array containing the information.
 */
function get_domain_info_from_id($id)
{
	global $db;
	if (!xs($id))
	{
		error(ERR_RECORD_ACCESS_DENIED);
	}
	if (is_numeric($id))
	{

	if ($_SESSION[$id."_ispartial"] == 1) {
	
	$sqlq = "SELECT 
	domains.type AS type,
	domains.name AS name,
	users.fullname AS owner,
	count(record_owners.id) AS aantal
	FROM domains, users, record_owners, records
	
        WHERE record_owners.user_id = ".$_SESSION["userid"]."
        AND record_owners.record_id = records.id
	AND records.domain_id = ".$id."

	GROUP BY name, owner, users.fullname
	ORDER BY name";
	
	$result = $db->queryRow($sqlq);

	$ret = array(
	"name"          =>              $result["name"],
	"ownerid"       =>              $_SESSION["userid"],
	"owner"         =>              $result["owner"],
	"type"		=>		$result["type"],
	"numrec"        =>              $result["aantal"]
	);

	return $ret;

	} else{
	
		// Query that retrieves the information we need.
		$sqlq = "SELECT 
			domains.type AS type,
			domains.name AS name,
			min(zones.owner) AS ownerid,
			users.fullname AS owner,
			count(records.domain_id) AS aantal
			FROM domains
			LEFT JOIN records ON domains.id=records.domain_id
			LEFT JOIN zones ON domains.id=zones.domain_id
			LEFT JOIN users ON zones.owner=users.id
			WHERE domains.id=$id
			GROUP BY name, owner, users.fullname
			ORDER BY zones.id";

		// Put the first occurence in an array and return it.
		$result = $db->queryRow($sqlq);

		//$result["ownerid"] = ($result["ownerid"] == NULL) ? $db->queryOne("select min(id) from users where users.level=10") : $result["ownerid"];

		$ret = array(
		"name"          =>              $result["name"],
		"ownerid"       =>              $result["ownerid"],
		"owner"         =>              $result["owner"],
		"type"          =>              $result["type"],
		"numrec"        =>              $result["aantal"]
		);
		return $ret;
	}

	}
	else
	{
		error(sprintf(ERR_INV_ARGC, "get_domain_num_records_from_id", "This is not a valid domainid: $id"));
	}
}


/*
 * Check if a domain is already existing.
 * return values: true if existing, false if it doesnt exist.
 */
function domain_exists($domain)
{
	global $db;

	if (!level(5))
	{
		error(ERR_LEVEL_5);
	}
	if (is_valid_domain($domain))
	{
		$result = $db->query("SELECT id FROM domains WHERE name='$domain'");
		if ($result->numRows() == 0)
		{
			return false;
		}
		elseif ($result->numRows() >= 1)
		{
			return true;
		}
	}
	else
	{
		error(ERR_DOMAIN_INVALID);
	}
}

function get_supermasters()
{
        global $db;
        $result = $db->query("SELECT ip, nameserver, account FROM supermasters");
        $ret = array();

        if($result->numRows() == 0)
        {
                return -1;
        }
        else
        {
                while ($r = $result->fetchRow())
                {
                        $ret[] = array(
                        "master_ip"     => $r["ip"],
                        "ns_name"       => $r["nameserver"],
                        "account"       => $r["account"],
                        );
                }
		return $ret;
        }
}

function supermaster_exists($master_ip)
{
        global $db;
        if (!level(5))
        {
                error(ERR_LEVEL_5);
        }
        if (is_valid_ip($master_ip) || is_valid_ip6($master_ip))
        {
                $result = $db->query("SELECT ip FROM supermasters WHERE ip = '$master_ip'");
                if ($result->numRows() == 0)
                {
                        return false;
                }
                elseif ($result->numRows() >= 1)
                {
                        return true;
                }
        }
        else
        {
                error(sprintf(ERR_INV_ARGC, "supermaster_exists", "No or no valid IPv4 or IPv6 address given."));
        }
}


/*
 * Get all domains from the database 
 * This function gets all the domains from the database unless a user id is below 5.
 * if a user id is below 5 this function will only retrieve records for that user.
 * return values: the array of domains or -1 if nothing is found.
 */
function get_domains($userid=true,$letterstart=all,$rowstart=0,$rowamount=999999)
{
	global $db;
	if((!level(5) || !$userid) && !level(10) && !level(5))
	{
		$add = " AND zones.owner=".$_SESSION["userid"];
	}
	else
	{
		$add = "";
	}

	$sqlq = "SELECT domains.id AS domain_id,
	min(zones.owner) AS owner,
	count(DISTINCT records.id) AS aantal,
	domains.name AS domainname
	FROM domains
	LEFT JOIN zones ON domains.id=zones.domain_id 
	LEFT JOIN records ON records.domain_id=domains.id
	WHERE 1 $add ";
	if ($letterstart!=all && $letterstart!=1) {
	   $sqlq.=" AND substring(domains.name,1,1) REGEXP '^".$letterstart."' ";
	} elseif ($letterstart==1) {
	   $sqlq.=" AND substring(domains.name,1,1) REGEXP '^[[:digit:]]'";
	}
	$sqlq.=" GROUP BY domainname, domain_id
	ORDER BY domainname
	LIMIT $rowstart,$rowamount";

	$result = $db->query($sqlq);
	$result2 = $db->query($sqlq); 
	
	$numrows = $result2->numRows();
	$i=1;
	if ($numrows > 0) {
		$andnot=" AND NOT domains.id IN (";
		while($r = $result2->fetchRow()) {
			$andnot.=$r["domain_id"];
			if ($i < $numrows) {
				$andnot.=",";
				$i++;
			}
		}
		$andnot.=")";
	}
	else
	{
		$andnot="";
	}

	if ($letterstart!=all && $letterstart!=1) {

		$sqlq = "SELECT domains.id AS domain_id,
		count(DISTINCT record_owners.record_id) AS aantal,
		domains.name AS domainname
		FROM domains, record_owners,records, zones
		WHERE record_owners.user_id = '".$_SESSION["userid"]."'
		AND (records.id = record_owners.record_id
		AND domains.id = records.domain_id)
		$andnot 
		AND domains.name LIKE '".$letterstart."%' 
		AND (zones.domain_id != records.domain_id AND zones.owner!='".$_SESSION["userid"]."')
		GROUP BY domainname, domain_id
		ORDER BY domainname";

		$result_extra = $db->query($sqlq);

	} else {

		$sqlq = "SELECT domains.id AS domain_id,
		count(DISTINCT record_owners.record_id) AS aantal,
		domains.name AS domainname
		FROM domains, record_owners,records, zones
		WHERE record_owners.user_id = '".$_SESSION["userid"]."'
		AND (records.id = record_owners.record_id
		AND domains.id = records.domain_id)
		$andnot 
		AND substring(domains.name,1,1) REGEXP '^[[:digit:]]'
		AND (zones.domain_id != records.domain_id AND zones.owner!='".$_SESSION["userid"]."')
		GROUP BY domainname, domain_id
		ORDER BY domainname";

		$result_extra[$i] = $db->query($sqlq);

	}

	while($r = $result->fetchRow())
	{
		$r["owner"] = ($r["owner"] == NULL) ? $db->queryOne("select min(id) from users where users.level=10") : $r["owner"];
	     	$ret[$r["domainname"]] = array(
		"name"          =>              $r["domainname"],
		"id"            =>              $r["domain_id"],
		"owner"         =>              $r["owner"],
		"numrec"        =>              $r["aantal"]
		);
	}


	if ($letterstart!=all && $letterstart!=1) {

		while($r = $result_extra->fetchRow())
		{
		       $ret[$r["domainname"]] = array(
		       "name"          =>              $r["domainname"]."*",
		       "id"            =>              $r["domain_id"],
		       "owner"         =>              $_SESSION["userid"],
		       "numrec"        =>              $r["aantal"]
		       );
		       $_SESSION["partial_".$r["domainname"]] = 1;
		}

	} else {

		foreach ($result_extra as $result_e) {
		while($r = $result_e->fetchRow())
		{
		       $ret[$r["domainname"]] = array(
		       "name"          =>              $r["domainname"]."*",
		       "id"            =>              $r["domain_id"],
		       "owner"         =>              $_SESSION["userid"],
		       "numrec"        =>              $r["aantal"]
		       );
		       $_SESSION["partial_".$r["domainname"]] = 1;
		}
		}

	}

	if (empty($ret)) {
	   return -1;
	} else {
	   sort($ret);
	   return $ret;
	}

}


/*
 * zone_count
 * Does a select query to count how many zones we have in the database
 *
 * @todo: see whether or not it is possible to add the records
 * @param $userid integer The userid of the current user
 * @return integer the number of zones
 */

function zone_count($userid=true, $letterstart=all) {
        global $db;
        if((!level(5) || !$userid) && !level(10) && !level(5))
        {
		// First select the zones for which we have ownership on one or more records.
		$query = 'SELECT records.domain_id FROM records, record_owners WHERE user_id = '.$_SESSION['userid'].' AND records.id = record_owners.record_id';
		$result = $db->query($query);
		$zones = array();
		if (!PEAR::isError($result)) {
			$zones = $result->fetchCol();
		}
	
                $add = " AND (zones.owner=".$_SESSION["userid"];
		if (count($zones) > 0) {
			$add .= ' OR zones.domain_id IN ('.implode(',', $zones).') '; 

		}
		$add .= ')';
        }
        else
        {
                $add = "";
        }

        if ($letterstart!=all && $letterstart!=1) {
           $add .=" AND domains.name LIKE '".$letterstart."%' ";
        } elseif ($letterstart==1) {
           $add .=" AND substring(domains.name,1,1) REGEXP '^[[:digit:]]'";
        }

        $query = 'SELECT count(distinct zones.domain_id) as zone_count FROM zones, domains WHERE zones.domain_id = domains.id '.$add;
        $numRows = $db->queryOne($query);
        return $numRows;
}

/*
 * Get a record from an id.
 * Retrieve all fields of the record and send it back to the function caller.
 * return values: the array with information, or -1 is nothing is found.
 */
function get_record_from_id($id)
{
	global $db;
	if (is_numeric($id))
	{
		$result = $db->query("SELECT id, domain_id, name, type, content, ttl, prio, change_date FROM records WHERE id=$id");
		if($result->numRows() == 0)
		{
			return -1;
		}
		elseif ($result->numRows() == 1)
		{
			$r = $result->fetchRow();
			$ret = array(
			"id"            =>      $r["id"],
			"domain_id"     =>      $r["domain_id"],
			"name"          =>      $r["name"],
			"type"          =>      $r["type"],
			"content"       =>      $r["content"],
			"ttl"           =>      $r["ttl"],
			"prio"          =>      $r["prio"],
			"change_date"   =>      $r["change_date"]
			);
			return $ret;
		}
		else
		{
			error(sprintf(ERR_INV_ARGC, "get_record_from_id", "More than one row returned! This is bad!"));
		}
	}
	else
	{
		error(sprintf(ERR_INV_ARG, "get_record_from_id"));
	}
}


/*
 * Get all records from a domain id.
 * Retrieve all fields of the records and send it back to the function caller.
 * return values: the array with information, or -1 is nothing is found.
 */
function get_records_from_domain_id($id,$rowstart=0,$rowamount=999999)
{
	global $db;
	if (is_numeric($id))
	{
		if ($_SESSION[$id."_ispartial"] == 1) {

		$result = $db->query("SELECT record_owners.record_id as id
		FROM record_owners,domains,records
		WHERE record_owners.user_id = ".$_SESSION["userid"]."
		AND record_owners.record_id = records.id
		AND records.domain_id = ".$id."
		GROUP bY record_owners.record_id
		LIMIT $rowstart,$rowamount");

		$ret = array();
		if($result->numRows() == 0)
		{
		return -1;
		}
		else
		{
		$ret[] = array();
		$retcount = 0;
		while($r = $result->fetchRow())
		{
		// Call get_record_from_id for each row.
		$ret[$retcount] = get_record_from_id($r["id"]);
		$retcount++;
		}
		return $ret;
		}

		} else {

		$result = $db->query("SELECT id FROM records WHERE domain_id=$id LIMIT $rowstart,$rowamount");
		$ret = array();
		if($result->numRows() == 0)
		{
			return -1;
		}
		else
		{
			$ret[] = array();
			$retcount = 0;
			while($r = $result->fetchRow())
			{
				// Call get_record_from_id for each row.
				$ret[$retcount] = get_record_from_id($r["id"]);
				$retcount++;
			}
			return $ret;
		}

		}
	}
	else
	{
		error(sprintf(ERR_INV_ARG, "get_records_from_domain_id"));
	}
}


function get_users_from_domain_id($id)
{
	global $db;
	$result = $db->queryCol("SELECT owner FROM zones WHERE domain_id=$id");
	$ret = array();
	foreach($result as $uid)
	{
		$fullname = $db->queryOne("SELECT fullname FROM users WHERE id=$uid");
		$ret[] = array(
		"id" 		=> 	$uid,
		"fullname"	=>	$fullname		
		);		
	}
	return $ret;	
}

function search_record($question)
{
	global $db;
	$question = trim($question);
	if (empty($question)) 
	{
		$S_INPUT_TYPE = -1;
	}

	/* now for some input-type searching */
	if (is_valid_ip($question) || is_valid_ip6($question))
	{
		$S_INPUT_TYPE = 0;
	}
	elseif(is_valid_domain($question) || 
		is_valid_hostname($question) ||
		is_valid_mboxfw($question)) // I guess this one can appear in records table too (content?!)
	{
		$S_INPUT_TYPE = 1;
	}	  
	else 
	{
		$S_INPUT_TYPE = -1;
	}
	switch($S_INPUT_TYPE)
	{
		case '0': 
			$sqlq = "SELECT * FROM `records` WHERE `content` = '".$question."' ORDER BY `type` DESC";
			$result = $db->query($sqlq);
			$ret_r = array();
			while ($r = $result->fetchRow())
			{
			    if(xs($r['domain_id']))
			    {
    				$ret_r[] = array(
    				  'id'			=>	$r['id'],
    				  'domain_id'		=>	$r['domain_id'],
    				  'name'		=>	$r['name'],
    				  'type'		=>	$r['type'],
    				  'content'		=>	$r['content'],
    				  'ttl'			=>	$r['ttl'],
    				  'prio'		=>	$r['prio'],
    				  'change_date'		=>	$r['change_date']
    				);
				}
			}
			break;
	    
		case '1' :
			$sqlq = "SELECT `domains`.*, count(`records`.`id`) AS `numrec`, `zones`.`owner`, `records`.`domain_id`
					FROM `domains`, `records`, `zones`  
					WHERE `domains`.`id` = `records`.`domain_id` 
					AND `zones`.`domain_id` = `domains`.`id` 
					AND `domains`.`name` = '".$question."' 
					GROUP BY (`domains`.`id`)";

			$result = $db->query($sqlq);
			$ret_d = array();
			while ($r = $result->fetchRow())
			{
			    if(xs($r['domain_id']))
			    {
				    $ret_d[] = array(
    					'id'			=>	$r['id'],
    					'name'		=>	$r['name'],
    					'numrec'		=>	$r['numrec'],
    					'owner'		=>	$r['owner']
    				);
				}
			}

			$sqlq = "SELECT * FROM `records` WHERE `name` = '".$question."' OR `content` = '".$question."' ORDER BY `type` DESC";
			$result = $db->query($sqlq);
			while ($r = $result->fetchRow())
			{
			    if(xs($r['domain_id']))
			    {
    				$ret_r[] = array(
    					'id'			=>	$r['id'],
    					'domain_id'		=>	$r['domain_id'],
    					'name'		=>	$r['name'],
    					'type'		=>	$r['type'],
    					'content'		=>	$r['content'],
    					'ttl'			=>	$r['ttl'],
    					'prio'		=>	$r['prio'],
    				);
    			}
			}
			break;
	}
	if($S_INPUT_TYPE == 1)
	{
		return array('domains' => $ret_d, 'records' => $ret_r);
	}
	return array('records' => $ret_r);
}

function get_domain_type($id)
{
	global $db;
        if (is_numeric($id))
	{
		$type = $db->queryOne("SELECT `type` FROM `domains` WHERE `id` = '".$id."'");
		if($type == "")
		{
			$type = "NATIVE";
		}
		return $type;
        }
        else
        {
                error(sprintf(ERR_INV_ARG, "get_record_from_id", "no or no valid zoneid given"));
        }
}

function get_domain_slave_master($id)
{
	global $db;
        if (is_numeric($id))
	{
		$slave_master = $db->queryOne("SELECT `master` FROM `domains` WHERE `type` = 'SLAVE' and `id` = '".$id."'");
		return $slave_master;
        }
        else
        {
                error(sprintf(ERR_INV_ARG, "get_domain_slave_master", "no or no valid zoneid given"));
        }
}

function change_domain_type($type, $id)
{
	global $db;
	unset($add);
        if (is_numeric($id))
	{
		// It is not really neccesary to clear the master field if a 
		// zone is not of the type "slave" as powerdns will ignore that
		// fiedl, but it is cleaner anyway.
		if ($type != "SLAVE")
		{
			$add = ", master=''";
		}
		$result = $db->query("UPDATE `domains` SET `type` = '" .$type. "'".$add." WHERE `id` = '".$id."'");
	}
        else
        {
                error(sprintf(ERR_INV_ARG, "change_domain_type", "no or no valid zoneid given"));
        }
}

function change_domain_slave_master($id, $slave_master)
{
	global $db;
        if (is_numeric($id))
	{
       		if (is_valid_ip($slave_master) || is_valid_ip6($slave_master))
		{
			$result = $db->query("UPDATE `domains` SET `master` = '" .$slave_master. "' WHERE `id` = '".$id."'");
		}
		else
		{
			error(sprintf(ERR_INV_ARGC, "change_domain_slave_master", "This is not a valid IPv4 or IPv6 address: $slave_master"));
		}
	}
        else
        {
                error(sprintf(ERR_INV_ARG, "change_domain_type", "no or no valid zoneid given"));
        }
}


function validate_account($account)
{
	
  	if(preg_match("/^[A-Z0-9._-]+$/i",$account))
	{
		return true;
	}
	else
	{
		return false;
	}
}
?>