r2276 added support for file attachments (re: ticket 56)
authorAaron Dummer <aaron@dummer.info>
Mon, 10 Nov 2008 17:13:27 +0000 (17:13 +0000)
committerAaron Dummer <aaron@dummer.info>
Mon, 10 Nov 2008 17:13:27 +0000 (17:13 +0000)
21 files changed:
ChangeLog
README
download.php [new file with mode: 0644]
file_link_helper.php [new file with mode: 0644]
inc/config.php
inc/database.php
inc/functions.php
inc/interface.php
inc/navigation.php
inc/ophandlers.php
inc/pagetitles.php
index.php
install.php
install/init-dictbase.sql
install/init-structure.sql
pix/download.png [new file with mode: 0644]
pix/files.png [new file with mode: 0644]
pix/filler.png [new file with mode: 0644]
port_link_helper.php [moved from link_helper.php with 81% similarity]
process.php
upgrade.php

index 1b87b1b..5da0969 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,5 @@
 0.17.0
+       new feature: file attachments (by Aaron)
        update: display row name when listing objects. closes ticket 16 (by Aaron)
        bugfix: show error message if snmp module isn't loaded.  closes ticket 43 (by Aaron)
 0.16.4 2008-11-04
diff --git a/README b/README
index 3769f0a..9da6046 100644 (file)
--- a/README
+++ b/README
@@ -17,8 +17,8 @@ Authors: <info/=@=/racktables.org>
 I. Dependencies.
 
 For database you must have a MySQL server installation
-version 4.x or 5.x. It is a good idea to make it use UTF-8
-by default.
+version 4.x or 5.x. InnoDB support must be enabled.
+It is a good idea to make it use UTF-8 by default.
 
 * Fedora 8/9: yum install mysql-server mysql
 put "default-character-set=utf8" into /etc/my.cnf
@@ -43,7 +43,7 @@ php2-snmp and php5-ldap
 II. Prepare the server.
 1. Unpack the tarball and make it web-accessible, e.g. http://yourcompany.com/racktables
 or http://racktables.mysite.org.
-2. mysql> create database_name; grant all privileges on database_name.* to XXX@YYY identified by 'ZZZ';
+2. mysql> create database database_name; grant all privileges on database_name.* to XXX@YYY identified by 'ZZZ';
 
 
 There are two mutually exclusive ways to install RackTables, they are described as III-A and III-B.
@@ -125,8 +125,14 @@ during the upgrade.
 
 *** Upgrading to 0.17.0 ***
 
-This release requires presence of release 0.16.4 or 0.16.5. To upgrade from
-older releases, first download a copy of RackTables-0.16.4 and use it to
-upgrade your installation to version 0.16.4. Then follow the usual procedure
-to finish the upgrade to 0.17.0.
-
+This release is the first to take advantage of the foreign key support 
+provided by the InnoDB storage engine in MySQL.  The installer and 
+upgrader scripts check for InnoDB support and cannot complete without it.
+If you have trouble, the first step is to make sure the 'skip-innodb'
+option in my.cnf is commented out.
+
+Another change is the addition of support for file uploads.  Files are stored
+in the database.  There are several settings in php.ini which you may need to modify:
+    file_uploads        - needs to be On
+    upload_max_filesize - max size for uploaded files
+    post_max_size       - max size of all form data submitted via POST (including files)                 
diff --git a/download.php b/download.php
new file mode 100644 (file)
index 0000000..6aa3212
--- /dev/null
@@ -0,0 +1,18 @@
+<?php
+require 'inc/init.php';
+
+if (empty($_REQUEST['file_id']))
+{
+       showError ("Invalid file specified", __FILE__);
+       die();
+}
+
+$file = getFile($_REQUEST['file_id']);
+if ($file != NULL) 
+{
+       header("Content-Type: {$file['type']}");
+       header("Content-Length: {$file['size']}");
+       header("Content-Disposition: attachment; filename={$file['name']}");
+       echo $file['contents'];
+}
+?>
diff --git a/file_link_helper.php b/file_link_helper.php
new file mode 100644 (file)
index 0000000..6a82236
--- /dev/null
@@ -0,0 +1,75 @@
+<?php
+       require 'inc/init.php';
+       // This is our context.
+       $pageno = 'files';
+       $tabno = 'default';
+       fixContext();
+       if (!permitted())
+       {
+               renderAccessDenied();
+               die;
+       }
+?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" style="height: 100%;">
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<?php
+echo '<title>' . getTitle ($pageno, $tabno) . "</title>\n";
+echo "<link rel=stylesheet type='text/css' href=pi.css />\n";
+echo "<link rel=icon href='" . getFaviconURL() . "' type='image/x-icon' />";
+?>
+</head>
+<body style="height: 100%;">
+<form action="javascript:;">
+<div style="background-color: #f0f0f0; border: 1px solid #3c78b5; padding: 10px; height: 100%; text-align: center; margin: 5px;">
+<h2>Choose a file:</h2><br><br>
+<input type=hidden id='file_name'>
+<select size=<?php echo getConfigVar ('MAXSELSIZE'); ?> id="file_id">
+<?php
+       $entity_type = $_REQUEST['entity_type'];
+       $entity_id = $_REQUEST['entity_id'];
+
+       // Append different param to URL depending on entity_type
+       switch ($entity_type)
+       {
+               case 'ipv4net':
+                       $entity_param = 'id';
+                       break;
+               case 'ipv4rspool':
+                       $entity_param = 'pool_id';
+                       break;
+               case 'ipv4vs':
+                       $entity_param = 'vs_id';
+                       break;
+               case 'object':
+                       $entity_param = 'object_id';
+                       break;
+               case 'rack':
+                       $entity_param = 'rack_id';
+                       break;
+               case 'user':
+                       $entity_param = 'user_id';
+                       break;
+       }
+
+
+       $files = getAllUnlinkedFiles($entity_type, $entity_id);
+       foreach ($files as $file)
+       {
+               echo "<option value='${file['id']}' onclick='getElementById(\"file_name\").value=\"${file['name']}\";'>${file['name']}</option>\n";
+       }
+?>
+</select><br><br>
+<?php
+       echo "<input type='submit' value='Proceed' onclick='" .
+       "if (getElementById(\"file_id\").value != \"\") {\n" .
+       "       opener.location=\"${root}process.php?page=$entity_type&tab=files&op=linkFile&entity_type=$entity_type&entity_id=$entity_id&$entity_param=$entity_id&file_id=\"+getElementById(\"file_id\").value+\"&file_name=\"+getElementById(\"file_name\").value; \n" .
+       "       window.close();" .
+       "}" .
+       "'>";
+?>
+</div>
+</form>
+</body>
+</html>
index de937cd..299cf73 100644 (file)
@@ -11,7 +11,7 @@
 
 
 // Current code version is subject to change with each new release.
-define ('CODE_VERSION', '0.16.4');
+define ('CODE_VERSION', '0.17.0');
 
 // The name of hash used to store account password hashes
 // in the database. I think, we are happy with this one forever.
index e491ffe..8a7c966 100644 (file)
@@ -5,6 +5,23 @@
 *
 */
 
+function isInnoDBSupported ($dbh = FALSE) {
+       global $dbxlink;
+
+       // sometimes db handle isn't available globally, must be passed
+       if (!$dbxlink)
+               $dbxlink = $dbh;
+
+       // create a temp table
+       $dbxlink->query("CREATE TABLE `innodb_test` (`id` int) ENGINE=InnoDB");
+       $row = $dbxlink->query("SHOW TABLE STATUS LIKE 'innodb_test'")->fetch(PDO::FETCH_ASSOC);
+       $dbxlink->query("DROP TABLE `innodb_test`");
+       if ($row['Engine'] == 'InnoDB')
+               return TRUE;
+
+       return FALSE;
+}
+
 function escapeString ($value, $do_db_escape = TRUE)
 {
        $ret = htmlspecialchars ($value, ENT_QUOTES, 'UTF-8');
@@ -1400,6 +1417,35 @@ function getAccountSearchResult ($terms)
        return array_merge ($byUsername, $byRealname);
 }
 
+function getFileSearchResult ($terms)
+{
+       $byFilename = getSearchResultByField
+       (
+               'File',
+               array ('id', 'name', 'comment'),
+               'name',
+               $terms,
+               'name'
+       );
+       $byComment = getSearchResultByField
+       (
+               'File',
+               array ('id', 'name', 'comment'),
+               'comment',
+               $terms,
+               'name'
+       );
+       // Filter out dupes.
+       foreach ($byFilename as $res1)
+               foreach (array_keys ($byComment) as $key2)
+                       if ($res1['id'] == $byComment[$key2]['id'])
+                       {
+                               unset ($byComment[$key2]);
+                               continue 2;
+                       }
+       return array_merge ($byFilename, $byComment);
+}
+
 function getSearchResultByField ($tname, $rcolumns, $scolumn, $terms, $ocolumn = '')
 {
        $pfx = '';
@@ -1678,17 +1724,18 @@ function renderTagStats ()
        echo '<th>IPv4 VS</th><th>IPv4 RS pools</th><th>users</th></tr>';
        $pagebyrealm = array
        (
-               'object' => 'objgroup&group_id=0',
+               'file' => 'filesbylink&entity_type=all',
                'ipv4net' => 'ipv4space&tab=default',
-               'rack' => 'rackspace&tab=default',
                'ipv4vs' => 'ipv4vslist&tab=default',
                'ipv4rspool' => 'ipv4rsplist&tab=default',
+               'object' => 'objgroup&group_id=0',
+               'rack' => 'rackspace&tab=default',
                'user' => 'userlist&tab=default'
        );
        foreach ($refc as $ref)
        {
                echo "<tr><td>${ref['tag']}</td><td>${ref['refcnt']}</td>";
-               foreach (array ('object', 'ipv4net', 'rack', 'ipv4vs', 'ipv4rspool', 'user') as $realm)
+               foreach (array ('file', 'ipv4net', 'ipv4rspool', 'ipv4vs', 'object', 'rack', 'user') as $realm)
                {
                        echo '<td>';
                        if (!isset ($taglist[$ref['id']]['refcnt'][$realm]))
@@ -1709,6 +1756,7 @@ function renderTagStats ()
 
 The following allows figuring out records in TagStorage, which refer to non-existing entities:
 
+mysql> select target_id from TagStorage left join Files on target_id = id where target_realm = 'file' and id is null;
 mysql> select target_id from TagStorage left join IPRanges on target_id = id where target_realm = 'ipv4net' and id is null;
 mysql> select target_id from TagStorage left join RackObject on target_id = id where target_realm = 'object' and id is null;
 mysql> select target_id from TagStorage left join Rack on target_id = id where target_realm = 'rack' and id is null;
@@ -2787,6 +2835,11 @@ function loadEntityTags ($entity_realm = '', $entity_id = 0)
        return getExplicitTagsOnly ($ret);
 }
 
+function loadFileTags ($id)
+{
+       return loadEntityTags ('file', $id);
+}
+
 function loadRackObjectTags ($id)
 {
        return loadEntityTags ('object', $id);
@@ -3293,4 +3346,391 @@ function getLostIPv4Addresses ()
        dragon();
 }
 
+// File-related functions
+function getAllFiles ()
+{
+       $query = "SELECT id, name, type, size, ctime, mtime, atime, comment FROM File ORDER BY name";
+       $result = useSelectBlade ($query, __FUNCTION__);
+       $ret=array();
+       $count=0;
+       while ($row = $result->fetch (PDO::FETCH_ASSOC))
+       {
+               $ret[$count]['id'] = $row['id'];
+               $ret[$count]['name'] = $row['name'];
+               $ret[$count]['type'] = $row['type'];
+               $ret[$count]['size'] = $row['size'];
+               $ret[$count]['ctime'] = $row['ctime'];
+               $ret[$count]['mtime'] = $row['mtime'];
+               $ret[$count]['atime'] = $row['atime'];
+               $ret[$count]['comment'] = $row['comment'];
+               $count++;
+       }
+       $result->closeCursor();
+       return $ret;
+}
+
+// Return a list of files which are not linked to the specified record
+function getAllUnlinkedFiles ($entity_type = NULL, $entity_id = 0)
+{
+       if ($entity_type == NULL || $entity_id == 0)
+       {
+               showError ('Invalid parameters', __FUNCTION__);
+               return NULL;
+       }
+       global $dbxlink;
+       $sql =
+               'SELECT id, name, type, size, ctime, mtime, atime, comment FROM File ' .
+               'WHERE id NOT IN (SELECT file_id FROM FileLink WHERE entity_type = ? AND entity_id = ?) ' .
+               'ORDER BY name';
+       $query = $dbxlink->prepare($sql);
+       $query->bindParam(1, $entity_type);
+       $query->bindParam(2, $entity_id);
+       $query->execute();
+       $ret=array();
+       $count=0;
+       while ($row = $query->fetch (PDO::FETCH_ASSOC))
+       {
+               $ret[$count]['id'] = $row['id'];
+               $ret[$count]['name'] = $row['name'];
+               $ret[$count]['type'] = $row['type'];
+               $ret[$count]['size'] = $row['size'];
+               $ret[$count]['ctime'] = $row['ctime'];
+               $ret[$count]['mtime'] = $row['mtime'];
+               $ret[$count]['atime'] = $row['atime'];
+               $ret[$count]['comment'] = $row['comment'];
+               $count++;
+       }
+       return $ret;
+}
+
+// Return a filtered, detailed file list.  Used on the main Files listing page.
+function getFileList ($entity_type = NULL, $tagfilter = array(), $tfmode = 'any')
+{
+       $whereclause = getWhereClause ($tagfilter);
+
+       if ($entity_type == 'no_links')
+               $whereclause .= 'AND File.id NOT IN (SELECT file_id FROM FileLink) ';
+       elseif ($entity_type != 'all')
+               $whereclause .= "AND entity_type = '${entity_type}' ";
+
+       $query =
+               'SELECT File.id, name, type, size, ctime, mtime, atime, comment ' .
+               'FROM File ' .
+               'LEFT JOIN FileLink ' .
+               'ON File.id = FileLink.file_id ' .
+               'LEFT JOIN TagStorage ' .
+               "ON File.id = TagStorage.target_id AND target_realm = 'file' " .
+               'WHERE size >= 0 ' .
+               $whereclause .
+               'ORDER BY name';
+
+       $result = useSelectBlade ($query, __FUNCTION__);
+       $ret = array();
+       while ($row = $result->fetch (PDO::FETCH_ASSOC))
+       {
+               foreach (array (
+                       'id',
+                       'name',
+                       'type',
+                       'size',
+                       'ctime',
+                       'mtime',
+                       'atime',
+                       'comment'
+                       ) as $cname)
+                       $ret[$row['id']][$cname] = $row[$cname];
+       }
+       $result->closeCursor();
+       return $ret;
+}
+
+function getFilesOfEntity ($entity_type = NULL, $entity_id = 0)
+{
+       if ($entity_type == NULL || $entity_id == 0)
+       {
+               showError ('Invalid parameters', __FUNCTION__);
+               return NULL;
+       }
+       global $dbxlink;
+       $sql =
+               'SELECT FileLink.file_id, FileLink.id AS link_id, name, type, size, ctime, mtime, atime, comment ' .
+               'FROM FileLink LEFT JOIN File ON FileLink.file_id = File.id ' .
+               'WHERE FileLink.entity_type = ? AND FileLink.entity_id = ? ORDER BY name';
+       $query  = $dbxlink->prepare($sql);
+       $query->bindParam(1, $entity_type);
+       $query->bindParam(2, $entity_id);
+       $query->execute();
+       $ret = array();
+       while ($row = $query->fetch (PDO::FETCH_ASSOC))
+               $ret[$row['file_id']] = array (
+                       'link_id' => $row['link_id'],
+                       'name' => $row['name'],
+                       'type' => $row['type'],
+                       'size' => $row['size'],
+                       'ctime' => $row['ctime'],
+                       'mtime' => $row['mtime'],
+                       'atime' => $row['atime'],
+                       'comment' => $row['comment'],
+               );
+       return $ret;
+}
+
+function getFile ($file_id = 0)
+{
+       if ($file_id == 0)
+       {
+               showError ('Invalid file_id', __FUNCTION__);
+               return NULL;
+       }
+       global $dbxlink;
+       $query = $dbxlink->prepare('SELECT * FROM File WHERE id = ?');
+       $query->bindParam(1, $file_id);
+       $query->execute();
+       if (($row = $query->fetch (PDO::FETCH_ASSOC)) == NULL)
+       {
+               showError ('Query succeeded, but returned no data', __FUNCTION__);
+               $ret = NULL;
+       }
+       else
+       {
+               $ret = array();
+               $ret['id'] = $row['id'];
+               $ret['name'] = $row['name'];
+               $ret['type'] = $row['type'];
+               $ret['size'] = $row['size'];
+               $ret['ctime'] = $row['ctime'];
+               $ret['mtime'] = $row['mtime'];
+               $ret['atime'] = $row['atime'];
+               $ret['contents'] = $row['contents'];
+               $ret['comment'] = $row['comment'];
+
+               // Someone accessed this file,date('YmdHis'); update atime
+               $q_atime = $dbxlink->prepare('UPDATE File SET atime = ? WHERE id = ?');
+               $q_atime->bindParam(1, date('YmdHis'));
+               $q_atime->bindParam(2, $file_id);
+               $q_atime->execute();
+       }
+       unset ($query);
+       return $ret;
+}
+
+function getFileInfo ($file_id = 0)
+{
+       if ($file_id == 0)
+       {
+               showError ('Invalid file_id', __FUNCTION__);
+               return NULL;
+       }
+       global $dbxlink;
+       $query = $dbxlink->prepare('SELECT id, name, type, size, ctime, mtime, atime, comment FROM File WHERE id = ?');
+       $query->bindParam(1, $file_id);
+       $query->execute();
+       if (($row = $query->fetch (PDO::FETCH_ASSOC)) == NULL)
+       {
+               showError ('Query succeeded, but returned no data', __FUNCTION__);
+               $ret = NULL;
+       }
+       else
+       {
+               $ret = array();
+               $ret['id'] = $row['id'];
+               $ret['name'] = $row['name'];
+               $ret['type'] = $row['type'];
+               $ret['size'] = $row['size'];
+               $ret['ctime'] = $row['ctime'];
+               $ret['mtime'] = $row['mtime'];
+               $ret['atime'] = $row['atime'];
+               $ret['comment'] = $row['comment'];
+       }
+       unset ($query);
+       return $ret;
+}
+
+function getFileLinks ($file_id = 0)
+{
+       if ($file_id <= 0)
+       {
+               showError ('Invalid file_id', __FUNCTION__);
+               return NULL;
+       }
+
+       global $dbxlink;
+       $query = $dbxlink->prepare('SELECT * FROM FileLink WHERE file_id = ?');
+       $query->bindParam(1, $file_id);
+       $query->execute();
+       $ret = array();
+       while ($row = $query->fetch (PDO::FETCH_ASSOC))
+       {
+               // get info of the parent
+               switch ($row['entity_type'])
+               {
+                       case 'ipv4net':
+                               $page = 'ipv4net';
+                               $id_name = 'id';
+                               $parent = getIPv4NetworkInfo($row['entity_id']);
+                               $name = sprintf("%s (%s/%s)", $parent['name'], $parent['ip'], $parent['mask']);
+                               break;
+                       case 'ipv4rspool':
+                               $page = 'ipv4rsp';
+                               $id_name = 'pool_id';
+                               $parent = getRSPoolInfo($row['entity_id']);
+                               $name = $parent['name'];
+                               break;
+                       case 'ipv4vs':
+                               $page = 'ipv4vs';
+                               $id_name = 'vs_id';
+                               $parent = getVServiceInfo($row['entity_id']);
+                               $name = $parent['name'];
+                               break;
+                       case 'object':
+                               $page = 'object';
+                               $id_name = 'object_id';
+                               $parent = getObjectInfo($row['entity_id']);
+                               $name = $parent['name'];
+                               break;
+                       case 'rack':
+                               $page = 'rack';
+                               $id_name = 'rack_id';
+                               $parent = getRackData($row['entity_id']);
+                               $name = $parent['name'];
+                               break;
+                       case 'user':
+                               $page = 'user';
+                               $id_name = 'user_id';
+                               global $accounts;
+                               foreach ($accounts as $account)
+                                       if ($account['user_id'] == $row['entity_id'])
+                                               $name = $account['user_name'];
+                               break;
+               }
+
+               $ret[$row['id']] = array(
+                               'page' => $page,
+                               'id_name' => $id_name,
+                               'entity_type' => $row['entity_type'],
+                               'entity_id' => $row['entity_id'],
+                               'name' => $name
+               );
+       }
+       return $ret;
+}
+
+// Return list of possible file parents along with the number of children.
+// Used on main Files listing page.
+function getFileLinkInfo ()
+{
+       global $dbxlink;
+       $query = 'SELECT entity_type, COUNT(*) AS count FROM FileLink GROUP BY entity_type';
+
+       $result = useSelectBlade ($query, __FUNCTION__);
+       $ret = array();
+       $ret[0] = array ('entity_type' => 'all', 'name' => 'ALL files');
+       $clist = array ('entity_type', 'name', 'count');
+       $total = 0;
+       $i=2;
+       while ($row = $result->fetch (PDO::FETCH_ASSOC))
+               if ($row['count'] > 0)
+               {
+                       $total += $row['count'];
+                       $row['name'] = formatEntityName ($row['entity_type']);
+                       foreach ($clist as $cname)
+                               $ret[$i][$cname] = $row[$cname];
+                               $i++;
+               }
+       $result->closeCursor();
+
+       // Find number of files without any linkage
+       $linkless_sql =
+               'SELECT COUNT(*) ' .
+               'FROM File ' .
+               'WHERE id NOT IN (SELECT file_id FROM FileLink)';
+       $q_linkless = useSelectBlade ($linkless_sql, __FUNCTION__);
+       $ret[1] = array ('entity_type' => 'no_links', 'name' => 'Files w/no links', 'count' => $q_linkless->fetchColumn ());
+       $q_linkless->closeCursor();
+
+       // Find total number of files
+       $total_sql = 'SELECT COUNT(*) FROM File';
+       $q_total = useSelectBlade ($total_sql, __FUNCTION__);
+       $ret[0]['count'] = $q_total->fetchColumn ();
+       $q_total->closeCursor();
+
+       ksort($ret);
+       return $ret;
+}
+
+function commitAddFile ($name, $type, $size, $contents, $comment)
+{
+       $now = date('YmdHis');
+
+       global $dbxlink;
+       $query  = $dbxlink->prepare('INSERT INTO File (name, type, size, ctime, mtime, atime, contents, comment) VALUES (?, ?, ?, ?, ?, ?, ?, ?)');
+       $query->bindParam(1, $name);
+       $query->bindParam(2, $type);
+       $query->bindParam(3, $size);
+       $query->bindParam(4, $now);
+       $query->bindParam(5, $now);
+       $query->bindParam(6, $now);
+       $query->bindParam(7, $contents, PDO::PARAM_LOB);
+       $query->bindParam(8, $comment);
+
+       $result = $query->execute();
+
+
+       if ($result)
+               return '';
+       else
+               return 'commitAddFile: SQL query failed';
+}
+
+function commitLinkFile ($file_id, $parent_type, $parent_id)
+{
+       global $dbxlink;
+       $query  = $dbxlink->prepare('INSERT INTO FileLink (file_id, entity_type, entity_id) VALUES (?, ?, ?)');
+       $query->bindParam(1, $file_id);
+       $query->bindParam(2, $parent_type);
+       $query->bindParam(3, $parent_id);
+
+       $result = $query->execute();
+
+       if ($result)
+               return '';
+       else
+               return 'commitLinkFile: SQL query failed';
+}
+
+function commitUpdateFile ($file_id = 0, $new_comment = '')
+{
+       if ($file_id == 0)
+       {
+               showError ('Not all required args are present.', __FUNCTION__);
+               return FALSE;
+       }
+       global $dbxlink;
+       $query = $dbxlink->prepare('UPDATE File SET comment = ? WHERE id = ?');
+       $query->bindParam(1, $new_comment);
+       $query->bindParam(2, $file_id);
+
+       $result = $query->execute();
+       if (!$result)
+       {
+               showError ('commitUpdateFile: SQL query failed', __FUNCTION__);
+               return FALSE;
+       }
+       return '';
+}
+
+function commitUnlinkFile ($link_id)
+{
+       if (useDeleteBlade ('FileLink', 'id', $link_id) != TRUE)
+               return __FUNCTION__ . ': useDeleteBlade() failed';
+       return '';
+}
+
+function commitDeleteFile ($file_id)
+{
+       if (useDeleteBlade ('File', 'id', $file_id) != TRUE)
+               return __FUNCTION__ . ': useDeleteBlade() failed';
+       return '';
+}
+
 ?>
index e6ac3d5..7fb96dd 100644 (file)
@@ -1007,6 +1007,15 @@ function loadRackObjectAutoTags ()
 }
 
 // Common code for both prefix and address tag listers.
+function loadFileAutoTags ()
+{
+       assertUIntArg ('file_id', __FUNCTION__);
+       $ret = array();
+       $ret[] = array ('tag' => '$fileid_' . $_REQUEST['file_id']);
+       $ret[] = array ('tag' => '$any_file');
+       return $ret;
+}
+
 function getIPv4PrefixTags ($netid)
 {
        $netinfo = getIPv4NetworkInfo ($netid);
@@ -1634,4 +1643,97 @@ function traceEntity ($tree, $target_id)
        return array();
 }
 
+// Convert entity name to human-readable value
+function formatEntityName ($name) {
+       switch ($name)
+       {
+               case 'ipv4net':
+                       return 'IPv4 Network';
+               case 'ipv4rspool':
+                       return 'IPv4 RS Pool';
+               case 'ipv4vs':
+                       return 'IPv4 Virtual Service';
+               case 'object':
+                       return 'Object';
+               case 'rack':
+                       return 'Rack';
+               case 'user':
+                       return 'User';
+       }
+       return 'invalid';
+}
+
+// Take a MySQL or other generic timestamp and make it prettier
+function formatTimestamp ($timestamp) {
+       return date('n/j/y g:iA', strtotime($timestamp));
+}
+
+// Display hrefs for all of a file's parents
+function serializeFileLinks ($links)
+{
+       global $root;
+
+       $comma = '';
+       $ret = '';
+       foreach ($links as $link_id => $li)
+       {
+               switch ($li['entity_type'])
+               {
+                       case 'ipv4net':
+                               $params = "page=ipv4net&id=";
+                               break;
+                       case 'ipv4rspool':
+                               $params = "page=ipv4rspool&pool_id=";
+                               break;
+                       case 'ipv4vs':
+                               $params = "page=ipv4vs&vs_id=";
+                               break;
+                       case 'object':
+                               $params = "page=object&object_id=";
+                               break;
+                       case 'rack':
+                               $params = "page=rack&rack_id=";
+                               break;
+                       case 'user':
+                               $params = "page=user&user_id=";
+                               break;
+               }
+               $ret .= sprintf("%s<a href='%s?%s%s'>%s</a>", $comma, $root, $params, $li['entity_id'], $li['name']);
+               $comma = ', ';
+       }
+
+       return $ret;
+}
+
+// Convert filesize to appropriate unit and make it human-readable
+function formatFileSize ($bytes) {
+       // bytes
+       if($bytes < 1024) // bytes
+               return "${bytes} bytes";
+
+       // kilobytes
+       if ($bytes < 1024000)
+               return sprintf ("%.1fk", round (($bytes / 1024), 1));
+       
+       // megabytes
+       return sprintf ("%.1f MB", round (($bytes / 1024000), 1));
+}
+
+// Reverse of formatFileSize, it converts human-readable value to bytes
+function convertToBytes ($value) {
+       $value = trim($value);
+       $last = strtolower($value[strlen($value)-1]);
+       switch ($last) 
+       {
+               case 'g':
+                       $value *= 1024;
+               case 'm':
+                       $value *= 1024;
+               case 'k':
+                       $value *= 1024;
+       }
+
+       return $value;
+}
+
 ?>
index 7aec59b..3790b4a 100644 (file)
@@ -47,6 +47,9 @@ $image['rackspace']['height'] = 200;
 $image['objects']['path'] = 'pix/server.png';
 $image['objects']['width'] = 218;
 $image['objects']['height'] = 200;
+$image['files']['path'] = 'pix/files.png';
+$image['files']['width'] = 218;
+$image['files']['height'] = 200;
 $image['ipv4space']['path'] = 'pix/addressspace.png';
 $image['ipv4space']['width'] = 218;
 $image['ipv4space']['height'] = 200;
@@ -59,6 +62,9 @@ $image['config']['height'] = 200;
 $image['reports']['path'] = 'pix/report.png';
 $image['reports']['width'] = 218;
 $image['reports']['height'] = 200;
+$image['download']['path'] = 'pix/download.png';
+$image['download']['width'] = 16;
+$image['download']['height'] = 16;
 $image['link']['path'] = 'pix/tango-network-wired.png';
 $image['link']['width'] = 16;
 $image['link']['height'] = 16;
@@ -149,25 +155,39 @@ function renderIndex ()
                                                <?php printImageHREF ('objects'); ?></a></h1>
                                        </td>
                                        <td>
-                                                       <h1><a href='<?php echo $root; ?>?page=ipv4space'>IPv4 space<br>
-                                                       <?php printImageHREF ('ipv4space'); ?></a></h1>
+                                               <h1><a href='<?php echo $root; ?>?page=reports'>Reports<br>
+                                               <?php printImageHREF ('reports'); ?></a></h1>
                                        </td>
                                </tr>
                        </table>
                        <table width='100%' cellspacing=0 cellpadding=30 class=mainmenu border=0>
                                <tr>
                                        <td>
-                                                       <h1><a href='<?php echo $root; ?>?page=config'>Configuration<br>
-                                                       <?php printImageHREF ('config'); ?></a></h1>
+                                               <h1><a href='<?php echo $root; ?>?page=ipv4space'>IPv4 space<br>
+                                               <?php printImageHREF ('ipv4space'); ?></a></h1>
                                        </td>
                                        <td>
-                                               <h1><a href='<?php echo $root; ?>?page=reports'>Reports<br>
-                                               <?php printImageHREF ('reports'); ?></a></h1>
+                                               <h1><a href='<?php echo $root; ?>?page=files'>Files<br>
+                                               <?php printImageHREF ('files'); ?></a></h1>
                                        </td>
+                                       <td>
+                                               <h1><a href='<?php echo $root; ?>?page=config'>Configuration<br>
+                                               <?php printImageHREF ('config'); ?></a></h1>
+                                       </td>
+                               </tr>
+                       </table>
+                       <table width='100%' cellspacing=0 cellpadding=30 class=mainmenu border=0>
+                               <tr>
                                        <td>
                                                <h1><a href='<?php echo $root; ?>?page=ipv4slb'>IPv4 SLB<br>
                                                <?php printImageHREF ('ipv4slb'); ?></a></h1>
                                        </td>
+                                       <td>
+                                               <img src=<?php echo $root; ?>pix/filler.png border=0>
+                                       </td>
+                                       <td>
+                                               <img src=<?php echo $root; ?>pix/filler.png border=0>
+                                       </td>
                                </tr>
                        </table>
                        </div>
@@ -776,6 +796,8 @@ function renderRackObject ($object_id = 0)
                finishPortlet ();
        }
 
+       renderFilesPortlet ('object', $object_id);
+
        $ports = getObjectPortsAndLinks ($object_id);
        if (count ($ports))
        {
@@ -971,7 +993,7 @@ function renderRackObject ($object_id = 0)
                        echo '</a>';
                        if (!empty ($info['name']))
                                echo "<br>${info['name']}";
-                       echo "</td><td class=tdleft><a href='${root}?page=ipv4rsp&pool_id=${info['pool_id']}'>";
+                       echo "</td><td class=tdleft><a href='${root}?page=ipv4rspool&pool_id=${info['pool_id']}'>";
                        echo (empty ($info['pool_name']) ? 'ANONYMOUS' : $info['pool_name']);
                        echo '</a></td><td class=tdleft>' . $info['rscount'] . '</td>';
                        echo "<td class=tdleft><pre>${info['vsconfig']}</pre></td>";
@@ -1095,7 +1117,7 @@ function renderPortsForObject ($object_id = 0)
                {
                        echo "<td>&nbsp;</td><td>&nbsp;</td>";
                        echo "<td>";
-                       echo "<a href='javascript:;' onclick='window.open(\"${root}link_helper.php?port=${port['id']}&type=${port['type_id']}&object_id=$object_id&port_name=";
+                       echo "<a href='javascript:;' onclick='window.open(\"${root}port_link_helper.php?port=${port['id']}&type=${port['type_id']}&object_id=$object_id&port_name=";
                        echo urlencode ($port['name']);
                        echo "\",\"findlink\",\"height=700, width=400, location=no, menubar=no, resizable=yes, scrollbars=no, status=no, titlebar=no, toolbar=no\");'>";
                        printImageHREF ('link', 'Link this port');
@@ -1326,6 +1348,11 @@ function printLog ($log)
                                66 => array ('code' => 'success', 'format' => "File sent Ok via handler '%s'"),
                                67 => array ('code' => 'success', 'format' => "Tag rolling done, %u objects involved"),
                                68 => array ('code' => 'success', 'format' => "Updated rack '%s'"),
+                               69 => array ('code' => 'success', 'format' => 'File %s was added successfully'),
+                               70 => array ('code' => 'success', 'format' => 'File %s was updated successfully'),
+                               71 => array ('code' => 'success', 'format' => 'File %s was linked successfully'),
+                               72 => array ('code' => 'success', 'format' => 'File %s was unlinked successfully'),
+                               73 => array ('code' => 'success', 'format' => 'File %s was deleted successfully'),
 
                                100 => array ('code' => 'error', 'format' => 'Generic error: %s'),
                                101 => array ('code' => 'error', 'format' => 'Port name cannot be empty'),
@@ -2118,7 +2145,7 @@ function renderIPv4SLB ()
                                else
                                {
                                        echo $vsdata['lblist'][$lb_object_id]['size'];
-//                                     echo " (<a href='${root}?page=ipv4rsp&pool_id=";
+//                                     echo " (<a href='${root}?page=ipv4rspool&pool_id=";
 //                                     echo $vsdata['lblist'][$lb_object_id]['id'] . "'>";
 //                                     echo $vsdata['lblist'][$lb_object_id]['name'] . '</a>)';
                                }
@@ -2338,6 +2365,8 @@ function renderIPv4Network ($id)
        printTagTRs ("${root}?page=ipv4space&tab=default&");
        echo "</table><br>\n";
        finishPortlet();
+
+       renderFilesPortlet ('ipv4net', $id);
        echo "</td>\n";
 
        echo "<td class=pcright>";
@@ -2424,7 +2453,7 @@ function renderIPv4Network ($id)
                {
                        echo $prologue;
                        $prologue = '';
-                       echo "${delim}&rarr;${ref['rsport']}@<a href='${root}?page=ipv4rsp&pool_id=${ref['rspool_id']}'>";
+                       echo "${delim}&rarr;${ref['rsport']}@<a href='${root}?page=ipv4rspool&pool_id=${ref['rspool_id']}'>";
                        echo "${ref['rspool_name']}</a>";
                        $delim = '; ';
                }
@@ -2527,7 +2556,7 @@ function renderIPv4Address ($dottedquad)
                                printImageHREF ('inservice', 'in service');
                        else
                                printImageHREF ('notinservice', 'NOT in service');
-                       echo "</td><td class=tdleft>${rsinfo['rsport']}</td><td class=tdleft><a href='${root}?page=ipv4rsp&pool_id=${rsinfo['rspool_id']}'>";
+                       echo "</td><td class=tdleft>${rsinfo['rsport']}</td><td class=tdleft><a href='${root}?page=ipv4rspool&pool_id=${rsinfo['rspool_id']}'>";
                        echo $rsinfo['rspool_name'] . "</a></td></tr>\n";
                }
                echo "</table><br><br>";
@@ -2999,6 +3028,13 @@ function renderSearchResults ()
                        $lasthit = 'user';
                        $summary['user'] = $tmp;
                }
+               $tmp = getFileSearchResult ($terms);
+               if (count ($tmp))
+               {
+                       $nhits += count ($tmp);
+                       $lasthit = 'file';
+                       $summary['file'] = $tmp;
+               }
        }
        if ($nhits == 0)
                echo "<center><h2>Nothing found for '${terms}'</h2></center>";
@@ -3015,19 +3051,19 @@ function renderSearchResults ()
                        case 'ipv4addressbydq':
                                $parentnet = getIPv4AddressNetworkId ($record);
                                if ($parentnet !== NULL)
-                                       echo "<script language='Javascript'>document.location='${root}?page=iprange&tab=default&id=${parentnet}&hl_ipv4_addr=${record}';//</script>";
+                                       echo "<script language='Javascript'>document.location='${root}?page=ipv4net&tab=default&id=${parentnet}&hl_ipv4_addr=${record}';//</script>";
                                else
                                        echo "<script language='Javascript'>document.location='${root}?page=ipaddress&ip=${record}';//</script>";
                                break;
                        case 'ipv4addressbydescr':
                                $parentnet = getIPv4AddressNetworkId ($record['ip']);
                                if ($parentnet !== NULL)
-                                       echo "<script language='Javascript'>document.location='${root}?page=iprange&tab=default&id=${parentnet}&hl_ipv4_addr=${record['ip']}';//</script>";
+                                       echo "<script language='Javascript'>document.location='${root}?page=ipv4net&tab=default&id=${parentnet}&hl_ipv4_addr=${record['ip']}';//</script>";
                                else
                                        echo "<script language='Javascript'>document.location='${root}?page=ipaddress&ip=${record['ip']}';//</script>";
                                break;
                        case 'ipv4network':
-                               echo "<script language='Javascript'>document.location='${root}?page=iprange";
+                               echo "<script language='Javascript'>document.location='${root}?page=ipv4net";
                                echo "&id=${record['id']}";
                                echo "';//</script>";
                                break;
@@ -3035,7 +3071,7 @@ function renderSearchResults ()
                                echo "<script language='Javascript'>document.location='${root}?page=object&object_id=${record['id']}';//</script>";
                                break;
                        case 'ipv4rspool':
-                               echo "<script language='Javascript'>document.location='${root}?page=ipv4rsp&pool_id=${record['pool_id']}';//</script>";
+                               echo "<script language='Javascript'>document.location='${root}?page=ipv4rspool&pool_id=${record['pool_id']}';//</script>";
                                break;
                        case 'ipv4vs':
                                echo "<script language='Javascript'>document.location='${root}?page=ipv4vs&vs_id=${record['id']}';//</script>";
@@ -3043,6 +3079,9 @@ function renderSearchResults ()
                        case 'user':
                                echo "<script language='Javascript'>document.location='${root}?page=user&user_id=${record['user_id']}';//</script>";
                                break;
+                       case 'file':
+                               echo "<script language='Javascript'>document.location='${root}?page=file&file_id=${record['id']}';//</script>";
+                               break;
                }
                return;
        }
@@ -3057,7 +3096,7 @@ function renderSearchResults ()
                                case 'object':
                                        startPortlet ("<a href='${root}?page=objects'>Objects</a>");
                                        echo '<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
-                                       echo '<tr><th>Common name</th><th>Visible label</th><th>Asset tag</th><th>barcode</th></tr>';
+                                       echo '<tr><th>Common name</th><th>Visible label</th><th>Asset tag</th><th>Barcode</th></tr>';
                                        foreach ($what as $obj)
                                        {
                                                $tags = loadRackObjectTags ($obj['id']);
@@ -3075,7 +3114,7 @@ function renderSearchResults ()
                                case 'ipv4network':
                                        startPortlet ("<a href='${root}?page=ipv4space'>IPv4 networks</a>");
                                        echo '<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
-                                       echo '<tr><th>network</th><th>name/tags</th></tr>';
+                                       echo '<tr><th>Network</th><th>Name/tags</th></tr>';
                                        foreach ($what as $netinfo)
                                        {
                                                echo "<tr class=row_${order} valign=top>";
@@ -3090,13 +3129,13 @@ function renderSearchResults ()
                                        startPortlet ('IPv4 addresses');
                                        echo '<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
                                        // FIXME: address, parent network, routers (if extended view is enabled)
-                                       echo '<tr><th>Address</th><th>Descritpion</th></tr>';
+                                       echo '<tr><th>Address</th><th>Description</th></tr>';
                                        foreach ($what as $addr)
                                        {
                                                echo "<tr class=row_${order}><td class=tdleft>";
                                                $parentnet = getIPv4AddressNetworkId ($addr['ip']);
                                                if ($parentnet !== NULL)
-                                                       echo "<a href='${root}?page=iprange&tab=default&id=${parentnet}&hl_ipv4_addr=${addr['ip']}'>${addr['ip']}</a></td>";
+                                                       echo "<a href='${root}?page=ipv4net&tab=default&id=${parentnet}&hl_ipv4_addr=${addr['ip']}'>${addr['ip']}</a></td>";
                                                else
                                                        echo "<a href='${root}?page=ipaddress&ip=${addr['ip']}'>${addr['ip']}</a></td>";
                                                echo "<td class=tdleft>${addr['name']}</td></tr>";
@@ -3110,7 +3149,7 @@ function renderSearchResults ()
                                        echo '<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
                                        foreach ($what as $rspool)
                                        {
-                                               echo "<tr class=row_${order}><td class=tdleft><a href='${root}?page=ipv4rsp&pool_id=${rspool['pool_id']}'>";
+                                               echo "<tr class=row_${order}><td class=tdleft><a href='${root}?page=ipv4rspool&pool_id=${rspool['pool_id']}'>";
                                                echo buildRSPoolName ($rspool);
                                                echo "</a></td></tr>";
                                                $order = $nextorder[$order];
@@ -3121,7 +3160,7 @@ function renderSearchResults ()
                                case 'ipv4vs':
                                        startPortlet ("<a href='${root}?page=ipv4vslist'>Virtual services</a>");
                                        echo '<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
-                                       echo '<tr><th>VS</th><th>Descritpion</th></tr>';
+                                       echo '<tr><th>VS</th><th>Description</th></tr>';
                                        foreach ($what as $vs)
                                        {
                                                echo "<tr class=row_${order}><td class=tdleft><a href='${root}?page=ipv4vs&vs_id=${vs['id']}'>";
@@ -3135,7 +3174,7 @@ function renderSearchResults ()
                                case 'user':
                                        startPortlet ("<a href='${root}?page=userlist'>Users</a>");
                                        echo '<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
-                                       echo '<tr><th>username</th><th>realname</th></tr>';
+                                       echo '<tr><th>Username</th><th>Real Name</th></tr>';
                                        foreach ($what as $item)
                                        {
                                                echo "<tr class=row_${order}><td class=tdleft><a href='${root}?page=user&user_id=${item['user_id']}'>";
@@ -3146,6 +3185,20 @@ function renderSearchResults ()
                                        echo '</table>';
                                        finishPortlet();
                                        break;
+                               case 'file':
+                                       startPortlet ("<a href='${root}?page=files'>Files</a>");
+                                       echo '<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
+                                       echo '<tr><th>Name</th><th>Comment</th></tr>';
+                                       foreach ($what as $item)
+                                       {
+                                               echo "<tr class=row_${order}><td class=tdleft><a href='${root}?page=file&file_id=${item['id']}'>";
+                                               echo $item['name'];
+                                               echo "</a></td><td class=tdleft>${item['comment']}</td></tr>";
+                                               $order = $nextorder[$order];
+                                       }
+                                       echo '</table>';
+                                       finishPortlet();
+                                       break;
                        }
        }
 }
@@ -3337,6 +3390,7 @@ function renderRackPage ($rack_id)
        // Left column with information.
        echo "<td class=pcleft>";
        renderRackInfoPortlet ($rackData);
+       renderFilesPortlet ('rack', $rack_id);
        echo '</td>';
 
        // Right column with rendered rack.
@@ -4082,7 +4136,7 @@ function renderVirtualService ($vsid)
                echo "<tr class=row_${order}><td class=tdleft>";
                // Pool info
                echo '<table width=100%>';
-               echo "<tr><td colspan=2><a href='${root}?page=ipv4rsp&pool_id=${pool_id}'>";
+               echo "<tr><td colspan=2><a href='${root}?page=ipv4rspool&pool_id=${pool_id}'>";
                if (!empty ($poolInfo['name']))
                        echo $poolInfo['name'];
                else
@@ -4289,7 +4343,7 @@ function renderVServiceLBForm ($vs_id = 0)
                                printImageHREF ('delete', 'Unconfigure');
                                echo "</a></td>";
                                echo "<td class=tdleft><a href='${root}?page=object&object_id=${object_id}'>${oi['dname']}</a></td>";
-                               echo "<td class=tdleft><a href='${root}?page=ipv4rsp&pool_id=${pool_id}'>${rspinfo['name']}</a></td>";
+                               echo "<td class=tdleft><a href='${root}?page=ipv4rspool&pool_id=${pool_id}'>${rspinfo['name']}</a></td>";
                                echo "<td><textarea name=vsconfig>${configs['vsconfig']}</textarea></td>";
                                echo "<td><textarea name=rsconfig>${configs['rsconfig']}</textarea></td><td>";
                                printImageHREF ('SAVE', 'Save changes', TRUE);
@@ -4518,7 +4572,7 @@ function renderRSPoolList ()
        {
                $pooltags = loadIPv4RSPoolTags ($pool_id);
                echo "<tr valign=top class=row_${order}><td class=tdleft>";
-               echo "<a href='${root}?page=ipv4rsp&pool_id=${pool_id}'>" . (empty ($pool_info['name']) ? 'ANONYMOUS' : $pool_info['name']) . '</a>';
+               echo "<a href='${root}?page=ipv4rspool&pool_id=${pool_id}'>" . (empty ($pool_info['name']) ? 'ANONYMOUS' : $pool_info['name']) . '</a>';
                echo ($pool_info['refcnt'] ? ", ${pool_info['refcnt']}" : '');
                if (count ($pooltags))
                {
@@ -4603,7 +4657,7 @@ function renderRealServerList ()
                        $order = $nextorder[$order];
                        $last_pool_id = $rsinfo['rspool_id'];
                }
-               echo "<tr valign=top class=row_${order}><td><a href='${root}?page=ipv4rsp&pool_id=${rsinfo['rspool_id']}'>";
+               echo "<tr valign=top class=row_${order}><td><a href='${root}?page=ipv4rspool&pool_id=${rsinfo['rspool_id']}'>";
                echo empty ($pool_list[$rsinfo['rspool_id']]['name']) ? 'ANONYMOUS' : $pool_list[$rsinfo['rspool_id']]['name'];
                echo '</a></td><td align=center>';
                if ($rsinfo['inservice'] == 'yes')
@@ -4973,6 +5027,11 @@ function renderTagOptionForFilter ($taginfo, $tagfilter, $realm, $level = 0)
                renderTagOptionForFilter ($kid, $tagfilter, $realm, $level + 1);
 }
 
+function renderFileTags ($id)
+{
+       renderEntityTagChainEditor ('file', 'file_id', $id);
+}
+
 function renderObjectTags ($id)
 {
        renderEntityTagChainEditor ('object', 'object_id', $id);
@@ -5262,6 +5321,8 @@ function renderUser ($user_id)
 {
        global $accounts, $expl_tags, $impl_tags;
        $username = getUsernameByID ($user_id);
+
+       startPortlet ('summary');
        echo '<table border=0 align=center>';
        echo "<tr><th class=tdright>Account name:</th><td>${username}</td></tr>";
        echo '<tr><th class=tdright>Real name:</th><td>' . $accounts[$username]['user_realname'] . '</td></tr>';
@@ -5293,6 +5354,9 @@ function renderUser ($user_id)
                echo serializeTags ($target_auto_tags) . "</td></tr>\n";
        }
        echo '</table>';
+       finishPortlet();
+
+       renderFilesPortlet ('user', $user_id);
 }
 
 function renderMyPasswordEditor ()
@@ -5347,12 +5411,327 @@ function renderMyAccount ()
        echo "</table>";
 }
 
+// File-related functions
+function renderFileSpace ()
+{
+       global $root, $taglist, $tagtree;
+       echo "<table border=0 class=objectview>\n";
+       echo "<tr><td class=pcleft width='50%'>";
+       startPortlet ('View all by link');
+       $linkInfo = getFileLinkInfo();
+       if ($linkInfo === NULL)
+       {
+               showError ('getFileLinkInfo() failed', __FUNCTION__);
+               return;
+       }
+       if (count ($linkInfo) == 0)
+               echo "No files exist in DB";
+       else
+       {
+               echo '<div align=left><ul>';
+               foreach ($linkInfo as $li)
+                       echo "<li><a href='${root}?page=filesbylink&entity_type=${li['entity_type']}'>${li['name']}</a> (${li['count']})</li>";
+               echo '</ul></div>';
+       }
+       finishPortlet();
+       echo '</td><td class=pcright>';
+       renderTagFilterPortlet (getTagFilter(), 'file');
+       echo "</td></tr></table>\n";
+}
+
+function renderFile ($file_id = 0)
+{
+       global $root, $nextorder, $aac;
+       if ($file_id <= 0)
+       {
+               showError ('Invalid file_id', __FUNCTION__);
+               return;
+       }
+       $file = getFileInfo ($file_id);
+       if ($file == NULL)
+       {
+               showError ('getFileInfo() failed', __FUNCTION__);
+               return;
+       }
+       echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
+       echo "<tr><td colspan=2 align=center><h1>${file['name']}</h1></td></tr>\n";
+       echo "<tr><td class=pcleft>";
+       startPortlet ('summary');
+       echo "<table border=0 cellspacing=0 cellpadding=3 width='100%'>\n";
+       echo "<tr><th width='50%' class=tdright>Type:</th>";
+       printf("<td class=tdleft>%s</td></tr>", $file['type']);
+       echo "<tr><th width='50%' class=tdright>Size:</th>";
+       printf("<td class=tdleft>%s</td></tr>", formatFileSize($file['size']));
+       echo "<tr><th width='50%' class=tdright>Created:</th>";
+       printf("<td class=tdleft>%s</td></tr>", formatTimestamp($file['ctime']));
+       echo "<tr><th width='50%' class=tdright>Modified:</th>";
+       printf("<td class=tdleft>%s</td></tr>", formatTimestamp($file['mtime']));
+       echo "<tr><th width='50%' class=tdright>Accessed:</th>";
+       printf("<td class=tdleft>%s</td></tr>", formatTimestamp($file['atime']));
+       printTagTRs ("${root}?page=files&tab=default&");
+       echo "</table><br>\n";
+       finishPortlet();
+
+       if (!empty ($file['comment']))
+       {
+               startPortlet ('comment');
+               echo '<div class=commentblock>' . string_insert_hrefs ($file['comment']) . '</div>';
+               finishPortlet ();
+       }
+
+       $links = getFileLinks ($file_id);
+       if (count ($links))
+       {
+               startPortlet ('Links');
+               ///usort($ports, 'sortByName');
+               echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n";
+               echo "<tr><th>Linked to</th><th>Name</th></tr>\n";
+               foreach ($links as $link)
+               {
+                       echo "<tr><td>${link['entity_type']}</td>";
+                       echo "<td><a href='${root}?page=${link['page']}&${link['id_name']}=${link['entity_id']}'>${link['name']}</a></td>";
+                       echo "</tr>\n";
+               }
+               echo "</table><br>\n";
+               finishPortlet();
+       }
+       echo "</td></tr>";
+       echo "</table>\n";
+}
+
+// Used for uploading a parentless file
+function renderFileUploadForm ()
+{
+       global $aat, $root, $pageno, $tabno, $nextorder;
+
+       showMessageOrError();
+       startPortlet ('Files');
+       echo "<table border=0 cellspacing=0 cellpadding='5' align='center' class='widetable'>\n";
+       echo "<tr><th>&nbsp;</th><th>File</th><th>Comment</th><th></th></tr>\n";
+
+       printOpFormIntro ('addFile', array ('MAX_FILE_SIZE' => convertToBytes(get_cfg_var('upload_max_filesize'))), TRUE);
+       echo "<tr><td>";
+       printImageHREF ('add', 'Upload file', TRUE, 99);
+       echo "</td>";
+       echo "<td class=tdleft><input type='file' size='10' name='file' tabindex=100></td>\n";
+       echo "<td class=tdleft><input type='text' size='15' name='comment' tabindex=101></td>\n";
+       echo '<td>';
+       printImageHREF ('add', 'Upload file', TRUE, 99);
+       echo '</td></tr></form>';
+       echo "</table><br>\n";
+       finishPortlet();
+}
+
+function renderFilesByLink ()
+{
+       global $root, $pageno, $tabno, $nextorder, $taglist, $tagtree;
+       assertStringArg ('entity_type', __FUNCTION__, TRUE);
+       $entity_type = $_REQUEST['entity_type'];
+       $tagfilter = getTagFilter();
+       $tagfilter_str = getTagFilterStr ($tagfilter);
+       echo "<table border=0 class=objectview>\n";
+       echo "<tr><td class=pcleft width='25%'>";
+
+       startPortlet ('change type');
+       $linkInfo = getFileLinkInfo();
+       if ($linkInfo === NULL)
+       {
+               showError ('getFileLinkInfo() failed', __FUNCTION__);
+               return;
+       }
+       if (count ($linkInfo) == 0)
+               echo 'No files exist in DB';
+       else
+       {
+               echo '<div align=left><ul>';
+               foreach ($linkInfo as $li)
+               {
+                       echo "<li><a href='${root}?page=${pageno}&entity_type=${li['entity_type']}${tagfilter_str}'>";
+                       if ($li['entity_type'] == $entity_type)
+                               echo '<strong>';
+                       echo "${li['name']}</a>";
+                       if ($li['entity_type'] == $entity_type)
+                               echo '</strong>';
+                       echo " (${li['count']})";
+                       if ($li['entity_type'] == $entity_type)
+                               echo ' &larr;';
+                       echo "</li>";
+               }
+               echo '</ul></div>';
+       }
+       finishPortlet();
+
+       echo '</td><td class=pcleft>';
+
+       $files = getFileList ($entity_type, $tagfilter, getTFMode());
+       startPortlet ('Files (' . count ($files) . ')');
+       if ($files === NULL)
+       {
+               showError ('getFileList() failed', __FUNCTION__);
+               return;
+       }
+       echo '<br><br><table cellpadding=5 cellspacing=0 align=center class=cooltable>';
+       echo '<tr><th>Name</th><th>Comment</th><th>Size</th><th>Created</th><th>Linked to</th><th>Actions</th></tr>';
+       $order = 'odd';
+       foreach ($files as $file)
+       {
+               printf("<tr class=row_%s valign=top>", $order);
+               printf("<td class='tdleft'><a href='%/?page=file&file_id=%s'><strong>%s</strong></a>", $root, $file['id'], $file['name']);
+               $tags = loadEntityTags ('file', $file['id']);
+               if (count ($tags))
+                       echo '<br><small>' . serializeTags ($tags, "${root}?page=${pageno}&tab=default&parent_id=${parent_id}&") . '</small>';
+               printf("</td><td class='tdleft'>%s</td>", $file['comment']);
+               printf("<td class='tdleft'>%s</td>", formatFileSize($file['size']));
+               printf("<td class='tdleft'>%s</td>", formatTimestamp($file['ctime']));
+               echo "<td class='tdleft'>";
+               $links = getFileLinks($file['id']);
+               if (count ($links))
+                       printf("<small>%s</small>", serializeFileLinks($links));
+               echo '</td>';
+               echo "<td><a href='${root}download.php?file_id=${file['id']}'>";
+               printImageHREF ('download', 'Download file');
+               echo '</a> ';
+               echo "<a href='${root}process.php?op=deleteFile&page=${pageno}&tab=${tabno}&file_id=${file['id']}&entity_type=${entity_type}'>";
+               printImageHREF ('delete', 'Delete file');
+               echo '</a></td>';
+               echo "</tr>\n";
+               $order = $nextorder[$order];
+       }
+       echo '</table>';
+       finishPortlet();
+
+       echo "</td><td class=pcright width='25%'>";
+
+       renderTagFilterPortlet ($tagfilter, 'file', 'entity_type', $entity_type);
+       echo "</td></tr></table>\n";
+}
+
+function renderFilesPortlet ($entity_type = NULL, $entity_id = 0)
+{
+       global $root;
+       if ($entity_type == NULL || $entity_id <= 0)
+       {
+               showError ('Invalid entity info', __FUNCTION__);
+               return;
+       }
+
+       $files = getFilesOfEntity ($entity_type, $entity_id);
+       if (count ($files))
+       {
+               startPortlet ('files');
+               echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n";
+               echo "<tr><th>Name</th><th>Size</th><th>Comment</th><th>Actions</th></tr>\n";
+               foreach ($files as $file_id => $file)
+               {
+                       printf("<td><a href='%/?page=file&file_id=%s'><strong>%s</strong></a></td>", $root, $file_id, $file['name']);
+                       printf("<td>%s</td>", formatFileSize($file['size']));
+                       echo "<td>${file['comment']}</td>";
+                       echo "<td><a href='${root}download.php?file_id=${file_id}'>";
+                       printImageHREF ('download', 'Download file');
+                       echo '</a></td></tr>';
+               }
+               echo "</table><br>\n";
+               finishPortlet();
+       }
+}
+
+function renderFilesForEntity ($entity_type = NULL, $id_name = NULL, $entity_id = 0)
+{
+       global $root, $pageno, $tabno;
+       if ($entity_type == NULL || $id_name == NULL || $entity_id <= 0)
+       {
+               showError ('Invalid entity info', __FUNCTION__);
+               return;
+       }
+
+       function printNewItemTR ($entity_type, $entity_id)
+       {
+               printOpFormIntro ('addFile', array ('entity_type' => $entity_type, 'entity_id' => $entity_id, 'MAX_FILE_SIZE' => convertToBytes(get_cfg_var('upload_max_filesize'))), TRUE);
+               echo "<tr><td>";
+               printImageHREF ('add', 'Upload file', TRUE, 99);
+               echo "</td>";
+               echo "<td class=tdleft><input type='file' size='10' name='file' tabindex=100></td>\n";
+               echo "<td class=tdleft><input type='text' size='15' name='comment' tabindex=101></td>\n";
+               echo "<td></td>\n";
+               echo "<td><a href='javascript:;' onclick='window.open(\"${root}file_link_helper.php?entity_type=$entity_type&entity_id=$entity_id";
+               echo "\",\"findlink\",\"height=700, width=400, location=no, menubar=no, resizable=yes, scrollbars=no, status=no, titlebar=no, toolbar=no\");'>";
+               printImageHREF ('link', 'Link an existing file');
+               echo "</a> &nbsp;&nbsp;";
+               printImageHREF ('add', 'Upload file', TRUE, 99);
+               echo "</td></tr></form>";
+       }
+
+       showMessageOrError();
+       startPortlet ('Files');
+       $filelist = getFilesOfEntity ($entity_type, $entity_id);
+       echo "<table border=0 cellspacing=0 cellpadding='5' align='center' class='widetable'>\n";
+       echo "<tr><th>&nbsp;</th><th>Name</th><th>Comment</th><th>Size</th><th>Actions</th></tr>\n";
+
+       if (getConfigVar ('ADDNEW_AT_TOP') == 'yes')
+               printNewItemTR($entity_type, $entity_id);
+       foreach ($filelist as $file_id => $file)
+       {
+               printOpFormIntro ('updateFile', array ('file_id' => $file_id, 'link_id' => $file['link_id'], 'name' => $file['name']));
+               echo "<tr class='$class' valign=top><td><a href='${root}process.php?op=deleteFile&page=${pageno}&tab=${tabno}&file_id=${file_id}&${id_name}=${entity_id}&name=${file['name']}'>";
+               printImageHREF ('delete', 'Unlink and delete file');
+               echo '</a></td>';
+               printf("<td class='tdleft'><a href='%/?page=file&file_id=%s'><strong>%s</strong></a>", $root, $file_id, $file['name']);
+               echo "<td class=tdleft><input type='text' name='comment' value='${file['comment']}' size=15></td>";
+               printf("<td class=tdleft>%s</td>", formatFileSize($file['size']));
+               echo "<td><a href='${root}download.php?file_id=${file_id}'>";
+               printImageHREF ('download', 'Download file');
+               echo '</a> ';
+               echo "<a href='${root}process.php?op=unlinkFile&page=${pageno}&tab=${tabno}&link_id=${file['link_id']}&${id_name}=${entity_id}&name=${file['name']}'>";
+               printImageHREF ('clear', 'Unlink file');
+               echo '</a> ';
+               printImageHREF ('save', 'Save changes', TRUE);
+               echo "</td></form></tr>\n";
+       }
+       if (getConfigVar ('ADDNEW_AT_TOP') != 'yes')
+               printNewItemTR($entity_type, $entity_id);
+
+       echo "</table><br>\n";
+       finishPortlet();
+
+}
+
+// Set of wrapper functions to reduce duplicate code
+// No data validation, that is done by renderFilesForEntity ()
+function renderFilesForObject ($object_id) {
+       renderFilesForEntity('object', 'object_id', $object_id);
+}
+
+function renderFilesForIPv4Network ($range_id) {
+       renderFilesForEntity('ipv4net', 'id', $range_id);
+}
+
+function renderFilesForRack ($rack_id) {
+       renderFilesForEntity('rack', 'rack_id', $rack_id);
+}
+
+function renderFilesForRSPool ($pool_id) {
+       renderFilesForEntity('ipv4rspool', 'pool_id', $pool_id);
+}
+
+function renderFilesForVService ($vs_id) {
+       renderFilesForEntity('ipv4vs', 'vs_id', $vs_id);
+}
+
+function renderFilesForUser ($user_id) {
+       renderFilesForEntity('user', 'user_id', $user_id);
+}
+
 // Print common operation form prologue, include bypass argument, if
 // appropriate, and some extra hidden inputs, if requested.
-function printOpFormIntro ($opname, $extra = array())
+// Use special encoding for upload forms
+function printOpFormIntro ($opname, $extra = array(), $upload = FALSE)
 {
        global $root, $pageno, $tabno, $page;
-       echo "<form method=post action='${root}process.php?page=${pageno}&tab=${tabno}&op=${opname}'>\n";
+
+       if ($upload)
+               $enctype = " enctype='multipart/form-data'";
+
+       echo "<form method=post action='${root}process.php?page=${pageno}&tab=${tabno}&op=${opname}'${enctype}>\n";
        if (isset ($page[$pageno]['bypass']) and isset ($_REQUEST[$page[$pageno]['bypass']]))
                $extra[$page[$pageno]['bypass']] = $_REQUEST[$page[$pageno]['bypass']];
        foreach ($extra as $inputname => $inputvalue)
@@ -5430,7 +5809,7 @@ function printIPv4NetInfoTDs ($netinfo, $tdclass = 'tdleft', $indent = 0, $symbo
                        echo '</a>';
        }
        if (isset ($netinfo['id']))
-               echo "<a href='${root}?page=iprange&id=${netinfo['id']}'>";
+               echo "<a href='${root}?page=ipv4net&id=${netinfo['id']}'>";
        echo "${netinfo['ip']}/${netinfo['mask']}";
        if (isset ($netinfo['id']))
                echo '</a>';
index 99bf212..a30b81d 100644 (file)
@@ -64,16 +64,33 @@ $tab['rack']['edit'] = 'Properties';
 $tab['rack']['design'] = 'Design';
 $tab['rack']['problems'] = 'Problems';
 $tab['rack']['tags'] = 'Tags';
+$tab['rack']['files'] = 'Files';
 $tabhandler['rack']['default'] = 'renderRackPage';
 $tabhandler['rack']['edit'] = 'renderEditRackForm';
 $tabhandler['rack']['design'] = 'renderRackDesign';
 $tabhandler['rack']['problems'] = 'renderRackProblems';
 $tabhandler['rack']['tags'] = 'renderRackTags';
+$tabhandler['rack']['files'] = 'renderFilesForRack';
 $trigger['rack']['tags'] = 'trigger_tags';
 $ophandler['rack']['edit']['updateRack'] = 'updateRack';
 $ophandler['rack']['tags']['saveTags'] = 'saveEntityTags';
+$ophandler['rack']['files']['addFile'] = 'addFileToEntity';
+$ophandler['rack']['files']['updateFile'] = 'updateFile';
+$ophandler['rack']['files']['linkFile'] = 'linkFileToEntity';
+$ophandler['rack']['files']['unlinkFile'] = 'unlinkFile';
+$ophandler['rack']['files']['deleteFile'] = 'deleteFile';
 $msgcode['rack']['edit']['updateRack']['OK'] = 68;
 $msgcode['rack']['edit']['updateRack']['ERR'] = 177;
+$msgcode['rack']['files']['addFile']['OK'] = 69;
+$msgcode['rack']['files']['addFile']['ERR'] = 100;
+$msgcode['rack']['files']['updateFile']['OK'] = 70;
+$msgcode['rack']['files']['updateFile']['ERR'] = 100;
+$msgcode['rack']['files']['linkFile']['OK'] = 71;
+$msgcode['rack']['files']['linkFile']['ERR'] = 100;
+$msgcode['rack']['files']['unlinkFile']['OK'] = 72;
+$msgcode['rack']['files']['unlinkFile']['ERR'] = 100;
+$msgcode['rack']['files']['deleteFile']['OK'] = 73;
+$msgcode['rack']['files']['deleteFile']['ERR'] = 100;
 
 $page['objgroup']['title_handler'] = 'dynamic_title_objgroup';
 $page['objgroup']['handler'] = 'renderObjectGroup';
@@ -99,6 +116,7 @@ $tab['object']['editrspvs'] = 'RS pools';
 $tab['object']['lvsconfig'] = 'LVS config';
 $tab['object']['autoports'] = 'AutoPorts';
 $tab['object']['tags'] = 'Tags';
+$tab['object']['files'] = 'Files';
 $tabhandler['object']['default'] = 'renderRackObject';
 $tabhandler['object']['edit'] = 'renderEditObjectForm';
 $tabhandler['object']['rackspace'] = 'renderRackSpaceForObject';
@@ -110,6 +128,7 @@ $tabhandler['object']['snmpportfinder'] = 'renderSNMPPortFinder';
 $tabhandler['object']['lvsconfig'] = 'renderLVSConfig';
 $tabhandler['object']['autoports'] = 'renderAutoPortsForm';
 $tabhandler['object']['tags'] = 'renderObjectTags';
+$tabhandler['object']['files'] = 'renderFilesForObject';
 $tabhandler['object']['editrspvs'] = 'renderObjectSLB';
 $tabextraclass['object']['snmpportfinder'] = 'attn';
 $tabextraclass['object']['autoports'] = 'attn';
@@ -140,6 +159,11 @@ $ophandler['object']['nat4']['updNATv4Rule'] = 'updPortForwarding';
 $ophandler['object']['livevlans']['setPortVLAN'] = 'setPortVLAN';
 $ophandler['object']['autoports']['generate'] = 'generateAutoPorts';
 $ophandler['object']['tags']['saveTags'] = 'saveEntityTags';
+$ophandler['object']['files']['addFile'] = 'addFileToEntity';
+$ophandler['object']['files']['updateFile'] = 'updateFile';
+$ophandler['object']['files']['linkFile'] = 'linkFileToEntity';
+$ophandler['object']['files']['unlinkFile'] = 'unlinkFile';
+$ophandler['object']['files']['deleteFile'] = 'deleteFile';
 $ophandler['object']['editrspvs']['addLB'] = 'addLoadBalancer';
 $ophandler['object']['editrspvs']['delLB'] = 'deleteLoadBalancer';
 $ophandler['object']['editrspvs']['updLB'] = 'updateLoadBalancer';
@@ -189,16 +213,26 @@ $msgcode['object']['editrspvs']['updLB']['OK'] = 20;
 $msgcode['object']['editrspvs']['updLB']['ERR'] = 134;
 $msgcode['object']['autoports']['generate']['OK'] = 21;
 $msgcode['object']['autoports']['generate']['ERR'] = 142;
+$msgcode['object']['livevlans']['setPortVLAN']['ERR1'] = 156;
 $msgcode['object']['tags']['saveTags']['OK'] = 22;
 $msgcode['object']['tags']['saveTags']['ERR'] = 143;
-$msgcode['object']['livevlans']['setPortVLAN']['ERR1'] = 156;
+$msgcode['object']['files']['addFile']['OK'] = $msgcode['rack']['files']['addFile']['OK'];
+$msgcode['object']['files']['addFile']['ERR'] = $msgcode['rack']['files']['addFile']['ERR'];
+$msgcode['object']['files']['updateFile']['OK'] = $msgcode['rack']['files']['updateFile']['OK'];
+$msgcode['object']['files']['updateFile']['ERR'] = $msgcode['rack']['files']['updateFile']['ERR'];
+$msgcode['object']['files']['linkFile']['OK'] = $msgcode['rack']['files']['linkFile']['OK'];
+$msgcode['object']['files']['linkFile']['ERR'] = $msgcode['rack']['files']['linkFile']['ERR'];
+$msgcode['object']['files']['unlinkFile']['OK'] = $msgcode['rack']['files']['unlinkFile']['OK'];
+$msgcode['object']['files']['unlinkFile']['ERR'] = $msgcode['rack']['files']['unlinkFile']['ERR'];
+$msgcode['object']['files']['deleteFile']['OK'] = $msgcode['rack']['files']['deleteFile']['OK'];
+$msgcode['object']['files']['deleteFile']['ERR'] = $msgcode['rack']['files']['deleteFile']['ERR'];
 $msgcode['rack']['tags']['saveTags'] = $msgcode['object']['tags']['saveTags'];
-$msgcode['iprange']['tags']['saveTags'] = $msgcode['object']['tags']['saveTags'];
+$msgcode['ipv4net']['tags']['saveTags'] = $msgcode['object']['tags']['saveTags'];
 $msgcode['ipv4vs']['tags']['saveTags'] = $msgcode['object']['tags']['saveTags'];
-$msgcode['ipv4rsp']['tags']['saveTags'] = $msgcode['object']['tags']['saveTags'];
+$msgcode['ipv4rspool']['tags']['saveTags'] = $msgcode['object']['tags']['saveTags'];
 $msgcode['user']['tags']['saveTags'] = $msgcode['object']['tags']['saveTags'];
 $msgcode['ipv4vs']['editlblist'] = $msgcode['object']['editrspvs'];
-$msgcode['ipv4rsp']['editlblist'] = $msgcode['object']['editrspvs'];
+$msgcode['ipv4rspool']['editlblist'] = $msgcode['object']['editrspvs'];
 $msgcode['ipaddress']['assignment'] = $msgcode['object']['ipv4'];
 
 $page['ipv4space']['title'] = 'IPv4 space';
@@ -219,32 +253,49 @@ $msgcode['ipv4space']['newrange']['addIPv4Prefix']['ERR4'] = 176;
 $msgcode['ipv4space']['newrange']['delIPv4Prefix']['OK'] = 24;
 $msgcode['ipv4space']['newrange']['delIPv4Prefix']['ERR'] = 100;
 
-$page['iprange']['title_handler'] = 'dynamic_title_iprange';
-$page['iprange']['parent'] = 'ipv4space';
-$page['iprange']['bypass'] = 'id';
-$page['iprange']['bypass_type'] = 'uint';
-$page['iprange']['autotagloader'] = 'loadIPv4PrefixAutoTags';
-$page['iprange']['tagloader'] = 'loadIPv4PrefixTags';
-$tab['iprange']['default'] = 'Browse';
-$tab['iprange']['properties'] = 'Properties';
-$tab['iprange']['liveptr'] = 'Live PTR';
-$tab['iprange']['tags'] = 'Tags';
-$tabhandler['iprange']['default'] = 'renderIPv4Network';
-$tabhandler['iprange']['properties'] = 'renderIPv4NetworkProperties';
-$tabhandler['iprange']['liveptr'] = 'renderLivePTR';
-$tabhandler['iprange']['tags'] = 'renderIPv4PrefixTags';
-$trigger['iprange']['tags'] = 'trigger_tags';
-$ophandler['iprange']['properties']['editRange'] = 'updIPv4Prefix';
-$ophandler['iprange']['liveptr']['importPTRData'] = 'importPTRData';
-$ophandler['iprange']['tags']['saveTags'] = 'saveEntityTags';
-$msgcode['iprange']['properties']['editRange']['OK'] = 25;
-$msgcode['iprange']['properties']['editRange']['ERR'] = 100;
-$msgcode['iprange']['liveptr']['importPTRData']['OK'] = 26;
-$msgcode['iprange']['liveptr']['importPTRData']['ERR'] = 141;
-$msgcode['ipv4space']['newrange']['updIPv4Prefix'] = $msgcode['iprange']['properties']['editRange'];
+$page['ipv4net']['title_handler'] = 'dynamic_title_ipv4net';
+$page['ipv4net']['parent'] = 'ipv4space';
+$page['ipv4net']['bypass'] = 'id';
+$page['ipv4net']['bypass_type'] = 'uint';
+$page['ipv4net']['autotagloader'] = 'loadIPv4PrefixAutoTags';
+$page['ipv4net']['tagloader'] = 'loadIPv4PrefixTags';
+$tab['ipv4net']['default'] = 'Browse';
+$tab['ipv4net']['properties'] = 'Properties';
+$tab['ipv4net']['liveptr'] = 'Live PTR';
+$tab['ipv4net']['tags'] = 'Tags';
+$tab['ipv4net']['files'] = 'Files';
+$tabhandler['ipv4net']['default'] = 'renderIPv4Network';
+$tabhandler['ipv4net']['properties'] = 'renderIPv4NetworkProperties';
+$tabhandler['ipv4net']['liveptr'] = 'renderLivePTR';
+$tabhandler['ipv4net']['tags'] = 'renderIPv4PrefixTags';
+$tabhandler['ipv4net']['files'] = 'renderFilesForIPv4Network';
+$trigger['ipv4net']['tags'] = 'trigger_tags';
+$ophandler['ipv4net']['properties']['editRange'] = 'updIPv4Prefix';
+$ophandler['ipv4net']['liveptr']['importPTRData'] = 'importPTRData';
+$ophandler['ipv4net']['tags']['saveTags'] = 'saveEntityTags';
+$ophandler['ipv4net']['files']['addFile'] = 'addFileToEntity';
+$ophandler['ipv4net']['files']['updateFile'] = 'updateFile';
+$ophandler['ipv4net']['files']['linkFile'] = 'linkFileToEntity';
+$ophandler['ipv4net']['files']['unlinkFile'] = 'unlinkFile';
+$ophandler['ipv4net']['files']['deleteFile'] = 'deleteFile';
+$msgcode['ipv4net']['properties']['editRange']['OK'] = 25;
+$msgcode['ipv4net']['properties']['editRange']['ERR'] = 100;
+$msgcode['ipv4net']['liveptr']['importPTRData']['OK'] = 26;
+$msgcode['ipv4net']['liveptr']['importPTRData']['ERR'] = 141;
+$msgcode['ipv4space']['newrange']['updIPv4Prefix'] = $msgcode['ipv4net']['properties']['editRange'];
+$msgcode['ipv4net']['files']['addFile']['OK'] = $msgcode['rack']['files']['addFile']['OK'];
+$msgcode['ipv4net']['files']['addFile']['ERR'] = $msgcode['rack']['files']['addFile']['ERR'];
+$msgcode['ipv4net']['files']['updateFile']['OK'] = $msgcode['rack']['files']['updateFile']['OK'];
+$msgcode['ipv4net']['files']['updateFile']['ERR'] = $msgcode['rack']['files']['updateFile']['ERR'];
+$msgcode['ipv4net']['files']['linkFile']['OK'] = $msgcode['rack']['files']['linkFile']['OK'];
+$msgcode['ipv4net']['files']['linkFile']['ERR'] = $msgcode['rack']['files']['linkFile']['ERR'];
+$msgcode['ipv4net']['files']['unlinkFile']['OK'] = $msgcode['rack']['files']['unlinkFile']['OK'];
+$msgcode['ipv4net']['files']['unlinkFile']['ERR'] = $msgcode['rack']['files']['unlinkFile']['ERR'];
+$msgcode['ipv4net']['files']['deleteFile']['OK'] = $msgcode['rack']['files']['deleteFile']['OK'];
+$msgcode['ipv4net']['files']['deleteFile']['ERR'] = $msgcode['rack']['files']['deleteFile']['ERR'];
 
 $page['ipaddress']['title_handler'] = 'dynamic_title_ipaddress';
-$page['ipaddress']['parent'] = 'iprange';
+$page['ipaddress']['parent'] = 'ipv4net';
 $page['ipaddress']['bypass'] = 'ip';
 $page['ipaddress']['bypass_type'] = 'inet4';
 $page['ipaddress']['autotagloader'] = 'loadIPv4AddressAutoTags';
@@ -295,16 +346,33 @@ $tab['ipv4vs']['default'] = 'View';
 $tab['ipv4vs']['edit'] = 'Edit';
 $tab['ipv4vs']['editlblist'] = 'Load balancers';
 $tab['ipv4vs']['tags'] = 'Tags';
+$tab['ipv4vs']['files'] = 'Files';
 $tabhandler['ipv4vs']['default'] = 'renderVirtualService';
 $tabhandler['ipv4vs']['edit'] = 'renderEditVService';
 $tabhandler['ipv4vs']['editlblist'] = 'renderVServiceLBForm';
 $tabhandler['ipv4vs']['tags'] = 'renderIPv4VSTags';
+$tabhandler['ipv4vs']['files'] = 'renderFilesForVService';
+$trigger['ipv4vs']['tags'] = 'trigger_tags';
 $ophandler['ipv4vs']['edit']['updIPv4VS'] = 'updateVService';
-$ophandler['ipv4vs']['tags']['saveTags'] = 'saveEntityTags';
 $ophandler['ipv4vs']['editlblist']['addLB'] = 'addLoadBalancer';
 $ophandler['ipv4vs']['editlblist']['delLB'] = 'deleteLoadBalancer';
 $ophandler['ipv4vs']['editlblist']['updLB'] = 'updateLoadBalancer';
-$trigger['ipv4vs']['tags'] = 'trigger_tags';
+$ophandler['ipv4vs']['tags']['saveTags'] = 'saveEntityTags';
+$ophandler['ipv4vs']['files']['addFile'] = 'addFileToEntity';
+$ophandler['ipv4vs']['files']['updateFile'] = 'updateFile';
+$ophandler['ipv4vs']['files']['linkFile'] = 'linkFileToEntity';
+$ophandler['ipv4vs']['files']['unlinkFile'] = 'unlinkFile';
+$ophandler['ipv4vs']['files']['deleteFile'] = 'deleteFile';
+$msgcode['ipv4vs']['files']['addFile']['OK'] = $msgcode['rack']['files']['addFile']['OK'];
+$msgcode['ipv4vs']['files']['addFile']['ERR'] = $msgcode['rack']['files']['addFile']['ERR'];
+$msgcode['ipv4vs']['files']['updateFile']['OK'] = $msgcode['rack']['files']['updateFile']['OK'];
+$msgcode['ipv4vs']['files']['updateFile']['ERR'] = $msgcode['rack']['files']['updateFile']['ERR'];
+$msgcode['ipv4vs']['files']['linkFile']['OK'] = $msgcode['rack']['files']['linkFile']['OK'];
+$msgcode['ipv4vs']['files']['linkFile']['ERR'] = $msgcode['rack']['files']['linkFile']['ERR'];
+$msgcode['ipv4vs']['files']['unlinkFile']['OK'] = $msgcode['rack']['files']['unlinkFile']['OK'];
+$msgcode['ipv4vs']['files']['unlinkFile']['ERR'] = $msgcode['rack']['files']['unlinkFile']['ERR'];
+$msgcode['ipv4vs']['files']['deleteFile']['OK'] = $msgcode['rack']['files']['deleteFile']['OK'];
+$msgcode['ipv4vs']['files']['deleteFile']['ERR'] = $msgcode['rack']['files']['deleteFile']['ERR'];
 
 $page['ipv4rsplist']['title'] = 'RS pools';
 $page['ipv4rsplist']['parent'] = 'ipv4slb';
@@ -321,49 +389,66 @@ $msgcode['ipv4rsplist']['edit']['del']['OK'] = 32;
 $msgcode['ipv4rsplist']['edit']['del']['ERR'] = 138;
 $msgcode['ipv4rsplist']['edit']['upd']['OK'] = 33;
 $msgcode['ipv4rsplist']['edit']['upd']['ERR'] = 139;
-$msgcode['ipv4rsp']['edit']['updIPv4RSP'] = $msgcode['ipv4rsplist']['edit']['upd'];
-
-$page['ipv4rsp']['title_handler'] = 'dynamic_title_rspool';
-$page['ipv4rsp']['parent'] = 'ipv4rsplist';
-$page['ipv4rsp']['bypass'] = 'pool_id';
-$page['ipv4rsp']['bypass_type'] = 'uint';
-$page['ipv4rsp']['tagloader'] = 'loadIPv4RSPoolTags';
-$page['ipv4rsp']['autotagloader'] = 'loadIPv4RSPoolAutoTags';
-$tab['ipv4rsp']['default'] = 'View';
-$tab['ipv4rsp']['edit'] = 'Edit';
-$tab['ipv4rsp']['editlblist'] = 'Load Balancers';
-$tab['ipv4rsp']['editrslist'] = 'RS list';
-$tab['ipv4rsp']['rsinservice'] = 'RS in service';
-$tab['ipv4rsp']['tags'] = 'Tags';
-$trigger['ipv4rsp']['rsinservice'] = 'trigger_poolrscount';
-$trigger['ipv4rsp']['tags'] = 'trigger_tags';
-$tabhandler['ipv4rsp']['default'] = 'renderRSPool';
-$tabhandler['ipv4rsp']['edit'] = 'renderEditRSPool';
-$tabhandler['ipv4rsp']['editrslist'] = 'renderRSPoolServerForm';
-$tabhandler['ipv4rsp']['editlblist'] = 'renderRSPoolLBForm';
-$tabhandler['ipv4rsp']['rsinservice'] = 'renderRSPoolRSInServiceForm';
-$tabhandler['ipv4rsp']['tags'] = 'renderIPv4RSPoolTags';
-$ophandler['ipv4rsp']['editrslist']['addRS'] = 'addRealServer';
-$ophandler['ipv4rsp']['editrslist']['delRS'] = 'deleteRealServer';
-$ophandler['ipv4rsp']['editrslist']['updRS'] = 'updateRealServer';
-$ophandler['ipv4rsp']['editrslist']['addMany'] = 'addRealServers';
-$ophandler['ipv4rsp']['editlblist']['addLB'] = 'addLoadBalancer';
-$ophandler['ipv4rsp']['editlblist']['delLB'] = 'deleteLoadBalancer';
-$ophandler['ipv4rsp']['editlblist']['updLB'] = 'updateLoadBalancer';
-$ophandler['ipv4rsp']['rsinservice']['upd'] = 'updateRSInService';
-$ophandler['ipv4rsp']['tags']['saveTags'] = 'saveEntityTags';
-$ophandler['ipv4rsp']['edit']['updIPv4RSP'] = 'updateRSPool';
-$msgcode['ipv4rsp']['editrslist']['addRS']['OK'] = 34;
-$msgcode['ipv4rsp']['editrslist']['addRS']['ERR'] = 126;
-$msgcode['ipv4rsp']['editrslist']['delRS']['OK'] = 35;
-$msgcode['ipv4rsp']['editrslist']['delRS']['ERR'] = 128;
-$msgcode['ipv4rsp']['editrslist']['updRS']['OK'] = 36;
-$msgcode['ipv4rsp']['editrslist']['updRS']['ERR'] = 133;
-$msgcode['ipv4rsp']['editrslist']['addMany']['OK'] = 37;
-$msgcode['ipv4rsp']['editrslist']['addMany']['ERR1'] = 131;
-$msgcode['ipv4rsp']['editrslist']['addMany']['ERR2'] = 127;
-$msgcode['ipv4rsp']['rsinservice']['upd']['OK'] = 38;
-$msgcode['ipv4rsp']['rsinservice']['upd']['ERR'] = 140;
+$msgcode['ipv4rspool']['edit']['updIPv4RSP'] = $msgcode['ipv4rsplist']['edit']['upd'];
+
+$page['ipv4rspool']['title_handler'] = 'dynamic_title_rspool';
+$page['ipv4rspool']['parent'] = 'ipv4rsplist';
+$page['ipv4rspool']['bypass'] = 'pool_id';
+$page['ipv4rspool']['bypass_type'] = 'uint';
+$page['ipv4rspool']['tagloader'] = 'loadIPv4RSPoolTags';
+$page['ipv4rspool']['autotagloader'] = 'loadIPv4RSPoolAutoTags';
+$tab['ipv4rspool']['default'] = 'View';
+$tab['ipv4rspool']['edit'] = 'Edit';
+$tab['ipv4rspool']['editlblist'] = 'Load Balancers';
+$tab['ipv4rspool']['editrslist'] = 'RS list';
+$tab['ipv4rspool']['rsinservice'] = 'RS in service';
+$tab['ipv4rspool']['tags'] = 'Tags';
+$tab['ipv4rspool']['files'] = 'Files';
+$trigger['ipv4rspool']['rsinservice'] = 'trigger_poolrscount';
+$trigger['ipv4rspool']['tags'] = 'trigger_tags';
+$tabhandler['ipv4rspool']['default'] = 'renderRSPool';
+$tabhandler['ipv4rspool']['edit'] = 'renderEditRSPool';
+$tabhandler['ipv4rspool']['editrslist'] = 'renderRSPoolServerForm';
+$tabhandler['ipv4rspool']['editlblist'] = 'renderRSPoolLBForm';
+$tabhandler['ipv4rspool']['rsinservice'] = 'renderRSPoolRSInServiceForm';
+$tabhandler['ipv4rspool']['tags'] = 'renderIPv4RSPoolTags';
+$tabhandler['ipv4rspool']['files'] = 'renderFilesForRSPool';
+$ophandler['ipv4rspool']['edit']['updIPv4RSP'] = 'updateRSPool';
+$ophandler['ipv4rspool']['editrslist']['addRS'] = 'addRealServer';
+$ophandler['ipv4rspool']['editrslist']['delRS'] = 'deleteRealServer';
+$ophandler['ipv4rspool']['editrslist']['updRS'] = 'updateRealServer';
+$ophandler['ipv4rspool']['editrslist']['addMany'] = 'addRealServers';
+$ophandler['ipv4rspool']['editlblist']['addLB'] = 'addLoadBalancer';
+$ophandler['ipv4rspool']['editlblist']['delLB'] = 'deleteLoadBalancer';
+$ophandler['ipv4rspool']['editlblist']['updLB'] = 'updateLoadBalancer';
+$ophandler['ipv4rspool']['rsinservice']['upd'] = 'updateRSInService';
+$ophandler['ipv4rspool']['tags']['saveTags'] = 'saveEntityTags';
+$ophandler['ipv4rspool']['files']['addFile'] = 'addFileToEntity';
+$ophandler['ipv4rspool']['files']['updateFile'] = 'updateFile';
+$ophandler['ipv4rspool']['files']['linkFile'] = 'linkFileToEntity';
+$ophandler['ipv4rspool']['files']['unlinkFile'] = 'unlinkFile';
+$ophandler['ipv4rspool']['files']['deleteFile'] = 'deleteFile';
+$msgcode['ipv4rspool']['editrslist']['addRS']['OK'] = 34;
+$msgcode['ipv4rspool']['editrslist']['addRS']['ERR'] = 126;
+$msgcode['ipv4rspool']['editrslist']['delRS']['OK'] = 35;
+$msgcode['ipv4rspool']['editrslist']['delRS']['ERR'] = 128;
+$msgcode['ipv4rspool']['editrslist']['updRS']['OK'] = 36;
+$msgcode['ipv4rspool']['editrslist']['updRS']['ERR'] = 133;
+$msgcode['ipv4rspool']['editrslist']['addMany']['OK'] = 37;
+$msgcode['ipv4rspool']['editrslist']['addMany']['ERR1'] = 131;
+$msgcode['ipv4rspool']['editrslist']['addMany']['ERR2'] = 127;
+$msgcode['ipv4rspool']['rsinservice']['upd']['OK'] = 38;
+$msgcode['ipv4rspool']['rsinservice']['upd']['ERR'] = 140;
+$msgcode['ipv4rspool']['files']['addFile']['OK'] = $msgcode['rack']['files']['addFile']['OK'];
+$msgcode['ipv4rspool']['files']['addFile']['ERR'] = $msgcode['rack']['files']['addFile']['ERR'];
+$msgcode['ipv4rspool']['files']['updateFile']['OK'] = $msgcode['rack']['files']['updateFile']['OK'];
+$msgcode['ipv4rspool']['files']['updateFile']['ERR'] = $msgcode['rack']['files']['updateFile']['ERR'];
+$msgcode['ipv4rspool']['files']['linkFile']['OK'] = $msgcode['rack']['files']['linkFile']['OK'];
+$msgcode['ipv4rspool']['files']['linkFile']['ERR'] = $msgcode['rack']['files']['linkFile']['ERR'];
+$msgcode['ipv4rspool']['files']['unlinkFile']['OK'] = $msgcode['rack']['files']['unlinkFile']['OK'];
+$msgcode['ipv4rspool']['files']['unlinkFile']['ERR'] = $msgcode['rack']['files']['unlinkFile']['ERR'];
+$msgcode['ipv4rspool']['files']['deleteFile']['OK'] = $msgcode['rack']['files']['deleteFile']['OK'];
+$msgcode['ipv4rspool']['files']['deleteFile']['ERR'] = $msgcode['rack']['files']['deleteFile']['ERR'];
 
 $page['rservers']['title'] = 'Real servers';
 $page['rservers']['parent'] = 'ipv4slb';
@@ -411,9 +496,26 @@ $page['user']['tagloader'] = 'loadUserTags';
 $page['user']['autotagloader'] = 'getUserAutoTags';
 $tab['user']['default'] = 'View';
 $tab['user']['tags'] = 'Tags';
+$tab['user']['files'] = 'Files';
 $tabhandler['user']['default'] = 'renderUser';
 $tabhandler['user']['tags'] = 'renderUserTags';
+$tabhandler['user']['files'] = 'renderFilesForUser';
 $ophandler['user']['tags']['saveTags'] = 'saveEntityTags';
+$ophandler['user']['files']['addFile'] = 'addFileToEntity';
+$ophandler['user']['files']['updateFile'] = 'updateFile';
+$ophandler['user']['files']['linkFile'] = 'linkFileToEntity';
+$ophandler['user']['files']['unlinkFile'] = 'unlinkFile';
+$ophandler['user']['files']['deleteFile'] = 'deleteFile';
+$msgcode['user']['files']['addFile']['OK'] = $msgcode['rack']['files']['addFile']['OK'];
+$msgcode['user']['files']['addFile']['ERR'] = $msgcode['rack']['files']['addFile']['ERR'];
+$msgcode['user']['files']['updateFile']['OK'] = $msgcode['rack']['files']['updateFile']['OK'];
+$msgcode['user']['files']['updateFile']['ERR'] = $msgcode['rack']['files']['updateFile']['ERR'];
+$msgcode['user']['files']['linkFile']['OK'] = $msgcode['rack']['files']['linkFile']['OK'];
+$msgcode['user']['files']['linkFile']['ERR'] = $msgcode['rack']['files']['linkFile']['ERR'];
+$msgcode['user']['files']['unlinkFile']['OK'] = $msgcode['rack']['files']['unlinkFile']['OK'];
+$msgcode['user']['files']['unlinkFile']['ERR'] = $msgcode['rack']['files']['unlinkFile']['ERR'];
+$msgcode['user']['files']['deleteFile']['OK'] = $msgcode['rack']['files']['deleteFile']['OK'];
+$msgcode['user']['files']['deleteFile']['ERR'] = $msgcode['rack']['files']['deleteFile']['ERR'];
 
 $page['perms']['title'] = 'Permissions';
 $page['perms']['parent'] = 'config';
@@ -548,6 +650,38 @@ $tabhandler['reports']['rackcode'] = 'renderRackCodeReports';
 $tabhandler['reports']['ipv4'] = 'renderIPv4Reports';
 $tabhandler['reports']['local'] = 'renderLocalReports';
 
+$page['files']['title'] = 'Files';
+$page['files']['parent'] = 'index';
+$tab['files']['default'] = 'View';
+$tab['files']['addmore'] = 'Upload';
+$tabhandler['files']['default'] = 'renderFileSpace';
+$tabhandler['files']['addmore'] = 'renderFileUploadForm';
+$ophandler['files']['addmore']['addFile'] = 'addFileWithoutLink';
+$msgcode['files']['addmore']['addFile']['OK'] = 69;
+$msgcode['files']['addmore']['addFile']['ERR'] = 100;
+
+$page['filesbylink']['title_handler'] = 'dynamic_title_file';
+$page['filesbylink']['handler'] = 'renderFilesByLink'; //renderObjectGroup
+$page['filesbylink']['bypass'] = 'entity_type';
+$page['filesbylink']['bypass_type'] = 'string';
+$page['filesbylink']['parent'] = 'files';
+$ophandler['filesbylink']['default']['deleteFile'] = 'deleteFile';
+
+$page['file']['title'] = 'File';
+$page['file']['bypass'] = 'file_id';
+$page['file']['bypass_type'] = 'uint';
+$page['file']['parent'] = 'index';
+$page['file']['tagloader'] = 'loadFileTags';
+$page['file']['autotagloader'] = 'loadFileAutoTags';
+$tab['file']['default'] = 'View';
+$tab['file']['tags'] = 'Tags';
+$trigger['file']['tags'] = 'trigger_tags';
+$tabhandler['file']['tags'] = 'renderFileTags';
+$tabhandler['file']['default'] = 'renderFile';
+$ophandler['file']['tags']['saveTags'] = 'saveEntityTags';
+$msgcode['file']['tags']['saveTags']['OK'] = 22;
+$msgcode['file']['tags']['saveTags']['ERR'] = 143;
+
 // This function returns array if page numbers leading to the target page
 // plus page number of target page itself. The first element is the target
 // page number and the last element is the index page number.
index 9e55867..2d7876f 100644 (file)
@@ -1148,11 +1148,12 @@ function saveEntityTags ()
 {
        $page2realm = array
        (
+               'file' => 'file',
+               'ipv4net' => 'ipv4net',
+               'ipv4rs' => 'ipv4rspool',
+               'ipv4vs' => 'ipv4vs',
                'object' => 'object',
-               'iprange' => 'ipv4net',
                'rack' => 'rack',
-               'ipv4vs' => 'ipv4vs',
-               'ipv4rsp' => 'ipv4rspool',
                'user' => 'user'
        );
        global $explicit_tags, $implicit_tags, $page, $pageno;
@@ -1413,4 +1414,94 @@ function querySNMPData ()
        return buildWideRedirectURL (doSNMPmining ($_REQUEST['object_id'], $_REQUEST['community']));
 }
 
+// File-related functions
+function addFileWithoutLink ()
+{
+       assertStringArg ('comment', __FUNCTION__, TRUE);
+
+       // Make sure the file can be uploaded
+       if (get_cfg_var('file_uploads') != 1)
+               return buildRedirectURL ('ERR', array ("file uploads not allowed, change 'file_uploads' parameter in php.ini"));
+
+       $fp = fopen($_FILES['file']['tmp_name'], 'rb');
+       $error = commitAddFile ($_FILES['file']['name'], $_FILES['file']['type'], $_FILES['file']['size'], $fp, $_REQUEST['comment']);
+
+       if ($error != '')
+               return buildRedirectURL ('ERR', array ($error));
+
+       return buildRedirectURL ('OK', array ($_FILES['file']['name']));
+}
+
+function addFileToEntity ()
+{
+       assertStringArg ('entity_type', __FUNCTION__);
+       assertUIntArg ('entity_id', __FUNCTION__);
+       assertStringArg ('comment', __FUNCTION__, TRUE);
+       if (empty ($_REQUEST['entity_type']) || empty ($_REQUEST['entity_id']))
+               return buildRedirectURL ('ERR');
+
+       // Make sure the file can be uploaded
+       if (get_cfg_var('file_uploads') != 1)
+               return buildRedirectURL ('ERR', array ("file uploads not allowed, change 'file_uploads' parameter in php.ini"));
+
+       $fp = fopen($_FILES['file']['tmp_name'], 'rb');
+       $error = commitAddFile ($_FILES['file']['name'], $_FILES['file']['type'], $_FILES['file']['size'], $fp, $_REQUEST['comment']);
+       if ($error != '')
+               return buildRedirectURL ('ERR', array ($error));
+
+       $file_id = lastInsertID();
+       $error = commitLinkFile ($file_id, $_REQUEST['entity_type'], $_REQUEST['entity_id']);   
+       if ($error != '')
+               return buildRedirectURL ('ERR', array ($error));
+
+       return buildRedirectURL ('OK', array ($_FILES['file']['name']));
+}
+
+function linkFileToEntity ()
+{
+       assertUIntArg ('entity_id', __FUNCTION__);
+       assertUIntArg ('file_id', __FUNCTION__);
+       assertStringArg ('file_name', __FUNCTION__);
+
+       $error = commitLinkFile ($_REQUEST['file_id'], $_REQUEST['entity_type'], $_REQUEST['entity_id']);
+       if ($error != '')
+               return buildRedirectURL ('ERR', array ($error));
+
+       return buildRedirectURL ('OK', array ($_REQUEST['file_name']));
+}
+
+function updateFile ()
+{
+       assertUIntArg ('file_id', __FUNCTION__);
+       assertStringArg ('name', __FUNCTION__);
+       assertStringArg ('comment', __FUNCTION__, TRUE);
+       $error = commitUpdateFile ($_REQUEST['file_id'], $_REQUEST['comment']);
+       if ($error != '')
+               return buildRedirectURL ('ERR', array ($error));
+
+       return buildRedirectURL ('OK', array ($_REQUEST['name']));
+}
+
+function unlinkFile ()
+{
+       assertUIntArg ('link_id', __FUNCTION__);
+       $error = commitUnlinkFile ($_REQUEST['link_id']);
+
+       if ($error != '')
+               return buildRedirectURL ('ERR', array ($error));
+
+       return buildRedirectURL ('OK', array ($_REQUEST['name']));
+}
+
+function deleteFile ()
+{
+       assertUIntArg ('file_id', __FUNCTION__);
+       $error = commitDeleteFile ($_REQUEST['file_id']);
+
+       if ($error != '')
+               return buildRedirectURL ('ERR', array ($error));
+
+       return buildRedirectURL ('OK', array ($_REQUEST['name']));
+}
+
 ?>
index c2a4ed9..4bcbb1f 100644 (file)
@@ -10,12 +10,12 @@ function dynamic_title_ipaddress ()
        return array ('name' => $_REQUEST['ip'], 'params' => array ('ip' => $_REQUEST['ip']));
 }
 
-function dynamic_title_iprange ()
+function dynamic_title_ipv4net ()
 {
        global $pageno;
        switch ($pageno)
        {
-               case 'iprange':
+               case 'ipv4net':
                        $range = getIPv4NetworkInfo ($_REQUEST['id']);
                        return array ('name' => $range['ip'].'/'.$range['mask'], 'params' => array('id'=>$_REQUEST['id']));
                        break;
@@ -194,4 +194,21 @@ function dynamic_title_user ()
        );
 }
 
+function dynamic_title_file ()
+{
+       global $pageno;
+       $ret = array();
+       switch ($pageno)
+       {
+               case 'filesbylink':
+                       assertStringArg ('entity_type', __FUNCTION__);
+                       $ret['name'] = $_REQUEST['entity_type'];
+                       $ret['params']['entity_type'] = $_REQUEST['entity_type'];
+                       break;
+               default:
+                       return NULL;
+       }
+       return $ret;
+}
+
 ?>
index da9c9c7..4bded0a 100644 (file)
--- a/index.php
+++ b/index.php
@@ -79,6 +79,9 @@ if (isset ($tabhandler[$pageno][$tabno]))
                        case 'inet4':
                                assertIPv4Arg ($page[$pageno]['bypass'], 'index');
                                break;
+                       case 'string':
+                               assertStringArg ($page[$pageno]['bypass'], 'index');
+                               break;
                        default:
                                showError ('Dispatching error for bypass parameter', __FILE__);
                                break;
index 41c6b13..595699a 100644 (file)
@@ -214,6 +214,15 @@ function init_config ()
                echo '</table>';
                return FALSE;
        }
+
+       // Make sure InnoDB is supported
+       require_once 'inc/database.php';
+       if (!isInnoDBSupported ($dbxlink))
+       {
+               echo 'Error: InnoDB support is disabled.  See the README for details.';
+               return FALSE;
+       }
+
        $conf = fopen ('inc/secret.php', 'w+');
        if ($conf === FALSE)
        {
index 63994b5..9913837 100644 (file)
@@ -63,19 +63,19 @@ INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_no`) VALUES (12,7,
 INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_no`) VALUES (12,8,0);
 INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_no`) VALUES (12,13,0);
 INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_no`) VALUES (12,20,0);
-INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_no`) VALUES (445, 1, 0);
-INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_no`) VALUES (445, 2, 21);
-INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_no`) VALUES (445, 3, 0);
-INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_no`) VALUES (445, 5, 0);
-INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_no`) VALUES (445, 14, 0);
-INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_no`) VALUES (445, 22, 0);
-INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_no`) VALUES (447, 1, 0);
-INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_no`) VALUES (447, 2, 22);
-INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_no`) VALUES (447, 3, 0);
-INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_no`) VALUES (447, 5, 0);
-INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_no`) VALUES (447, 14, 0);
-INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_no`) VALUES (447, 22, 0);
-INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_no`) VALUES (15, 2, 23);
+INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_no`) VALUES (445,1,0);
+INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_no`) VALUES (445,2,21);
+INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_no`) VALUES (445,3,0);
+INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_no`) VALUES (445,5,0);
+INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_no`) VALUES (445,14,0);
+INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_no`) VALUES (445,22,0);
+INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_no`) VALUES (447,1,0);
+INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_no`) VALUES (447,2,22);
+INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_no`) VALUES (447,3,0);
+INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_no`) VALUES (447,5,0);
+INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_no`) VALUES (447,14,0);
+INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_no`) VALUES (447,22,0);
+INSERT INTO `AttributeMap` (`objtype_id`, `attr_id`, `chapter_no`) VALUES (15,2,23);
 
 INSERT INTO `Chapter` (`chapter_no`, `sticky`, `chapter_name`) VALUES (11,'no','server models');
 INSERT INTO `Chapter` (`chapter_no`, `sticky`, `chapter_name`) VALUES (12,'no','network switch models');
@@ -90,7 +90,7 @@ INSERT INTO `Chapter` (`chapter_no`, `sticky`, `chapter_name`) VALUES (18,'no','
 INSERT INTO `Chapter` (`chapter_no`, `sticky`, `chapter_name`) VALUES (19,'no','tape library models');
 INSERT INTO `Chapter` (`chapter_no`, `sticky`, `chapter_name`) VALUES (21,'no','KVM switch models');
 INSERT INTO `Chapter` (`chapter_no`, `sticky`, `chapter_name`) VALUES (22,'no','multiplexer models');
-INSERT INTO `Chapter` (`chapter_no`, `sticky`, `chapter_name`) VALUES (23, 'no', 'console models');
+INSERT INTO `Chapter` (`chapter_no`, `sticky`, `chapter_name`) VALUES (23,'no','console models');
 
 INSERT INTO `PortCompat` (`type1`, `type2`) VALUES (17,17);
 INSERT INTO `PortCompat` (`type1`, `type2`) VALUES (18,18);
@@ -260,6 +260,6 @@ INSERT INTO `Config` (varname, varvalue, vartype, emptyok, is_hidden, descriptio
 INSERT INTO `Config` (varname, varvalue, vartype, emptyok, is_hidden, description) VALUES ('TREE_THRESHOLD','25','uint','yes','no','Tree view auto-collapse threshold');
 INSERT INTO `Config` (varname, varvalue, vartype, emptyok, is_hidden, description) VALUES ('IPV4_JAYWALK','no','string','no','no','Enable IPv4 address allocations w/o covering network');
 INSERT INTO `Config` (varname, varvalue, vartype, emptyok, is_hidden, description) VALUES ('ADDNEW_AT_TOP','yes','string','no','no','Render "add new" line at top of the list');
-INSERT INTO `Config` (varname, varvalue, vartype, emptyok, is_hidden, description) VALUES ('DB_VERSION','0.16.4','string','no','yes','Database version.');
+INSERT INTO `Config` (varname, varvalue, vartype, emptyok, is_hidden, description) VALUES ('DB_VERSION','0.17.0','string','no','yes','Database version.');
 
 INSERT INTO `Script` VALUES ('RackCode','allow {$userid_1}');
index 79b245d..6bf548b 100644 (file)
@@ -59,6 +59,29 @@ CREATE TABLE `Dictionary` (
   UNIQUE KEY `chap_to_val` (`chapter_no`,`dict_value`)
 ) ENGINE=MyISAM AUTO_INCREMENT=50000;
 
+CREATE TABLE `File` (
+  `id` int(10) unsigned NOT NULL auto_increment,
+  `name` char(255) NOT NULL,
+  `type` char(255) NOT NULL,
+  `size` int(10) unsigned NOT NULL,
+  `ctime` datetime NOT NULL,
+  `mtime` datetime NOT NULL,
+  `atime` datetime NOT NULL,
+  `contents` longblob NOT NULL,
+  `comment` text,
+  PRIMARY KEY  (`id`)
+) ENGINE=InnoDB;
+
+CREATE TABLE `FileLink` (
+  `id` int(10) unsigned NOT NULL auto_increment,
+  `file_id` int(10) unsigned NOT NULL,
+  `entity_type` enum('ipv4net','ipv4rspool','ipv4vs','object','rack','user') NOT NULL default 'object',
+  `entity_id` int(10) NOT NULL,
+  PRIMARY KEY  (`id`),
+  KEY `FileLink-file_id` (`file_id`),
+  CONSTRAINT `FileLink-File_fkey` FOREIGN KEY (`file_id`) REFERENCES `File` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
+) ENGINE=InnoDB;
+
 CREATE TABLE `IPAddress` (
   `ip` int(10) unsigned NOT NULL,
   `name` char(255) NOT NULL,
@@ -252,7 +275,7 @@ CREATE TABLE `Script` (
 ) TYPE=MyISAM;
 
 CREATE TABLE `TagStorage` (
-  `target_realm` enum('object','ipv4net','rack','ipv4vs','ipv4rspool','user') NOT NULL default 'object',
+  `target_realm` enum('file','ipv4net','ipv4vs','ipv4rspool','object','rack','user') NOT NULL default 'object',
   `target_id` int(10) unsigned NOT NULL,
   `tag_id` int(10) unsigned NOT NULL,
   UNIQUE KEY `entity_tag` (`target_realm`,`target_id`,`tag_id`),
diff --git a/pix/download.png b/pix/download.png
new file mode 100644 (file)
index 0000000..4325343
Binary files /dev/null and b/pix/download.png differ
diff --git a/pix/files.png b/pix/files.png
new file mode 100644 (file)
index 0000000..a36e22e
Binary files /dev/null and b/pix/files.png differ
diff --git a/pix/filler.png b/pix/filler.png
new file mode 100644 (file)
index 0000000..eece129
Binary files /dev/null and b/pix/filler.png differ
similarity index 81%
rename from link_helper.php
rename to port_link_helper.php
index 43a6a2a..ec69b9b 100644 (file)
@@ -38,7 +38,7 @@ echo "<link rel=icon href='" . getFaviconURL() . "' type='image/x-icon' />";
 <?php
        echo "<input type='submit' value='Proceed' onclick='".
        "if (getElementById(\"ports\").value != \"\") {".
-       "       opener.location=\"$root/process.php?page=object&tab=ports&op=linkPort&object_id=$object_id&port_id=$port_id&port_name=$port_name&remote_port_name=\"+getElementById(\"remote_port_name\").value+\"&remote_object_name=\"+getElementById(\"remote_object_name\").value+\"&remote_port_id=\"+getElementById(\"ports\").value; ".
+       "       opener.location=\"${root}process.php?page=object&tab=ports&op=linkPort&object_id=$object_id&port_id=$port_id&port_name=$port_name&remote_port_name=\"+getElementById(\"remote_port_name\").value+\"&remote_object_name=\"+getElementById(\"remote_object_name\").value+\"&remote_port_id=\"+getElementById(\"ports\").value; ".
        "       window.close();".
        "}".
        "'>";
index d4fca85..3bdb075 100644 (file)
@@ -1,6 +1,12 @@
 <?php
 
 require 'inc/init.php';
+
+// FIXME: find a better way to handle this error
+if ($_REQUEST['op'] == 'addFile' && !isset($_FILES['file']['error'])) {
+       showError ("File upload error, it's size probably exceeds upload_max_filesize directive in php.ini");
+       die;
+}
 fixContext();
 
 if (empty ($op) or !isset ($ophandler[$pageno][$tabno][$op]))
index 78267e0..3217ab7 100644 (file)
@@ -56,7 +56,36 @@ function executeUpgradeBatch ($batchid)
        switch ($batchid)
        {
                case '0.17.0':
-                       $query[] = "update Config set varvalue = '0.17.0' where varname = 'DB_VERSION'";
+                       // create tables for storing files (requires InnoDB support)
+                       if (!isInnoDBSupported ())
+                       {
+                               die ('<b>Cannot upgrade because InnoDB tables are not supported by your MySQL server. See the README for details.</b>');
+                       }
+                       $query[] = "
+CREATE TABLE `File` (
+  `id` int(10) unsigned NOT NULL auto_increment,
+  `name` char(255) NOT NULL,
+  `type` char(255) NOT NULL,
+  `size` int(10) unsigned NOT NULL,
+  `ctime` datetime NOT NULL,
+  `mtime` datetime NOT NULL,
+  `atime` datetime NOT NULL,
+  `contents` longblob NOT NULL,
+  `comment` text,
+  PRIMARY KEY  (`id`)
+) ENGINE=InnoDB";
+                       $query[] = "
+CREATE TABLE `FileLink` (
+  `id` int(10) unsigned NOT NULL auto_increment,
+  `file_id` int(10) unsigned NOT NULL,
+  `entity_type` enum('ipv4net','ipv4rspool','ipv4vs','object','rack','user') NOT NULL default 'object',
+  `entity_id` int(10) NOT NULL,
+  PRIMARY KEY  (`id`),
+  KEY `FileLink-file_id` (`file_id`),
+  CONSTRAINT `FileLink-File_fkey` FOREIGN KEY (`file_id`) REFERENCES `File` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
+) ENGINE=InnoDB";
+                       $query[] = "ALTER TABLE TagStorage MODIFY COLUMN target_realm enum('file','ipv4net','ipv4rspool','ipv4vs','object','rack','user') NOT NULL default 'object'";
+                       $query[] = "UPDATE Config SET varvalue = '0.17.0' WHERE varname = 'DB_VERSION'";
                        break;
                default:
                        showError ("executeUpgradeBatch () failed, because batch '${batchid}' isn't defined", __FILE__);