diff --git a/.gitignore b/.gitignore
index 8f4e287..0db8385 100644
--- a/.gitignore
+++ b/.gitignore
@@ -28,3 +28,4 @@ web.config
 #libraries
 library/jpgraph
 library/FirePHPCore
+patches
diff --git a/admin/schema.php b/admin/schema.php
index c87f0a6..b10b315 100644
--- a/admin/schema.php
+++ b/admin/schema.php
@@ -606,3 +606,12 @@ $upgrade[] = Array( 'CreateIndexSQL', Array( 'idx_project_hierarchy_parent_id',
 /* 180 */
 $upgrade[] = Array( 'CreateIndexSQL', Array( 'idx_tag_name', db_get_table( 'tag' ), 'name' ) );
 $upgrade[] = Array( 'CreateIndexSQL', Array( 'idx_bug_tag_tag_id', db_get_table( 'bug_tag' ), 'tag_id' ) );
+
+/* 190 */
+$upgrade[] = Array( 'AddColumnSQL', Array( db_get_table( 'user' ), "
+	password_128 		C(128) NOTNULL DEFAULT \" '' \" " ) );
+$upgrade[] = Array( 'AddColumnSQL', Array( db_get_table( 'user' ), "
+	password_hash 		C(10) NOTNULL DEFAULT \" 'MD5' \" " ) );
+$upgrade[] = Array( 'UpdateFunction', "password_hash_migrate", Array( 'password_128', 'password_hash' ) );
+$upgrade[] = Array( 'DropColumnSQL', Array( db_get_table( 'user' ), "password" ) );
+$upgrade[] = Array( 'RenameColumnSQL', Array( db_get_table( 'user' ), "password_128", "password", "password 		C(128) NOTNULL DEFAULT \" '' \" " ) );
diff --git a/config_defaults_inc.php b/config_defaults_inc.php
index 702b5dc..eee3566 100644
--- a/config_defaults_inc.php
+++ b/config_defaults_inc.php
@@ -2571,8 +2571,9 @@ $g_allow_no_category = OFF;
 
 /**
  * login method
- * CRYPT or PLAIN or MD5 or LDAP or BASIC_AUTH. You can simply change this at
- * will. MantisBT will try to figure out how the passwords were encrypted.
+ * CRYPT or PLAIN or MD5 or SHA1 or LDAP or BASIC_AUTH. 
+ * You can simply change this at will. MantisBT will try to figure out how the 
+ * passwords were encrypted.
  * @global int $g_login_method
  */
 $g_login_method = MD5;
diff --git a/core/authentication_api.php b/core/authentication_api.php
index 8e0b422..e7e6afa 100644
--- a/core/authentication_api.php
+++ b/core/authentication_api.php
@@ -345,10 +345,22 @@ function auth_does_password_match( $p_user_id, $p_test_password ) {
 
 	$t_password = user_get_field( $p_user_id, 'password' );
 	$t_login_methods = Array(
+		SHA1,
 		MD5,
 		CRYPT,
 		PLAIN,
 	);
+	if( substr($t_password, 0, 1) == '{' && strpos($t_password, '}') > 1 ) {
+		$t_method = substr( $t_password, 1, strpos($t_password, '}')-1 );
+		$t_methods_arr = Array('SHA'=>SHA1, 'MD5'=>MD5, 'CRYPT'=>CRYPT,
+			'PLAIN'=>PLAIN);
+		if( in_array($t_method, $t_methods_arr)
+			&& in_array($t_methods_arr[$t_method], $t_login_methods) ) {
+			$t_login_methods = Array($t_methods_arr[$t_method]);
+			$t_password = substr( $t_password, strlen($t_method)+2 );
+		}
+	}
+
 	foreach( $t_login_methods as $t_login_method ) {
 
 		# pass the stored password in as the salt
@@ -405,6 +417,9 @@ function auth_does_password_match( $p_user_id, $p_test_password ) {
 		case MD5:
 			$t_processed_password = md5( $p_password );
 			break;
+		case SHA1:
+			$t_processed_password = sha1( $p_password );
+			break;
 		case BASIC_AUTH:
 		case PLAIN:
 		default:
diff --git a/core/bug_api.php b/core/bug_api.php
index fb32839..4326199 100644
--- a/core/bug_api.php
+++ b/core/bug_api.php
@@ -1324,6 +1324,28 @@ function bug_get_newest_bugnote_timestamp( $p_bug_id ) {
 }
 
 /**
+ * return the reporter (user_id) for the most recent time at which a bugnote
+ *  associated with the bug was modified
+ * @param int p_bug_id integer representing bug id
+ * @return bool|int false or user id in integer format representing last bugnote reporter
+ * @access public
+ * @uses database_api.php
+ */
+function bug_get_last_bugnote_reporter( $p_bug_id ) {
+	$c_bug_id = db_prepare_int( $p_bug_id );
+	$t_bugnote_table = db_get_table( 'bugnote' );
+
+	$query = "SELECT MIN(reporter_id)
+				  FROM $t_bugnote_table A
+				  WHERE A.date_submitted = (SELECT MAX(X.date_submitted)
+				                               FROM $t_bugnote_table X
+				                               WHERE X.bug_id = A.bug_id) AND
+				        A.bug_id=" . db_param();
+	$result = db_query_bound( $query, Array( $c_bug_id ), 1 );
+	return db_result( $result );
+}
+
+/**
  * return the timestamp for the most recent time at which a bugnote
  *  associated with the bug was modified and the total bugnote
  *  count in one db query
diff --git a/core/constant_inc.php b/core/constant_inc.php
index 7e3e274..42bde13 100644
--- a/core/constant_inc.php
+++ b/core/constant_inc.php
@@ -134,6 +134,7 @@ define( 'MD5', 3 );
 define( 'LDAP', 4 );
 define( 'BASIC_AUTH', 5 );
 define( 'HTTP_AUTH', 6 );
+define( 'SHA1', 7 );
 
 # file upload methods
 define( 'DISK', 1 );
@@ -552,6 +553,6 @@ define( 'PHPMAILER_METHOD_SMTP',		2 );
 # Lengths - NOTE: these may represent hard-coded values in db schema and should not be changed.
 define( 'USERLEN', 32);
 define( 'REALLEN', 64);
-define( 'PASSLEN', 32);
+define( 'PASSLEN', 128);
 
 define( 'SECONDS_PER_DAY', 86400 );
diff --git a/core/filter_api.php b/core/filter_api.php
index 7e61912..01b2292 100644
--- a/core/filter_api.php
+++ b/core/filter_api.php
@@ -1865,19 +1865,19 @@ function filter_get_bug_rows( &$p_page_number, &$p_per_page, &$p_page_count, &$p
 							break;
 						case CUSTOM_FIELD_DATE_NONE:
 							array_push( $t_join_clauses, $t_cf_join_clause );
-							$t_custom_where_clause = '(( ' . $t_table_name . '.bug_id is null) OR ( ' . $t_table_name . '.value = 0)';
+							$t_custom_where_clause = '(( ' . $t_table_name . '.bug_id is null) OR ( CAST(' . $t_table_name . '.value AS FLOAT) = 0)';
 							break;
 						case CUSTOM_FIELD_DATE_BEFORE:
 							array_push( $t_join_clauses, $t_cf_join_clause );
-							$t_custom_where_clause = '(( ' . $t_table_name . '.value != 0 AND (' . $t_table_name . '.value+0) < ' . ( $t_filter['custom_fields'][$t_cfid][2] ) . ')';
+							$t_custom_where_clause = '(( CAST(' . $t_table_name . '.value AS FLOAT) != 0 AND ( CAST(' . $t_table_name . '.value AS FLOAT) + 0) < ' . ( $t_filter['custom_fields'][$t_cfid][2] ) . ')';
 							break;
 						case CUSTOM_FIELD_DATE_AFTER:
 							array_push( $t_join_clauses, $t_cf_join_clause );
-							$t_custom_where_clause = '( (' . $t_table_name . '.value+0) > ' . ( $t_filter['custom_fields'][$t_cfid][1] + 1 );
+							$t_custom_where_clause = '( (CAST(' . $t_table_name . '.value AS FLOAT) + 0) > ' . ( $t_filter['custom_fields'][$t_cfid][1] + 1 );
 							break;
 						default:
 							array_push( $t_join_clauses, $t_cf_join_clause );
-							$t_custom_where_clause = '( (' . $t_table_name . '.value+0) BETWEEN ' . $t_filter['custom_fields'][$t_cfid][1] . ' AND ' . $t_filter['custom_fields'][$t_cfid][2];
+							$t_custom_where_clause = '( ( CAST(' . $t_table_name . '.value AS FLOAT) + 0) BETWEEN ' . $t_filter['custom_fields'][$t_cfid][1] . ' AND ' . $t_filter['custom_fields'][$t_cfid][2];
 							break;
 					}
 				} else {
diff --git a/core/html_api.php b/core/html_api.php
index 4bdf300..1f37ca1 100644
--- a/core/html_api.php
+++ b/core/html_api.php
@@ -1201,11 +1201,19 @@ function html_status_legend() {
 
 	# draw the status bar
 	$width = (int)( 100 / count( $t_status_array ) );
-	foreach( $t_status_array as $t_status => $t_name ) {
-		$t_val = $t_status_names[$t_status];
-		$t_color = get_status_color( $t_status );
+		for($i=0; $i<10; $i++) {
+			if ( $i != 0 ) {
+				echo '<tr>';
+			}
+			foreach( $t_status_array as $t_status => $t_name ) {
+				if($t_status % 10 == $i) {
+					$t_val = $t_status_names[$t_status];
+					$t_color = get_status_color( $t_status );
 
-		echo "<td class=\"small-caption\" width=\"$width%\" bgcolor=\"$t_color\">$t_val</td>";
+					echo "<td class=\"small-caption\" width=\"$width%\" bgcolor=\"$t_color\">$t_val</td>";
+				}
+			}
+		echo '</tr>';
 	}
 
 	echo '</tr>';
diff --git a/core/install_helper_functions_api.php b/core/install_helper_functions_api.php
index f33e4c5..9a36745 100644
--- a/core/install_helper_functions_api.php
+++ b/core/install_helper_functions_api.php
@@ -221,4 +221,63 @@ function install_date_migrate( $p_data) {
 function install_do_nothing() {
 	# return 2 because that's what ADOdb/DataDict does when things happen properly
 	return 2;
-}
\ No newline at end of file
+}
+
+function install_password_hash_migrate( $p_data) {
+	// $p_data = [0] temp_password column, [1] password_hash column
+	global $g_db_log_queries;
+	global $g_login_method;
+
+	if( $g_login_method === LDAP ) {
+		return 2;
+	}
+	
+	$t_login_method = array(PLAIN => 'PLAIN', CRYPT => 'CRYPT',
+		CRYPT_FULL_SALT => 'CRYPT_FULL_SALT', MD5 => 'MD5', SHA1 => 'SHA1'
+		)[$g_login_method];
+
+
+	// disable query logging (even if it's enabled in config for this)
+	if ( $g_db_log_queries !== 0 ) {
+		$t_log_queries = $g_db_log_queries;
+		$g_db_log_queries = 0;
+	} else {
+		$t_log_queries = null;
+	}
+
+	$t_table = db_get_table( 'user' );
+	$t_temp_col = $p_data[0];
+	$t_password_hash_col = $p_data[1];
+
+	// fill password_hash and temp_col
+	$query = "SELECT id, password FROM $t_table";
+	$t_result = db_query_bound( $query );
+
+	while( $row = db_fetch_array( $t_result ) ) {
+		
+		$t_id = (int)$row['id'];
+		$t_hash_mode = $t_login_method;
+		$t_password = $row['password'];
+
+		if( substr($t_password, 0, 1) == '{'
+			&& strpos($t_password, '}') > 1 ) {
+
+			$t_hash_mode = substr($t_password, 1, strpos($t_password, '}') - 1);
+			$t_password = substr($t_password, strlen($t_hash_mode) + 2);
+		}
+
+		$query = "UPDATE $t_table SET $t_temp_col=" . db_param() . ", "
+				    "$t_password_hash_col=" . db_param() . " 
+					WHERE id=" . db_param();
+		db_query_bound( $query, array( $t_password, $t_hash_mode, $t_id ) );
+	}
+
+	// re-enabled query logging if we disabled it
+	if ( $t_log_queries !== null ) {
+		$g_db_log_queries = $t_log_queries;
+	}
+
+	# return 2 because that's what ADOdb/DataDict does when things happen properly
+	return 2;
+
+}
diff --git a/docbook/adminguide/en/authentication.sgml b/docbook/adminguide/en/authentication.sgml
index a960c1e..ffbe0f6 100644
--- a/docbook/adminguide/en/authentication.sgml
+++ b/docbook/adminguide/en/authentication.sgml
@@ -14,6 +14,7 @@
                 <listitem><para>CRYPT_FULL_SALT - deprecated.</para></listitem>
                 <listitem><para>PLAIN - deprecated.</para></listitem>
                 <listitem><para>MD5 - This is default and recommended approach.  See <ulink url="http://en.wikipedia.org/wiki/MD5">MD5 topic on Wikipedia</ulink> for more details.</para></listitem>
+                <listitem><para>SHA1 - Even stronger than MD5.  See <ulink url="http://en.wikipedia.org/wiki/SHA1">SHA1 topic on Wikipedia</ulink> for more details.</para></listitem>
             </itemizedlist>
         </para>
 
diff --git a/docbook/adminguide/en/configuration.sgml b/docbook/adminguide/en/configuration.sgml
index bce4bdd..99df312 100644
--- a/docbook/adminguide/en/configuration.sgml
+++ b/docbook/adminguide/en/configuration.sgml
@@ -1583,6 +1583,9 @@
                 <listitem><para>
                         <itemizedlist>
                             <listitem>
+                                <para>SHA1</para>
+                            </listitem>
+                            <listitem>
                                 <para>MD5</para>
                             </listitem>
                             <listitem>
diff --git a/my_view_inc.php b/my_view_inc.php
index 97c131c..ff2e62d 100644
--- a/my_view_inc.php
+++ b/my_view_inc.php
@@ -434,6 +434,9 @@ echo "($v_start - $v_end / $t_bug_count)";
 	$t_summary = string_display_line_links( $t_bug->summary );
 	$t_last_updated = date( config_get( 'normal_date_format' ), $t_bug->last_updated );
 
+	$t_last_reporter_id = bug_get_last_bugnote_reporter( $t_bug->id );
+	$t_last_reporter = $t_last_reporter_id ? user_get_name( $t_last_reporter_id ) : '';
+
 	# choose color based on status
 	$status_color = get_status_color( $t_bug->status );
 
@@ -498,9 +501,9 @@ echo "($v_start - $v_end / $t_bug_count)";
 	echo string_display_line( category_full_name( $t_bug->category_id, true, $t_bug->project_id ) );
 
 	if( $t_bug->last_updated > strtotime( '-' . $t_filter[FILTER_PROPERTY_HIGHLIGHT_CHANGED] . ' hours' ) ) {
-		echo ' - <b>' . $t_last_updated . '</b>';
+		echo ' - <b>' . $t_last_updated . ' - ' . $t_last_reporter . '</b>';
 	} else {
-		echo ' - ' . $t_last_updated;
+		echo ' - ' . $t_last_updated . ' - ' . $t_last_reporter;
 	}
 	?>
 		</span>
diff --git a/plugins/AutoMonitor/AutoMonitor.API.php b/plugins/AutoMonitor/AutoMonitor.API.php
new file mode 100644
index 0000000..ab86729
--- /dev/null
+++ b/plugins/AutoMonitor/AutoMonitor.API.php
@@ -0,0 +1,89 @@
+<?php
+# TODO : include header
+
+/**
+ * Get the list of users for the specified project (and category)
+ *
+ * This will include the explicit and inherited settings
+ */
+function AutoMonitor_get_users ( $p_project_id, $p_category_id )
+{
+	/* Return values */
+	$t_users     = array();
+
+	/* Tables */
+	$t_user_table        = db_get_table('user');
+	$t_automonitor_table = plugin_table('list');
+
+	/* DB params */
+	$c_project_id  = db_prepare_int($p_project_id);
+	$c_category_id = db_prepare_int($p_category_id);
+
+	/* Add all users with initial settings */
+	foreach ( project_get_all_user_rows($p_project_id) as $val ) {
+		$val['automonitor_state']    = 0;
+		$val['automonitor_explicit'] = false;
+		$t_users[$val['id']] = $val;
+	}
+
+	/* Get list of parent projects */
+	$c_parents = array();
+	$t_parents = project_hierarchy_inheritance($p_project_id);
+	foreach ( $t_parents as $t_parent ) {
+		if ( $t_parent != 0 ) {
+			$c_parents[] = db_prepare_int($t_parent);
+		}
+	}
+
+	/* Query for all data related to relevant projects / categories */
+	$params = array(db_prepare_int(0), $c_category_id);
+	$query  = "SELECT u.id, u.username, u.realname, c.state as automonitor_state,
+							c.project_id, c.category_id
+							FROM $t_user_table u, $t_automonitor_table c
+							WHERE u.id = c.user_id
+							AND c.project_id IN (" . implode(',', $c_parents) . ")
+								AND ( c.category_id = " . db_param() . "
+									OR c.category_id = " . db_param() . ")
+							ORDER BY u.id, c.category_id ASC";
+	$result = db_query_bound($query, $params);
+
+	/* Process into project keyed list
+	 *   Note: since the sub project ids might not be in order we can't
+	 *         use SQL to provide the project ordering
+	 */
+	$t_proj_list = array();
+	$t_proj_list = array();
+	$t_row_count = db_num_rows( $result );
+	for( $i = 0;$i < $t_row_count;$i++ ) {
+		$row = db_fetch_array( $result );
+		$t_proj_list[$row['project_id']][] = $row;
+	}
+
+	/* Process projects in reverse order (oldest ancestor first) */
+	foreach ( array_reverse($t_parents) as $t_parent_id ) {
+
+		/* Ignore the global project - we can't set anything here! */
+		if ( $t_parent_id != 0 ) {
+
+			/* Process each row from project
+			 * Note: categories (max 2) should be in ascending order so the
+			 *       project (cat = 0) will be first and overridden (if
+			 *       applicable) by the explicit category
+			 */
+			if ( array_key_exists($t_parent_id, $t_proj_list) ) {
+				foreach ( $t_proj_list[$t_parent_id] as $row ) {
+					$row['automonitor_explicit'] = ($row['project_id']  == $p_project_id) &&
+					                               ($row['category_id'] == $p_category_id);
+					$t_users[$row['id']] = $row;
+				}
+			}
+		}
+	}
+
+	/* Return result (as simple array) */
+	$t_ret = array();
+	foreach ( $t_users as $key => $val ) {
+		$t_ret[] = $val;
+	}
+	return $t_ret;
+}
diff --git a/plugins/AutoMonitor/AutoMonitor.ViewAPI.php b/plugins/AutoMonitor/AutoMonitor.ViewAPI.php
new file mode 100644
index 0000000..d2fcddf
--- /dev/null
+++ b/plugins/AutoMonitor/AutoMonitor.ViewAPI.php
@@ -0,0 +1,105 @@
+<?php
+# TODO: include header
+
+/**
+ * Display a project configuration table
+ *
+ * Note: this doesn't actually display the entire table, just the main
+ *       contents (3 user selection inputs and control buttons)
+ */
+function AutoMonitor_print_project_config_table ( $p_users )
+{
+?>
+<tr <?php echo helper_alternate_class() ?>>
+		<td style='width:20%'>
+				<select name='inherited[]' multiple='multiple' size='10' style='width:90%'>
+						<?php AutoMonitor_print_user_option_list($p_users, false, 1); ?>
+				</select>
+		</td>
+		<td style='width:13%'>
+				<input style='width:90%' type='submit' name='inherit_inc'
+				       value='<?php echo plugin_lang_get('include'); ?>'/><br/>
+				<input style='width:90%' type='submit' name='inherit_exc'
+				       value='<?php echo plugin_lang_get('exclude'); ?>'/>
+		</td>
+		<td style='width:20%'>
+				<select name='excluded[]' multiple='multiple' size='10' style='width:90%'>
+						<?php AutoMonitor_print_user_option_list($p_users, true, 0); ?>
+				</select>
+		</td>
+		<td style='width:13%'>
+				<input style='width:90%' type='submit' name='exclude_inc'
+				       value='<?php echo plugin_lang_get('include'); ?>'/><br/>
+				<input style='width:90%' type='submit' name='exclude_clr'
+				       value='<?php echo plugin_lang_get('clear'); ?>'/>
+		</td>
+		<td style='width:20%'>
+				<select name='included[]' multiple='multiple' size='10' style='width:90%'>
+						<?php AutoMonitor_print_user_option_list($p_users, true, 1); ?>
+				</select>
+		</td>
+		<td style='width:14%'>
+				<input style='width:90%' type='submit' name='include_exc'
+				       value='<?php echo plugin_lang_get('exclude'); ?>'/><br/>
+				<input style='width:90%' type='submit' name='include_clr'
+				       value='<?php echo plugin_lang_get('clear'); ?>'/>
+		</td>
+</tr>
+<?php
+}
+
+/**
+ * Print a list of users
+ *
+ * @param p_users    The complete list of users
+ * @param p_explicit Print users with matching explicit value
+ * @param p_state    Print users with matching state value (if explicit = true)
+ *                   otherwise if explicit = false this indicates whether to
+ *                   to prefix with Inc/Ext (=1) or not (=0)
+ */
+function AutoMonitor_print_user_option_list ( $p_users, $p_explicit, $p_state )
+{
+		/* Configuration */
+		$t_show_realname     = ( ON == config_get( 'show_realname' ) );
+		$t_sort_by_last_name = ( ON == config_get( 'sort_by_last_name' ) );
+
+		/* Display details */
+		$t_id_a              = array();
+		$t_display_a         = array();
+		$t_sort_a            = array();
+		
+		/* Process each user */
+		foreach ( $p_users as $t_user ) {
+				if ( ($t_user['automonitor_explicit'] == $p_explicit) &&
+				     (!$p_explicit || ($t_user['automonitor_state'] == $p_state)) ) {
+						$t_name = string_attribute($t_user['username']);
+						$t_sort = $t_name;
+						if ( isset($t_user['realname']) && 
+						     !empty($t_user['realname']) &&
+								$t_show_realname ) {
+								$t_name = string_attribute($t_user['realname']);
+								if ( $t_sort_by_last_name ) {
+										$t_bits = explode(' ', utf8_strtolower($t_name));
+										$t_sort = (isset($t_bits[1]) ? $t_bits[1] . ', ' : '') . $t_bits[0];
+								} else {
+										$t_sort = utf8_strtolower($t_name);
+								}
+						}
+						if ( !$p_explicit && ($p_state == 1) ) {
+								$t_name = (($t_user['automonitor_state'] == 1) ? 'Inc: ' : 'Exc: ') . $t_name;
+						}
+						$t_id_a[]      = $t_user['id'];
+						$t_display_a[] = $t_name;
+						$t_sort_a[]    = $t_sort;
+				}
+		}
+
+		/* Sort */
+		array_multisort($t_sort_a, SORT_ASC, SORT_STRING, $t_id_a, $t_display_a);
+
+		/* Output */
+		for ( $i = 0; $i < count($t_sort_a); $i++ ) {
+				echo "<option value='$t_id_a[$i]'>$t_display_a[$i]</option>\n";
+		}
+}
+?>
diff --git a/plugins/AutoMonitor/AutoMonitor.php b/plugins/AutoMonitor/AutoMonitor.php
new file mode 100644
index 0000000..90e8d3b
--- /dev/null
+++ b/plugins/AutoMonitor/AutoMonitor.php
@@ -0,0 +1,146 @@
+<?php
+
+# TODO: create a header (must have one somewhere)
+
+/* Include parent class */
+require_once( config_get( 'class_path' ) . 'MantisPlugin.class.php' );
+
+/*
+ * Auto project/category monitoring
+ */
+class AutoMonitorPlugin
+	extends MantisPlugin
+{
+
+	/*
+	 * Register the module
+	 */
+	function register ()
+	{
+		$this->name        = plugin_lang_get('title');
+		$this->description = plugin_lang_get('description');
+		$this->author      = 'Adam Sutton';
+		$this->contact     = 'adam@adamsutton.co.uk';
+		$this->url         = 'http://www.adamsutton.co.uk';
+		$this->version     = '0.0.0';
+		$this->requires    = array(
+			'MantisCore' => '1.2.0',
+		);
+		$this->page        = 'config';
+	}
+
+	/**
+	 * Initialise
+	 */
+	function init ()
+	{
+		require_once('AutoMonitor.API.php');
+		require_once('AutoMonitor.ViewAPI.php');
+	}
+
+	/**
+	 * Configuration
+	 */
+  function config ()
+	{
+		return array(
+		);
+	}
+
+	/**
+	 * Schema
+	 */
+	function schema ()
+	{
+		return array(
+			array('CreateTableSQL', array(plugin_table('list'), "
+				user_id     I UNSIGNED NOTNULL PRIMARY,
+				project_id  I UNSIGNED NOTNULL PRIMARY,
+				category_id I UNSIGNED NOTNULL PRIMARY,
+				state       L NOTNULL")),
+		);
+	}
+
+	/**
+	 * Event hooks
+	 */
+	function hooks ()
+	{
+		return array(
+			'EVENT_MANAGE_PROJECT_PAGE' => 'manage_project_list',
+			'EVENT_REPORT_BUG' => 'add_monitors',
+		);
+	}
+
+	/* ************************************************************************
+	 * Hook handlers
+	 * ***********************************************************************/
+
+  function manage_project_list ()
+  {
+		/* Check access */
+		$f_project_id = gpc_get_int('project_id');
+		if ( !access_has_project_level(config_get('project_user_threshold'), $f_project_id) ) {
+			return;
+		}
+
+		/* Get user list */
+		$t_users = AutoMonitor_get_users($f_project_id, 0);
+?>
+<!-- AUTOMONITOR LIST -->
+<br/>
+<a name='automonitor'/>
+<div align='center'>
+	<table class='width75' cellspacing='1'>
+
+		<!-- Title -->
+		<tr>
+			<td class='form-title' colspan='6'>
+				<?php echo plugin_lang_get( 'manage_project_title' ); ?>
+			</td>
+		</tr>
+
+		<!-- Titles -->
+		<tr class='row-category'>
+			<td width='33%' colspan='2'><?php echo plugin_lang_get( 'inherit_title' ); ?></td>
+			<td width='33%' colspan='2'><?php echo plugin_lang_get( 'exclude_title' ); ?></td>
+			<td width='34%' colspan='2'><?php echo plugin_lang_get( 'include_title' ); ?></td>
+		</tr>
+
+		<!-- User lists -->
+		<form method='post' action='<?php echo plugin_page('project_update') ?>'>
+			<input type="hidden" name="project_id" value="<?php echo $f_project_id ?>" />
+			<?php echo form_security_field('plugin_AutoMonitor_project_update'); ?>
+			<?php AutoMonitor_print_project_config_table($t_users); ?>
+		</form>
+
+		<!-- Category edit page -->
+		<form method='post' action='<?php echo plugin_page('category_edit_page') ?>'>
+			<input type="hidden" name="project_id" value="<?php echo $f_project_id ?>" />
+			<?php echo form_security_field('plugin_AutoMonitor_project_category_select'); ?>
+			<tr>
+				<td class='left' colspan='6'>
+					<select name='category_id'>
+						<?php print_category_option_list(0, $f_project_id); ?>
+					</select>
+					<input type='submit' name='cat_update' value='<?php echo plugin_lang_get('edit_category'); ?>'/>
+				</td>
+			</tr>
+		</form>
+	</table>
+</div>
+<?php
+	}
+
+	function add_monitors($p_event, $p_bug, $p_bug_id) {
+		if( $p_event == 'EVENT_REPORT_BUG' ) {
+			$t_users = AutoMonitor_get_users($p_bug->project_id, 0);
+			print_r($t_users);
+			foreach($t_users as $t_user) {
+				if($t_user['automonitor_state'] > 0)
+					bug_monitor($p_bug_id, $t_user['id']);
+			}
+		}
+	}
+}
+?>
diff --git a/plugins/AutoMonitor/lang/strings_english.txt b/plugins/AutoMonitor/lang/strings_english.txt
new file mode 100644
index 0000000..7df3ee8
--- /dev/null
+++ b/plugins/AutoMonitor/lang/strings_english.txt
@@ -0,0 +1,17 @@
+<?php
+# TODO: must have a standard header
+
+$s_plugin_AutoMonitor_title = 'AutoMonitor';
+$s_plugin_AutoMonitor_description = 'Allow users to be automatically assigned to new issues in a project/category';
+
+$s_plugin_AutoMonitor_manage_project_title = 'Project Monitors';
+$s_plugin_AutoMonitor_inherit_title = 'Inherited';
+$s_plugin_AutoMonitor_include_title = 'Included';
+$s_plugin_AutoMonitor_exclude_title = 'Excluded';
+$s_plugin_AutoMonitor_exclude = 'Exclude';
+$s_plugin_AutoMonitor_include = 'Include';
+$s_plugin_AutoMonitor_clear   = 'Clear';
+$s_plugin_AutoMonitor_edit_category = 'Edit Category';
+$s_plugin_AutoMonitor_category_edit_title = 'Category Monitors';
+$s_plugin_AutoMonitor_exit_button = 'Exit';
+?>
diff --git a/plugins/AutoMonitor/lang/strings_hungarian.txt b/plugins/AutoMonitor/lang/strings_hungarian.txt
new file mode 100644
index 0000000..3f597b9
--- /dev/null
+++ b/plugins/AutoMonitor/lang/strings_hungarian.txt
@@ -0,0 +1,17 @@
+<?php
+# TODO: must have a standard header
+
+$s_plugin_AutoMonitor_title = 'AutoMonitor';
+$s_plugin_AutoMonitor_description = 'Megadott felhasználók automatikusan ellenőrizzék az új projekteket/ügyeket';
+
+$s_plugin_AutoMonitor_manage_project_title = 'Projekt Ellenőrök';
+$s_plugin_AutoMonitor_inherit_title = 'Örökölt';
+$s_plugin_AutoMonitor_include_title = 'Bennfoglalt';
+$s_plugin_AutoMonitor_exclude_title = 'Kizárt';
+$s_plugin_AutoMonitor_exclude = 'Kizár';
+$s_plugin_AutoMonitor_include = 'Hozzáad';
+$s_plugin_AutoMonitor_clear   = 'Töröl';
+$s_plugin_AutoMonitor_edit_category = 'Kategória Szerkesztése';
+$s_plugin_AutoMonitor_category_edit_title = 'Kategória Ellenőrök';
+$s_plugin_AutoMonitor_exit_button = 'Kilépés';
+?>
diff --git a/plugins/AutoMonitor/pages/category_edit_page.php b/plugins/AutoMonitor/pages/category_edit_page.php
new file mode 100644
index 0000000..c52ffda
--- /dev/null
+++ b/plugins/AutoMonitor/pages/category_edit_page.php
@@ -0,0 +1,72 @@
+<?php
+# TODO: add header
+
+/* Validate authentication */
+auth_reauthenticate();
+
+/* Get form vars */
+$f_project_id  = gpc_get_int('project_id');
+$f_category_id = gpc_get_int('category_id');
+
+/* Validate params */
+project_ensure_exists($f_project_id);
+if ( $f_category_id === 0 ) {
+  print_header_redirect("manage_proj_edit_page.php?project_id=$f_project_id#automonitor");
+  exit;
+}
+category_ensure_exists($f_category_id);
+
+/* Double check permissions */
+access_ensure_project_level(config_get('manage_project_threshold'));
+access_ensure_project_level(config_get('project_user_threshold'));
+
+/* Start page */
+html_page_top(project_get_field($f_project_id, 'name'));
+print_manage_menu();
+
+/* Get user list */
+$t_users = AutoMonitor_get_users($f_project_id, $f_category_id);
+
+/* Display the main table */
+?>
+<div align='center'>
+	<table class='width75' cellspacing='1'>
+
+		<!-- Title -->
+		<tr>
+			<td class='form-title' colspan='6'>
+				<?php echo plugin_lang_get( 'category_edit_title' ); ?>
+			</td>
+		</tr>
+
+		<!-- Titles -->
+		<tr class='row-category'>
+			<td width='33%' colspan='2'><?php echo plugin_lang_get( 'inherit_title' ); ?></td>
+			<td width='33%' colspan='2'><?php echo plugin_lang_get( 'exclude_title' ); ?></td>
+			<td width='34%' colspan='2'><?php echo plugin_lang_get( 'include_title' ); ?></td>
+		</tr>
+
+		<!-- User lists -->
+		<form method='post' action='<?php echo plugin_page('project_update') ?>'>
+			<input type="hidden" name="project_id" value="<?php echo $f_project_id ?>" />
+			<input type='hidden' name='category_id' value='<?php echo $f_category_id ?>'/>
+			<?php echo form_security_field('plugin_AutoMonitor_project_update'); ?>
+			<?php AutoMonitor_print_project_config_table($t_users); ?>
+		</form>
+
+		<!-- Cancel button -->
+		<form method='post' action='manage_proj_edit_page.php'>
+			<input type="hidden" name="project_id" value="<?php echo $f_project_id ?>" />
+			<tr>
+				<td class='left' colspan='6'>
+					<input type='submit' name='cancel' value='<?php echo plugin_lang_get('exit_button') ?>'/>
+				</td>
+			</tr>
+		</form>
+	</table>
+</div>
+<?php
+
+/* End page */
+html_page_bottom();
+?>
diff --git a/plugins/AutoMonitor/pages/project_update.php b/plugins/AutoMonitor/pages/project_update.php
new file mode 100644
index 0000000..afcaca6
--- /dev/null
+++ b/plugins/AutoMonitor/pages/project_update.php
@@ -0,0 +1,78 @@
+<?php
+
+/* Validate authentication */
+form_security_validate('plugin_AutoMonitor_project_update');
+auth_reauthenticate();
+
+/* Get submission values (should all be mutually exclusive) */
+$f_project_id  = gpc_get_int('project_id');
+$f_category_id = gpc_get_int('category_id', 0);
+
+/* Table params */
+$t_automonitor_table = plugin_table('list');
+$c_project_id        = db_prepare_int($f_project_id);
+$c_category_id       = db_prepare_int($f_category_id);
+
+/* Validate params */
+project_ensure_exists($f_project_id);
+if ( $f_category_id !== 0 ) category_ensure_exists($f_category_id);
+
+/* Double check permissions */
+access_ensure_project_level(config_get('manage_project_threshold'));
+access_ensure_project_level(config_get('project_user_threshold'));
+
+/* Get the submit buttons */
+$f_exclude_inc = gpc_get_bool('exclude_inc');
+$f_exclude_clr = gpc_get_bool('exclude_clr');
+$f_include_exc = gpc_get_bool('include_exc');
+$f_include_clr = gpc_get_bool('include_clr');
+$f_inherit_inc = gpc_get_bool('inherit_inc');
+$f_inherit_exc = gpc_get_bool('inherit_exc');
+
+/* Update the inherited users */
+if ( $f_inherit_inc || $f_inherit_exc ) {
+	$f_users = gpc_get_int_array('inherited');
+	$c_state = db_prepare_int($f_inherit_inc ? 1 : 0);
+	$query   = "INSERT INTO $t_automonitor_table 
+		(user_id, project_id, category_id, state)
+		VALUES (" . db_param() . "," . db_param() . "," .  db_param() . "," . db_param() . ")";
+	foreach ( $f_users as $t_user ) {
+		db_query_bound($query, array(db_prepare_int($t_user), $c_project_id, $c_category_id, $c_state));
+	}
+
+/* Clear */
+} else if ( $f_include_clr || $f_exclude_clr ) {
+	$f_users = gpc_get_int_array($f_include_clr ? 'included' : 'excluded');
+	$c_users = array();
+	foreach ( $f_users as $t_user ) {
+		$c_users[] = db_prepare_int($t_user);
+	}
+	$query   = "DELETE FROM $t_automonitor_table 
+		WHERE project_id = " . db_param() . "
+		AND category_id = " . db_param() . "
+		AND user_id IN (" . implode(',', $c_users) . ")";
+	db_query_bound($query, array($c_project_id, $c_category_id));
+
+/* Set */
+} else if ( $f_include_exc || $f_exclude_inc ) {
+	$f_users = gpc_get_int_array($f_include_exc ? 'included' : 'excluded');
+	$c_users = array();
+	foreach ( $f_users as $t_user ) {
+		$c_users[] = db_prepare_int($t_user);
+	}
+	$c_state = db_prepare_int($f_include_exc ? 0 : 1);
+	$query   = "UPDATE $t_automonitor_table 
+		SET state = " . db_param() . "
+		WHERE project_id = " . db_param() . "
+		AND category_id = " . db_param() . "
+		AND user_id IN (" . implode(',', $c_users) . ")";
+	db_query_bound($query, array($c_state, $c_project_id, $c_category_id));
+}
+
+/* Done */
+form_security_purge('plugin_AutoMonitor_project_update');
+if ( $f_category_id == 0 ) {
+	print_header_redirect("manage_proj_edit_page.php?project_id=$f_project_id#automonitor");
+} else {
+	print_header_redirect(plugin_page("category_edit_page&project_id=$f_project_id&category_id=$f_category_id", true));
+}
diff --git a/plugins/FileDistribution/FileDistribution.php b/plugins/FileDistribution/FileDistribution.php
new file mode 100755
index 0000000..db01b70
--- /dev/null
+++ b/plugins/FileDistribution/FileDistribution.php
@@ -0,0 +1,55 @@
+<?php
+
+require_once( config_get( 'class_path' ) . 'MantisPlugin.class.php' );
+
+class FileDistributionPlugin extends MantisPlugin {
+	function register() {
+		$this->name = 'FileDistribution';	# Proper name of plugin
+		$this->description = 'Static file distrubution';	# Short description of the plugin
+		$this->page = '';		   # Default plugin page
+
+		$this->version = '1.0';	 # Plugin version string
+		$this->requires = array(	# Plugin dependencies, array of basename => version pairs
+			'MantisCore' => '1.2.0',  #   Should always depend on an appropriate version of MantisBT
+			);
+
+		$this->author = 'Tamás Gulácsi';		 # Author/team name
+		$this->contact = 'T.Gulacsi@unosoft.hu';		# Author/team e-mail address
+		$this->url = 'http://www.unosoft.hu';			# Support webpage
+	}
+
+	function config() {
+		return array(
+			'url' => NULL,
+			'path' => NULL,
+			'users' => array(),
+			'secret_word' => '1234567890',
+		);
+	}
+
+	function hooks() {
+		return array(
+            'EVENT_MENU_MAIN' => 'menu',
+            'EVENT_MENU_MANAGE' => 'manage',
+        );
+	}
+
+	function menu( ) {
+        //require_once( 'core.php' );
+        require_once( dirname(__FILE__).'/core/filedistrib_api.php' );
+
+        if ( user_allowed() ) {
+            return array( '<a href="' . plugin_page( 'static_files.php' ) . '">' .
+                plugin_lang_get('static_files') . '</a>', );
+        }
+	}
+
+    function manage( ) {
+        require_once( 'core.php' );
+
+        if ( access_get_project_level() >= MANAGER) {
+            return array( '<a href="' . plugin_page( 'config.php' ) . '">'
+                .  plugin_lang_get('config') . '</a>', );
+        }
+    }
+}
diff --git a/plugins/FileDistribution/core/filedistrib_api.php b/plugins/FileDistribution/core/filedistrib_api.php
new file mode 100644
index 0000000..ac978cd
--- /dev/null
+++ b/plugins/FileDistribution/core/filedistrib_api.php
@@ -0,0 +1,49 @@
+<?php
+
+function str2list($p_text) {
+    $t_arr = $p_text != null ? explode(',', $p_text) : array();
+    $t_arr = uids2names(names2uids($t_arr));
+    sort($t_arr);
+    return $t_arr;
+}
+
+function list2str($p_arr) {
+    $p_arr = uids2names(names2uids($p_arr));
+    sort($p_arr);
+    return implode(',', $p_arr);
+}
+
+function names2uids($p_arr) {
+    require_once( 'core.php' );
+    $ret = array();
+    foreach($p_arr as $name) {
+        $t_id = user_get_id_by_name($name);
+        if( $t_id && user_is_enabled($t_id) ) {
+            $ret[] = $t_id;
+        }
+    }
+    return $ret;
+}
+
+function uids2names($p_arr) {
+    require_once( 'core.php' );
+
+    $ret = array();
+    foreach($p_arr as $t_id) {
+        if( user_is_enabled($t_id) ) {
+            $ret[] = user_get_name($t_id);
+        }
+    }
+    return $ret;
+}
+
+function user_allowed() {
+    require_once( 'core.php' );
+
+    $t_act_uid = auth_get_current_user_id();
+
+    $t_users = str2list( plugin_config_get( 'users' ) );
+
+    return in_array( $t_act_uid, names2uids($t_users) );
+}
+?>
diff --git a/plugins/FileDistribution/lang/strings_english.txt b/plugins/FileDistribution/lang/strings_english.txt
new file mode 100755
index 0000000..3fbaf47
--- /dev/null
+++ b/plugins/FileDistribution/lang/strings_english.txt
@@ -0,0 +1,8 @@
+<?php
+$s_plugin_FileDistribution_name = 'FileDistribution';
+$s_plugin_FileDistribution_config = 'FileDistribution configuration';
+$s_plugin_FileDistribution_url = 'URL';
+$s_plugin_FileDistribution_path = 'PATH';
+$s_plugin_FileDistribution_users = 'allowed users';
+$s_plugin_FileDistribution_secret_word = 'shared secret';
+$s_plugin_FileDistribution_static_files = 'Downloadable files';
diff --git a/plugins/FileDistribution/lang/strings_hungarian.txt b/plugins/FileDistribution/lang/strings_hungarian.txt
new file mode 100755
index 0000000..a634ae3
--- /dev/null
+++ b/plugins/FileDistribution/lang/strings_hungarian.txt
@@ -0,0 +1,8 @@
+<?php
+$s_plugin_FileDistribution_name = 'FileDistribution';
+$s_plugin_FileDistribution_config = 'FileDistrib beállítások';
+$s_plugin_FileDistribution_url = 'URL';
+$s_plugin_FileDistribution_path = 'PATH';
+$s_plugin_FileDistribution_users = 'engedélyezett felhasználók';
+$s_plugin_FileDistribution_secret_word = 'megosztott titok';
+$s_plugin_FileDistribution_static_files = 'Letölthető fájlok';
diff --git a/plugins/FileDistribution/pages/config.php b/plugins/FileDistribution/pages/config.php
new file mode 100644
index 0000000..5ee1244
--- /dev/null
+++ b/plugins/FileDistribution/pages/config.php
@@ -0,0 +1,91 @@
+<?php
+# MantisBT - a php based bugtracking system
+# Copyright (C) 2002 - 2009  MantisBT Team - mantisbt-dev@lists.sourceforge.net
+# MantisBT is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# MantisBT is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with MantisBT.  If not, see <http://www.gnu.org/licenses/>.
+
+auth_reauthenticate( );
+access_ensure_global_level( config_get( 'manage_plugin_threshold' ) );
+
+html_page_top( plugin_lang_get( 'name' ) );
+
+print_manage_menu( );
+
+?>
+
+<br/>
+<form action="<?php echo plugin_page( 'config_edit' )?>" method="post">
+<?php echo form_security_field( 'plugin_filedistrib_config_edit' ) ?>
+<table align="center" class="width50" cellspacing="1">
+
+<tr>
+	<td class="form-title" colspan="3">
+		<?php echo plugin_lang_get( 'config' )?>
+	</td>
+</tr>
+
+<tr <?php echo helper_alternate_class( )?>>
+	<td class="category" width="60%">
+		<?php echo plugin_lang_get( 'url' )?>
+	</td>
+	<td class="center" width="20%">
+		<label><?php echo plugin_lang_get( 'url' )?></label>
+		<input type="text" name="url" value="<?php echo plugin_config_get( 'url', NULL ); ?>" />
+	</td>
+</tr>
+<tr <?php echo helper_alternate_class( )?>>
+	<td class="category" width="60%">
+		<?php echo plugin_lang_get( 'path' )?>
+	</td>
+	<td class="center" width="20%">
+		<label><?php echo plugin_lang_get( 'path' )?></label>
+		<input type="text" name="path" value="<?php echo plugin_config_get( 'path', NULL ); ?>" />
+	</td>
+</tr>
+<tr <?php echo helper_alternate_class( )?>>
+	<td class="category" width="60%">
+		<?php echo plugin_lang_get( 'secret_word' )?>
+	</td>
+	<td class="center" width="20%">
+		<label><?php echo plugin_lang_get( 'secret_word' )?></label>
+		<input type="text" name="secret_word" value="<?php echo plugin_config_get( 'secret_word', NULL ); ?>" />
+	</td>
+</tr>
+<tr <?php echo helper_alternate_class( )?>>
+	<td class="category" width="60%">
+		<?php echo plugin_lang_get( 'users' )?>
+	</td>
+<?php
+
+	require_once( dirname(__FILE__).'/../core/filedistrib_api.php' );
+
+	$t_users_s = list2str(str2list(plugin_config_get( 'users', '' )));
+?>
+	<td class="center" width="20%">
+		<label><?php echo plugin_lang_get( 'users' )?></label>
+		<input type="text" name="users" value="<?php echo $t_users_s; ?>" />
+	</td>
+</tr>
+
+<tr>
+	<td class="center" colspan="3">
+		<input type="submit" class="button" value="<?php echo lang_get( 'change_configuration' )?>" />
+	</td>
+</tr>
+
+</table>
+</form>
+
+<?php
+html_page_bottom();
+?>
diff --git a/plugins/FileDistribution/pages/config_edit.php b/plugins/FileDistribution/pages/config_edit.php
new file mode 100644
index 0000000..2fc7aee
--- /dev/null
+++ b/plugins/FileDistribution/pages/config_edit.php
@@ -0,0 +1,51 @@
+<?php
+# MantisBT - a php based bugtracking system
+# Copyright (C) 2002 - 2009  MantisBT Team - mantisbt-dev@lists.sourceforge.net
+# MantisBT is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# MantisBT is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with MantisBT.  If not, see <http://www.gnu.org/licenses/>.
+
+form_security_validate( 'plugin_filedistrib_config_edit' );
+
+auth_reauthenticate( );
+access_ensure_global_level( config_get( 'manage_plugin_threshold' ) );
+
+$f_url = gpc_get_string( 'url', NULL );
+$f_path = gpc_get_string( 'path', NULL );
+$f_secret_word = gpc_get_string( 'secret_word', NULL );
+/*
+echo '<pre>old_url='.plugin_config_get( 'url' ).', new_url='.$f_url.'</pre>';
+*/
+
+if( plugin_config_get( 'url' ) != $f_url ) {
+	plugin_config_set( 'url', $f_url );
+}
+if( plugin_config_get( 'path' ) != $f_path && is_dir($f_path) && file_exists($f_path) ) {
+	plugin_config_set( 'path', $f_path );
+}
+if( plugin_config_get( 'secret_word' ) != $f_secret_word && $f_secret_word != NULL) {
+	plugin_config_set( 'secret_word', $f_secret_word );
+}
+
+//require_once( 'core.php' );
+require_once( dirname(__FILE__).'/../core/filedistrib_api.php' );
+
+$t_users_old = list2str(str2list(plugin_config_get( 'users', '' )));
+$f_users = list2str(str2list(gpc_get_string( 'users', '' )));
+if( $t_users_old != $f_users ) {
+	plugin_config_set( 'users', list2str(str2list($f_users)) );
+}
+
+form_security_purge( 'plugin_filedistrib_config_edit' );
+
+print_successful_redirect( plugin_page( 'config', true ) );
+?>
diff --git a/plugins/FileDistribution/pages/send_file.php b/plugins/FileDistribution/pages/send_file.php
new file mode 100755
index 0000000..cde6946
--- /dev/null
+++ b/plugins/FileDistribution/pages/send_file.php
@@ -0,0 +1,84 @@
+<?php
+require_once( dirname(__FILE__).'/../../../core.php' );
+
+/*
+form_security_validate( 'plugin_filedistrib_send' );
+form_security_purge( 'plugin_filedistrib_send' );
+*/
+
+function phpMinV($v) {
+    $phpV = PHP_VERSION;
+
+    if ($phpV[0] >= $v[0]) {
+        if (empty($v[2]) || $v[2] == '*') {
+            return true;
+        } elseif ($phpV[2] >= $v[2]) {
+            if (empty($v[4]) || $v[4] == '*' || $phpV[4] >= $v[4]) {
+                return true;
+            }
+        }
+    }
+
+    return false;
+}
+
+//header('HTTP/1.1 200 OK');
+//header('Content-Type: text/plain');
+
+$f_url = $_REQUEST['url'];
+if($f_url == false) {
+    $p = strpos($_SERVER['QUERY_STRING'], '%3Furl%3D');
+    if($p >= 0) {
+        //echo '!' . substr($_SERVER['QUERY_STRING'], $p+9) . "!\n";
+        $f_url = urldecode(substr($_SERVER['QUERY_STRING'], $p+9));
+    } else {
+        //echo '!QS='.$_SERVER['QUERY_STRING']."! p=$p\n";
+    }
+}
+//if($f_url == false) phpinfo();
+//echo "URL=$f_url\n";
+
+$arr = explode('/', $f_url);
+//print_r($arr);
+$f_time = array_pop(&$arr);
+$t_time = hexdec($f_time);
+$t_now = time();
+if ($t_now >= $t_time) {
+    header('HTTP/1.1 403 Timeout');
+    header('Content-Type: text/plain');
+    echo "Your link has expired (actual=$t_now, link=$t_time).\n";
+    exit();
+}
+$f_hash = array_pop(&$arr);
+$f_fn = implode('/', $arr);
+//echo "fn=$f_fn, hash=$f_hash, time=$f_time";
+
+$t_secret = plugin_config_get('secret_word');
+$t_hash = md5($f_fn . '/' . $t_secret . '/' . $f_time);
+if($t_hash != $f_hash) {
+    header('HTTP/1.1 403 Bad Request');
+    header('Content-Type: text/plain');
+    echo "Your link has bad hash (actual=$t_hash, link=$f_hash).\n";
+    exit();
+}
+
+$t_path_base = plugin_config_get('path');
+$t_url_base = plugin_config_get('url');
+
+$f_path = $t_path_base . '/' . $f_fn;
+if ($f_fn != false && file_exists($f_path)) {
+    $mime = mime_content_type($f_fn);
+    header('Content-Description: File Transfer');
+    header('Content-Type: ' . $mime);
+    header('Content-Disposition: attachment; filename=' . basename($f_fn));
+    header('Content-Transfer-Encoding: binary');
+    header('Expires: 0');
+    header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
+    header('Pragma: public');
+    header('Content-Length: ' . filesize($f_path));
+
+    header('X-Accel-Redirect: /protected' . $t_url_base . '/' . $f_fn);
+} else {
+    header('Content-Type: text/plain');
+    echo "NOT EXISTS (fn=$f_fn, path=$f_path, url_base=$t_url_base, path_base=$t_path_base)";
+}
diff --git a/plugins/FileDistribution/pages/static_files.php b/plugins/FileDistribution/pages/static_files.php
new file mode 100755
index 0000000..288a107
--- /dev/null
+++ b/plugins/FileDistribution/pages/static_files.php
@@ -0,0 +1,115 @@
+<?php
+
+// auth_reauthenticate( );
+
+html_page_top( plugin_lang_get( 'name' ) );
+
+$t_this_page = plugin_page('static_files'); //FIXME with plugins this does not work...
+/*
+print_manage_menu( $t_this_page );
+*/
+require_once( 'core.php' );
+require_once( dirname(__FILE__).'/../core/filedistrib_api.php' );
+
+if(!user_allowed()) {
+    exit;
+}
+
+$t_url = plugin_config_get('url');
+$t_path = plugin_config_get('path');
+//print 'URL='.$t_url.' PATH='.$t_path;
+
+$t_secu = form_security_field( 'plugin_filedistrib_send' );
+
+/*
+echo "Handle: " . $d->handle . "\n";
+echo "Path: " . $d->path . "\n";
+*/
+$t_post_url = plugin_page( 'send_file.php' );
+/*
+$t_post_url = str_replace('FileDistribution/', 'FileDistribution/pages/',
+    str_replace('plugin.php?page=', 'plugins/', $t_post_url ));
+*/
+/*
+$d = scandir($t_url);
+echo '<ul>';
+foreach($d as $entry) {
+    if(preg_match('/\.(tar\.|t)(gz|bz2)$/', $entry)) {
+    ?>
+    <li>
+        <form action="<?php echo $t_post_url;?>" method="post">
+            <?php echo $t_secu; ?>
+            <input type="hidden" name="fn"
+                value="<?php echo $t_url.'/'.$entry;?>" />
+            <input type="submit" class="button"
+                value="<?php echo $entry;?>" />
+        </form>
+    </li>
+<?php
+    }
+}
+echo '</ul>';
+*/
+function get_dirs($path) {
+    $arr = array();
+    foreach(scandir($path, TRUE) as $elt) {
+        $p = $path . '/' . $elt;
+        if( is_dir($p) && $elt != '.' && $elt != '..' ) {
+            $arr[] = $p;
+        }
+    }
+    return $arr;
+}
+
+function get_files($path, $regex) {
+    $arr = array();
+    foreach(scandir($path, FALSE) as $elt) {
+        $p = $path . '/' . $elt;
+        if( is_file($p) && is_readable($p) && preg_match($regex, $elt) ) {
+            $arr[] = $p;
+        }
+    }
+    return $arr;
+}
+
+function print_struct($path, $regex, $level=0) {
+    if($level > 10) return;
+    $t_path = plugin_config_get('path');
+    $t_secret = plugin_config_get('secret_word');
+    $t_timeout = plugin_config_get('timeout', 300);
+
+    $t_plugin_page = plugin_page('send_file.php');
+    $t_url = $t_plugin_page;
+    $t_url = substr($t_url, 0, strpos($t_url, '/plugin.php'))
+        . plugin_config_get('url');
+    print '<p>';
+    print '<h'.($level+1).'>'.basename($path).'</h'.($level+1).'>';
+    $i = 0;
+    foreach(get_dirs($path) as $d) {
+        # DFS
+        //print 'd: '.$d.' lev='.$level;
+        print_struct($d, $regex, $level+1);
+        if($i++ > 100) break;
+    }
+    print '<ul>';
+    $i = 0;
+    foreach(get_files($path, $regex) as $f) {
+        # md5 (reference, secret_word);
+        $t_resource = substr($f, strlen($t_path)+1);
+        $t_pre = $t_resource; #$t_url . '/' . $t_resource;
+        $t_time = sprintf("%X", time() + $t_timeout);
+        $t_hash = md5($t_pre . '/' . $t_secret . '/' . $t_time);
+        $t_link = $t_pre . '/' . $t_hash . '/' . $t_time;
+        //print "<pre>pre=$t_pre, time=$t_time, hash=$t_hash, secr=$t_secret, $t_pre/$t_secret/$t_time</pre>";
+        //print '<li><a href="' . $t_link . '">' . basename($f).'</a></li>';
+        print '<li><a href="' . $t_plugin_page . urlencode('?url=' . $t_link) . '">'.basename($f).'</a></li>';
+        if($i++ > 100) break;
+    }
+    print '</ul>';
+    print '</p>';
+} #mantIs3456
+
+print_struct($t_path, '/.*/');
+
+
+html_page_bottom();
