View Issue Details

IDProjectCategoryView StatusLast Update
0008257mantisbtfeaturepublic2019-09-23 09:59
Reportermkornatzki Assigned To 
PrioritynormalSeverityminorReproducibilityN/A
Status acknowledgedResolutionopen 
Product Version1.1.0a4 
Summary0008257: store avatar local
Description

Hi,

i like the avatar-feature but for me it is neccessary to store the files local and give the user the possibility to handle their avatar.

for this i made a patch:

  • you can see in the user_list which user has an avatar (with picture or as boolean)
  • the user can upload or delete his avatar
  • if a user didn't have an avatar there is no default image

if you want to use this patch you have to add a directory "/avatar".

this is the first try and i hope someone of you will make it better (errorhandling, maybe performance, ...).

thanks for the integration of avatars in mantis.
Mike

Tagsavatar, patch
Attached Files
add_local_avatar.patch (10,285 bytes)   
Index: bugnote_view_inc.php
===================================================================
--- bugnote_view_inc.php	(revision 376)
+++ bugnote_view_inc.php	(working copy)
@@ -124,6 +124,7 @@
 ?>
 <tr class="bugnote" id="c<?php echo $v3_id ?>">
         <td class="<?php echo $t_bugnote_css ?>">
+    <?php if ( ON  == config_get("show_avatar") ) print_avatar( $v3_reporter_id ); ?>    
 		<span class="small">(<?php echo $t_bugnote_id_formatted ?>)</span><br />
 		<?php
 			echo print_user( $v3_reporter_id );
Index: config_inc.php
===================================================================
--- config_inc.php	(revision 391)
+++ config_inc.php	(working copy)
@@ -122,12 +122,46 @@

+	
+	##############################################################################
+	# Show user avatar
+	# the current implementation is based on http://www.gravatar.com
+	# users will need to register there the same address used in 
+	# this mantis installation to have their avatar shown
+	# Please note: upon registration or avatar change, it takes some time for
+	# the updated gravatar images to show on sites
+	$g_show_avatar = ON;
+	
+	# Only users above this threshold will have their avatar shown
+	$g_show_avatar_threshold = DEVELOPER;	
 
+	# Maximum file size that can be uploaded
+	$g_max_avatar_file_size		= 100000; # 100kB
+
+       # Show avatar in manage_user_list
+       $g_show_avatar_in_manage_user_list = ON;
+  

Index: core/print_api.php
===================================================================
--- core/print_api.php	(revision 390)
+++ core/print_api.php	(working copy)
@@ -103,6 +103,27 @@
 	function print_header_redirect_report() {
 		print_header_redirect( string_get_bug_report_url() );
 	}
+
+  # ----------------------------------------
+	# Print avatar image for the given user ID
+	function print_avatar( $p_user_id , $t_class = "avatar") {
+		$t_avatar_exist = false;
+		
+		if ( access_has_project_level( config_get( 'show_avatar_threshold' ), null, $p_user_id ) ) {
+			$t_avatar = user_get_local_avatar( $p_user_id );
+			$t_avatar_url = $t_avatar[0];
+			$t_width = $t_avatar[1];
+			$t_height = $t_avatar[2];
+			$t_avatar_exist = $t_avatar[3];
+			
+			if ($t_avatar_exist) {
+  			echo '<img class="' . $t_class. '" src="' . $t_avatar_url . '" alt=""' .
+	  			' width="' . $t_width . '" height="' . $t_height . '" />';
+			}
+		}
+		return $t_avatar_exist;
+	}
+	
 	# --------------------
 	# prints the name of the user given the id.  also makes it an email link.
 	function print_user( $p_user_id ) {
Index: core/user_api.php
===================================================================
--- core/user_api.php	(revision 376)
+++ core/user_api.php	(working copy)
@@ -629,6 +629,58 @@
 	}
 
 	# --------------------
+	# return the user avatar image 
+	# return value is an array( URL, width, height )
+	# in this first implementation, only gravatar.com avatars are supported
+	function user_get_avatar( $p_user_id ) {
+		$t_email = user_get_email( $p_user_id );
+		$t_default_image = "/images/gravatar_logo.gif";
+		$t_size = 80;
+		$t_avatar_url = "http://www.gravatar.com/avatar.php?gravatar_id=" . md5( $t_email ) .
+				"&amp;default=" . urlencode( $t_default_image ) .
+				"&amp;size=" . $t_size .
+				"&amp;rating=G";
+
+		return array( $t_avatar_url, $t_size, $t_size );
+	}
+
+	# --------------------
+	# return the user avatar image 
+	# return value is an array( URL, width, height )
+	# in this first implementation, only gravatar.com avatars are supported
+	function user_get_local_avatar( $p_user_id ) {
+		global $g_path;
+		$t_avatar_exist = true;
+    
+    # default imagesize
+    $t_height = 80;
+    $t_width = 80;
+
+		$t_username = user_get_name( $p_user_id );
+		$t_avatar_url = $g_path . "/avatar/" . $t_username . ".gif";
+    if (!file_exists(dirname( dirname( __FILE__ ) ).DIRECTORY_SEPARATOR.'avatar'.DIRECTORY_SEPARATOR.$t_username .".gif")) {
+    	$t_avatar_url = $g_path . "/avatar/" . $t_username . ".jpg";
+      if (!file_exists(dirname( dirname( __FILE__ ) ).DIRECTORY_SEPARATOR.'avatar'.DIRECTORY_SEPARATOR.$t_username .".jpg")) {
+        $t_avatar_exist = false;	
+      }
+    }
+
+    if ($t_avatar_exist) {
+      # get image dimensions
+      list($width_orig, $height_orig) = getimagesize($t_avatar_url);
+      $ratio_orig = $width_orig/$height_orig;
+
+      if ($t_width/$t_height > $ratio_orig) {
+        $t_width = $t_height*$ratio_orig;
+      } else {
+        $t_height = $t_width/$ratio_orig;
+      }
+    }      
+    
+		return array( $t_avatar_url, $t_width, $t_height, $t_avatar_exist );
+	}
+
+	# --------------------
 	# return the user's access level
 	#  account for private project and the project user lists
 	function user_get_access_level( $p_user_id, $p_project_id = ALL_PROJECTS ) {
Index: css/default.css
===================================================================
--- css/default.css	(revision 376)
+++ css/default.css	(working copy)
@@ -144,5 +144,17 @@
 	border-bottom: 1px dotted black;
 }
 
+.avatar
+{
+	float: right;
+	border: 0;
+}
+
+.manage_avatar
+{
+	float: left;
+	border: 0;
+}
+
 .progress400				{ position: relative; width: 400px; border: 1px solid #d7d7d7; margin-top: 1em; margin-bottom: 1em; padding: 1px; }
 .progress400 .bar			{ display: block; position: relative; background: #6bba70; text-align: center; font-weight: normal; color: #333; height: 2em; line-height: 2em; }
Index: custom_strings_inc.php
===================================================================
--- custom_strings_inc.php	(revision 387)
+++ custom_strings_inc.php	(working copy)
@@ -9,9 +9,14 @@
         
+    #avatar
+    $s_avatar = 'Avatar';        
+    $s_upload_avatar = 'Avatar hochladen';
+    $s_delete_avatar = 'Avatar l�schen';
+    
   } else {
+    
+    #avatar
+    $s_avatar = 'Avatar';
+    $s_upload_avatar = 'Upload Avatar';
+    $s_delete_avatar = 'Delete Avatar';
   }
 
 	if ( file_exists( dirname( __FILE__ ) . DIRECTORY_SEPARATOR . 'plugins' . DIRECTORY_SEPARATOR . 'pluginmanager' . DIRECTORY_SEPARATOR . 'lang_inc.php' ) ) {
Index: manage_user_edit_page.php
===================================================================
--- manage_user_edit_page.php	(revision 376)
+++ manage_user_edit_page.php	(working copy)
@@ -9,7 +9,10 @@
 	# $Id: manage_user_edit_page.php,v 1.17 2007/03/06 07:05:18 vboctor Exp $
 	# --------------------------------------------------------
 ?>
 <?php
 	access_ensure_global_level( config_get( 'manage_user_threshold' ) );
 
@@ -29,7 +32,7 @@
 
 <!-- USER INFO -->
 <div align="center">
-<form method="post" action="manage_user_update.php">
+<form method="post" action="manage_user_update.php" enctype="multipart/form-data">
 <table class="width75" cellspacing="1">
 <!-- Title -->
 <tr>
@@ -101,6 +104,33 @@
 	</td>
 </tr>
 
+<!-- Avatar -->
+<tr <?php echo helper_alternate_class() ?>>
+	<td class="category">
+		<?php echo lang_get( 'avatar' ) ?>:
+	</td>
+	<td>
+		<?php $t_avatar_exist = print_avatar( $t_user['id'], "manage_avatar" ); ?>&nbsp;
+		<?php if ($t_avatar_exist) { ?>
+		  <input class="button-small" type="submit" name="delete_avatar" value="<?php echo lang_get( 'delete_avatar' ) ?>" />
+	  <?php } ?>
+	</td>
+</tr>
+<?php 
+	$t_max_file_size = (int) config_get( 'max_avatar_file_size' );
+?>
+<tr <?php echo helper_alternate_class() ?>>
+	<td class="category">
+		<?php echo lang_get( 'upload_avatar' ) ?>
+		<?php echo '<span class="small">(' . lang_get( 'max_file_size' ) . ': ' . number_format( $t_max_file_size/1000 ) . 'k)</span>'?>
+	</td>
+	<td>
+		<input type="hidden" name="max_file_size" value="<?php echo $t_max_file_size ?>" />
+		<input <?php echo helper_get_tab_index() ?> name="avatar_file" type="file" size="60" />
+	</td>
+</tr>
+
+
 <!-- Submit Button -->
 <tr>
 	<td colspan="2" class="center">
Index: manage_user_page.php
===================================================================
--- manage_user_page.php	(revision 376)
+++ manage_user_page.php	(working copy)
@@ -251,6 +251,10 @@
 		<?php print_manage_user_sort_link(  'manage_user_page.php', lang_get( 'last_visit' ), 'last_visit', $c_dir, $c_sort, $c_hide ) ?>
 		<?php print_sort_icon( $c_dir, $c_sort, 'last_visit' ) ?>
 	</td>
+	<td>
+		<?php print_manage_user_sort_link(  'manage_user_page.php', lang_get( 'avatar' ), 'avatar', $c_dir, $c_sort, $c_hide ) ?>
+		<?php print_sort_icon( $c_dir, $c_sort, 'avatar' ) ?>
+	</td>
 </tr>
 <?php
 	for ($i=0;$i<$user_count;$i++) {
@@ -260,6 +264,9 @@
 
 		$u_date_created  = date( config_get( 'normal_date_format' ), db_unixtimestamp( $u_date_created ) );
 		$u_last_visit    = date( config_get( 'normal_date_format' ), db_unixtimestamp( $u_last_visit ) );
+		# has avatar
+		$t_avatar = user_get_local_avatar( $u_id );
+		$has_avatar = $t_avatar[3];
 ?>
 <tr <?php echo helper_alternate_class( $i ) ?>>
 	<td>
@@ -280,6 +287,14 @@
         </td>
 	<td><?php echo $u_date_created ?></td>
 	<td><?php echo $u_last_visit ?></td>
+	<td><?php 
+	          if (config_get("show_avatar_in_manage_user_list")) {
+	            print_avatar( $u_id , $t_class = "manage_avatar");
+	          } else {
+	            echo trans_bool( $has_avatar ); 
+	          }
+	    ?>
+	</td>
 </tr>
 <?php
 	}  # end for
Index: manage_user_update.php
===================================================================
--- manage_user_update.php	(revision 376)
+++ manage_user_update.php	(working copy)
@@ -88,6 +88,29 @@
 	}
 
 	$result = db_query( $query );
+	
+	#upload avatar
+	$target_path = "avatar/";
+	$ext = end(explode('.', $_FILES['avatar_file']['name'])); 
+  $target_file = $target_path . $c_username . '.' . $ext; 
+  move_uploaded_file($_FILES['avatar_file']['tmp_name'], $target_file);
+	
+	# delete avatar
+	$f_delete_avatar	= gpc_get_string( 'delete_avatar', '' );
+	if ($f_delete_avatar != '') {
+		$avatar_file = $target_path . '/' . $c_username . '.gif';
+    $fh = fopen($avatar_file, 'w') or die("can't open file");
+    fclose($fh);
+		
+		unlink($avatar_file);
+
+		$avatar_file = $target_path . '/' . $c_username . '.jpg';
+    $fh = fopen($avatar_file, 'w') or die("can't open file");
+    fclose($fh);
+		
+		unlink($avatar_file);
+	}
+	
 	$t_redirect_url = 'manage_user_edit_page.php?user_id=' . $c_user_id;
 ?>
 <?php html_page_top1() ?>
add_local_avatar.patch (10,285 bytes)   
edit_user.gif (9,350 bytes)   
edit_user.gif (9,350 bytes)   
manage_user_list.gif (10,593 bytes)   
manage_user_list.gif (10,593 bytes)   
gmail_contact_data.gif (15,910 bytes)   
gmail_contact_data.gif (15,910 bytes)   
local_avatar_cvs.patch (16,548 bytes)   
### Eclipse Workspace Patch 1.0
#P mantiscvs
Index: core/user_api.php
===================================================================
RCS file: /cvsroot/mantisbt/mantisbt/core/user_api.php,v
retrieving revision 1.111
diff -u -r1.111 user_api.php
--- core/user_api.php	10 Aug 2007 22:17:22 -0000	1.111
+++ core/user_api.php	12 Aug 2007 12:23:18 -0000
@@ -643,6 +643,42 @@
 
 		return array( $t_avatar_url, $t_size, $t_size );
 	}
+	
+	# --------------------
+	# return the user avatar image 
+	# return value is an array( URL, width, height, file_exist )
+	function user_get_local_avatar( $p_user_id ) {
+		global $g_path;
+		$t_avatar_exist = true;
+		$avatar_dir = config_get('directory_avatar');
+
+		# default imagesize
+		$t_height = config_get('avatar_max_height');
+		$t_width = config_get('avatar_max_width');
+
+		$t_username = user_get_name( $p_user_id );
+		$t_avatar_url = $g_path . '/' . $avatar_dir . '/' . $t_username . '.gif';
+		if (!file_exists(dirname( dirname( __FILE__ ) ).DIRECTORY_SEPARATOR.$avatar_dir.DIRECTORY_SEPARATOR.$t_username .".gif")) {
+			$t_avatar_url = $g_path . '/' . $avatar_dir . '/' . $t_username . '.jpg';
+			if (!file_exists(dirname( dirname( __FILE__ ) ).DIRECTORY_SEPARATOR.$avatar_dir.DIRECTORY_SEPARATOR.$t_username .".jpg")) {
+				$t_avatar_exist = false;	
+			}
+		}
+
+		if ($t_avatar_exist) {
+			# get image dimensions
+			list($width_orig, $height_orig) = getimagesize($t_avatar_url);
+			$ratio_orig = $width_orig/$height_orig;
+
+			if ($t_width/$t_height > $ratio_orig) {
+				$t_width = $t_height*$ratio_orig;
+			} else {
+				$t_height = $t_width/$ratio_orig;
+			}
+		}
+
+		return array( $t_avatar_url, $t_width, $t_height, $t_avatar_exist );
+	}
 
 
 	# --------------------
Index: core/print_api.php
===================================================================
RCS file: /cvsroot/mantisbt/mantisbt/core/print_api.php,v
retrieving revision 1.177
diff -u -r1.177 print_api.php
--- core/print_api.php	8 Aug 2007 22:28:54 -0000	1.177
+++ core/print_api.php	12 Aug 2007 12:23:18 -0000
@@ -106,16 +106,35 @@
 
 	
 	# Print avatar image for the given user ID
-	function print_avatar( $p_user_id ) {
+	function print_avatar( $p_user_id, $t_class = "avatar" ) {
+		$t_avatar_exist = false;
+ 		
 		if ( access_has_project_level( config_get( 'show_avatar_threshold' ), null, $p_user_id ) ) {
-			$t_avatar = user_get_avatar( $p_user_id );
-			$t_avatar_url = $t_avatar[0];
-			$t_width = $t_avatar[1];
-			$t_height = $t_avatar[2];
-			echo '<a rel="nofollow" href="http://site.gravatar.com">' .
-				'<img class="avatar" src="' . $t_avatar_url . '" alt="Gravatar image"' .
-				' width="' . $t_width . '" height="' . $t_height . '" /></a>';
+			$t_use_gravatar = config_get( 'use_gravatar', false, $p_user_id, ALL_PROJECTS );
+ 			
+			if ($t_use_gravatar) {
+				$t_avatar = user_get_avatar( $p_user_id );
+				$t_avatar_url = $t_avatar[0];
+				$t_width = $t_avatar[1];
+				$t_height = $t_avatar[2];
+				$t_avatar_exist = true;
+				echo '<a rel="nofollow" href="http://site.gravatar.com">' .
+					'<img class="' . $t_class. '" src="' . $t_avatar_url . '" alt="Gravatar image"' .
+					' width="' . $t_width . '" height="' . $t_height . '" /></a>';
+				} else {
+					$t_avatar = user_get_local_avatar( $p_user_id );
+					$t_avatar_url = $t_avatar[0];
+					$t_width = $t_avatar[1];
+					$t_height = $t_avatar[2];
+					$t_avatar_exist = $t_avatar[3];
+					
+					if ($t_avatar_exist) {
+						echo '<img class="' . $t_class. '" src="' . $t_avatar_url . '" alt=""' .
+						' width="' . $t_width . '" height="' . $t_height . '" />';
+				}
+			}
 		}
+		return $t_avatar_exist;
 	}
 
 
Index: config_defaults_inc.php
===================================================================
RCS file: /cvsroot/mantisbt/mantisbt/config_defaults_inc.php,v
retrieving revision 1.353
diff -u -r1.353 config_defaults_inc.php
--- config_defaults_inc.php	8 Aug 2007 22:28:53 -0000	1.353
+++ config_defaults_inc.php	12 Aug 2007 12:23:17 -0000
@@ -526,6 +526,19 @@
 	# Only users above this threshold will have their avatar shown
 	$g_show_avatar_threshold = DEVELOPER;
 
+	# Maximum file size that can be uploaded
+	$g_max_avatar_file_size		= 100000; # 100kB
+
+	# Show avatar (image) in manage_user_list
+	$g_show_avatar_in_manage_user_list = ON;	
+
+	# max size of avatar
+	$g_avatar_max_width = 80;
+	$g_avatar_max_height = 80;
+
+	# local directory to store avatar
+	$g_directory_avatar = 'avatar';
+
 	############################
 	# Mantis JPGRAPH Addon
 	############################
Index: manage_user_edit_page.php
===================================================================
RCS file: /cvsroot/mantisbt/mantisbt/manage_user_edit_page.php,v
retrieving revision 1.17
diff -u -r1.17 manage_user_edit_page.php
--- manage_user_edit_page.php	6 Mar 2007 07:05:18 -0000	1.17
+++ manage_user_edit_page.php	12 Aug 2007 12:23:17 -0000
@@ -18,6 +18,8 @@
 
 	$t_user = user_get_row( $f_user_id );
 
+	$t_use_gravatar = config_get( 'use_gravatar', false, $f_user_id, ALL_PROJECTS );
+
 	html_page_top1();
 	html_page_top2();
 
@@ -29,7 +31,7 @@
 
 <!-- USER INFO -->
 <div align="center">
-<form method="post" action="manage_user_update.php">
+<form method="post" action="manage_user_update.php" enctype="multipart/form-data">
 <table class="width75" cellspacing="1">
 <!-- Title -->
 <tr>
@@ -101,6 +103,40 @@
 	</td>
 </tr>
 
+<!-- Avatar -->
+<tr <?php echo helper_alternate_class() ?>>
+	<td class="category">
+		<?php echo lang_get( 'use_gravatar' ) ?>:
+	</td>
+	<td>
+		<input type="checkbox" name="use_gravatar" <?php check_checked( $t_use_gravatar, ON ); ?> />
+	</td>
+</tr>
+<tr <?php echo helper_alternate_class() ?>>
+	<td class="category">
+		<?php echo lang_get( 'avatar' ) ?>:
+	</td>
+	<td>
+		<?php $t_avatar_exist = print_avatar( $t_user['id'], "manage_avatar" ); ?>&nbsp;
+		<?php if ($t_avatar_exist and !config_get( 'use_gravatar', false, $f_user_id, ALL_PROJECTS )) { ?>
+			<input class="button-small" type="submit" name="delete_avatar" value="<?php echo lang_get( 'delete_avatar' ) ?>" />
+		<?php } ?>
+	</td>
+</tr>
+<?php 
+	$t_max_file_size = (int) config_get( 'max_avatar_file_size' );
+?>
+<tr <?php echo helper_alternate_class() ?>>
+	<td class="category">
+		<?php echo lang_get( 'upload_avatar' ) ?>
+		<?php echo '<span class="small">(' . lang_get( 'max_file_size' ) . ': ' . number_format( $t_max_file_size/1000 ) . 'k)</span>'?>
+	</td>
+	<td>
+		<input type="hidden" name="max_file_size" value="<?php echo $t_max_file_size ?>" />
+		<input <?php echo helper_get_tab_index() ?> name="avatar_file" type="file" size="60" />
+	</td>
+</tr>
+
 <!-- Submit Button -->
 <tr>
 	<td colspan="2" class="center">
Index: account_page.php
===================================================================
RCS file: /cvsroot/mantisbt/mantisbt/account_page.php,v
retrieving revision 1.52
diff -u -r1.52 account_page.php
--- account_page.php	6 Mar 2007 07:05:18 -0000	1.52
+++ account_page.php	12 Aug 2007 12:23:16 -0000
@@ -36,6 +36,8 @@
 	$t_core_path = config_get( 'core_path' );
 
 	require_once( $t_core_path.'current_user_api.php' );
+	
+	$t_use_gravatar = config_get( 'use_gravatar', false, auth_get_current_user_id(), ALL_PROJECTS );
 
 	#============ Parameters ============
 	# (none)
@@ -80,7 +82,7 @@
 <br />
 <?php } ?>
 <div align="center">
-<form method="post" action="account_update.php">
+<form method="post" action="account_update.php" enctype="multipart/form-data">
 <table class="width75" cellspacing="1">
 
 	<!-- Headings -->
@@ -191,9 +193,43 @@
 		</td>
 	</tr>
 
-	<!-- Access level -->
+<!-- Avatar -->
+	<tr class="row-2">
+		<td class="category">
+			<?php echo lang_get( 'use_gravatar' ) ?>:
+		</td>
+		<td>
+			<input type="checkbox" name="use_gravatar" <?php check_checked( $t_use_gravatar, ON ); ?> />
+		</td>
+	</tr>
+	<tr class="row-1">
+		<td class="category">
+			<?php echo lang_get( 'avatar' ) ?>:
+		</td>
+		<td>
+			<?php $t_avatar_exist = print_avatar( $u_id, "manage_avatar" ); ?>&nbsp;
+			<?php if ($t_avatar_exist and !config_get( 'use_gravatar', false, $u_id, ALL_PROJECTS )) { ?>
+		  	<input class="button-small" type="submit" name="delete_avatar" value="<?php echo lang_get( 'delete_avatar' ) ?>" />
+	  	<?php } ?>
+		</td>
+	</tr>
+<?php 
+	$t_max_file_size = (int) config_get( 'max_avatar_file_size' );
+?>
 	<tr class="row-2">
 		<td class="category">
+			<?php echo lang_get( 'upload_avatar' ) ?>
+			<?php echo '<span class="small">(' . lang_get( 'max_file_size' ) . ': ' . number_format( $t_max_file_size/1000 ) . 'k)</span>'?>
+		</td>
+		<td>
+			<input type="hidden" name="max_file_size" value="<?php echo $t_max_file_size ?>" />
+			<input <?php echo helper_get_tab_index() ?> name="avatar_file" type="file" size="60" />
+		</td>
+	</tr>
+
+	<!-- Access level -->
+	<tr class="row-1">
+		<td class="category">
 			<?php echo lang_get( 'access_level' ) ?>
 		</td>
 		<td>
@@ -202,7 +238,7 @@
 	</tr>
 
 	<!-- Project access level -->
-	<tr class="row-1">
+	<tr class="row-2">
 		<td class="category">
 			<?php echo lang_get( 'access_level_project' ) ?>
 		</td>
@@ -212,7 +248,7 @@
 	</tr>
 
 	<!-- Assigned project list -->
-	<tr class="row-2" valign="top">
+	<tr class="row-1" valign="top">
 		<td class="category">
 			<?php echo lang_get( 'assigned_projects' ) ?>
 		</td>
Index: manage_user_page.php
===================================================================
RCS file: /cvsroot/mantisbt/mantisbt/manage_user_page.php,v
retrieving revision 1.63
diff -u -r1.63 manage_user_page.php
--- manage_user_page.php	6 Mar 2007 07:05:18 -0000	1.63
+++ manage_user_page.php	12 Aug 2007 12:23:17 -0000
@@ -251,6 +251,10 @@
 		<?php print_manage_user_sort_link(  'manage_user_page.php', lang_get( 'last_visit' ), 'last_visit', $c_dir, $c_sort, $c_hide ) ?>
 		<?php print_sort_icon( $c_dir, $c_sort, 'last_visit' ) ?>
 	</td>
+	<td>
+		<?php print_manage_user_sort_link(  'manage_user_page.php', lang_get( 'avatar' ), 'avatar', $c_dir, $c_sort, $c_hide ) ?>
+		<?php print_sort_icon( $c_dir, $c_sort, 'avatar' ) ?>
+	</td>	
 </tr>
 <?php
 	for ($i=0;$i<$user_count;$i++) {
@@ -260,6 +264,10 @@
 
 		$u_date_created  = date( config_get( 'normal_date_format' ), db_unixtimestamp( $u_date_created ) );
 		$u_last_visit    = date( config_get( 'normal_date_format' ), db_unixtimestamp( $u_last_visit ) );
+		
+		# has avatar
+		$t_avatar = user_get_local_avatar( $u_id );
+		$has_avatar = $t_avatar[3];		
 ?>
 <tr <?php echo helper_alternate_class( $i ) ?>>
 	<td>
@@ -280,6 +288,14 @@
         </td>
 	<td><?php echo $u_date_created ?></td>
 	<td><?php echo $u_last_visit ?></td>
+	<td><?php 
+				if (config_get("show_avatar_in_manage_user_list")) {
+					print_avatar( $u_id , $t_class = "manage_avatar");
+				} else {
+					echo trans_bool( $has_avatar ); 
+				}
+			?>
+	</td>	
 </tr>
 <?php
 	}  # end for
Index: account_update.php
===================================================================
RCS file: /cvsroot/mantisbt/mantisbt/account_update.php,v
retrieving revision 1.41
diff -u -r1.41 account_update.php
--- account_update.php	16 Jun 2007 23:04:32 -0000	1.41
+++ account_update.php	12 Aug 2007 12:23:16 -0000
@@ -31,6 +31,7 @@
 	$f_realname        	= gpc_get_string( 'realname', '' );
 	$f_password        	= gpc_get_string( 'password', '' );
 	$f_password_confirm	= gpc_get_string( 'password_confirm', '' );
+	$f_use_gravatar	    = gpc_get_bool( 'use_gravatar' );
 
 	$f_email = email_append_domain( $f_email );
 
@@ -81,6 +82,34 @@
 		}
 	}
 
+	# avatar
+	$t_username = user_get_field( $t_user_id, 'username' );
+  # store use_avatar in config
+	config_set('use_gravatar', $f_use_gravatar, $t_user_id, ALL_PROJECTS);
+
+	# upload avatar
+	$target_path = config_get('directory_avatar') . '/';
+	$avatar_file_name = $_FILES['avatar_file']['name'];
+	$ext = end(explode('.', $_FILES['avatar_file']['name'])); 
+	$target_file = $target_path . $t_username . '.' . $ext; 
+	move_uploaded_file($_FILES['avatar_file']['tmp_name'], $target_file);
+
+	# delete avatar
+	$f_delete_avatar	= gpc_get_string( 'delete_avatar', '' );
+	if ($f_delete_avatar != '') {
+		$avatar_file = $target_path . '/' . $t_username . '.gif';
+		$fh = fopen($avatar_file, 'w') or die("can't open file");
+		fclose($fh);
+		
+		unlink($avatar_file);
+
+		$avatar_file = $target_path . '/' . $t_username . '.jpg';
+		$fh = fopen($avatar_file, 'w') or die("can't open file");
+		fclose($fh);
+
+		unlink($avatar_file);
+	}
+	
 	html_page_top1();
 	html_meta_redirect( $t_redirect );
 	html_page_top2();
Index: manage_user_update.php
===================================================================
RCS file: /cvsroot/mantisbt/mantisbt/manage_user_update.php,v
retrieving revision 1.40
diff -u -r1.40 manage_user_update.php
--- manage_user_update.php	16 Jun 2007 23:04:33 -0000	1.40
+++ manage_user_update.php	12 Aug 2007 12:23:17 -0000
@@ -26,6 +26,7 @@
 	$f_realname		= gpc_get_string( 'realname', '' );
 	$f_access_level	= gpc_get_int( 'access_level' );
 	$f_user_id		= gpc_get_int( 'user_id' );
+	$f_use_gravatar	= gpc_get_bool( 'use_gravatar' );
 
 	$f_email	= trim( $f_email );
 	$f_username	= trim( $f_username );
@@ -88,6 +89,34 @@
 	}
 
 	$result = db_query( $query );
+	
+	# avatar
+  # store use_avatar in config
+	config_set('use_gravatar', $f_use_gravatar, $c_user_id, ALL_PROJECTS);
+
+	# upload avatar
+	$target_path = config_get('directory_avatar') . '/';
+	$avatar_file_name = $_FILES['avatar_file']['name'];
+	$ext = end(explode('.', $_FILES['avatar_file']['name'])); 
+	$target_file = $target_path . $c_username . '.' . $ext; 
+	move_uploaded_file($_FILES['avatar_file']['tmp_name'], $target_file);
+
+	# delete avatar
+	$f_delete_avatar	= gpc_get_string( 'delete_avatar', '' );
+	if ($f_delete_avatar != '') {
+		$avatar_file = $target_path . '/' . $c_username . '.gif';
+		$fh = fopen($avatar_file, 'w') or die("can't open file");
+		fclose($fh);
+		
+		unlink($avatar_file);
+
+		$avatar_file = $target_path . '/' . $c_username . '.jpg';
+		$fh = fopen($avatar_file, 'w') or die("can't open file");
+		fclose($fh);
+
+		unlink($avatar_file);
+	}
+
 	$t_redirect_url = 'manage_user_edit_page.php?user_id=' . $c_user_id;
 ?>
 <?php html_page_top1() ?>
Index: lang/strings_english.txt
===================================================================
RCS file: /cvsroot/mantisbt/mantisbt/lang/strings_english.txt,v
retrieving revision 1.309
diff -u -r1.309 strings_english.txt
--- lang/strings_english.txt	8 Aug 2007 20:59:25 -0000	1.309
+++ lang/strings_english.txt	12 Aug 2007 12:23:19 -0000
@@ -1365,4 +1365,10 @@
 
 # Project Page
 $s_development_team = 'Development Team';
+
+# Avatar
+$s_avatar = 'Avatar';
+$s_use_gravatar = 'Use Gravatar for Avatar';
+$s_upload_avatar = 'Upload Avatar';
+$s_delete_avatar = 'Delete Avatar';
 ?>
Index: lang/strings_german.txt
===================================================================
RCS file: /cvsroot/mantisbt/mantisbt/lang/strings_german.txt,v
retrieving revision 1.152
diff -u -r1.152 strings_german.txt
--- lang/strings_german.txt	19 Jul 2007 06:20:21 -0000	1.152
+++ lang/strings_german.txt	12 Aug 2007 12:23:20 -0000
@@ -1329,4 +1329,10 @@
 
 # wiki related strings
 $s_wiki = 'Wiki';
+
+# Avatar
+$s_avatar = 'Avatar';        
+$s_use_gravatar = 'Gravatar f�r Avatar benutzen';
+$s_upload_avatar = 'Avatar hochladen';
+$s_delete_avatar = 'Avatar l�schen';
 ?>
Index: css/default.css
===================================================================
RCS file: /cvsroot/mantisbt/mantisbt/css/default.css,v
retrieving revision 1.26
diff -u -r1.26 default.css
--- css/default.css	8 Aug 2007 22:28:54 -0000	1.26
+++ css/default.css	12 Aug 2007 12:23:18 -0000
@@ -150,5 +150,11 @@
 	border: 0;
 }
 
+.manage_avatar
+{
+	float: left;
+	border: 0;
+}
+
 .progress400				{ position: relative; width: 400px; border: 1px solid #d7d7d7; margin-top: 1em; margin-bottom: 1em; padding: 1px; }
 .progress400 .bar			{ display: block; position: relative; background: #6bba70; text-align: center; font-weight: normal; color: #333; height: 2em; line-height: 2em; }
local_avatar_cvs.patch (16,548 bytes)   
edit_account.gif (13,953 bytes)   
edit_account.gif (13,953 bytes)   
local_avatar_cvs_2.patch (18,623 bytes)   
### Eclipse Workspace Patch 1.0
#P mantiscvs
Index: core/user_api.php
===================================================================
RCS file: /cvsroot/mantisbt/mantisbt/core/user_api.php,v
retrieving revision 1.111
diff -u -r1.111 user_api.php
--- core/user_api.php	10 Aug 2007 22:17:22 -0000	1.111
+++ core/user_api.php	14 Aug 2007 20:20:59 -0000
@@ -643,6 +643,43 @@
 
 		return array( $t_avatar_url, $t_size, $t_size );
 	}
+	
+	# --------------------
+	# return the user avatar image 
+	# return value is an array( URL, width, height, file_exist )
+	function user_get_local_avatar( $p_user_id ) {
+		global $g_path;
+		$t_avatar_exist = true;
+		$avatar_dir = config_get('directory_avatar');
+
+		# default imagesize
+		$t_height = config_get('avatar_max_height');
+		$t_width = config_get('avatar_max_width');
+
+		$t_username = user_get_name( $p_user_id );
+		$t_avatar_url = $g_path . '/' . $avatar_dir . '/' . $t_username . '.gif';
+		if (!file_exists(dirname( dirname( __FILE__ ) ).DIRECTORY_SEPARATOR.$avatar_dir.DIRECTORY_SEPARATOR.$t_username .".gif")) {
+			$t_avatar_url = $g_path . '/' . $avatar_dir . '/' . $t_username . '.jpg';
+			if (!file_exists(dirname( dirname( __FILE__ ) ).DIRECTORY_SEPARATOR.$avatar_dir.DIRECTORY_SEPARATOR.$t_username .".jpg")) {
+				$t_avatar_exist = false;	
+			}
+		}
+
+		if ($t_avatar_exist) {
+			# get image dimensions
+			list($width_orig, $height_orig) = getimagesize($t_avatar_url);
+			
+			$ratio_orig = $width_orig / $height_orig;
+
+			if ($t_width / $t_height > $ratio_orig) {
+				$t_width = $t_height * $ratio_orig;
+			} else {
+				$t_height = $t_width / $ratio_orig;
+			}
+		}
+
+		return array( $t_avatar_url, $t_width, $t_height, $t_avatar_exist );
+	}
 
 
 	# --------------------
Index: core/print_api.php
===================================================================
RCS file: /cvsroot/mantisbt/mantisbt/core/print_api.php,v
retrieving revision 1.177
diff -u -r1.177 print_api.php
--- core/print_api.php	8 Aug 2007 22:28:54 -0000	1.177
+++ core/print_api.php	14 Aug 2007 20:20:59 -0000
@@ -106,16 +106,35 @@
 
 	
 	# Print avatar image for the given user ID
-	function print_avatar( $p_user_id ) {
+	function print_avatar( $p_user_id, $t_class = "avatar" ) {
+		$t_avatar_exist = false;
+ 		
 		if ( access_has_project_level( config_get( 'show_avatar_threshold' ), null, $p_user_id ) ) {
-			$t_avatar = user_get_avatar( $p_user_id );
-			$t_avatar_url = $t_avatar[0];
-			$t_width = $t_avatar[1];
-			$t_height = $t_avatar[2];
-			echo '<a rel="nofollow" href="http://site.gravatar.com">' .
-				'<img class="avatar" src="' . $t_avatar_url . '" alt="Gravatar image"' .
-				' width="' . $t_width . '" height="' . $t_height . '" /></a>';
+			$t_use_gravatar = config_get( 'use_gravatar', false, $p_user_id, ALL_PROJECTS );
+ 			
+			if ($t_use_gravatar) {
+				$t_avatar = user_get_avatar( $p_user_id );
+				$t_avatar_url = $t_avatar[0];
+				$t_width = $t_avatar[1];
+				$t_height = $t_avatar[2];
+				$t_avatar_exist = true;
+				echo '<a rel="nofollow" href="http://site.gravatar.com">' .
+					'<img class="' . $t_class. '" src="' . $t_avatar_url . '" alt="Gravatar image"' .
+					' width="' . $t_width . '" height="' . $t_height . '" /></a>';
+				} else {
+					$t_avatar = user_get_local_avatar( $p_user_id );
+					$t_avatar_url = $t_avatar[0];
+					$t_width = $t_avatar[1];
+					$t_height = $t_avatar[2];
+					$t_avatar_exist = $t_avatar[3];
+					
+					if ($t_avatar_exist) {
+						echo '<img class="' . $t_class. '" src="' . $t_avatar_url . '" alt=""' .
+						' width="' . $t_width . '" height="' . $t_height . '" />';
+				}
+			}
 		}
+		return $t_avatar_exist;
 	}
 
 
Index: core/file_api.php
===================================================================
RCS file: /cvsroot/mantisbt/mantisbt/core/file_api.php,v
retrieving revision 1.83
diff -u -r1.83 file_api.php
--- core/file_api.php	1 Aug 2007 08:02:58 -0000	1.83
+++ core/file_api.php	14 Aug 2007 20:20:58 -0000
@@ -780,4 +780,56 @@
 			return '';
 		}
 	}
+
+  # --------------------
+	# Upload avatar to the directory defined in $g_directory_avatar
+	# $p_resize = false makea a copy without resizing
+  function file_avatar_upload ( $p_username, $p_tmp_filename, $p_ext, $p_resize = false) {
+		$target_path = config_get('directory_avatar') . '/';	
+		$target_file = $target_path . $p_username . '.' . $p_ext; 
+
+    if ($p_resize) {
+			switch($p_ext){
+				case "jpg":
+					header('Content-type: image/jpeg');
+					$source = imagecreatefromjpeg($p_tmp_filename);
+				break;	
+				case "gif":
+					header('Content-type: image/gif');
+					$source = imagecreatefromgif($p_tmp_filename);
+				break;
+			}	
+
+			# default imagesize
+			$t_height = config_get('avatar_max_height');
+			$t_width = config_get('avatar_max_width');
+			
+			list($width_orig, $height_orig) = getimagesize($p_tmp_filename);
+
+			$ratio_orig = $width_orig / $height_orig;
+
+			if ($t_width / $t_height > $ratio_orig) {
+				$t_width = $t_height * $ratio_orig;
+			} else {
+				$t_height = $t_width / $ratio_orig;
+			}
+			
+			$thumb = ImageCreateTrueColor($t_width, $t_height);
+			imagealphablending($thumb, false);		
+			ImageCopyResized($thumb, $source, 0, 0, 0, 0, $t_width, $t_height, $width_orig, $height_orig);
+			@imagejpeg($thumb, $target_file);
+    } else {
+    	move_uploaded_file($p_tmp_filename, $target_file);
+    }
+  }
+
+  # --------------------
+  # delete an avatar 
+  function file_avatar_delete($p_username, $p_ext) {
+  	$target_path = config_get('directory_avatar') . '/';
+		$avatar_file = $target_path . $p_username . '.' . $p_ext;
+    $fh = fopen($avatar_file, 'w') or die("can't open file");
+    fclose($fh);
+		unlink($avatar_file);  	
+  }
 ?>
Index: config_defaults_inc.php
===================================================================
RCS file: /cvsroot/mantisbt/mantisbt/config_defaults_inc.php,v
retrieving revision 1.353
diff -u -r1.353 config_defaults_inc.php
--- config_defaults_inc.php	8 Aug 2007 22:28:53 -0000	1.353
+++ config_defaults_inc.php	14 Aug 2007 20:20:58 -0000
@@ -526,6 +526,22 @@
 	# Only users above this threshold will have their avatar shown
 	$g_show_avatar_threshold = DEVELOPER;
 
+	# Maximum file size that can be uploaded
+	$g_max_avatar_file_size		= 100000; # 100kB
+
+	# Show avatar (image) in manage_user_list
+	$g_show_avatar_in_manage_user_list = ON;	
+
+	# resize the avatar on storage
+	$g_resize_avatar_on_store	= OFF;
+	
+	# max size of avatar
+	$g_avatar_max_width = 80;
+	$g_avatar_max_height = 80;
+
+	# local directory to store avatar
+	$g_directory_avatar = 'avatar';
+
 	############################
 	# Mantis JPGRAPH Addon
 	############################
Index: manage_user_edit_page.php
===================================================================
RCS file: /cvsroot/mantisbt/mantisbt/manage_user_edit_page.php,v
retrieving revision 1.17
diff -u -r1.17 manage_user_edit_page.php
--- manage_user_edit_page.php	6 Mar 2007 07:05:18 -0000	1.17
+++ manage_user_edit_page.php	14 Aug 2007 20:20:58 -0000
@@ -18,6 +18,8 @@
 
 	$t_user = user_get_row( $f_user_id );
 
+	$t_use_gravatar = config_get( 'use_gravatar', false, $f_user_id, ALL_PROJECTS );
+
 	html_page_top1();
 	html_page_top2();
 
@@ -29,7 +31,7 @@
 
 <!-- USER INFO -->
 <div align="center">
-<form method="post" action="manage_user_update.php">
+<form method="post" action="manage_user_update.php" enctype="multipart/form-data">
 <table class="width75" cellspacing="1">
 <!-- Title -->
 <tr>
@@ -101,6 +103,40 @@
 	</td>
 </tr>
 
+<!-- Avatar -->
+<tr <?php echo helper_alternate_class() ?>>
+	<td class="category">
+		<?php echo lang_get( 'use_gravatar' ) ?>:
+	</td>
+	<td>
+		<input type="checkbox" name="use_gravatar" <?php check_checked( $t_use_gravatar, ON ); ?> />
+	</td>
+</tr>
+<tr <?php echo helper_alternate_class() ?>>
+	<td class="category">
+		<?php echo lang_get( 'avatar' ) ?>:
+	</td>
+	<td>
+		<?php $t_avatar_exist = print_avatar( $t_user['id'], "manage_avatar" ); ?>&nbsp;
+		<?php if ($t_avatar_exist and !config_get( 'use_gravatar', false, $f_user_id, ALL_PROJECTS )) { ?>
+			<input class="button-small" type="submit" name="delete_avatar" value="<?php echo lang_get( 'delete_avatar' ) ?>" />
+		<?php } ?>
+	</td>
+</tr>
+<?php 
+	$t_max_file_size = (int) config_get( 'max_avatar_file_size' );
+?>
+<tr <?php echo helper_alternate_class() ?>>
+	<td class="category">
+		<?php echo lang_get( 'upload_avatar' ) ?>
+		<?php echo '<span class="small">(' . lang_get( 'max_file_size' ) . ': ' . number_format( $t_max_file_size/1000 ) . 'k)</span>'?>
+	</td>
+	<td>
+		<input type="hidden" name="max_file_size" value="<?php echo $t_max_file_size ?>" />
+		<input <?php echo helper_get_tab_index() ?> name="avatar_file" type="file" size="60" />
+	</td>
+</tr>
+
 <!-- Submit Button -->
 <tr>
 	<td colspan="2" class="center">
Index: account_page.php
===================================================================
RCS file: /cvsroot/mantisbt/mantisbt/account_page.php,v
retrieving revision 1.52
diff -u -r1.52 account_page.php
--- account_page.php	6 Mar 2007 07:05:18 -0000	1.52
+++ account_page.php	14 Aug 2007 20:20:57 -0000
@@ -36,6 +36,8 @@
 	$t_core_path = config_get( 'core_path' );
 
 	require_once( $t_core_path.'current_user_api.php' );
+	
+	$t_use_gravatar = config_get( 'use_gravatar', false, auth_get_current_user_id(), ALL_PROJECTS );
 
 	#============ Parameters ============
 	# (none)
@@ -80,7 +82,7 @@
 <br />
 <?php } ?>
 <div align="center">
-<form method="post" action="account_update.php">
+<form method="post" action="account_update.php" enctype="multipart/form-data">
 <table class="width75" cellspacing="1">
 
 	<!-- Headings -->
@@ -191,9 +193,43 @@
 		</td>
 	</tr>
 
-	<!-- Access level -->
+<!-- Avatar -->
+	<tr class="row-2">
+		<td class="category">
+			<?php echo lang_get( 'use_gravatar' ) ?>:
+		</td>
+		<td>
+			<input type="checkbox" name="use_gravatar" <?php check_checked( $t_use_gravatar, ON ); ?> />
+		</td>
+	</tr>
+	<tr class="row-1">
+		<td class="category">
+			<?php echo lang_get( 'avatar' ) ?>:
+		</td>
+		<td>
+			<?php $t_avatar_exist = print_avatar( $u_id, "manage_avatar" ); ?>&nbsp;
+			<?php if ($t_avatar_exist and !config_get( 'use_gravatar', false, $u_id, ALL_PROJECTS )) { ?>
+		  	<input class="button-small" type="submit" name="delete_avatar" value="<?php echo lang_get( 'delete_avatar' ) ?>" />
+	  	<?php } ?>
+		</td>
+	</tr>
+<?php 
+	$t_max_file_size = (int) config_get( 'max_avatar_file_size' );
+?>
 	<tr class="row-2">
 		<td class="category">
+			<?php echo lang_get( 'upload_avatar' ) ?>
+			<?php echo '<span class="small">(' . lang_get( 'max_file_size' ) . ': ' . number_format( $t_max_file_size/1000 ) . 'k)</span>'?>
+		</td>
+		<td>
+			<input type="hidden" name="max_file_size" value="<?php echo $t_max_file_size ?>" />
+			<input <?php echo helper_get_tab_index() ?> name="avatar_file" type="file" size="60" />
+		</td>
+	</tr>
+
+	<!-- Access level -->
+	<tr class="row-1">
+		<td class="category">
 			<?php echo lang_get( 'access_level' ) ?>
 		</td>
 		<td>
@@ -202,7 +238,7 @@
 	</tr>
 
 	<!-- Project access level -->
-	<tr class="row-1">
+	<tr class="row-2">
 		<td class="category">
 			<?php echo lang_get( 'access_level_project' ) ?>
 		</td>
@@ -212,7 +248,7 @@
 	</tr>
 
 	<!-- Assigned project list -->
-	<tr class="row-2" valign="top">
+	<tr class="row-1" valign="top">
 		<td class="category">
 			<?php echo lang_get( 'assigned_projects' ) ?>
 		</td>
Index: manage_user_page.php
===================================================================
RCS file: /cvsroot/mantisbt/mantisbt/manage_user_page.php,v
retrieving revision 1.63
diff -u -r1.63 manage_user_page.php
--- manage_user_page.php	6 Mar 2007 07:05:18 -0000	1.63
+++ manage_user_page.php	14 Aug 2007 20:20:58 -0000
@@ -251,6 +251,10 @@
 		<?php print_manage_user_sort_link(  'manage_user_page.php', lang_get( 'last_visit' ), 'last_visit', $c_dir, $c_sort, $c_hide ) ?>
 		<?php print_sort_icon( $c_dir, $c_sort, 'last_visit' ) ?>
 	</td>
+	<td>
+		<?php print_manage_user_sort_link(  'manage_user_page.php', lang_get( 'avatar' ), 'avatar', $c_dir, $c_sort, $c_hide ) ?>
+		<?php print_sort_icon( $c_dir, $c_sort, 'avatar' ) ?>
+	</td>	
 </tr>
 <?php
 	for ($i=0;$i<$user_count;$i++) {
@@ -260,6 +264,10 @@
 
 		$u_date_created  = date( config_get( 'normal_date_format' ), db_unixtimestamp( $u_date_created ) );
 		$u_last_visit    = date( config_get( 'normal_date_format' ), db_unixtimestamp( $u_last_visit ) );
+		
+		# has avatar
+		$t_avatar = user_get_local_avatar( $u_id );
+		$has_avatar = $t_avatar[3];		
 ?>
 <tr <?php echo helper_alternate_class( $i ) ?>>
 	<td>
@@ -280,6 +288,14 @@
         </td>
 	<td><?php echo $u_date_created ?></td>
 	<td><?php echo $u_last_visit ?></td>
+	<td><?php 
+				if (config_get("show_avatar_in_manage_user_list")) {
+					print_avatar( $u_id , $t_class = "manage_avatar");
+				} else {
+					echo trans_bool( $has_avatar ); 
+				}
+			?>
+	</td>	
 </tr>
 <?php
 	}  # end for
Index: account_update.php
===================================================================
RCS file: /cvsroot/mantisbt/mantisbt/account_update.php,v
retrieving revision 1.41
diff -u -r1.41 account_update.php
--- account_update.php	16 Jun 2007 23:04:32 -0000	1.41
+++ account_update.php	14 Aug 2007 20:20:57 -0000
@@ -20,6 +20,7 @@
 	$t_core_path = config_get( 'core_path' );
 
 	require_once( $t_core_path.'email_api.php' );
+	require_once( $t_core_path.'file_api.php' );
 ?>
 <?php
 	auth_ensure_user_authenticated();
@@ -31,6 +32,7 @@
 	$f_realname        	= gpc_get_string( 'realname', '' );
 	$f_password        	= gpc_get_string( 'password', '' );
 	$f_password_confirm	= gpc_get_string( 'password_confirm', '' );
+	$f_use_gravatar	    = gpc_get_bool( 'use_gravatar' );
 
 	$f_email = email_append_domain( $f_email );
 
@@ -81,6 +83,25 @@
 		}
 	}
 
+	# avatar
+	$t_username = user_get_field( $t_user_id, 'username' );
+  # store use_avatar in config
+	config_set('use_gravatar', $f_use_gravatar, $t_user_id, ALL_PROJECTS);
+
+	# upload avatar
+	$avatar_tmp_file_name = $_FILES['avatar_file']['tmp_name'];
+	$p_ext = end(explode('.', $_FILES['avatar_file']['name']));
+	if ($avatar_tmp_file_name != '') {
+    file_avatar_upload($t_username, $avatar_tmp_file_name, $p_ext, true);
+	}
+	
+	# delete avatar
+	$f_delete_avatar	= gpc_get_string( 'delete_avatar', '' );
+	if ($f_delete_avatar != '') {
+		file_avatar_delete($t_username, 'gif');
+		file_avatar_delete($t_username, 'jpg');
+	}
+	
 	html_page_top1();
 	html_meta_redirect( $t_redirect );
 	html_page_top2();
Index: manage_user_update.php
===================================================================
RCS file: /cvsroot/mantisbt/mantisbt/manage_user_update.php,v
retrieving revision 1.40
diff -u -r1.40 manage_user_update.php
--- manage_user_update.php	16 Jun 2007 23:04:33 -0000	1.40
+++ manage_user_update.php	14 Aug 2007 20:20:58 -0000
@@ -15,6 +15,7 @@
 	$t_core_path = config_get( 'core_path' );
 
 	require_once( $t_core_path.'email_api.php' );
+	require_once( $t_core_path.'file_api.php' );
 ?>
 <?php
 	access_ensure_global_level( config_get( 'manage_user_threshold' ) );
@@ -26,6 +27,7 @@
 	$f_realname		= gpc_get_string( 'realname', '' );
 	$f_access_level	= gpc_get_int( 'access_level' );
 	$f_user_id		= gpc_get_int( 'user_id' );
+	$f_use_gravatar	= gpc_get_bool( 'use_gravatar' );
 
 	$f_email	= trim( $f_email );
 	$f_username	= trim( $f_username );
@@ -88,6 +90,24 @@
 	}
 
 	$result = db_query( $query );
+	
+  # store use_avatar in config
+  config_set('use_gravatar', $f_use_gravatar, $c_user_id, ALL_PROJECTS);
+  	
+	# upload avatar
+	$avatar_tmp_file_name = $_FILES['avatar_file']['tmp_name'];
+	$p_ext = end(explode('.', $_FILES['avatar_file']['name']));
+	if ($avatar_tmp_file_name != '') {
+    file_avatar_upload($c_username, $avatar_tmp_file_name, $p_ext, config_get('resize_avatar_on_store', false));
+	}
+	
+	# delete avatar
+	$f_delete_avatar	= gpc_get_string( 'delete_avatar', '' );
+	if ($f_delete_avatar != '') {
+		file_avatar_delete($c_username, 'gif');
+		file_avatar_delete($c_username, 'jpg');
+	}
+
 	$t_redirect_url = 'manage_user_edit_page.php?user_id=' . $c_user_id;
 ?>
 <?php html_page_top1() ?>
Index: lang/strings_english.txt
===================================================================
RCS file: /cvsroot/mantisbt/mantisbt/lang/strings_english.txt,v
retrieving revision 1.309
diff -u -r1.309 strings_english.txt
--- lang/strings_english.txt	8 Aug 2007 20:59:25 -0000	1.309
+++ lang/strings_english.txt	14 Aug 2007 20:21:00 -0000
@@ -1365,4 +1365,10 @@
 
 # Project Page
 $s_development_team = 'Development Team';
+
+# Avatar
+$s_avatar = 'Avatar';
+$s_use_gravatar = 'Use Gravatar for Avatar';
+$s_upload_avatar = 'Upload Avatar';
+$s_delete_avatar = 'Delete Avatar';
 ?>
Index: lang/strings_german.txt
===================================================================
RCS file: /cvsroot/mantisbt/mantisbt/lang/strings_german.txt,v
retrieving revision 1.152
diff -u -r1.152 strings_german.txt
--- lang/strings_german.txt	19 Jul 2007 06:20:21 -0000	1.152
+++ lang/strings_german.txt	14 Aug 2007 20:21:01 -0000
@@ -1329,4 +1329,10 @@
 
 # wiki related strings
 $s_wiki = 'Wiki';
+
+# Avatar
+$s_avatar = 'Avatar';        
+$s_use_gravatar = 'Gravatar f�r Avatar benutzen';
+$s_upload_avatar = 'Avatar hochladen';
+$s_delete_avatar = 'Avatar l�schen';
 ?>
Index: css/default.css
===================================================================
RCS file: /cvsroot/mantisbt/mantisbt/css/default.css,v
retrieving revision 1.26
diff -u -r1.26 default.css
--- css/default.css	8 Aug 2007 22:28:54 -0000	1.26
+++ css/default.css	14 Aug 2007 20:21:00 -0000
@@ -150,5 +150,11 @@
 	border: 0;
 }
 
+.manage_avatar
+{
+	float: left;
+	border: 0;
+}
+
 .progress400				{ position: relative; width: 400px; border: 1px solid #d7d7d7; margin-top: 1em; margin-bottom: 1em; padding: 1px; }
 .progress400 .bar			{ display: block; position: relative; background: #6bba70; text-align: center; font-weight: normal; color: #333; height: 2em; line-height: 2em; }
local_avatar_cvs_2.patch (18,623 bytes)   
local_avatar.patch (13,966 bytes)   
Index: account_page.php
===================================================================
--- account_page.php	(revision 5305)
+++ account_page.php	(working copy)
@@ -48,6 +48,8 @@
 	$t_core_path = config_get( 'core_path' );
 
 	require_once( $t_core_path.'current_user_api.php' );
+	
+	$t_use_gravatar = config_get( 'use_gravatar', false, auth_get_current_user_id(), ALL_PROJECTS );
 
 	#============ Parameters ============
 	# (none)
@@ -92,7 +94,7 @@
 <br />
 <?php } ?>
 <div align="center">
-<form method="post" action="account_update.php">
+<form method="post" action="account_update.php" enctype="multipart/form-data">
 <table class="width75" cellspacing="1">
 
 	<!-- Headings -->
@@ -203,9 +205,43 @@
 		</td>
 	</tr>
 
-	<!-- Access level -->
+	<!-- Avatar -->
 	<tr <?php echo helper_alternate_class() ?>>
 		<td class="category">
+			<?php echo lang_get( 'use_gravatar' ) ?>:
+		</td>
+		<td>
+			<input type="checkbox" name="use_gravatar" <?php check_checked( $t_use_gravatar, ON ); ?> />
+		</td>
+	</tr>
+	<tr <?php echo helper_alternate_class() ?> >
+		<td class="category">
+			<?php echo lang_get( 'avatar' ) ?>:
+		</td>
+		<td>
+			<?php $t_avatar_exist = print_avatar( $u_id, null, $t_class = "manage_avatar" ); ?>&nbsp;
+			<?php if ($t_avatar_exist and !config_get( 'use_gravatar', false, $u_id, ALL_PROJECTS )) { ?>
+		  	<input class="button-small" type="submit" name="delete_avatar" value="<?php echo lang_get( 'delete_avatar' ) ?>" />
+	  	<?php } ?>
+		</td>
+	</tr>
+<?php 
+	$t_max_file_size = (int) config_get( 'max_avatar_file_size' );
+?>
+	<tr <?php echo helper_alternate_class() ?> >
+		<td class="category">
+			<?php echo lang_get( 'upload_avatar' ) ?>
+			<?php echo '<span class="small">(' . lang_get( 'max_file_size' ) . ': ' . number_format( $t_max_file_size/1000 ) . 'k)</span>'?>
+		</td>
+		<td>
+			<input type="hidden" name="max_file_size" value="<?php echo $t_max_file_size ?>" />
+			<input <?php echo helper_get_tab_index() ?> name="avatar_file" type="file" size="60" />
+		</td>
+	</tr>
+
+	<!-- Access level -->
+	<tr <?php echo helper_alternate_class() ?> >
+		<td class="category">
 			<?php echo lang_get( 'access_level' ) ?>
 		</td>
 		<td>
Index: account_update.php
===================================================================
--- account_update.php	(revision 5305)
+++ account_update.php	(working copy)
@@ -41,6 +41,7 @@
 	$f_realname        	= gpc_get_string( 'realname', '' );
 	$f_password        	= gpc_get_string( 'password', '' );
 	$f_password_confirm	= gpc_get_string( 'password_confirm', '' );
+	$f_use_gravatar	    = gpc_get_bool( 'use_gravatar' );
 
 	$f_email = email_append_domain( $f_email );
 
@@ -91,6 +92,34 @@
 		}
 	}
 
+	# avatar
+	$t_username = user_get_field( $t_user_id, 'username' );
+	# store use_avatar in config
+	config_set('use_gravatar', $f_use_gravatar, $t_user_id, ALL_PROJECTS);
+
+	# upload avatar
+	$target_path = config_get('directory_avatar') . '/';
+	$avatar_file_name = $_FILES['avatar_file']['name'];
+	$ext = end(explode('.', $_FILES['avatar_file']['name'])); 
+	$target_file = $target_path . $t_username . '.' . $ext; 
+	move_uploaded_file($_FILES['avatar_file']['tmp_name'], $target_file);
+
+	# delete avatar
+	$f_delete_avatar	= gpc_get_string( 'delete_avatar', '' );
+	if ($f_delete_avatar != '') {
+		$avatar_file = $target_path . '/' . $t_username . '.gif';
+		$fh = fopen($avatar_file, 'w') or die("can't open file");
+		fclose($fh);
+		
+		unlink($avatar_file);
+
+		$avatar_file = $target_path . '/' . $t_username . '.jpg';
+		$fh = fopen($avatar_file, 'w') or die("can't open file");
+		fclose($fh);
+
+		unlink($avatar_file);
+	}
+	
 	html_page_top1();
 	html_meta_redirect( $t_redirect );
 	html_page_top2();
Index: config_defaults_inc.php
===================================================================
--- config_defaults_inc.php	(revision 5305)
+++ config_defaults_inc.php	(working copy)
@@ -600,6 +600,15 @@
 	# Default avatar for users without a gravatar account
 	$g_default_avatar = "%path%images/no_avatar.png";
 
+	$g_avatar_max_width = 80;
+	$g_avatar_max_height = 80;
+
+	# local directory to store avatar
+	$g_directory_avatar = 'avatar';
+
+	# Show avatar in manage_user_list
+	$g_show_avatar_in_manage_user_list = OFF;
+
 	# Show release dates on roadmap/changelog
 	$g_show_changelog_dates = ON;
 	$g_show_roadmap_dates = ON;
Index: core/print_api.php
===================================================================
--- core/print_api.php	(revision 5305)
+++ core/print_api.php	(working copy)
@@ -137,22 +137,39 @@
 
 	
 	# Print avatar image for the given user ID
-	function print_avatar( $p_user_id, $p_size = 80 ) {
+	function print_avatar( $p_user_id, $p_size = 80, $t_class = "avatar") {
+		$t_avatar_exist = false;
+		
 		if ( !user_exists( $p_user_id ) ) {
 			return;
 		}
 
 		if ( access_has_project_level( config_get( 'show_avatar_threshold' ), null, $p_user_id ) ) {
-			$t_avatar = user_get_avatar( $p_user_id, $p_size );
-			if ( false !== $t_avatar ) {
+			$t_use_gravatar = config_get( 'use_gravatar', false, $p_user_id, ALL_PROJECTS );
+			if ($t_use_gravatar) {
+				$t_avatar = user_get_avatar( $p_user_id, $p_size );
+				if ( false !== $t_avatar ) {
+					$t_avatar_url = $t_avatar[0];
+					$t_width = $t_avatar[1];
+					$t_height = $t_avatar[2];
+					echo '<a rel="nofollow" href="http://site.gravatar.com">' .
+						'<img class="avatar" src="' . $t_avatar_url . '" alt="User avatar"' .
+						' width="' . $t_width . '" height="' . $t_height . '" /></a>';
+				}
+			} else {
+				$t_avatar = user_get_local_avatar( $p_user_id );
 				$t_avatar_url = $t_avatar[0];
 				$t_width = $t_avatar[1];
 				$t_height = $t_avatar[2];
-				echo '<a rel="nofollow" href="http://site.gravatar.com">' .
-					'<img class="avatar" src="' . $t_avatar_url . '" alt="User avatar"' .
-					' width="' . $t_width . '" height="' . $t_height . '" /></a>';
+				$t_avatar_exist = $t_avatar[3];
+
+				if ($t_avatar_exist) {
+					echo '<img class="' . $t_class. '" src="' . $t_avatar_url . '" alt=""' .
+					' width="' . $t_width . '" height="' . $t_height . '" />';
+				}
 			}
 		}
+		return $t_avatar_exist;
 	}
 
 
Index: core/user_api.php
===================================================================
--- core/user_api.php	(revision 5305)
+++ core/user_api.php	(working copy)
@@ -773,7 +773,43 @@
 		return $t_result;
 	}
 
+	/**
+	 * return the local stored user avatar image URL
+	 * @return array|bool an array( URL, width, height ) or false when the given user has no avatar 
+	 */
+	function user_get_local_avatar( $p_user_id ) {
+		$t_avatar_exist = true;
+		$avatar_dir = config_get('directory_avatar');
 
+		# default imagesize
+		$t_height = config_get('avatar_max_height');
+		$t_width = config_get('avatar_max_width');
+
+    $t_username = user_get_field($p_user_id, 'username');
+
+		$t_avatar_url = $avatar_dir . '/' . $t_username . '.gif';
+		if (!file_exists($t_avatar_url)) {
+			$t_avatar_url = $avatar_dir . '/' . $t_username . '.jpg';
+			if (!file_exists($t_avatar_url)) {
+				$t_avatar_exist = false; 
+			}
+		}
+
+		if ($t_avatar_exist) {
+			# get image dimensions
+			list($width_orig, $height_orig) = getimagesize($t_avatar_url);
+			$ratio_orig = $width_orig/$height_orig;
+
+			if ($t_width/$t_height > $ratio_orig) {
+				$t_width = $t_height*$ratio_orig;
+			} else {
+				$t_height = $t_width/$ratio_orig;
+			}
+		}      
+
+		return array( $t_avatar_url, $t_width, $t_height, $t_avatar_exist );
+	}
+
 	# --------------------
 	# return the user's access level
 	#  account for private project and the project user lists
Index: css/default.css
===================================================================
--- css/default.css	(revision 5305)
+++ css/default.css	(working copy)
@@ -161,5 +161,11 @@
 	border: 0;
 }
 
+.manage_avatar
+{
+	float: left;
+	border: 2;
+}
+
 .progress400				{ position: relative; width: 400px; border: 1px solid #d7d7d7; margin-top: 1em; margin-bottom: 1em; padding: 1px; }
 .progress400 .bar			{ display: block; position: relative; background: #6bba70; text-align: center; font-weight: normal; color: #333; height: 2em; line-height: 2em; }
Index: lang/strings_english.txt
===================================================================
--- lang/strings_english.txt	(revision 5305)
+++ lang/strings_english.txt	(working copy)
@@ -1528,4 +1528,9 @@
 #account_view_page.php
 $s_view_account_title = 'User Information';
 
+#avatar
+$s_avatar = 'Avatar';
+$s_use_gravatar = 'Use Gravatar for Avatar';
+$s_upload_avatar = 'Upload Avatar';
+$s_delete_avatar = 'Delete Avatar';
 ?>
Index: lang/strings_german.txt
===================================================================
--- lang/strings_german.txt	(revision 5305)
+++ lang/strings_german.txt	(working copy)
@@ -1485,4 +1485,10 @@
 $s_graph_page = 'Grafische Eintrags-Historie';
 $s_graph_bug_page_link = 'Grafik';
 
+#avatar
+$s_avatar = 'Avatar'; 
+$s_use_gravatar = 'Gravatar für Avatar benutzen';
+$s_upload_avatar = 'Avatar hochladen';
+$s_delete_avatar = 'Avatar löschen';
+
 ?>
Index: manage_user_edit_page.php
===================================================================
--- manage_user_edit_page.php	(revision 5305)
+++ manage_user_edit_page.php	(working copy)
@@ -32,6 +32,8 @@
 
 	$t_user = user_get_row( $f_user_id );
 
+	$t_use_gravatar = config_get( 'use_gravatar', false, $f_user_id, ALL_PROJECTS );
+
 	html_page_top1();
 	html_page_top2();
 
@@ -43,7 +45,7 @@
 
 <!-- USER INFO -->
 <div align="center">
-<form method="post" action="manage_user_update.php">
+<form method="post" action="manage_user_update.php" enctype="multipart/form-data">
 <table class="width75" cellspacing="1">
 <!-- Title -->
 <tr>
@@ -115,6 +117,40 @@
 	</td>
 </tr>
 
+<!-- Avatar -->
+<tr <?php echo helper_alternate_class() ?>>
+	<td class="category">
+		<?php echo lang_get( 'use_gravatar' ) ?>:
+	</td>
+	<td>
+		<input type="checkbox" name="use_gravatar" <?php check_checked( $t_use_gravatar, ON ); ?> />
+	</td>
+</tr>
+<tr <?php echo helper_alternate_class() ?>>
+	<td class="category">
+		<?php echo lang_get( 'avatar' ) ?>:
+	</td>
+	<td>
+		<?php $t_avatar_exist = print_avatar( $t_user['id'], "manage_avatar" ); ?>&nbsp;
+		<?php if ($t_avatar_exist and !config_get( 'use_gravatar', false, $f_user_id, ALL_PROJECTS )) { ?>
+		  <input class="button-small" type="submit" name="delete_avatar" value="<?php echo lang_get( 'delete_avatar' ) ?>" />
+	  <?php } ?>
+	</td>
+</tr>
+<?php 
+	$t_max_file_size = (int) config_get( 'max_avatar_file_size' );
+?>
+<tr <?php echo helper_alternate_class() ?>>
+	<td class="category">
+		<?php echo lang_get( 'upload_avatar' ) ?>
+		<?php echo '<span class="small">(' . lang_get( 'max_file_size' ) . ': ' . number_format( $t_max_file_size/1000 ) . 'k)</span>'?>
+	</td>
+	<td>
+		<input type="hidden" name="max_file_size" value="<?php echo $t_max_file_size ?>" />
+		<input <?php echo helper_get_tab_index() ?> name="avatar_file" type="file" size="60" />
+	</td>
+</tr>
+
 <!-- Submit Button -->
 <tr>
 	<td colspan="2" class="center">
Index: manage_user_page.php
===================================================================
--- manage_user_page.php	(revision 5305)
+++ manage_user_page.php	(working copy)
@@ -275,6 +275,10 @@
 		<?php print_manage_user_sort_link(  'manage_user_page.php', lang_get( 'last_visit' ), 'last_visit', $c_dir, $c_sort, $c_hide, $c_filter ) ?>
 		<?php print_sort_icon( $c_dir, $c_sort, 'last_visit' ) ?>
 	</td>
+	<td>
+		<?php print_manage_user_sort_link(  'manage_user_page.php', lang_get( 'avatar' ), 'avatar', $c_dir, $c_sort, $c_hide ) ?>
+		<?php print_sort_icon( $c_dir, $c_sort, 'avatar' ) ?>
+	</td>
 </tr>
 <?php
 	$t_date_format = config_get( 'normal_date_format' );
@@ -290,6 +294,10 @@
 		if( !isset( $t_access_level[$u_access_level] ) ) {
 			$t_access_level[$u_access_level] = get_enum_element( 'access_levels', $u_access_level );
 		}
+		
+		# has avatar
+		$t_avatar = user_get_local_avatar( $u_id );
+		$has_avatar = $t_avatar[3];		
 ?>
 <tr <?php echo helper_alternate_class( $i ) ?>>
 	<td>
@@ -310,6 +318,14 @@
         </td>
 	<td><?php echo $u_date_created ?></td>
 	<td><?php echo $u_last_visit ?></td>
+	<td><?php 
+		if (config_get("show_avatar_in_manage_user_list")) {
+			print_avatar( $u_id , null, $t_class = "manage_avatar");
+		} else {
+			echo trans_bool( $has_avatar ); 
+		}
+		?>
+	</td>	
 </tr>
 <?php
 	}  # end for
Index: manage_user_update.php
===================================================================
--- manage_user_update.php	(revision 5305)
+++ manage_user_update.php	(working copy)
@@ -40,7 +40,8 @@
 	$f_realname		= gpc_get_string( 'realname', '' );
 	$f_access_level	= gpc_get_int( 'access_level' );
 	$f_user_id		= gpc_get_int( 'user_id' );
-
+	$f_use_gravatar	= gpc_get_bool( 'use_gravatar' );
+	
 	user_ensure_exists( $f_user_id );
 
 	$f_email	= trim( $f_email );
@@ -107,6 +108,32 @@
 	}
 
 	$result = db_query_bound( $query, $query_params );
+	
+	# store use_avatar in config
+	config_set('use_gravatar', $f_use_gravatar, $c_user_id, ALL_PROJECTS);
+
+	# upload avatar
+	$target_path = config_get('directory_avatar') . '/';
+	$ext = end(explode('.', $_FILES['avatar_file']['name'])); 
+	$target_file = $target_path . $c_username . '.' . $ext; 
+	move_uploaded_file($_FILES['avatar_file']['tmp_name'], $target_file);
+
+	# delete avatar
+	$f_delete_avatar	= gpc_get_string( 'delete_avatar', '' );
+	if ($f_delete_avatar != '') {
+		$avatar_file = $target_path . '/' . $c_username . '.gif';
+		$fh = fopen($avatar_file, 'w') or die("can't open file");
+		fclose($fh);
+
+		unlink($avatar_file);
+
+		$avatar_file = $target_path . '/' . $c_username . '.jpg';
+		$fh = fopen($avatar_file, 'w') or die("can't open file");
+		fclose($fh);
+
+		unlink($avatar_file);
+	}
+	
 	$t_redirect_url = 'manage_user_edit_page.php?user_id=' . $c_user_id;
 ?>
 <?php html_page_top1() ?>
local_avatar.patch (13,966 bytes)   
file_avatar_mthibeault.diff (21,649 bytes)   
diff -N -a --unified -r mantisbt/account_page.php mantisbt-file_avatar/account_page.php
--- mantisbt/account_page.php	2008-11-30 14:16:41.000000000 -0500
+++ mantisbt-file_avatar/account_page.php	2008-12-01 11:43:10.032455300 -0500
@@ -50,6 +50,9 @@
 	$t_core_path = config_get( 'core_path' );
 
 	require_once( $t_core_path.'current_user_api.php' );
+	require_once( $t_core_path.'avatar_api.php' );
+	
+	$t_use_gravatar = config_get( 'use_gravatar', false, auth_get_current_user_id(), ALL_PROJECTS );
 
 	#============ Parameters ============
 	# (none)
@@ -94,7 +97,7 @@
 <br />
 <?php } ?>
 <div align="center">
-<form method="post" action="account_update.php">
+<form method="post" action="account_update.php" enctype="multipart/form-data">
 <?php  echo form_security_field( 'account_update' )?>
 <?php if ( isset( $g_session_pass_id ) ) { ?>
 <input type="hidden" name="session_id" value="<?php echo session_id() ?>"/>
@@ -209,6 +212,40 @@
 		</td>
 	</tr>
 
+	<!-- Avatar -->
+ 	<tr <?php echo helper_alternate_class() ?>>
+		<td class="category">
+			<?php echo lang_get( 'use_gravatar' ) ?>:
+		</td>
+		<td>
+			<input type="checkbox" name="use_gravatar" <?php check_checked( $t_use_gravatar, ON ); ?> />
+		</td>
+	</tr>
+	<tr <?php echo helper_alternate_class() ?> >
+		<td class="category">
+			<?php echo lang_get( 'avatar' ) ?>:
+		</td>
+		<td>
+			<?php $t_avatar_exist = avatar_print( $u_id, null, "manage_avatar" ); echo NBSP; ?>
+			<?php if ($t_avatar_exist and !config_get( 'use_gravatar', false, $u_id, ALL_PROJECTS )) { ?>
+		  	<input class="button-small" type="submit" name="delete_avatar" value="<?php echo lang_get( 'delete_avatar' ) ?>" />
+	  	<?php } ?>
+		</td>
+	</tr>
+<?php 
+	$t_max_file_size = (int) config_get( 'max_avatar_file_size' );
+?>
+	<tr <?php echo helper_alternate_class() ?> >
+		<td class="category">
+			<?php echo lang_get( 'upload_avatar' ) ?>
+			<?php echo '<span class="small">(' . lang_get( 'max_file_size' ) . ': ' . number_format( $t_max_file_size/1000 ) . 'k)</span>'?>
+		</td>
+		<td>
+			<input type="hidden" name="max_file_size" value="<?php echo $t_max_file_size ?>" />
+			<input <?php echo helper_get_tab_index() ?> name="avatar_file" type="file" size="60" />
+		</td>
+	</tr>
+
 	<!-- Access level -->
 	<tr <?php echo helper_alternate_class() ?>>
 		<td class="category">
diff -N -a --unified -r mantisbt/account_update.php mantisbt-file_avatar/account_update.php
--- mantisbt/account_update.php	2008-11-30 14:16:41.000000000 -0500
+++ mantisbt-file_avatar/account_update.php	2008-12-01 11:44:17.262957600 -0500
@@ -32,6 +32,7 @@
 	$t_core_path = config_get( 'core_path' );
 
 	require_once( $t_core_path.'email_api.php' );
+	require_once( $t_core_path.'avatar_api.php' );
 
 	form_security_validate('account_update');
 
@@ -43,6 +44,7 @@
 	$f_realname        	= gpc_get_string( 'realname', '' );
 	$f_password        	= gpc_get_string( 'password', '' );
 	$f_password_confirm	= gpc_get_string( 'password_confirm', '' );
+	$f_use_gravatar	    = gpc_get_bool( 'use_gravatar' );
 
 	$f_email = email_append_domain( $f_email );
 
@@ -57,6 +59,7 @@
 	$t_email_updated = false;
 	$t_password_updated = false;
 	$t_realname_updated = false;
+	$t_avatar_updated = false;
 
 	# @@@ Listing what fields were updated is not standard behaviour of Mantis
 	#     it also complicates the code.
@@ -88,6 +91,24 @@
 		}
 	}
 
+	# avatar
+	$t_username = user_get_field( $t_user_id, 'username' );
+	# store use_avatar in config
+	if( config_get('use_gravatar', false) != $f_use_gravatar )
+		$t_avatar_updated = true;
+
+	config_set('use_gravatar', $f_use_gravatar, $t_user_id, ALL_PROJECTS);
+
+	$f_delete_avatar = gpc_get_string( 'delete_avatar', '' );
+	if( is_blank( $f_delete_avatar ) ) {
+		if( isset( $_FILES['avatar_file'] ) && !is_blank($_FILES['avatar_file']['name']) ) {
+			avatar_upload( $t_username, $_FILES['avatar_file']['name'], $_FILES['avatar_file']['tmp_name'] );
+			$t_avatar_updated = true;
+		}
+	} else {
+		avatar_delete( $t_username );
+	}
+
 	form_security_purge('account_update');
 
 	html_page_top1();
@@ -107,6 +128,10 @@
 	if ( $t_realname_updated ) {
 		echo lang_get( 'realname_updated' ) . '<br />';
 	}
+	
+	if ( $t_avatar_updated ) {
+		echo lang_get( 'avatar_updated' ) . '<br />';
+	}
 
 	echo lang_get( 'operation_successful' ) . '<br />';
 	print_bracket_link( $t_redirect, lang_get( 'proceed' ) );
diff -N -a --unified -r mantisbt/bugnote_view_inc.php mantisbt-file_avatar/bugnote_view_inc.php
--- mantisbt/bugnote_view_inc.php	2008-11-30 14:16:41.000000000 -0500
+++ mantisbt-file_avatar/bugnote_view_inc.php	2008-12-01 11:45:55.851028600 -0500
@@ -30,6 +30,7 @@
  * Requires bugnote API
  */
 require_once( $t_core_path.'current_user_api.php' );
+require_once( $t_core_path.'avatar_api.php' );
 
 # grab the user id currently logged in
 $t_user_id = auth_get_current_user_id();
@@ -113,7 +114,7 @@
 ?>
 <tr class="bugnote" id="c<?php echo $t_bugnote->id ?>">
         <td class="<?php echo $t_bugnote_css ?>">
-		<?php if ( ON  == config_get("show_avatar") ) print_avatar( $t_bugnote->reporter_id ); ?>
+		<?php if ( ON  == config_get("show_avatar") ) avatar_print( $t_bugnote->reporter_id ); ?>
 		<span class="small">(<?php echo $t_bugnote_id_formatted ?>)</span><br />
 		<?php
 			echo print_user( $t_bugnote->reporter_id );
@@ -121,7 +122,11 @@
 		<span class="small"><?php
 			if ( user_exists( $t_bugnote->reporter_id ) ) {
 				$t_access_level = access_get_project_level( null, (int)$t_bugnote->reporter_id );
-				echo '(', get_enum_element( 'access_levels', $t_access_level ), ')';
+				if( $t_access_level == ANYBODY ) {
+					echo '(no access)';
+				} else {
+					echo '(', get_enum_element( 'access_levels', $t_access_level ), ')';
+				}
 			} 
 		?></span>
 		<?php if ( VS_PRIVATE == $t_bugnote->view_state ) { ?>
diff -N -a --unified -r mantisbt/config_defaults_inc.php mantisbt-file_avatar/config_defaults_inc.php
--- mantisbt/config_defaults_inc.php	2008-11-30 14:16:41.000000000 -0500
+++ mantisbt-file_avatar/config_defaults_inc.php	2008-12-01 12:00:05.739572200 -0500
@@ -635,8 +635,19 @@
 	# Only users above this threshold will have their avatar shown
 	$g_show_avatar_threshold = DEVELOPER;
 
-	# Default avatar for users without a gravatar account
-	$g_default_avatar = "%path%images/no_avatar.png";
+	# local directory to store avatar
+	$g_directory_avatar = 'avatar';
+
+        # Default avatar for users without a gravatar account
+	$g_default_avatar = "images/no_avatar.png";
+	
+	$g_avatar_max_width = 96;
+	$g_avatar_max_height = 96;
+
+	$g_max_avatar_file_size = 1048576; // 1 MB, will be resized anyway.
+	
+	# Show avatar in manage_user_list
+	$g_show_avatar_in_manage_user_list = OFF;
 
 	# Show release dates on roadmap/changelog
 	$g_show_changelog_dates = ON;
diff -N -a --unified -r mantisbt/core/avatar_api.php mantisbt-file_avatar/core/avatar_api.php
--- mantisbt/core/avatar_api.php	1969-12-31 19:00:00.000000000 -0500
+++ mantisbt-file_avatar/core/avatar_api.php	2008-12-01 12:02:45.355377800 -0500
@@ -0,0 +1,115 @@
+<?php
+	function avatar_upload( $p_username, $p_name, $p_filename )
+	{
+		global $g_avatar_max_width, $g_avatar_max_height;
+		$target_path = config_get('directory_avatar') . '/';
+		
+		# upload avatar
+		$avatar_file_name = $p_name;
+		$ext = end(explode('.', $p_name));
+		$target_file = $target_path . $p_username . '.png';
+		if( get_imagick_version() != 0 ) {
+			$t_avatar_image = new Imagick($p_filename);
+			$t_avatar_image->thumbnailImage( $g_avatar_max_width, 0 ); // 0 to keep aspect ratio.
+			$t_avatar_image->borderImage( new ImagickPixel("black"), 1, 1 );
+			$t_avatar_image->setImageFormat("png");
+			$t_avatar_image->writeImage( $target_file );
+		}
+		else if( get_gd_version() != 0 )
+		{
+			$ext = end(explode('.', $p_name)); 
+			$t_image = gd_open_image($p_filename, '.' . $ext);
+			if( $t_image === false ) {
+				trigger_error( "Bad image file." );
+			}
+
+			// Get original width and height
+			$t_width = imagesx($t_image);
+			$t_height = imagesy($t_image);
+			
+			// New width and height
+			$t_new_width = $g_avatar_max_width;
+			$t_new_height = $g_avatar_max_height;
+
+			// Resample
+			if( $t_width > $t_height ) {
+				$t_new_height = $t_height * ($t_new_width/$t_width);
+			} else {
+				$t_new_width = $t_width * ($t_new_height/$t_height);
+			}
+
+			$image_resized = imagecreatetruecolor($t_new_width, $t_new_height);
+			imagecopyresampled($image_resized, $t_image, 0, 0, 0, 0, $t_new_width, $t_new_height, $t_width, $t_height);
+			
+			imagepng( $image_resized, $target_file );
+		} else
+			move_uploaded_file($p_filename, $target_file);
+	}
+	
+	function avatar_delete( $p_username )
+	{
+		$target_path = config_get('directory_avatar') . '/';
+		
+		# delete avatar
+		$avatar_file = $target_path . '/' . $p_username . '.gif';
+		$fh = fopen($avatar_file, 'w') or die("can't open file");
+		fclose($fh);
+		
+		unlink($avatar_file);
+
+		$avatar_file = $target_path . '/' . $p_username . '.jpg';
+		$fh = fopen($avatar_file, 'w') or die("can't open file");
+		fclose($fh);
+
+		unlink($avatar_file);
+		
+		$avatar_file = $target_path . '/' . $p_username . '.png';
+		$fh = fopen($avatar_file, 'w') or die("can't open file");
+		fclose($fh);
+
+		unlink($avatar_file);
+	}
+	
+	# Print avatar image for the given user ID
+	function avatar_print( $p_user_id, $p_size = 80, $t_class = "avatar" ) {
+		global $g_default_avatar;
+		
+		$t_avatar_exist = false;
+		if ( !user_exists( $p_user_id ) ) {
+			return false;
+		}
+
+		if ( access_has_project_level( config_get( 'show_avatar_threshold' ), null ) ) {
+			$t_use_gravatar = config_get( 'use_gravatar', false, $p_user_id, ALL_PROJECTS );
+			if ($t_use_gravatar) {
+				$t_avatar = user_get_avatar( $p_user_id, $p_size );
+				if ( false !== $t_avatar ) {
+					$t_avatar_url = $t_avatar[0];
+					$t_width = $t_avatar[1];
+					$t_height = $t_avatar[2];
+					echo '<a rel="nofollow" href="http://site.gravatar.com">' .
+						'<img class="avatar" src="' . $t_avatar_url . '" alt="User avatar"' .
+						' width="' . $t_width . '" height="' . $t_height . '" /></a>';
+				}
+			} else {
+				$t_avatar = user_get_local_avatar( $p_user_id );
+				$t_avatar_url = $t_avatar[0];
+				$t_width = $t_avatar[1];
+				$t_height = $t_avatar[2];
+					
+				$t_avatar_exist = $t_avatar[3];
+
+				if ($t_avatar_exist) {
+					echo '<img class="' . $t_class. '" src="' . $t_avatar_url . '" alt="User avatar"' .
+					' width="' . $t_width . '" height="' . $t_height . '" />';
+				}
+				else {
+					if( $t_class == "avatar" ) {
+						echo '<img class="' . $t_class . '" src="' . $g_default_avatar . '" alt="User avatar"' .
+						' width=" ' . $t_width . '" height="' . $t_height . '" />';
+					}
+				}
+			}
+		}
+		return $t_avatar_exist;
+	}
diff -N -a --unified -r mantisbt/core/custom_field_api.php mantisbt-file_avatar/core/custom_field_api.php
--- mantisbt/core/custom_field_api.php	2008-11-30 14:16:41.000000000 -0500
+++ mantisbt-file_avatar/core/custom_field_api.php	2008-12-01 11:51:50.205616600 -0500
@@ -716,7 +716,6 @@
 	db_query_bound( $query, Array( $c_field_id ) );
 
 	$t_custom_field_table = db_get_table( 'mantis_custom_field_table' );
-
 	# delete the definition
 	$query = "DELETE FROM $t_custom_field_table
 				  WHERE id=";
diff -N -a --unified -r mantisbt/core/user_api.php mantisbt-file_avatar/core/user_api.php
--- mantisbt/core/user_api.php	2008-11-30 14:16:41.000000000 -0500
+++ mantisbt-file_avatar/core/user_api.php	2008-12-01 11:53:45.558346900 -0500
@@ -769,13 +769,15 @@
 * in this first implementation, only gravatar.com avatars are supported
 * @return array|bool an array( URL, width, height ) or false when the given user has no avatar
 */
-function user_get_avatar( $p_user_id, $p_size = 80 ) {
+function user_get_avatar( $p_user_id ) {
+	global $g_avatar_max_width, $g_avatar_max_height;
+
 	$t_email = strtolower( user_get_email( $p_user_id ) );
 	if( is_blank( $t_email ) ) {
 		$t_result = false;
 	} else {
 		$t_default_image = config_get( 'default_avatar' );
-		$t_size = $p_size;
+		$t_size = $g_avatar_max_width;
 
 		$t_use_ssl = false;
 		if( isset( $_SERVER['HTTPS'] ) && ( strtolower( $_SERVER['HTTPS'] ) != 'off' ) ) {
@@ -799,6 +801,46 @@
 	return $t_result;
 }
 
+/**
+ * return the local stored user avatar image URL
+ * @return array|bool an array( URL, width, height ) or false when the given user has no avatar 
+ */
+function user_get_local_avatar( $p_user_id ) {
+	$t_avatar_exist = true;
+	$avatar_dir = config_get('directory_avatar');
+
+	# default imagesize
+	$t_height = config_get('avatar_max_height');
+	$t_width = config_get('avatar_max_width');
+
+	$t_username = user_get_field($p_user_id, 'username');
+
+	$t_avatar_url = $avatar_dir . '/' . $t_username . '.png'; // mthibeault: Using DIRECTORY_SEPARATOR was not accepted by Firefox
+	if (!file_exists($t_avatar_url)) {
+		$t_avatar_url = $avatar_dir . '/' . $t_username . '.gif';
+		if (!file_exists($t_avatar_url)) {
+			$t_avatar_url = $avatar_dir . '/' . $t_username . '.jpg';
+			if (!file_exists($t_avatar_url)) {
+				$t_avatar_exist = false; 
+			}
+		}
+	}
+
+	if ($t_avatar_exist) {
+		# get image dimensions
+		list($width_orig, $height_orig) = getimagesize($t_avatar_url);
+		$ratio_orig = $width_orig/$height_orig;
+
+		if ($t_width/$t_height > $ratio_orig) {
+			$t_width = $t_height*$ratio_orig;
+		} else {
+			$t_height = $t_width/$ratio_orig;
+		}
+	}      
+
+	return array( $t_avatar_url, $t_width, $t_height, $t_avatar_exist );
+}
+
 # --------------------
 # return the user's access level
 #  account for private project and the project user lists
diff -N -a --unified -r mantisbt/core/utility_api.php mantisbt-file_avatar/core/utility_api.php
--- mantisbt/core/utility_api.php	2008-11-30 14:16:41.000000000 -0500
+++ mantisbt-file_avatar/core/utility_api.php	2008-12-01 11:54:06.275903500 -0500
@@ -236,6 +236,46 @@
 	}
 }
 
+function gd_open_image ($file, $extension='') {
+    // Get extension
+	if( is_blank( $extension ) ) {
+		$extension = strrchr($file, '.');
+	}
+	$extension = strtolower($extension);
+    switch($extension) {
+            case '.jpg':
+            case '.jpeg':
+                    $im = @imagecreatefromjpeg($file);
+                    break;
+            case '.gif':
+                    $im = @imagecreatefromgif($file);
+					break;
+			case '.png':
+					$im = @imagecreatefrompng($file);
+                    break;
+
+            // ... etc
+
+            default:
+                    $im = false;
+                    break;
+    }
+
+    return $im;
+}
+
+
+# Return Imagick version
+function get_imagick_version()
+{
+	$t_ImagickfuncList = get_extension_funcs('imagick');
+	if( ! is_array( $t_ImagickfuncList ) ) {
+		return 0;
+	} else {
+		return 1;
+	}
+}
+
 /**
  * return true or false if string matches current page name 
  * @param string $p_string page name
diff -N -a --unified -r mantisbt/css/default.css mantisbt-file_avatar/css/default.css
--- mantisbt/css/default.css	2008-11-30 14:16:41.000000000 -0500
+++ mantisbt-file_avatar/css/default.css	2008-12-01 11:54:30.821364600 -0500
@@ -175,5 +175,11 @@
 	border: 0;
 }
 
+.manage_avatar
+{
+	float: left;
+	border: 2;
+}
+
 .progress400				{ position: relative; width: 400px; border: 1px solid #d7d7d7; margin-top: 1em; margin-bottom: 1em; padding: 1px; }
 .progress400 .bar			{ display: block; position: relative; background: #6bba70; text-align: center; font-weight: normal; color: #333; height: 2em; line-height: 2em; }
diff -N -a --unified -r mantisbt/lang/strings_english.txt mantisbt-file_avatar/lang/strings_english.txt
--- mantisbt/lang/strings_english.txt	2008-11-30 14:16:41.000000000 -0500
+++ mantisbt-file_avatar/lang/strings_english.txt	2008-12-01 11:55:07.506751400 -0500
@@ -532,6 +532,7 @@
 $s_realname_duplicated = 'Real name is used by another user';
 $s_realname_updated = 'Real name successfully updated';
 $s_password_updated = 'Password successfully updated';
+$s_avatar_updated = 'Avatar successfully updated. You may need to refresh the next page to see the new avatar.';
 
 # adm_permission_report.php
 
@@ -1558,4 +1559,9 @@
 $s_view_account_title = 'User Information';
 
 # view_user_page.php
-$s_manage_user = 'Manage User';
\ No newline at end of file
+$s_manage_user = 'Manage User';
+
+$s_avatar = 'Avatar';
+$s_use_gravatar = 'Use Gravatar for Avatar';
+$s_upload_avatar = 'Upload Avatar';
+$s_delete_avatar = 'Delete Avatar';
diff -N -a --unified -r mantisbt/manage_user_edit_page.php mantisbt-file_avatar/manage_user_edit_page.php
--- mantisbt/manage_user_edit_page.php	2008-11-30 14:16:41.000000000 -0500
+++ mantisbt-file_avatar/manage_user_edit_page.php	2008-12-01 11:48:13.905576200 -0500
@@ -24,7 +24,8 @@
 	  * Mantis Core API's
 	  */
 	require_once( 'core.php' );
-
+	require_once( $t_core_path.'avatar_api.php' );
+	
 	auth_reauthenticate();
 
 	access_ensure_global_level( config_get( 'manage_user_threshold' ) );
@@ -44,6 +45,8 @@
 
 	$t_user = user_get_row( $t_user_id );
 
+	$t_use_gravatar = config_get( 'use_gravatar', false, $f_user_id, ALL_PROJECTS );
+	
 	html_page_top1();
 	html_page_top2();
 
@@ -55,7 +58,7 @@
 
 <!-- USER INFO -->
 <div align="center">
-<form method="post" action="manage_user_update.php">
+<form method="post" action="manage_user_update.php" enctype="multipart/form-data">
 <?php echo form_security_field( 'manage_user_update' ) ?>
 <table class="width75" cellspacing="1">
 <!-- Title -->
@@ -127,6 +130,39 @@
 		<input type="checkbox" name="protected" <?php check_checked( $t_user['protected'], ON ); ?> />
 	</td>
 </tr>
+<!-- Avatar -->
+<tr <?php echo helper_alternate_class() ?>>
+	<td class="category">
+		<?php echo lang_get( 'use_gravatar' ) ?>:
+	</td>
+	<td>
+		<input type="checkbox" name="use_gravatar" <?php check_checked( $t_use_gravatar, ON ); ?> />
+	</td>
+</tr>
+<tr <?php echo helper_alternate_class() ?>>
+	<td class="category">
+		<?php echo lang_get( 'avatar' ) ?>:
+	</td>
+	<td>
+		<?php $t_avatar_exist = avatar_print( $t_user['id'], null, "manage_avatar" ); ?>&nbsp;
+		<?php if ($t_avatar_exist and !config_get( 'use_gravatar', false, $f_user_id, ALL_PROJECTS )) { ?>
+		  <input class="button-small" type="submit" name="delete_avatar" value="<?php echo lang_get( 'delete_avatar' ) ?>" />
+	  <?php } ?>
+	</td>
+</tr>
+<?php 
+	$t_max_file_size = (int) config_get( 'max_avatar_file_size' );
+?>
+<tr <?php echo helper_alternate_class() ?>>
+	<td class="category">
+		<?php echo lang_get( 'upload_avatar' ) ?>
+		<?php echo '<span class="small">(' . lang_get( 'max_file_size' ) . ': ' . number_format( $t_max_file_size/1000 ) . 'k)</span>'?>
+	</td>
+	<td>
+		<input type="hidden" name="max_file_size" value="<?php echo $t_max_file_size ?>" />
+		<input <?php echo helper_get_tab_index() ?> name="avatar_file" type="file" size="60" />
+	</td>
+</tr>
 
 <!-- Submit Button -->
 <tr>
diff -N -a --unified -r mantisbt/manage_user_page.php mantisbt-file_avatar/manage_user_page.php
--- mantisbt/manage_user_page.php	2008-11-30 14:16:41.000000000 -0500
+++ mantisbt-file_avatar/manage_user_page.php	2008-12-01 11:49:27.463839000 -0500
@@ -28,6 +28,7 @@
 	$t_core_path = config_get( 'core_path' );
 
 	require_once( $t_core_path . 'icon_api.php' );
+	require_once( $t_core_path . 'avatar_api.php' );
 
 	auth_reauthenticate();
 
@@ -277,6 +278,10 @@
 		<?php print_manage_user_sort_link(  'manage_user_page.php', lang_get( 'last_visit' ), 'last_visit', $c_dir, $c_sort, $c_hide, $c_filter ) ?>
 		<?php print_sort_icon( $c_dir, $c_sort, 'last_visit' ) ?>
 	</td>
+	<td>
+		<?php print_manage_user_sort_link(  'manage_user_page.php', lang_get( 'avatar' ), 'avatar', $c_dir, $c_sort, $c_hide ) ?>
+		<?php print_sort_icon( $c_dir, $c_sort, 'avatar' ) ?>
+	</td>
 </tr>
 <?php
 	$t_date_format = config_get( 'normal_date_format' );
@@ -292,6 +297,10 @@
 		if( !isset( $t_access_level[$u_access_level] ) ) {
 			$t_access_level[$u_access_level] = get_enum_element( 'access_levels', $u_access_level );
 		}
+
+		# has avatar
+		$t_avatar = user_get_local_avatar( $u_id );
+		$has_avatar = $t_avatar[3];
 ?>
 <tr <?php echo helper_alternate_class( $i ) ?>>
 	<td>
@@ -312,6 +321,14 @@
         </td>
 	<td><?php echo $u_date_created ?></td>
 	<td><?php echo $u_last_visit ?></td>
+	<td class="center"><?php 
+		if (config_get("show_avatar_in_manage_user_list")) {
+			avatar_print( $u_id , null, "manage_avatar");
+		} else {
+			echo trans_bool( $has_avatar ); 
+		}
+		?>
+	</td>
 </tr>
 <?php
 	}  # end for
diff -N -a --unified -r mantisbt/manage_user_update.php mantisbt-file_avatar/manage_user_update.php
--- mantisbt/manage_user_update.php	2008-11-30 14:16:41.000000000 -0500
+++ mantisbt-file_avatar/manage_user_update.php	2008-12-01 11:49:59.133889700 -0500
@@ -42,6 +42,8 @@
 	$f_access_level	= gpc_get_int( 'access_level' );
 	$f_user_id		= gpc_get_int( 'user_id' );
 
+	$f_use_gravatar	= gpc_get_bool( 'use_gravatar' );
+	
 	user_ensure_exists( $f_user_id );
 
 	$f_email	= trim( $f_email );
@@ -111,6 +113,17 @@
 	}
 
 	$result = db_query_bound( $query, $query_params );
+
+	# store use_avatar in config
+	config_set('use_gravatar', $f_use_gravatar, $c_user_id, ALL_PROJECTS);
+
+	$f_delete_avatar = gpc_get_string( 'delete_avatar', '' );
+	if( is_blank( $f_delete_avatar ) ) {
+		if( isset( $_FILES['avatar_file'] ) && !is_blank($_FILES['avatar_file']['name']) )
+			avatar_upload( $t_username, $_FILES['avatar_file']['name'], $_FILES['avatar_file']['tmp_name'] );
+	} else {
+		avatar_delete( $t_username );
+	}
 	$t_redirect_url = 'manage_user_edit_page.php?user_id=' . $c_user_id;
 
 	form_security_purge('manage_user_update');
file_avatar_mthibeault.diff (21,649 bytes)   
local_avatar_another_take.diff (15,693 bytes)   
diff --git account_prefs_inc.php account_prefs_inc.php
index fa05b13..b975cf0 100644
--- account_prefs_inc.php
+++ account_prefs_inc.php
@@ -304,10 +304,61 @@
 </tr>
 </table>
 </form>
-</div>
 
 <br />
 
+<?php
+	if ( access_has_global_level ( config_get( 'show_avatar_threshold'), $p_user_id ) ) {
+		collapse_open( 'upload_form' );
+?>
+<form method="post" enctype="multipart/form-data" action="account_prefs_avatar_add.php">
+<table class="width75" cellspacing="1">
+<tr>
+	<td class="form-title">
+<?php
+		collapse_icon( 'upload_form' );
+		echo lang_get( 'upload_avatar' ) ?>
+	</td>
+	<td>
+		<?php print_avatar ( $p_user_id ); ?>
+	</td>
+</tr>
+<tr class="row-1">
+	<td class="category" width="15%">
+		<?php echo lang_get( 'select_file' ) ?><br />
+		<?php echo '<span class="small">(' . lang_get( 'max_file_size' ) . ': ' . number_format( $t_max_file_size/1000 ) . 'k)</span>'?>
+	</td>
+	<td width="85%">
+		<input type="hidden" name="avatar_id" value="<?php echo $p_user_id ?>" />
+		<input type="hidden" name="max_file_size" value="<?php echo $t_max_file_size ?>" />
+		<input name="file" type="file" size="40" />
+		<input type="submit" class="button" value="<?php echo lang_get( 'upload_file_button' ) ?>" />
+	</td>
+</tr>
+</table>
+</form>
+<?php
+	collapse_closed( 'upload_form' );
+?>
+<table class="width75" cellspacing="1">
+<tr>
+	<td class="form-title">
+		<?php
+			collapse_icon( 'upload_form' );
+			echo lang_get( 'upload_avatar' ) ?>
+	</td>
+	<td>
+		<?php print_avatar ( $p_user_id ); ?>
+	</td>
+</tr>
+</table>
+
+<?php
+		collapse_end( 'upload_form' );
+	}
+?>
+</div>
+
 <div class="border-center">
 	<form method="post" action="account_prefs_reset.php">
 	<input type="hidden" name="user_id" value="<?php echo $p_user_id ?>" />
diff --git core/file_api.php core/file_api.php
index 5bcc0a7..0ea495e 100644
--- core/file_api.php
+++ core/file_api.php
@@ -282,19 +282,18 @@ document.getElementById( span ).style.display = displayType;
 			}
 		}
 	}
-	# --------------------
-	# delete all files that are associated with the given bug
-	function file_delete_attachments( $p_bug_id ) {
-		$c_bug_id = db_prepare_int( $p_bug_id );
 
-		$t_bug_file_table = config_get( 'mantis_bug_file_table' );
+	function file_delete_many( $p_item_id, $p_item_type ) {
+		$c_item_id = db_prepare_int( $p_item_id );
+
+		$t_item_file_table = config_get( 'mantis_'.$p_item_type.'_file_table' );
 
 		$t_method = config_get( 'file_upload_method' );
 
 		# Delete files from disk
 		$query = "SELECT diskfile, filename
-				FROM $t_bug_file_table
-				WHERE bug_id='$c_bug_id'";
+				FROM $t_item_file_table
+				WHERE ".$p_item_type."_id='$c_item_id'";
 		$result = db_query( $query );
 
 		$file_count = db_num_rows( $result );
@@ -302,6 +301,20 @@ document.getElementById( span ).style.display = displayType;
 			return true;
 		}
 
+		/*
+		 *  the part below could be replaced by
+		 *  
+		 * 	for ( $i = 0 ; $i < $file_count ; $i++ ) {
+		 *		$row = db_fetch_array( $result );
+		 *		file_delete ( $row['id'], $p_item_type );
+		 * 	}
+		 *  
+		 *  but that would result in quite a lot of queries
+		 *  and ftp connections etc. on the other hand the
+		 *  history would be updated and the operation would
+		 *  be somewhat more fine grained
+		 */
+		
 		if ( ( DISK == $t_method ) || ( FTP == $t_method ) ) {
 			# there may be more than one file
 			$ftp = 0;
@@ -325,52 +338,26 @@ document.getElementById( span ).style.display = displayType;
 		}
 
 		# Delete the corresponding db records
-		$query = "DELETE FROM $t_bug_file_table
-				  WHERE bug_id='$c_bug_id'";
+		$query = "DELETE FROM $t_item_file_table
+				  WHERE ".$p_item_type."_id='$c_item_id'";
 		$result = db_query( $query );
 
 		# db_query() errors on failure so:
 		return true;
 	}
+	
+	# --------------------
+	# delete all files that are associated with the given bug
+	function file_delete_attachments( $p_bug_id ) {
+		return file_delete_many ( $p_bug_id, 'bug' );
+	}
 	# --------------------
 	function file_delete_project_files( $p_project_id ) {
-		$t_project_file_table	= config_get( 'mantis_project_file_table' );
-		$t_method				= config_get( 'file_upload_method' );
-
-		# Delete the file physically (if stored via DISK or FTP)
-		if ( ( DISK == $t_method ) || ( FTP == $t_method ) ) {
-			# Delete files from disk
-			$query = "SELECT diskfile, filename
-					FROM $t_project_file_table
-					WHERE project_id=$p_project_id";
-			$result = db_query( $query );
-
-			$file_count = db_num_rows( $result );
-
-			$ftp = 0;
-			if ( FTP == $t_method ) {
-				$ftp = file_ftp_connect();
-			}
-
-			for ( $i = 0 ; $i < $file_count ; $i++ ) {
-				$row = db_fetch_array( $result );
-
-				file_delete_local ( $row['diskfile'] );
-
-				if ( FTP == $t_method ) {
-					file_ftp_delete ( $ftp, $row['diskfile'] );
-				}
-			}
-
-			if ( FTP == $t_method ) {
-				file_ftp_disconnect( $ftp );
-			}
-		}
-
-		# Delete the corresponding db records
-		$query = "DELETE FROM $t_project_file_table
-				WHERE project_id=$p_project_id";
-		$result = db_query($query);
+		return file_delete_many ( $p_project_id, 'project' );
+	}
+	# --------------------
+	function file_delete_avatar_files( $p_avatar_id ) {
+		return file_delete_many ( $p_avatar_id, 'avatar' );
 	}
 	# --------------------
 	# Delete all cached files that are older than configured number of days.
@@ -550,15 +537,15 @@ document.getElementById( span ).style.display = displayType;
 
 	# --------------------
 	# Return true if the file name identifier is unique, false otherwise
-	function file_is_name_unique( $p_name, $p_bug_id ) {
-		$t_file_table = config_get( 'mantis_bug_file_table' );
+	function file_is_name_unique( $p_name, $p_item_id, $p_item_type ) {
+		$t_file_table = config_get( 'mantis_'.$p_item_type.'_file_table' );
 
 		$c_name = db_prepare_string( $p_name );
-		$c_bug = db_prepare_string( $p_bug_id );
+		$c_item = db_prepare_string( $p_item_id );
 
 		$query = "SELECT COUNT(*)
 				  FROM $t_file_table
-				  WHERE filename='$c_name' and bug_id=$c_bug";
+				  WHERE filename='$c_name' and ".$p_item_type."_id=$c_item";
 		$result = db_query( $query );
 		$t_count = db_result( $result );
 
@@ -598,24 +585,27 @@ document.getElementById( span ).style.display = displayType;
 			trigger_error( ERROR_FILE_NOT_ALLOWED, ERROR );
 		}
 
-		if ( !file_is_name_unique( $p_file_name, $p_bug_id ) ) {
+		if ( !file_is_name_unique( $p_file_name, $p_bug_id, $p_table ) ) {
 			trigger_error( ERROR_DUPLICATE_FILE, ERROR );
 		}
-
+		
+		$t_project_id	= helper_get_current_project();
+		$t_bug_id		= 0;
 		if ( 'bug' == $p_table ) {
 			$t_project_id	= bug_get_field( $p_bug_id, 'project_id' );
 			$t_bug_id		= bug_format_id( $p_bug_id );
-		} else {
-			$t_project_id	= helper_get_current_project();
-			$t_bug_id		= 0;
+		} else if ( 'avatar' == $p_table ) {
+			$t_user_id = auth_get_current_user_id ();
+			$t_bug_id  = 0; 
 		}
-
+		
 		# prepare variables for insertion
 		$c_bug_id		= db_prepare_int( $p_bug_id );
-		$c_project_id		= db_prepare_int( $t_project_id );
+		$c_project_id	= db_prepare_int( $t_project_id );
+		$c_user_id		= db_prepare_int( $t_user_id );
 		$c_file_type	= db_prepare_string( $p_file_type );
-		$c_title = db_prepare_string( $p_title );
-		$c_desc = db_prepare_string( $p_desc );
+		$c_title 		= db_prepare_string( $p_title );
+		$c_desc 		= db_prepare_string( $p_desc );
 
 		if( $t_project_id == ALL_PROJECTS ) {
 			$t_file_path = config_get( 'absolute_path_default_upload_folder' );
@@ -629,7 +619,13 @@ document.getElementById( span ).style.display = displayType;
 		$c_file_path = db_prepare_string( $t_file_path );
 		$c_new_file_name = db_prepare_string( $p_file_name );
 
-		$t_file_hash = ( 'bug' == $p_table ) ? $t_bug_id : config_get( 'document_files_prefix' ) . '-' . $t_project_id;
+		$t_file_hash = config_get( 'document_files_prefix' ) . '-' . $t_project_id;
+		if ( 'avatar' == $p_table ) {
+			$t_file_hash = config_get ( 'avatar_files_prefix' ) . '-' . $t_user_id;
+		} else if ( 'bug' == $p_table ) {
+			$t_file_hash = $t_bug_id;
+		}
+
 		$t_disk_file_name = $t_file_path . file_generate_unique_name( $t_file_hash . '-' . $p_file_name, $t_file_path );
 		$c_disk_file_name = db_prepare_string( $t_disk_file_name );
 
@@ -676,8 +672,14 @@ document.getElementById( span ).style.display = displayType;
 		}
 
 		$t_file_table	= config_get( 'mantis_' . $p_table . '_file_table' );
-		$c_id = ( 'bug' == $p_table ) ? $c_bug_id : $c_project_id;
-					
+		$c_id = $c_project_id;
+		if ( 'bug' == $p_table ) {
+			$c_id = $c_bug_id;
+		} else if ( 'avatar' == $p_table ) {
+			file_delete_avatar_files ( $c_user_id, 'avatar');
+			$c_id = $c_user_id;
+		}
+		
 		$query = "INSERT INTO $t_file_table
 						(" . $p_table . "_id, title, description, diskfile, filename, folder, filesize, file_type, date_added, content)
 					  VALUES
diff --git core/print_api.php core/print_api.php
index cf8dd42..b9016e5 100644
--- core/print_api.php
+++ core/print_api.php
@@ -130,7 +130,8 @@
 				$t_avatar_url = $t_avatar[0];
 				$t_width = $t_avatar[1];
 				$t_height = $t_avatar[2];
-				echo '<a rel="nofollow" href="http://site.gravatar.com">' .
+				$t_href = $t_avatar[3];
+				echo '<a rel="nofollow" href="'. $t_href .'">' .
 					'<img class="avatar" src="' . $t_avatar_url . '" alt="User avatar"' .
 					' width="' . $t_width . '" height="' . $t_height . '" /></a>';
 			}
diff --git core/user_api.php core/user_api.php
index 23dbb45..a31ae19 100644
--- core/user_api.php
+++ core/user_api.php
@@ -491,6 +491,21 @@
 	}
 
 	# --------------------
+	# delete avatars for the specified user
+	# returns true when successfully deleted
+	function user_delete_avatar( $p_user_id ) {
+		$c_user_id = db_prepare_int($p_user_id);
+
+		user_ensure_unprotected( $p_user_id );
+
+		file_delete_avatar_files ( $p_user_id );
+		
+		user_clear_cache( $p_user_id );
+
+		return true;
+	}
+	
+	# --------------------
 	# delete a user account (account, profiles, preferences, project-specific access levels)
 	# returns true when the account was successfully deleted
 	function user_delete( $p_user_id ) {
@@ -499,6 +514,9 @@
 
 		user_ensure_unprotected( $p_user_id );
 
+		# Remove the user avatar
+		user_delete_avatar ( $p_user_id );
+		
 		# Remove associated profiles
 		user_delete_profiles( $p_user_id );
 
@@ -649,34 +667,66 @@
 	/**
 	* Return the user avatar image URL
 	* in this first implementation, only gravatar.com avatars are supported
-	* @return array|bool an array( URL, width, height ) or false when the given user has no avatar
+	* @return array|bool an array( URL, width, height, href ) or false when the given user has no avatar
 	*/
 	function user_get_avatar( $p_user_id ) {
-		$t_email = strtolower( user_get_email( $p_user_id ) );
-		if ( is_blank( $t_email ) ) {
-			$t_result = false;
-		} else {
-			$t_default_image = config_get( 'default_avatar' );
-			$t_size = 80;
-
-			$t_use_ssl = false;
-			if ( isset( $_SERVER['HTTPS'] ) && ( strtolower( $_SERVER['HTTPS'] ) != 'off' ) ) {
-				$t_use_ssl = true;
+		/*
+		 *  First try to find a local avatar
+		 *  - if it is found then this one is delivered
+		 *  - if it isn't found proceed with original handling
+		 *  - if you disabled local avatars then anyway try to deliver the gravatar
+		 */
+		$t_avatar_type = strtolower ( config_get ( 'avatar_type' ) );
+		$t_found_local_avatar = false;
+
+		if ( $t_avatar_type == 'local' ) {
+			$c_user_id = db_prepare_int ( $p_user_id );
+			$t_avatar_table = config_get ( 'mantis_avatar_file_table' );
+			$query = "SELECT id
+					  FROM $t_avatar_table
+					  WHERE avatar_id='$c_user_id'";
+			$t_db_result = db_query ( $query );
+			/*
+			 * theoretically you could have more than one local avatar
+			 * but for now only one is allowed.
+			 */
+			if ( 1 == db_num_rows( $t_db_result )) {
+				$t_found_local_avatar = true;
+				$t_avatar_id = db_result ( $t_db_result );
+				$t_avatar_url = "file_download.php?type=avatar&amp;file_id=".$t_avatar_id;
+				$t_avatar_ref = "manage_user_edit_page.php?user_id=".$p_user_id;
+				$t_size = 80;
+				$t_result = array( $t_avatar_url, $t_size, $t_size, $t_avatar_ref );
 			}
-
-			if ( !$t_use_ssl ) {
-				$t_gravatar_domain = 'http://www.gravatar.com/';
+		}
+		
+		if ( ! $t_found_local_avatar ) {
+			$t_email = strtolower( user_get_email( $p_user_id ) );
+			if ( is_blank( $t_email ) ) {
+				$t_result = false;
 			} else {
-				$t_gravatar_domain = 'https://secure.gravatar.com/';
+				$t_default_image = config_get( 'default_avatar' );
+				$t_size = 80;
+	
+				$t_use_ssl = false;
+				if ( isset( $_SERVER['HTTPS'] ) && ( strtolower( $_SERVER['HTTPS'] ) != 'off' ) ) {
+					$t_use_ssl = true;
+				}
+	
+				if ( !$t_use_ssl ) {
+					$t_gravatar_domain = 'http://www.gravatar.com/';
+				} else {
+					$t_gravatar_domain = 'https://secure.gravatar.com/';
+				}
+	
+				$t_avatar_url = $t_gravatar_domain . 'avatar.php?gravatar_id=' . md5( $t_email ) .
+					'&amp;default=' . urlencode( $t_default_image ) .
+					'&amp;size=' . $t_size .
+					'&amp;rating=G';
+				$t_result = array( $t_avatar_url, $t_size, $t_size, "http://site.gravatar.com" );
 			}
-
-			$t_avatar_url = $t_gravatar_domain . 'avatar.php?gravatar_id=' . md5( $t_email ) .
-				'&amp;default=' . urlencode( $t_default_image ) .
-				'&amp;size=' . $t_size .
-				'&amp;rating=G';
-			$t_result = array( $t_avatar_url, $t_size, $t_size );
 		}
-
+		
 		return $t_result;
 	}
 
diff --git file_download.php file_download.php
index 8074cc4..6d2f29e 100644
--- file_download.php
+++ file_download.php
@@ -37,27 +37,18 @@
 	$f_file_id	= gpc_get_int( 'file_id' );
 	$f_type		= gpc_get_string( 'type' );
 
+	$t_allowed_tables = array ( 'bug', 'doc', 'avatar' );
+	if ( ! in_array ($f_type, $t_allowed_tables) ) {
+		access_denied();
+	}
+	
 	$c_file_id = (integer)$f_file_id;
 
-	# we handle the case where the file is attached to a bug
-	# or attached to a project as a project doc.
 	$query = '';
-	switch ( $f_type ) {
-		case 'bug':
-			$t_bug_file_table = config_get( 'mantis_bug_file_table' );
-			$query = "SELECT *
-				FROM $t_bug_file_table
-				WHERE id='$c_file_id'";
-			break;
-		case 'doc':
-			$t_project_file_table = config_get( 'mantis_project_file_table' );
-			$query = "SELECT *
-				FROM $t_project_file_table
-				WHERE id='$c_file_id'";
-			break;
-		default:
-			access_denied();
-	}
+	$t_file_table = config_get( 'mantis_'.$f_type.'_file_table' );
+	$query = "SELECT *
+		FROM $t_file_table
+		WHERE id='$c_file_id'";
 	$result = db_query( $query );
 	$row = db_fetch_array( $result );
 	extract( $row, EXTR_PREFIX_ALL, 'v' );
diff --git lang/strings_english.txt lang/strings_english.txt
index 68091d6..f637024 100644
--- lang/strings_english.txt
+++ lang/strings_english.txt
@@ -1452,3 +1452,6 @@ $s_show_graph = 'Show Graph';
 $s_graph_page = 'Graph Bug History';
 $s_graph_bug_page_link = 'Graph';
 
+# avatar
+$s_upload_avatar = 'Upload avatar';
+$s_avatar = 'Avatar';
diff --git manage_user_page.php manage_user_page.php
index 68e6594..8d93782 100644
--- manage_user_page.php
+++ manage_user_page.php
@@ -263,6 +263,9 @@ for ($i=0;$i<$new_user_count;$i++) {
 		<?php print_manage_user_sort_link(  'manage_user_page.php', lang_get( 'last_visit' ), 'last_visit', $c_dir, $c_sort, $c_hide ) ?>
 		<?php print_sort_icon( $c_dir, $c_sort, 'last_visit' ) ?>
 	</td>
+	<td>
+		<?php echo lang_get( 'avatar' ); ?>
+	</td>
 </tr>
 <?php
 	for ($i=0;$i<$user_count;$i++) {
@@ -292,6 +295,7 @@ for ($i=0;$i<$new_user_count;$i++) {
         </td>
 	<td><?php echo $u_date_created ?></td>
 	<td><?php echo $u_last_visit ?></td>
+	<td><?php print_avatar ( $u_id ); ?></td>
 </tr>
 <?php
 	}  # end for
local_avatar_another_take.diff (15,693 bytes)   
local_avatar_1.2.x.diff (35,983 bytes)   
diff --git a/account_prefs_inc.php b/account_prefs_inc.php
index 404d3b4..06dde6e 100644
--- a/account_prefs_inc.php
+++ b/account_prefs_inc.php
@@ -307,6 +307,14 @@
 </tr>
 </table>
 </form>
+
+<?php
+# File upload box
+if ( config_get( 'show_avatar' ) ) {
+	include( $t_mantis_dir . 'account_prefs_avatar_upload_inc.php' );
+}
+?>
+
 </div>
 
 <br />
diff --git a/config_defaults_inc.php b/config_defaults_inc.php
index 1b754f5..eca438b 100644
--- a/config_defaults_inc.php
+++ b/config_defaults_inc.php
@@ -1571,7 +1571,8 @@
 	 * @global string $g_document_files_prefix
 	 */
 	$g_document_files_prefix = 'doc';
-
+	$g_avatar_files_prefix = 'avatar';
+	
 	/**
 	 * absolute path to the default upload folder.  Requires trailing / or \
 	 * @global string $g_absolute_path_default_upload_folder
@@ -2553,6 +2554,7 @@
 	 * table names
 	 * @global array $g_db_table
 	 */
+	$g_db_table['mantis_avatar_file_table']				= '%db_table_prefix%_avatar_file%db_table_suffix%';
 	$g_db_table['mantis_bug_file_table']				= '%db_table_prefix%_bug_file%db_table_suffix%';
 	$g_db_table['mantis_bug_history_table']				= '%db_table_prefix%_bug_history%db_table_suffix%';
 	$g_db_table['mantis_bug_monitor_table']				= '%db_table_prefix%_bug_monitor%db_table_suffix%';
diff --git a/core/bug_api.php b/core/bug_api.php
index 8473404..a08846b 100644
--- a/core/bug_api.php
+++ b/core/bug_api.php
@@ -765,7 +765,7 @@ function bug_copy( $p_bug_id, $p_target_project_id = null, $p_copy_custom_fields
 
 			# prepare the new diskfile name and then copy the file
 			$t_file_path = dirname( $t_bug_file['folder'] );
-			$t_new_diskfile_name = $t_file_path . file_generate_unique_name( 'bug-' . $t_bug_file['filename'], $t_file_path );
+			$t_new_diskfile_name = $t_file_path . file_generate_unique_name( 'bug' );
 			$t_new_file_name = file_get_display_name( $t_bug_file['filename'] );
 			if(( config_get( 'file_upload_method' ) == DISK ) ) {
 				copy( $t_bug_file['diskfile'], $t_new_diskfile_name );
diff --git a/core/file_api.php b/core/file_api.php
index 625e924..88f0d6c 100644
--- a/core/file_api.php
+++ b/core/file_api.php
@@ -36,7 +36,15 @@ require_once( $t_core_dir . 'bug_api.php' );
 $g_cache_file_count = array();
 
 # ## File API ###
-# Gets the filename without the bug id prefix.
+
+/**
+ * Gets the filename without the bug id prefix 
+ * 
+ * In fact no code really cares for whats coming from here
+ * 
+ * @param	string	$p_filename	The file name
+ * @return	string				The file name
+ */
 function file_get_display_name( $p_filename ) {
 	$t_array = explode( '-', $p_filename, 2 );
 
@@ -48,18 +56,21 @@ function file_get_display_name( $p_filename ) {
 	$t_name = preg_split( $t_doc_match, $p_filename );
 	if( isset( $t_name[1] ) ) {
 		return $t_name[1];
-	} else {
-		$t_bug_match = '/^\d{7}-/';
-		$t_name = preg_split( $t_bug_match, $p_filename );
-		if( isset( $t_name[1] ) ) {
-			return $t_name[1];
-		} else {
-			return $p_filename;
-		}
 	}
+	$t_bug_match = '/^\d{7}-/';
+	$t_name = preg_split( $t_bug_match, $p_filename );
+	if( isset( $t_name[1] ) ) {
+		return $t_name[1];
+	}
+	return $p_filename;
 }
 
-# Check the number of attachments a bug has (if any)
+/**
+ * Check the number of attachments a bug has (if any)
+ * 
+ *  @param	integer	$p_bug_id
+ *  @return	integer				Number of attachments
+ */
 function file_bug_attachment_count( $p_bug_id ) {
 	global $g_cache_file_count;
 
@@ -102,7 +113,11 @@ function file_bug_attachment_count( $p_bug_id ) {
 	return $t_file_count;
 }
 
-# Check if a specific bug has attachments
+/**
+ * Check if a specific bug has attachments
+ * @param	integer	$p_bug_id
+ * @return	bool
+ */
 function file_bug_has_attachments( $p_bug_id ) {
 	if( file_bug_attachment_count( $p_bug_id ) > 0 ) {
 		return true;
@@ -111,45 +126,50 @@ function file_bug_has_attachments( $p_bug_id ) {
 	}
 }
 
-# Check if the current user can view attachments for the specified bug.
-function file_can_view_bug_attachments( $p_bug_id ) {
+function file_can_do_with_bug ( $p_bug_id, $p_what ) {
 	$t_reported_by_me = bug_is_user_reporter( $p_bug_id, auth_get_current_user_id() );
-	$t_can_view = access_has_bug_level( config_get( 'view_attachments_threshold' ), $p_bug_id );
+	$t_can_do = access_has_bug_level( config_get( $p_what.'_attachments_threshold' ), $p_bug_id );
+	$t_can_do_own = config_get( 'allow_'.$p_what.'_own_attachments' ); 
 
-	/** @todo Fix this to be readable */
-	$t_can_view = $t_can_view || ( $t_reported_by_me && config_get( 'allow_view_own_attachments' ) );
+	$t_can_do = $t_can_do || ( $t_reported_by_me && $t_can_do_own );
 
-	return $t_can_view;
+	return $t_can_do;
+}
+/**
+ * Check if the current user can view attachments for the specified bug.
+ * @param	integer	$p_bug_id
+ * @return	bool
+ */
+function file_can_view_bug_attachments( $p_bug_id ) {
+	return file_can_do_with_bug ( $p_bug_id, 'view');
 }
 
-# Check if the current user can download attachments for the specified bug.
+/**
+ * Check if the current user can download attachments for the specified bug.
+ * @param	integer	$p_bug_id
+ * @return	bool
+ */
 function file_can_download_bug_attachments( $p_bug_id ) {
-	$t_reported_by_me = bug_is_user_reporter( $p_bug_id, auth_get_current_user_id() );
-	$t_can_download = access_has_bug_level( config_get( 'download_attachments_threshold' ), $p_bug_id );
-
-	/** @todo Fix this to be readable */
-	$t_can_download = $t_can_download || ( $t_reported_by_me && config_get( 'allow_download_own_attachments' ) );
-
-	return $t_can_download;
+	return file_can_do_with_bug ( $p_bug_id, 'download');
 }
 
-# Check if the current user can delete attachments from the specified bug.
+/**
+ * Check if the current user can delete attachments from the specified bug.
+ * @param	integer	$p_bug_id
+ * @return	bool
+ */
 function file_can_delete_bug_attachments( $p_bug_id ) {
 	if( bug_is_readonly( $p_bug_id ) ) {
 		return false;
 	}
-
-	$t_reported_by_me = bug_is_user_reporter( $p_bug_id, auth_get_current_user_id() );
-	$t_can_download = access_has_bug_level( config_get( 'delete_attachments_threshold' ), $p_bug_id );
-
-	/** @todo Fix this to be readable */
-	$t_can_download = $t_can_download || ( $t_reported_by_me && config_get( 'allow_delete_own_attachments' ) );
-
-	return $t_can_download;
+	return file_can_do_with_bug ( $p_bug_id, 'delete');
 }
 
-# Get icon corresponding to the specified filename
-# returns an associative array with "url" and "alt" text.
+/**
+ * Get icon corresponding to the specified filename
+ * @param	string	$p_display_filename
+ * @return	array						which has url and alt members
+ */
 function file_get_icon_url( $p_display_filename ) {
 	$t_file_type_icons = config_get( 'file_type_icons' );
 
@@ -165,8 +185,8 @@ function file_get_icon_url( $p_display_filename ) {
 /**
  * Combines a path and a file name making sure that the separator exists.
  *
- * @param string $p_path       The path.
- * @param string $p_filename   The file name.
+ * @param string $p_path		The path.
+ * @param string $p_filename	The file name.
  *
  * @return The combined full path.
  */
@@ -182,16 +202,18 @@ function file_path_combine( $p_path, $p_filename ) {
 }
 
 /**
- * Nomalizes the disk file path based on the following algorithm:
- * 1. If disk file exists, then return as is.
- * 2. If not, and a project path is available, then check with that, if exists return it.
- * 3. If not, then use default upload path, then check with that, if exists return it.
- * 4. If disk file doesn't include a path, then return expected path based on project path or default path.
- * 5. Otherwise return as is.
+ * Nomalizes the disk file path.
+ * 
+ * Uses the following algorithm:
+ * 1 If disk file exists, then return as is
+ * 2 If not, and a project path is available, then check with that, if exists return it
+ * 3 If not, then use default upload path, then check with that, if exists return it
+ * 4 If disk file doesn't include a path, then return expected path based on project path or default path
+ * 5 Otherwise return as is.
  *
- * @param string $p_diskfile  The disk file (full path or just filename).
- * @param integer The project id - shouldn't be 0 (ALL_PROJECTS).
- * @return The normalized full path.
+ * @param string $p_diskfile	The disk file (full path or just filename).
+ * @param integer $p_project_id	The project id - shouldn't be 0 (ALL_PROJECTS).
+ * @return string				The normalized full path.
  */
 function file_normalize_attachment_path( $p_diskfile, $p_project_id ) {
 	if ( file_exists( $p_diskfile ) ) {
@@ -239,21 +261,26 @@ function file_normalize_attachment_path( $p_diskfile, $p_project_id ) {
 	return $p_diskfile;
 }
 
-# --------------------
-# Gets an array of attachments that are visible to the currently logged in user.
-# Each element of the array contains the following:
-# display_name - The attachment display name (i.e. file name dot extension)
-# size - The attachment size in bytes.
-# date_added - The date where the attachment was added.
-# can_download - true: logged in user has access to download the attachment, false: otherwise.
-# diskfile - The name of the file on disk.  Typically this is a hash without an extension.
-# download_url - The download URL for the attachment (only set if can_download is true).
-# exists - Applicable for DISK attachments.  true: file exists, otherwise false.
-# can_delete - The logged in user can delete the attachments.
-# preview - true: the attachment should be previewable, otherwise false.
-# type - Can be "image", "text" or empty for other types.
-# alt - The alternate text to be associated with the icon.
-# icon - array with icon information, contains 'url' and 'alt' elements.
+/**
+ * Gets an array of attachments that are visible to the currently logged in user.
+ * 
+ * Each element of the array contains the following:
+ * display_name	- The attachment display name (file name dot extension)
+ * size			- The attachment size in bytes
+ * date_added	- The date where the attachment was added
+ * can_download	- true: logged in user has access to download the attachment, false: otherwise
+ * diskfile		- The name of the file on disk Typically this is a hash without an extension
+ * download_url - The download URL for the attachment (only set if can_download is true) 
+ * exists - Applicable for DISK attachments.  true: file exists, otherwise false.
+ * can_delete - The logged in user can delete the attachments.
+ * preview - true: the attachment should be previewable, otherwise false.
+ * type - Can be "image", "text" or empty for other types.
+ * alt - The alternate text to be associated with the icon.
+ * icon - array with icon information, contains 'url' and 'alt' elements.
+ * 
+ * @param	integer	$p_bug_id
+ * @return	array
+ */
 function file_get_visible_attachments( $p_bug_id ) {
 	$t_attachment_rows = bug_get_attachments( $p_bug_id );
 	$t_visible_attachments = array();
@@ -324,101 +351,64 @@ function file_get_visible_attachments( $p_bug_id ) {
 	return $t_attachments;
 }
 
-# delete all files that are associated with the given bug
-function file_delete_attachments( $p_bug_id ) {
-	$c_bug_id = db_prepare_int( $p_bug_id );
-
-	$t_bug_file_table = db_get_table( 'mantis_bug_file_table' );
-
+/**
+ * Remove files from the given table based on the key
+ * 
+ * This is used to remove all the attachments, documents or avatars This function
+ * should be called only by the specialized functions which know the table from
+ * where to delete.
+ * 
+ * @param	integer	$p_id
+ * @param	string	$p_table
+ * @return	boolean	true
+ * @access	private
+ */
+function file_delete_many ( $p_id, $p_table ) {
+	$c_id = db_prepare_int( $p_id );
+	$t_file_table = db_get_table( 'mantis_'.$p_table.'_file_table' );
 	$t_method = config_get( 'file_upload_method' );
 
 	# Delete files from disk
-	$query = "SELECT diskfile, filename
-				FROM $t_bug_file_table
-				WHERE bug_id=" . db_param();
-	$result = db_query_bound( $query, Array( $c_bug_id ) );
+	$query = "SELECT id
+				FROM $t_file_table
+				WHERE ".$p_table."_id=" . db_param();
+	$result = db_query_bound( $query, Array( $c_id ) );
 
 	$file_count = db_num_rows( $result );
 	if( 0 == $file_count ) {
 		return true;
 	}
-
-	if(( DISK == $t_method ) || ( FTP == $t_method ) ) {
-
-		# there may be more than one file
-		$ftp = 0;
-		if( FTP == $t_method ) {
-			$ftp = file_ftp_connect();
-		}
-
-		for( $i = 0;$i < $file_count;$i++ ) {
-			$row = db_fetch_array( $result );
-
-			$t_local_diskfile = file_normalize_attachment_path( $row['diskfile'], bug_get_field( $p_bug_id, 'project_id' ) );
-			file_delete_local( $t_local_diskfile );
-
-			if( FTP == $t_method ) {
-				file_ftp_delete( $ftp, $row['diskfile'] );
-			}
-		}
-
-		if( FTP == $t_method ) {
-			file_ftp_disconnect( $ftp );
-		}
-	}
-
-	# Delete the corresponding db records
-	$query = "DELETE FROM $t_bug_file_table
-				  WHERE bug_id=" . db_param();
-	$result = db_query_bound( $query, Array( $c_bug_id ) );
-
+	for( $i = 0;$i < $file_count;$i++ ) {
+		$row = db_fetch_array( $result );
+		file_delete ( $row['id'], $p_table );
+	}	
 	# db_query errors on failure so:
 	return true;
 }
 
-function file_delete_project_files( $p_project_id ) {
-	$t_project_file_table = db_get_table( 'mantis_project_file_table' );
-	$t_method = config_get( 'file_upload_method' );
-
-	# Delete the file physically (if stored via DISK or FTP)
-	if(( DISK == $t_method ) || ( FTP == $t_method ) ) {
-
-		# Delete files from disk
-		$query = "SELECT diskfile, filename
-					FROM $t_project_file_table
-					WHERE project_id=" . db_param();
-		$result = db_query_bound( $query, array( (int) $p_project_id ) );
-
-		$file_count = db_num_rows( $result );
-
-		$ftp = 0;
-		if( FTP == $t_method ) {
-			$ftp = file_ftp_connect();
-		}
-
-		for( $i = 0;$i < $file_count;$i++ ) {
-			$row = db_fetch_array( $result );
-
-			$t_local_diskfile = file_normalize_attachment_path( $row['diskfile'], $p_project_id );
-			file_delete_local( $t_local_diskfile );
 
-			if( FTP == $t_method ) {
-				file_ftp_delete( $ftp, $row['diskfile'] );
-			}
-		}
+/**
+ * Delete all files that are associated with the given bug
+ * @param $p_bug_id
+ * @return unknown_type
+ */
+function file_delete_attachments( $p_bug_id ) {
+	return file_delete_many ( $p_bug_id, 'bug');
+}
 
-		if( FTP == $t_method ) {
-			file_ftp_disconnect( $ftp );
-		}
-	}
+function file_delete_project_files( $p_project_id ) {
+	return file_delete_many ( $p_project_id, 'project');
+}
 
-	# Delete the corresponding db records
-	$query = "DELETE FROM $t_project_file_table
-				WHERE project_id=" . db_param();
-	$result = db_query_bound( $query, Array( (int) $p_project_id ) );
+function file_delete_avatars( $p_avatar_id ) {
+	return file_delete_many ( $p_avatar_id, 'avatar');
 }
 
-# Delete all cached files that are older than configured number of days.
+/**
+ * Delete all cached files that are older than configured number of days.
+ * 
+ * @return unknown_type
+ */
 function file_ftp_cache_cleanup() {
 }
 
@@ -434,7 +424,14 @@ function file_ftp_connect() {
 	return $conn_id;
 }
 
-# Put a file to the ftp server.
+/**
+ * Put a file to the ftp server.
+ * 
+ * @param $p_conn_id
+ * @param $p_remote_filename
+ * @param $p_local_filename
+ * @return unknown_type
+ */
 function file_ftp_put( $p_conn_id, $p_remote_filename, $p_local_filename ) {
 	helper_begin_long_process();
 	$upload = ftp_put( $p_conn_id, $p_remote_filename, $p_local_filename, FTP_BINARY );
@@ -485,11 +482,10 @@ function file_delete( $p_file_id, $p_table = 'bug' ) {
 	$t_filename = file_get_field( $p_file_id, 'filename', $p_table );
 	$t_diskfile = file_get_field( $p_file_id, 'diskfile', $p_table );
 
+	$t_project_id = file_get_field( $p_file_id, $p_table.'_id', $p_table );
+	$t_bug_id = $t_project_id;
 	if ( $p_table == 'bug' ) {
-		$t_bug_id = file_get_field( $p_file_id, 'bug_id', $p_table );
 		$t_project_id = bug_get_field( $t_bug_id, 'project_id' );
-	} else {
-		$t_project_id = file_get_field( $p_file_id, 'project_id', $p_table );
 	}
 
 	if(( DISK == $t_upload_method ) || ( FTP == $t_upload_method ) ) {
@@ -523,35 +519,23 @@ function file_delete( $p_file_id, $p_table = 'bug' ) {
 
 # File type check
 function file_type_check( $p_file_name ) {
-	$t_allowed_files = config_get( 'allowed_files' );
-	$t_disallowed_files = config_get( 'disallowed_files' );;
+	$t_allowed_files = strtolower(config_get( 'allowed_files' ));
+	$t_disallowed_files = strtolower(config_get( 'disallowed_files' ));
 
 	# grab extension
-	$t_ext_array = explode( '.', $p_file_name );
-	$last_position = count( $t_ext_array ) - 1;
-	$t_extension = $t_ext_array[$last_position];
+	$t_extension = strtolower(file_get_extension( $p_file_name ));
 
 	# check against disallowed files
-	$t_disallowed_arr = explode( ',', $t_disallowed_files );
-	foreach( $t_disallowed_arr as $t_val ) {
-		if( 0 == strcasecmp( $t_val, $t_extension ) ) {
-			return false;
-		}
+	if ( in_array($t_extension, explode( ',', $t_disallowed_files ))) {
+		return false;
 	}
 
 	# if the allowed list is note populated then the file must be allowed
-	if( is_blank( $t_allowed_files ) ) {
+	# or check against allowed files
+	if ( is_blank( $t_allowed_files ) || in_array($t_extension, explode( ',', $t_allowed_files ))) {
 		return true;
 	}
 
-	# check against allowed files
-	$t_allowed_arr = explode( ',', $t_allowed_files );
-	foreach( $t_allowed_arr as $t_val ) {
-		if( 0 == strcasecmp( $t_val, $t_extension ) ) {
-			return true;
-		}
-	}
-
 	return false;
 }
 
@@ -560,53 +544,29 @@ function file_clean_name( $p_filename ) {
 	return preg_replace( "/[\/\\ :&]/", "_", $p_filename );
 }
 
-# Generate a string to use as the identifier for the file
-# It is not guaranteed to be unique and should be checked
-# The string returned should be 32 characters in length
-function file_generate_name( $p_seed ) {
-	$t_val = md5( $p_seed . time() );
-
-	return substr( $t_val, 0, 32 );
-}
-
-# Generate a UNIQUE string to use as the identifier for the file
-# The string returned should be 64 characters in length
-function file_generate_unique_name( $p_seed, $p_filepath ) {
-	do {
-		$t_string = file_generate_name( $p_seed );
-	}
-	while( !diskfile_is_name_unique( $t_string, $p_filepath ) );
-
-	return $t_string;
-}
-
-# Return true if the diskfile name identifier is unique, false otherwise
-function diskfile_is_name_unique( $p_name, $p_filepath ) {
-	$t_file_table = db_get_table( 'mantis_bug_file_table' );
-
-	$c_name = $p_filepath . $p_name;
-
-	$query = "SELECT COUNT(*)
-				  FROM $t_file_table
-				  WHERE diskfile=" . db_param();
-	$result = db_query_bound( $query, Array( $c_name ) );
-	$t_count = db_result( $result );
-
-	if( $t_count > 0 ) {
-		return false;
-	} else {
-		return true;
-	}
+function file_generate_unique_name( $p_prefix ) {
+	return uniqid( $p_prefix, true );
 }
 
-# Return true if the file name identifier is unique, false otherwise
-function file_is_name_unique( $p_name, $p_bug_id ) {
-	$t_file_table = db_get_table( 'mantis_bug_file_table' );
+/**
+ * Check if filename is unique.
+ * 
+ * The function will check the appropriate table for
+ * duplicate file names.
+ * 
+ * @param	string	$p_name		file name
+ * @param 	integer	$p_key_id	bug_id, avatar_id or document_id
+ * @param 	string	$p_table	bug, doc, avatar
+ * @return	boolean
+ */
+function file_is_name_unique( $p_name, $p_key_id, $p_table = 'bug' ) {
+	if ( 'doc' == $p_table ) { $p_table = 'project'; }
+	$t_file_table = db_get_table( 'mantis_'.$p_table.'_file_table' );
 
 	$query = "SELECT COUNT(*)
 				  FROM $t_file_table
-				  WHERE filename=" . db_param() . " AND bug_id=" . db_param();
-	$result = db_query_bound( $query, Array( $p_name, $p_bug_id ) );
+				  WHERE filename=" . db_param() . " AND ".$p_table."_id=" . db_param();
+	$result = db_query_bound( $query, Array( $p_name, $p_key_id ) );
 	$t_count = db_result( $result );
 
 	if( $t_count > 0 ) {
@@ -622,30 +582,42 @@ function file_is_name_unique( $p_name, $p_bug_id ) {
  * @param integer $p_bug_id the bug id
  * @param array $p_file the uploaded file info, as retrieved from gpc_get_file()
  */
-function file_add( $p_bug_id, $p_file, $p_table = 'bug', $p_title = '', $p_desc = '' ) {
+function file_add( $p_key_id, $p_file, $p_table = 'bug', $p_title = '', $p_desc = '' ) {
 
 	file_ensure_uploaded( $p_file );
 	$t_file_name = $p_file['name'];
 	$t_tmp_file = $p_file['tmp_name'];
-
+	$t_file_table = db_get_table( 'mantis_' . $p_table . '_file_table' );
+	
 	if( !file_type_check( $t_file_name ) ) {
 		trigger_error( ERROR_FILE_NOT_ALLOWED, ERROR );
 	}
-
-	if( !file_is_name_unique( $t_file_name, $p_bug_id ) ) {
+	
+	if( !file_is_name_unique( $t_file_name, $p_key_id, $p_table ) ) {
 		trigger_error( ERROR_DUPLICATE_FILE, ERROR );
 	}
-
-	if( 'bug' == $p_table ) {
-		$t_project_id = bug_get_field( $p_bug_id, 'project_id' );
-		$t_bug_id = bug_format_id( $p_bug_id );
-	} else {
-		$t_project_id = helper_get_current_project();
-		$t_bug_id = 0;
+	
+	switch ( $p_table ) {
+		case 'bug':
+			$t_project_id = bug_get_field( $p_key_id, 'project_id' );
+			$t_key_id = bug_format_id( $p_key_id );
+			$t_file_hash = $t_key_id;
+			$c_id = db_prepare_int( $p_key_id );
+			break;
+		case 'avatar':
+			$t_project_id = ALL_PROJECTS;
+			$t_file_name = config_get( 'avatar_files_prefix' ) . '-' . $p_key_id;
+			$c_id = db_prepare_int( $p_key_id );
+			break;
+		default:
+			$t_project_id = helper_get_current_project();
+			$t_file_name = config_get( 'document_files_prefix' ) . '-' . $t_project_id;
+			$c_id = db_prepare_int( $t_project_id );
+			break;
 	}
 
 	# prepare variables for insertion
-	$c_bug_id = db_prepare_int( $p_bug_id );
+	$c_key_id = db_prepare_int( $p_key_id );
 	$c_project_id = db_prepare_int( $t_project_id );
 	$c_file_type = db_prepare_string( $p_file['type'] );
 	$c_title = db_prepare_string( $p_title );
@@ -661,9 +633,7 @@ function file_add( $p_bug_id, $p_file, $p_table = 'bug', $p_title = '', $p_desc
 	}
 	$c_file_path = db_prepare_string( $t_file_path );
 	$c_new_file_name = db_prepare_string( $t_file_name );
-
-	$t_file_hash = ( 'bug' == $p_table ) ? $t_bug_id : config_get( 'document_files_prefix' ) . '-' . $t_project_id;
-	$t_unique_name = file_generate_unique_name( $t_file_hash . '-' . $t_file_name, $t_file_path );
+	$t_unique_name = file_generate_unique_name( $p_table );
 	$t_disk_file_name = $t_file_path . $t_unique_name;
 	$c_unique_name = db_prepare_string( $t_unique_name );
 
@@ -709,9 +679,6 @@ function file_add( $p_bug_id, $p_file, $p_table = 'bug', $p_title = '', $p_desc
 			trigger_error( ERROR_GENERIC, ERROR );
 	}
 
-	$t_file_table = db_get_table( 'mantis_' . $p_table . '_file_table' );
-	$c_id = ( 'bug' == $p_table ) ? $c_bug_id : $c_project_id;
-
 	$query = "INSERT INTO $t_file_table
 						(" . $p_table . "_id, title, description, diskfile, filename, folder, filesize, file_type, date_added, content)
 					  VALUES
@@ -721,10 +688,10 @@ function file_add( $p_bug_id, $p_file, $p_table = 'bug', $p_title = '', $p_desc
 	if( 'bug' == $p_table ) {
 
 		# updated the last_updated date
-		$result = bug_update_date( $p_bug_id );
+		$result = bug_update_date( $p_key_id );
 
 		# log new bug
-		history_log_event_special( $p_bug_id, FILE_ADDED, $t_file_name );
+		history_log_event_special( $p_key_id, FILE_ADDED, $t_file_name );
 	}
 }
 
@@ -836,27 +803,5 @@ function file_ensure_uploaded( $p_file ) {
 
 # Get extension given the filename or its full path.
 function file_get_extension( $p_filename ) {
-	$ext = '';
-	$dot_found = false;
-	$i = strlen( $p_filename ) - 1;
-	while( $i >= 0 ) {
-		if( '.' == $p_filename[$i] ) {
-			$dot_found = true;
-			break;
-		}
-
-		# foung a directoryarker before a period.
-		if(( $p_filename[$i] == "/" ) || ( $p_filename[$i] == "\\" ) ) {
-			return '';
-		}
-
-		$ext = $p_filename[$i] . $ext;
-		$i--;
-	}
-
-	if( $dot_found ) {
-		return $ext;
-	} else {
-		return '';
-	}
+	return pathinfo($p_filename, PATHINFO_EXTENSION);
 }
diff --git a/core/print_api.php b/core/print_api.php
index c2c4eea..7cb304b 100644
--- a/core/print_api.php
+++ b/core/print_api.php
@@ -146,22 +146,23 @@ function print_successful_redirect( $p_redirect_to ) {
 }
 
 # Print avatar image for the given user ID
-function print_avatar( $p_user_id, $p_size = 80 ) {
-	if( !user_exists( $p_user_id ) ) {
+function print_avatar( $p_user_id ) {
+	if ( !user_exists( $p_user_id ) ) {
 		return;
 	}
 
-	if( access_has_project_level( config_get( 'show_avatar_threshold' ), null, $p_user_id ) ) {
-		$t_avatar = user_get_avatar( $p_user_id, $p_size );
-		if( false !== $t_avatar ) {
+	if ( access_has_project_level( config_get( 'show_avatar_threshold' ), null, $p_user_id ) ) {
+		$t_avatar = user_get_avatar( $p_user_id );
+		if ( false !== $t_avatar ) {
 			$t_avatar_url = $t_avatar[0];
 			$t_width = $t_avatar[1];
 			$t_height = $t_avatar[2];
-			echo '<a rel="nofollow" href="http://site.gravatar.com">' . '<img class="avatar" src="' . $t_avatar_url . '" alt="User avatar"' . ' width="' . $t_width . '" height="' . $t_height . '" /></a>';
+			$t_href = $t_avatar[3];
+			echo '<a rel="nofollow" href="'.$t_href.'"><img class="avatar" src="'.$t_avatar_url.'" alt="User avatar" width="'.$t_width.'" height="'.$t_height.'" /></a>';
 		}
 	}
 }
-
+	
 # --------------------
 # prints the name of the user given the id.  also makes it an email link.
 function print_user( $p_user_id ) {
diff --git a/core/user_api.php b/core/user_api.php
index cb908fb..4569319 100644
--- a/core/user_api.php
+++ b/core/user_api.php
@@ -518,18 +518,16 @@ function user_signup( $p_username, $p_email = null ) {
 	return user_create( $p_username, $t_password, $p_email );
 }
 
-# --------------------
-# delete project-specific user access levels.
-# returns true when successfully deleted
-function user_delete_project_specific_access_levels( $p_user_id ) {
+function user_delete_from ( $p_user_id, $p_key_id, $p_table ) {
 	$c_user_id = db_prepare_int( $p_user_id );
 
 	user_ensure_unprotected( $p_user_id );
 
-	$t_project_user_list_table = db_get_table( 'mantis_project_user_list_table' );
+	$t_table = db_get_table( $p_table );
 
-	$query = "DELETE FROM $t_project_user_list_table
-				  WHERE user_id=" . db_param();
+	# Remove associated profiles
+	$query = "DELETE FROM $t_table
+				  WHERE '.$p_key_id.'=" . db_param();
 	db_query_bound( $query, Array( $c_user_id ) );
 
 	user_clear_cache( $p_user_id );
@@ -538,23 +536,26 @@ function user_delete_project_specific_access_levels( $p_user_id ) {
 }
 
 # --------------------
+# delete project-specific user access levels.
+# returns true when successfully deleted
+function user_delete_project_specific_access_levels( $p_user_id ) {
+	return user_delete_from ( $p_user_id, 'user_id', 'mantis_project_user_list_table' );
+}
+
+# --------------------
 # delete profiles for the specified user
 # returns true when successfully deleted
 function user_delete_profiles( $p_user_id ) {
-	$c_user_id = db_prepare_int( $p_user_id );
-
-	user_ensure_unprotected( $p_user_id );
-
-	$t_user_profile_table = db_get_table( 'mantis_user_profile_table' );
-
-	# Remove associated profiles
-	$query = "DELETE FROM $t_user_profile_table
-				  WHERE user_id=" . db_param();
-	db_query_bound( $query, Array( $c_user_id ) );
-
-	user_clear_cache( $p_user_id );
+	return user_delete_from ( $p_user_id, 'user_id', 'mantis_user_profile_table' );
+}
 
-	return true;
+# --------------------
+# delete avatar(s) for the specified user
+# returns true when successfully deleted
+function user_delete_avatar ( $p_avatar_id ) {
+	user_ensure_unprotected( $p_avatar_id );
+	file_delete_avatars ( $p_avatar_id );
+	return user_delete_from ( $p_avatar_id, 'avatar_id', 'mantis_avatar_profile_table' );
 }
 
 # --------------------
@@ -567,6 +568,9 @@ function user_delete( $p_user_id ) {
 	user_ensure_unprotected( $p_user_id );
 
 	# Remove associated profiles
+	user_delete_avatar( $p_user_id );
+	
+	# Remove associated profiles
 	user_delete_profiles( $p_user_id );
 
 	# Remove associated preferences
@@ -608,11 +612,9 @@ function user_delete( $p_user_id ) {
 # Data Access
 # ===================================
 # --------------------
-# get a user id from a username
-#  return false if the username does not exist
-function user_get_id_by_name( $p_username ) {
+function user_get_id_by ( $p_key, $p_value ) {
 	global $g_cache_user;
-	if( $t_user = user_search_cache( 'username', $p_username ) ) {
+	if( $t_user = user_search_cache( $p_key, $p_value ) ) {
 		return $t_user['id'];
 	}
 
@@ -620,8 +622,8 @@ function user_get_id_by_name( $p_username ) {
 
 	$query = "SELECT *
 				  FROM $t_user_table
-				  WHERE username=" . db_param();
-	$result = db_query_bound( $query, Array( $p_username ) );
+				  WHERE $p_key=" . db_param();
+	$result = db_query_bound( $query, Array( $p_value ) );
 
 	if( 0 == db_num_rows( $result ) ) {
 		return false;
@@ -632,50 +634,19 @@ function user_get_id_by_name( $p_username ) {
 	}
 }
 
-# Get a user id from an email address
-function user_get_id_by_email( $p_email ) {
-	global $g_cache_user;
-	if( $t_user = user_search_cache( 'email', $p_email ) ) {
-		return $t_user['id'];
-	}
-
-	$t_user_table = db_get_table( 'mantis_user_table' );
 
-	$query = "SELECT *
-				  FROM $t_user_table
-				  WHERE email=" . db_param();
-	$result = db_query_bound( $query, Array( $p_email ) );
+function user_get_id_by_name( $p_username ) {
+	return user_get_id_by ( 'username', $p_username );
+}
 
-	if( 0 == db_num_rows( $result ) ) {
-		return false;
-	} else {
-		$row = db_fetch_array( $result );
-		user_cache_database_result( $row );
-		return $row['id'];
-	}
+# Get a user id from an email address
+function user_get_id_by_email( $p_email ) {
+	return user_get_id_by ( 'email', $p_email );
 }
 
 # Get a user id from their real name
 function user_get_id_by_realname( $p_realname ) {
-	global $g_cache_user;
-	if( $t_user = user_search_cache( 'realname', $p_realname ) ) {
-		return $t_user['id'];
-	}
-
-	$t_user_table = db_get_table( 'mantis_user_table' );
-
-	$query = "SELECT *
-				  FROM $t_user_table
-				  WHERE realname=" . db_param();
-	$result = db_query_bound( $query, Array( $p_realname ) );
-
-	if( 0 == db_num_rows( $result ) ) {
-		return false;
-	} else {
-		$row = db_fetch_array( $result );
-		user_cache_database_result( $row );
-		return $row['id'];
-	}
+	return user_get_id_by ( 'realname', $p_realname );
 }
 
 # --------------------
@@ -770,30 +741,59 @@ function user_get_name( $p_user_id ) {
 * @return array|bool an array( URL, width, height ) or false when the given user has no avatar
 */
 function user_get_avatar( $p_user_id, $p_size = 80 ) {
-	$t_email = strtolower( user_get_email( $p_user_id ) );
-	if( is_blank( $t_email ) ) {
-		$t_result = false;
-	} else {
-		$t_default_image = config_get( 'default_avatar' );
-		$t_size = $p_size;
+	$t_avatar_type = strtolower ( config_get ( 'avatar_type' ) );
+	$t_found_local_avatar = false;
 
-		$t_use_ssl = false;
-		if( isset( $_SERVER['HTTPS'] ) && ( strtolower( $_SERVER['HTTPS'] ) != 'off' ) ) {
-			$t_use_ssl = true;
+	if ( $t_avatar_type == 'local' ) {
+		$c_user_id = db_prepare_int ( $p_user_id );
+		$t_avatar_table = db_get_table ( 'mantis_avatar_file_table' );
+		$query = "SELECT id
+				  FROM $t_avatar_table
+				  WHERE avatar_id='$c_user_id'";
+		$t_db_result = db_query ( $query );
+		/*
+		 * theoretically you could have more than one local avatar
+		 * but for now only one is allowed.
+		 */
+		if ( 1 == db_num_rows( $t_db_result )) {
+			$t_found_local_avatar = true;
+			$t_avatar_id = db_result ( $t_db_result );
+			$t_avatar_url = "file_download.php?type=avatar&amp;file_id=".$t_avatar_id;
+			$t_avatar_ref = "manage_user_edit_page.php?user_id=".$p_user_id;
+			$t_size = $p_size;
+			$t_result = array( $t_avatar_url, $t_size, $t_size, $t_avatar_ref );
 		}
+	}
 
-		if( !$t_use_ssl ) {
-			$t_gravatar_domain = 'http://www.gravatar.com/';
+	// if local avatar is disabled or not found check the gravatar
+	if ( ! $t_found_local_avatar ) {
+		// for gravatar you need a valid email
+		$t_email = strtolower( user_get_email( $p_user_id ) );
+		if( is_blank( $t_email ) ) {
+			$t_result = false;
 		} else {
-			$t_gravatar_domain = 'https://secure.gravatar.com/';
+			$t_default_image = config_get( 'default_avatar' );
+			$t_size = $p_size;
+	
+			$t_use_ssl = false;
+			if( isset( $_SERVER['HTTPS'] ) && ( strtolower( $_SERVER['HTTPS'] ) != 'off' ) ) {
+				$t_use_ssl = true;
+			}
+	
+			if( !$t_use_ssl ) {
+				$t_avatar_domain = 'http://www.gravatar.com/';
+			} else {
+				$t_avatar_domain = 'https://secure.gravatar.com/';
+			}
+	
+			$t_avatar_url = $t_avatar_domain . 'avatar.php?gravatar_id=' . md5( $t_email ) . '&amp;default=' . urlencode( $t_default_image ) . '&amp;size=' . $t_size . '&amp;rating=G';
+			$t_result = array(
+				$t_avatar_url,
+				$t_size,
+				$t_size,
+				$t_avatar_domain,
+			);
 		}
-
-		$t_avatar_url = $t_gravatar_domain . 'avatar.php?gravatar_id=' . md5( $t_email ) . '&amp;default=' . urlencode( $t_default_image ) . '&amp;size=' . $t_size . '&amp;rating=G';
-		$t_result = array(
-			$t_avatar_url,
-			$t_size,
-			$t_size,
-		);
 	}
 
 	return $t_result;
diff --git a/file_download.php b/file_download.php
index eec4d4d..9b4cd8a 100644
--- a/file_download.php
+++ b/file_download.php
@@ -34,54 +34,47 @@
 ?>
 <?php auth_ensure_user_authenticated() ?>
 <?php
+	$f_type	= gpc_get_string( 'type' );
+	$t_allowed_tables = array ( 'bug', 'doc', 'avatar' );
+	if ( ! in_array ($f_type, $t_allowed_tables) ) {
+		access_denied();
+	}
+	
+	if ( $f_type == 'doc' ) {
+		$f_type = 'project';
+	}
 	$f_file_id	= gpc_get_int( 'file_id' );
-	$f_type		= gpc_get_string( 'type' );
-
 	$c_file_id = (integer)$f_file_id;
 
 	# we handle the case where the file is attached to a bug
 	# or attached to a project as a project doc.
 	$query = '';
-	switch ( $f_type ) {
-		case 'bug':
-			$t_bug_file_table = db_get_table( 'mantis_bug_file_table' );
-			$query = "SELECT *
-				FROM $t_bug_file_table
-				WHERE id=" . db_param();
-			break;
-		case 'doc':
-			$t_project_file_table = db_get_table( 'mantis_project_file_table' );
-			$query = "SELECT *
-				FROM $t_project_file_table
-				WHERE id=" . db_param();
-			break;
-		default:
-			access_denied();
-	}
+	$t_file_table = db_get_table( 'mantis_'.$f_type.'_file_table' );
+	$query = "SELECT *
+		FROM $t_file_table
+		WHERE id=" . db_param();
 	$result = db_query_bound( $query, Array( $c_file_id ) );
 	$row = db_fetch_array( $result );
 	extract( $row, EXTR_PREFIX_ALL, 'v' );
 
-	if ( $f_type == 'bug' ) {
-		$t_project_id = bug_get_field( $v_bug_id, 'project_id' );
-	} else {
-		$t_project_id = $v_project_id;
-	}
-
 	# Check access rights
 	switch ( $f_type ) {
 		case 'bug':
 			if ( !file_can_download_bug_attachments( $v_bug_id ) ) {
 				access_denied();
 			}
+			$t_project_id = bug_get_field( $v_bug_id, 'project_id' );
 			break;
-		case 'doc':
+		case 'project':
 			# Check if project documentation feature is enabled.
 			if ( OFF == config_get( 'enable_project_documentation' ) ) {
 				access_denied();
 			}
-
 			access_ensure_project_level( config_get( 'view_proj_doc_threshold' ), $v_project_id );
+			$t_project_id = $v_project_id;
+			break;
+		case 'avatar':
+			$t_project_id = $v_avatar_id;
 			break;
 	}
 
diff --git a/manage_user_page.php b/manage_user_page.php
index b674dbd..e06a3f1 100644
--- a/manage_user_page.php
+++ b/manage_user_page.php
@@ -270,6 +270,7 @@
 		<?php print_manage_user_sort_link(  'manage_user_page.php', lang_get( 'last_visit' ), 'last_visit', $c_dir, $c_sort, $c_hide, $c_filter ) ?>
 		<?php print_sort_icon( $c_dir, $c_sort, 'last_visit' ) ?>
 	</td>
+	<td>Avatar</td>
 </tr>
 <?php
 	$t_date_format = config_get( 'normal_date_format' );
@@ -305,6 +306,9 @@
         </td>
 	<td><?php echo $u_date_created ?></td>
 	<td><?php echo $u_last_visit ?></td>
+	<?php if ( config_get( 'show_avatar' ) ) {?>
+	<td><?php print_avatar ( $u_id ); ?></td>
+	<?php }	?>
 </tr>
 <?php
 	}  # end for
local_avatar_1.2.x.diff (35,983 bytes)   
0001-Loacal-avatar.patch (41,850 bytes)   
From 5e2b6ac3aee89649d4bf8f6dd49f0628646b3515 Mon Sep 17 00:00:00 2001
From: unknown <Peter@.(none)>
Date: Thu, 16 Apr 2009 06:44:43 +0200
Subject: [PATCH] Loacal avatar

---
 account_prefs_avatar_add.php        |   57 +++++
 account_prefs_avatar_upload_inc.php |   81 +++++++
 account_prefs_inc.php               |    8 +
 config_defaults_inc.php             |    4 +-
 core/bug_api.php                    |    2 +-
 core/file_api.php                   |  441 +++++++++++++++--------------------
 core/print_api.php                  |   15 +-
 core/user_api.php                   |  166 +++++++-------
 file_download.php                   |   45 ++--
 manage_user_page.php                |    4 +
 10 files changed, 457 insertions(+), 366 deletions(-)
 create mode 100644 account_prefs_avatar_add.php
 create mode 100644 account_prefs_avatar_upload_inc.php

diff --git a/account_prefs_avatar_add.php b/account_prefs_avatar_add.php
new file mode 100644
index 0000000..052f021
--- /dev/null
+++ b/account_prefs_avatar_add.php
@@ -0,0 +1,57 @@
+<?php
+# Mantis - a php based bugtracking system
+
+# Copyright (C) 2000 - 2002  Kenzaburo Ito - kenito@300baud.org
+# Copyright (C) 2002 - 2008  Mantis Team   - mantisbt-dev@lists.sourceforge.net
+
+# Mantis 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.
+#
+# Mantis 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 Mantis.  If not, see <http://www.gnu.org/licenses/>.
+
+	# Add avatar to the user profile
+
+	require_once( 'core.php' );
+
+	$t_core_path = config_get( 'core_path' );
+
+	require_once( $t_core_path.'file_api.php' );
+
+	# helper_ensure_post();
+
+	# avatar id is actually the same as user id
+	$f_user_id = gpc_get_int( 'avatar_id', -1 );
+	$f_file	   = gpc_get_file( 'file', -1 );
+
+	if ( $f_user_id == -1 && $f_file == -1 ) {
+		# _POST/_FILES does not seem to get populated if you exceed size limit so check if user_id is -1
+		trigger_error( ERROR_FILE_TOO_BIG, ERROR );
+	}
+	
+	access_ensure_global_level( config_get( 'show_avatar_threshold' ), $f_user_id );
+
+	file_add( $f_user_id, $f_file, 'avatar' );
+
+	# Determine which view page to redirect back to.
+	$t_redirect_url = 'account_prefs_page.php';
+
+	html_page_top( null, $t_redirect_url );
+?>
+<br />
+<div align="center">
+<?php
+	echo lang_get( 'operation_successful' ) . '<br />';
+	print_bracket_link( $t_redirect_url, lang_get( 'proceed' ) );
+?>
+</div>
+
+<?php
+	html_page_bottom( __FILE__ );
diff --git a/account_prefs_avatar_upload_inc.php b/account_prefs_avatar_upload_inc.php
new file mode 100644
index 0000000..ae514ad
--- /dev/null
+++ b/account_prefs_avatar_upload_inc.php
@@ -0,0 +1,81 @@
+<?php
+# MantisBT - a php based bugtracking system
+
+# 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/>.
+
+	/**
+	 * This include file prints out the bug file upload form
+	 * It POSTs to bug_file_add.php
+	 * @package MantisBT
+	 * @copyright Copyright (C) 2000 - 2002  Kenzaburo Ito - kenito@300baud.org
+	 * @copyright Copyright (C) 2002 - 2009  MantisBT Team - mantisbt-dev@lists.sourceforge.net
+	 * @link http://www.mantisbt.org
+	 */
+
+	$t_core_path = config_get( 'core_path' );
+	require_once( $t_core_path.'file_api.php' );
+
+	$t_max_file_size = (int)min( ini_get_number( 'upload_max_filesize' ), ini_get_number( 'post_max_size' ), config_get( 'max_file_size' ) );
+?>
+<br />
+
+<?php
+	collapse_open( 'upload_form' );
+?>
+<form method="post" enctype="multipart/form-data" action="account_prefs_avatar_add.php">
+<table class="width75" cellspacing="1">
+<tr>
+	<td class="form-title" colspan="2">
+<?php
+		collapse_icon( 'upload_form' );
+		echo lang_get( 'upload_file' ) ?>
+	</td>
+	<td>
+<?php 
+		print_avatar ( $p_user_id ); ?>
+	</td>
+</tr>
+<tr class="row-1">
+	<td class="category" width="15%">
+		<?php echo lang_get( 'select_file' ) ?><br />
+		<?php echo '<span class="small">(' . lang_get( 'max_file_size' ) . ': ' . number_format( $t_max_file_size/1000 ) . 'k)</span>'?>
+	</td>
+	<td width="85%" colspan="2">
+		<input type="hidden" name="avatar_id" value="<?php echo $p_user_id ?>" />
+		<input type="hidden" name="max_file_size" value="<?php echo $t_max_file_size ?>" />
+		<input name="file" type="file" size="40" />
+		<input type="submit" class="button" value="<?php echo lang_get( 'upload_file_button' ) ?>" />
+	</td>
+</tr>
+</table>
+</form>
+<?php
+	collapse_closed( 'upload_form' );
+?>
+<table class="width75" cellspacing="1">
+<tr>
+	<td class="form-title" colspan="2">
+		<?php
+			collapse_icon( 'upload_form' );
+			echo lang_get( 'upload_file' ) ?>
+	</td>
+	<td>
+		<?php 
+			print_avatar ( $p_user_id ); ?>
+	</td>
+</tr>
+</table>
+
+<?php
+	collapse_end( 'upload_form' );
diff --git a/account_prefs_inc.php b/account_prefs_inc.php
index 404d3b4..06dde6e 100644
--- a/account_prefs_inc.php
+++ b/account_prefs_inc.php
@@ -307,6 +307,14 @@
 </tr>
 </table>
 </form>
+
+<?php
+# File upload box
+if ( config_get( 'show_avatar' ) ) {
+	include( $t_mantis_dir . 'account_prefs_avatar_upload_inc.php' );
+}
+?>
+
 </div>
 
 <br />
diff --git a/config_defaults_inc.php b/config_defaults_inc.php
index 1b754f5..eca438b 100644
--- a/config_defaults_inc.php
+++ b/config_defaults_inc.php
@@ -1571,7 +1571,8 @@
 	 * @global string $g_document_files_prefix
 	 */
 	$g_document_files_prefix = 'doc';
-
+	$g_avatar_files_prefix = 'avatar';
+	
 	/**
 	 * absolute path to the default upload folder.  Requires trailing / or \
 	 * @global string $g_absolute_path_default_upload_folder
@@ -2553,6 +2554,7 @@
 	 * table names
 	 * @global array $g_db_table
 	 */
+	$g_db_table['mantis_avatar_file_table']				= '%db_table_prefix%_avatar_file%db_table_suffix%';
 	$g_db_table['mantis_bug_file_table']				= '%db_table_prefix%_bug_file%db_table_suffix%';
 	$g_db_table['mantis_bug_history_table']				= '%db_table_prefix%_bug_history%db_table_suffix%';
 	$g_db_table['mantis_bug_monitor_table']				= '%db_table_prefix%_bug_monitor%db_table_suffix%';
diff --git a/core/bug_api.php b/core/bug_api.php
index 8473404..a08846b 100644
--- a/core/bug_api.php
+++ b/core/bug_api.php
@@ -765,7 +765,7 @@ function bug_copy( $p_bug_id, $p_target_project_id = null, $p_copy_custom_fields
 
 			# prepare the new diskfile name and then copy the file
 			$t_file_path = dirname( $t_bug_file['folder'] );
-			$t_new_diskfile_name = $t_file_path . file_generate_unique_name( 'bug-' . $t_bug_file['filename'], $t_file_path );
+			$t_new_diskfile_name = $t_file_path . file_generate_unique_name( 'bug' );
 			$t_new_file_name = file_get_display_name( $t_bug_file['filename'] );
 			if(( config_get( 'file_upload_method' ) == DISK ) ) {
 				copy( $t_bug_file['diskfile'], $t_new_diskfile_name );
diff --git a/core/file_api.php b/core/file_api.php
index 625e924..88f0d6c 100644
--- a/core/file_api.php
+++ b/core/file_api.php
@@ -36,7 +36,15 @@ require_once( $t_core_dir . 'bug_api.php' );
 $g_cache_file_count = array();
 
 # ## File API ###
-# Gets the filename without the bug id prefix.
+
+/**
+ * Gets the filename without the bug id prefix 
+ * 
+ * In fact no code really cares for whats coming from here
+ * 
+ * @param	string	$p_filename	The file name
+ * @return	string				The file name
+ */
 function file_get_display_name( $p_filename ) {
 	$t_array = explode( '-', $p_filename, 2 );
 
@@ -48,18 +56,21 @@ function file_get_display_name( $p_filename ) {
 	$t_name = preg_split( $t_doc_match, $p_filename );
 	if( isset( $t_name[1] ) ) {
 		return $t_name[1];
-	} else {
-		$t_bug_match = '/^\d{7}-/';
-		$t_name = preg_split( $t_bug_match, $p_filename );
-		if( isset( $t_name[1] ) ) {
-			return $t_name[1];
-		} else {
-			return $p_filename;
-		}
 	}
+	$t_bug_match = '/^\d{7}-/';
+	$t_name = preg_split( $t_bug_match, $p_filename );
+	if( isset( $t_name[1] ) ) {
+		return $t_name[1];
+	}
+	return $p_filename;
 }
 
-# Check the number of attachments a bug has (if any)
+/**
+ * Check the number of attachments a bug has (if any)
+ * 
+ *  @param	integer	$p_bug_id
+ *  @return	integer				Number of attachments
+ */
 function file_bug_attachment_count( $p_bug_id ) {
 	global $g_cache_file_count;
 
@@ -102,7 +113,11 @@ function file_bug_attachment_count( $p_bug_id ) {
 	return $t_file_count;
 }
 
-# Check if a specific bug has attachments
+/**
+ * Check if a specific bug has attachments
+ * @param	integer	$p_bug_id
+ * @return	bool
+ */
 function file_bug_has_attachments( $p_bug_id ) {
 	if( file_bug_attachment_count( $p_bug_id ) > 0 ) {
 		return true;
@@ -111,45 +126,50 @@ function file_bug_has_attachments( $p_bug_id ) {
 	}
 }
 
-# Check if the current user can view attachments for the specified bug.
-function file_can_view_bug_attachments( $p_bug_id ) {
+function file_can_do_with_bug ( $p_bug_id, $p_what ) {
 	$t_reported_by_me = bug_is_user_reporter( $p_bug_id, auth_get_current_user_id() );
-	$t_can_view = access_has_bug_level( config_get( 'view_attachments_threshold' ), $p_bug_id );
+	$t_can_do = access_has_bug_level( config_get( $p_what.'_attachments_threshold' ), $p_bug_id );
+	$t_can_do_own = config_get( 'allow_'.$p_what.'_own_attachments' ); 
 
-	/** @todo Fix this to be readable */
-	$t_can_view = $t_can_view || ( $t_reported_by_me && config_get( 'allow_view_own_attachments' ) );
+	$t_can_do = $t_can_do || ( $t_reported_by_me && $t_can_do_own );
 
-	return $t_can_view;
+	return $t_can_do;
+}
+/**
+ * Check if the current user can view attachments for the specified bug.
+ * @param	integer	$p_bug_id
+ * @return	bool
+ */
+function file_can_view_bug_attachments( $p_bug_id ) {
+	return file_can_do_with_bug ( $p_bug_id, 'view');
 }
 
-# Check if the current user can download attachments for the specified bug.
+/**
+ * Check if the current user can download attachments for the specified bug.
+ * @param	integer	$p_bug_id
+ * @return	bool
+ */
 function file_can_download_bug_attachments( $p_bug_id ) {
-	$t_reported_by_me = bug_is_user_reporter( $p_bug_id, auth_get_current_user_id() );
-	$t_can_download = access_has_bug_level( config_get( 'download_attachments_threshold' ), $p_bug_id );
-
-	/** @todo Fix this to be readable */
-	$t_can_download = $t_can_download || ( $t_reported_by_me && config_get( 'allow_download_own_attachments' ) );
-
-	return $t_can_download;
+	return file_can_do_with_bug ( $p_bug_id, 'download');
 }
 
-# Check if the current user can delete attachments from the specified bug.
+/**
+ * Check if the current user can delete attachments from the specified bug.
+ * @param	integer	$p_bug_id
+ * @return	bool
+ */
 function file_can_delete_bug_attachments( $p_bug_id ) {
 	if( bug_is_readonly( $p_bug_id ) ) {
 		return false;
 	}
-
-	$t_reported_by_me = bug_is_user_reporter( $p_bug_id, auth_get_current_user_id() );
-	$t_can_download = access_has_bug_level( config_get( 'delete_attachments_threshold' ), $p_bug_id );
-
-	/** @todo Fix this to be readable */
-	$t_can_download = $t_can_download || ( $t_reported_by_me && config_get( 'allow_delete_own_attachments' ) );
-
-	return $t_can_download;
+	return file_can_do_with_bug ( $p_bug_id, 'delete');
 }
 
-# Get icon corresponding to the specified filename
-# returns an associative array with "url" and "alt" text.
+/**
+ * Get icon corresponding to the specified filename
+ * @param	string	$p_display_filename
+ * @return	array						which has url and alt members
+ */
 function file_get_icon_url( $p_display_filename ) {
 	$t_file_type_icons = config_get( 'file_type_icons' );
 
@@ -165,8 +185,8 @@ function file_get_icon_url( $p_display_filename ) {
 /**
  * Combines a path and a file name making sure that the separator exists.
  *
- * @param string $p_path       The path.
- * @param string $p_filename   The file name.
+ * @param string $p_path		The path.
+ * @param string $p_filename	The file name.
  *
  * @return The combined full path.
  */
@@ -182,16 +202,18 @@ function file_path_combine( $p_path, $p_filename ) {
 }
 
 /**
- * Nomalizes the disk file path based on the following algorithm:
- * 1. If disk file exists, then return as is.
- * 2. If not, and a project path is available, then check with that, if exists return it.
- * 3. If not, then use default upload path, then check with that, if exists return it.
- * 4. If disk file doesn't include a path, then return expected path based on project path or default path.
- * 5. Otherwise return as is.
+ * Nomalizes the disk file path.
+ * 
+ * Uses the following algorithm:
+ * 1 If disk file exists, then return as is
+ * 2 If not, and a project path is available, then check with that, if exists return it
+ * 3 If not, then use default upload path, then check with that, if exists return it
+ * 4 If disk file doesn't include a path, then return expected path based on project path or default path
+ * 5 Otherwise return as is.
  *
- * @param string $p_diskfile  The disk file (full path or just filename).
- * @param integer The project id - shouldn't be 0 (ALL_PROJECTS).
- * @return The normalized full path.
+ * @param string $p_diskfile	The disk file (full path or just filename).
+ * @param integer $p_project_id	The project id - shouldn't be 0 (ALL_PROJECTS).
+ * @return string				The normalized full path.
  */
 function file_normalize_attachment_path( $p_diskfile, $p_project_id ) {
 	if ( file_exists( $p_diskfile ) ) {
@@ -239,21 +261,26 @@ function file_normalize_attachment_path( $p_diskfile, $p_project_id ) {
 	return $p_diskfile;
 }
 
-# --------------------
-# Gets an array of attachments that are visible to the currently logged in user.
-# Each element of the array contains the following:
-# display_name - The attachment display name (i.e. file name dot extension)
-# size - The attachment size in bytes.
-# date_added - The date where the attachment was added.
-# can_download - true: logged in user has access to download the attachment, false: otherwise.
-# diskfile - The name of the file on disk.  Typically this is a hash without an extension.
-# download_url - The download URL for the attachment (only set if can_download is true).
-# exists - Applicable for DISK attachments.  true: file exists, otherwise false.
-# can_delete - The logged in user can delete the attachments.
-# preview - true: the attachment should be previewable, otherwise false.
-# type - Can be "image", "text" or empty for other types.
-# alt - The alternate text to be associated with the icon.
-# icon - array with icon information, contains 'url' and 'alt' elements.
+/**
+ * Gets an array of attachments that are visible to the currently logged in user.
+ * 
+ * Each element of the array contains the following:
+ * display_name	- The attachment display name (file name dot extension)
+ * size			- The attachment size in bytes
+ * date_added	- The date where the attachment was added
+ * can_download	- true: logged in user has access to download the attachment, false: otherwise
+ * diskfile		- The name of the file on disk Typically this is a hash without an extension
+ * download_url - The download URL for the attachment (only set if can_download is true) 
+ * exists - Applicable for DISK attachments.  true: file exists, otherwise false.
+ * can_delete - The logged in user can delete the attachments.
+ * preview - true: the attachment should be previewable, otherwise false.
+ * type - Can be "image", "text" or empty for other types.
+ * alt - The alternate text to be associated with the icon.
+ * icon - array with icon information, contains 'url' and 'alt' elements.
+ * 
+ * @param	integer	$p_bug_id
+ * @return	array
+ */
 function file_get_visible_attachments( $p_bug_id ) {
 	$t_attachment_rows = bug_get_attachments( $p_bug_id );
 	$t_visible_attachments = array();
@@ -324,101 +351,64 @@ function file_get_visible_attachments( $p_bug_id ) {
 	return $t_attachments;
 }
 
-# delete all files that are associated with the given bug
-function file_delete_attachments( $p_bug_id ) {
-	$c_bug_id = db_prepare_int( $p_bug_id );
-
-	$t_bug_file_table = db_get_table( 'mantis_bug_file_table' );
-
+/**
+ * Remove files from the given table based on the key
+ * 
+ * This is used to remove all the attachments, documents or avatars This function
+ * should be called only by the specialized functions which know the table from
+ * where to delete.
+ * 
+ * @param	integer	$p_id
+ * @param	string	$p_table
+ * @return	boolean	true
+ * @access	private
+ */
+function file_delete_many ( $p_id, $p_table ) {
+	$c_id = db_prepare_int( $p_id );
+	$t_file_table = db_get_table( 'mantis_'.$p_table.'_file_table' );
 	$t_method = config_get( 'file_upload_method' );
 
 	# Delete files from disk
-	$query = "SELECT diskfile, filename
-				FROM $t_bug_file_table
-				WHERE bug_id=" . db_param();
-	$result = db_query_bound( $query, Array( $c_bug_id ) );
+	$query = "SELECT id
+				FROM $t_file_table
+				WHERE ".$p_table."_id=" . db_param();
+	$result = db_query_bound( $query, Array( $c_id ) );
 
 	$file_count = db_num_rows( $result );
 	if( 0 == $file_count ) {
 		return true;
 	}
-
-	if(( DISK == $t_method ) || ( FTP == $t_method ) ) {
-
-		# there may be more than one file
-		$ftp = 0;
-		if( FTP == $t_method ) {
-			$ftp = file_ftp_connect();
-		}
-
-		for( $i = 0;$i < $file_count;$i++ ) {
-			$row = db_fetch_array( $result );
-
-			$t_local_diskfile = file_normalize_attachment_path( $row['diskfile'], bug_get_field( $p_bug_id, 'project_id' ) );
-			file_delete_local( $t_local_diskfile );
-
-			if( FTP == $t_method ) {
-				file_ftp_delete( $ftp, $row['diskfile'] );
-			}
-		}
-
-		if( FTP == $t_method ) {
-			file_ftp_disconnect( $ftp );
-		}
-	}
-
-	# Delete the corresponding db records
-	$query = "DELETE FROM $t_bug_file_table
-				  WHERE bug_id=" . db_param();
-	$result = db_query_bound( $query, Array( $c_bug_id ) );
-
+	for( $i = 0;$i < $file_count;$i++ ) {
+		$row = db_fetch_array( $result );
+		file_delete ( $row['id'], $p_table );
+	}	
 	# db_query errors on failure so:
 	return true;
 }
 
-function file_delete_project_files( $p_project_id ) {
-	$t_project_file_table = db_get_table( 'mantis_project_file_table' );
-	$t_method = config_get( 'file_upload_method' );
-
-	# Delete the file physically (if stored via DISK or FTP)
-	if(( DISK == $t_method ) || ( FTP == $t_method ) ) {
-
-		# Delete files from disk
-		$query = "SELECT diskfile, filename
-					FROM $t_project_file_table
-					WHERE project_id=" . db_param();
-		$result = db_query_bound( $query, array( (int) $p_project_id ) );
-
-		$file_count = db_num_rows( $result );
-
-		$ftp = 0;
-		if( FTP == $t_method ) {
-			$ftp = file_ftp_connect();
-		}
-
-		for( $i = 0;$i < $file_count;$i++ ) {
-			$row = db_fetch_array( $result );
-
-			$t_local_diskfile = file_normalize_attachment_path( $row['diskfile'], $p_project_id );
-			file_delete_local( $t_local_diskfile );
 
-			if( FTP == $t_method ) {
-				file_ftp_delete( $ftp, $row['diskfile'] );
-			}
-		}
+/**
+ * Delete all files that are associated with the given bug
+ * @param $p_bug_id
+ * @return unknown_type
+ */
+function file_delete_attachments( $p_bug_id ) {
+	return file_delete_many ( $p_bug_id, 'bug');
+}
 
-		if( FTP == $t_method ) {
-			file_ftp_disconnect( $ftp );
-		}
-	}
+function file_delete_project_files( $p_project_id ) {
+	return file_delete_many ( $p_project_id, 'project');
+}
 
-	# Delete the corresponding db records
-	$query = "DELETE FROM $t_project_file_table
-				WHERE project_id=" . db_param();
-	$result = db_query_bound( $query, Array( (int) $p_project_id ) );
+function file_delete_avatars( $p_avatar_id ) {
+	return file_delete_many ( $p_avatar_id, 'avatar');
 }
 
-# Delete all cached files that are older than configured number of days.
+/**
+ * Delete all cached files that are older than configured number of days.
+ * 
+ * @return unknown_type
+ */
 function file_ftp_cache_cleanup() {
 }
 
@@ -434,7 +424,14 @@ function file_ftp_connect() {
 	return $conn_id;
 }
 
-# Put a file to the ftp server.
+/**
+ * Put a file to the ftp server.
+ * 
+ * @param $p_conn_id
+ * @param $p_remote_filename
+ * @param $p_local_filename
+ * @return unknown_type
+ */
 function file_ftp_put( $p_conn_id, $p_remote_filename, $p_local_filename ) {
 	helper_begin_long_process();
 	$upload = ftp_put( $p_conn_id, $p_remote_filename, $p_local_filename, FTP_BINARY );
@@ -485,11 +482,10 @@ function file_delete( $p_file_id, $p_table = 'bug' ) {
 	$t_filename = file_get_field( $p_file_id, 'filename', $p_table );
 	$t_diskfile = file_get_field( $p_file_id, 'diskfile', $p_table );
 
+	$t_project_id = file_get_field( $p_file_id, $p_table.'_id', $p_table );
+	$t_bug_id = $t_project_id;
 	if ( $p_table == 'bug' ) {
-		$t_bug_id = file_get_field( $p_file_id, 'bug_id', $p_table );
 		$t_project_id = bug_get_field( $t_bug_id, 'project_id' );
-	} else {
-		$t_project_id = file_get_field( $p_file_id, 'project_id', $p_table );
 	}
 
 	if(( DISK == $t_upload_method ) || ( FTP == $t_upload_method ) ) {
@@ -523,35 +519,23 @@ function file_delete( $p_file_id, $p_table = 'bug' ) {
 
 # File type check
 function file_type_check( $p_file_name ) {
-	$t_allowed_files = config_get( 'allowed_files' );
-	$t_disallowed_files = config_get( 'disallowed_files' );;
+	$t_allowed_files = strtolower(config_get( 'allowed_files' ));
+	$t_disallowed_files = strtolower(config_get( 'disallowed_files' ));
 
 	# grab extension
-	$t_ext_array = explode( '.', $p_file_name );
-	$last_position = count( $t_ext_array ) - 1;
-	$t_extension = $t_ext_array[$last_position];
+	$t_extension = strtolower(file_get_extension( $p_file_name ));
 
 	# check against disallowed files
-	$t_disallowed_arr = explode( ',', $t_disallowed_files );
-	foreach( $t_disallowed_arr as $t_val ) {
-		if( 0 == strcasecmp( $t_val, $t_extension ) ) {
-			return false;
-		}
+	if ( in_array($t_extension, explode( ',', $t_disallowed_files ))) {
+		return false;
 	}
 
 	# if the allowed list is note populated then the file must be allowed
-	if( is_blank( $t_allowed_files ) ) {
+	# or check against allowed files
+	if ( is_blank( $t_allowed_files ) || in_array($t_extension, explode( ',', $t_allowed_files ))) {
 		return true;
 	}
 
-	# check against allowed files
-	$t_allowed_arr = explode( ',', $t_allowed_files );
-	foreach( $t_allowed_arr as $t_val ) {
-		if( 0 == strcasecmp( $t_val, $t_extension ) ) {
-			return true;
-		}
-	}
-
 	return false;
 }
 
@@ -560,53 +544,29 @@ function file_clean_name( $p_filename ) {
 	return preg_replace( "/[\/\\ :&]/", "_", $p_filename );
 }
 
-# Generate a string to use as the identifier for the file
-# It is not guaranteed to be unique and should be checked
-# The string returned should be 32 characters in length
-function file_generate_name( $p_seed ) {
-	$t_val = md5( $p_seed . time() );
-
-	return substr( $t_val, 0, 32 );
-}
-
-# Generate a UNIQUE string to use as the identifier for the file
-# The string returned should be 64 characters in length
-function file_generate_unique_name( $p_seed, $p_filepath ) {
-	do {
-		$t_string = file_generate_name( $p_seed );
-	}
-	while( !diskfile_is_name_unique( $t_string, $p_filepath ) );
-
-	return $t_string;
-}
-
-# Return true if the diskfile name identifier is unique, false otherwise
-function diskfile_is_name_unique( $p_name, $p_filepath ) {
-	$t_file_table = db_get_table( 'mantis_bug_file_table' );
-
-	$c_name = $p_filepath . $p_name;
-
-	$query = "SELECT COUNT(*)
-				  FROM $t_file_table
-				  WHERE diskfile=" . db_param();
-	$result = db_query_bound( $query, Array( $c_name ) );
-	$t_count = db_result( $result );
-
-	if( $t_count > 0 ) {
-		return false;
-	} else {
-		return true;
-	}
+function file_generate_unique_name( $p_prefix ) {
+	return uniqid( $p_prefix, true );
 }
 
-# Return true if the file name identifier is unique, false otherwise
-function file_is_name_unique( $p_name, $p_bug_id ) {
-	$t_file_table = db_get_table( 'mantis_bug_file_table' );
+/**
+ * Check if filename is unique.
+ * 
+ * The function will check the appropriate table for
+ * duplicate file names.
+ * 
+ * @param	string	$p_name		file name
+ * @param 	integer	$p_key_id	bug_id, avatar_id or document_id
+ * @param 	string	$p_table	bug, doc, avatar
+ * @return	boolean
+ */
+function file_is_name_unique( $p_name, $p_key_id, $p_table = 'bug' ) {
+	if ( 'doc' == $p_table ) { $p_table = 'project'; }
+	$t_file_table = db_get_table( 'mantis_'.$p_table.'_file_table' );
 
 	$query = "SELECT COUNT(*)
 				  FROM $t_file_table
-				  WHERE filename=" . db_param() . " AND bug_id=" . db_param();
-	$result = db_query_bound( $query, Array( $p_name, $p_bug_id ) );
+				  WHERE filename=" . db_param() . " AND ".$p_table."_id=" . db_param();
+	$result = db_query_bound( $query, Array( $p_name, $p_key_id ) );
 	$t_count = db_result( $result );
 
 	if( $t_count > 0 ) {
@@ -622,30 +582,42 @@ function file_is_name_unique( $p_name, $p_bug_id ) {
  * @param integer $p_bug_id the bug id
  * @param array $p_file the uploaded file info, as retrieved from gpc_get_file()
  */
-function file_add( $p_bug_id, $p_file, $p_table = 'bug', $p_title = '', $p_desc = '' ) {
+function file_add( $p_key_id, $p_file, $p_table = 'bug', $p_title = '', $p_desc = '' ) {
 
 	file_ensure_uploaded( $p_file );
 	$t_file_name = $p_file['name'];
 	$t_tmp_file = $p_file['tmp_name'];
-
+	$t_file_table = db_get_table( 'mantis_' . $p_table . '_file_table' );
+	
 	if( !file_type_check( $t_file_name ) ) {
 		trigger_error( ERROR_FILE_NOT_ALLOWED, ERROR );
 	}
-
-	if( !file_is_name_unique( $t_file_name, $p_bug_id ) ) {
+	
+	if( !file_is_name_unique( $t_file_name, $p_key_id, $p_table ) ) {
 		trigger_error( ERROR_DUPLICATE_FILE, ERROR );
 	}
-
-	if( 'bug' == $p_table ) {
-		$t_project_id = bug_get_field( $p_bug_id, 'project_id' );
-		$t_bug_id = bug_format_id( $p_bug_id );
-	} else {
-		$t_project_id = helper_get_current_project();
-		$t_bug_id = 0;
+	
+	switch ( $p_table ) {
+		case 'bug':
+			$t_project_id = bug_get_field( $p_key_id, 'project_id' );
+			$t_key_id = bug_format_id( $p_key_id );
+			$t_file_hash = $t_key_id;
+			$c_id = db_prepare_int( $p_key_id );
+			break;
+		case 'avatar':
+			$t_project_id = ALL_PROJECTS;
+			$t_file_name = config_get( 'avatar_files_prefix' ) . '-' . $p_key_id;
+			$c_id = db_prepare_int( $p_key_id );
+			break;
+		default:
+			$t_project_id = helper_get_current_project();
+			$t_file_name = config_get( 'document_files_prefix' ) . '-' . $t_project_id;
+			$c_id = db_prepare_int( $t_project_id );
+			break;
 	}
 
 	# prepare variables for insertion
-	$c_bug_id = db_prepare_int( $p_bug_id );
+	$c_key_id = db_prepare_int( $p_key_id );
 	$c_project_id = db_prepare_int( $t_project_id );
 	$c_file_type = db_prepare_string( $p_file['type'] );
 	$c_title = db_prepare_string( $p_title );
@@ -661,9 +633,7 @@ function file_add( $p_bug_id, $p_file, $p_table = 'bug', $p_title = '', $p_desc
 	}
 	$c_file_path = db_prepare_string( $t_file_path );
 	$c_new_file_name = db_prepare_string( $t_file_name );
-
-	$t_file_hash = ( 'bug' == $p_table ) ? $t_bug_id : config_get( 'document_files_prefix' ) . '-' . $t_project_id;
-	$t_unique_name = file_generate_unique_name( $t_file_hash . '-' . $t_file_name, $t_file_path );
+	$t_unique_name = file_generate_unique_name( $p_table );
 	$t_disk_file_name = $t_file_path . $t_unique_name;
 	$c_unique_name = db_prepare_string( $t_unique_name );
 
@@ -709,9 +679,6 @@ function file_add( $p_bug_id, $p_file, $p_table = 'bug', $p_title = '', $p_desc
 			trigger_error( ERROR_GENERIC, ERROR );
 	}
 
-	$t_file_table = db_get_table( 'mantis_' . $p_table . '_file_table' );
-	$c_id = ( 'bug' == $p_table ) ? $c_bug_id : $c_project_id;
-
 	$query = "INSERT INTO $t_file_table
 						(" . $p_table . "_id, title, description, diskfile, filename, folder, filesize, file_type, date_added, content)
 					  VALUES
@@ -721,10 +688,10 @@ function file_add( $p_bug_id, $p_file, $p_table = 'bug', $p_title = '', $p_desc
 	if( 'bug' == $p_table ) {
 
 		# updated the last_updated date
-		$result = bug_update_date( $p_bug_id );
+		$result = bug_update_date( $p_key_id );
 
 		# log new bug
-		history_log_event_special( $p_bug_id, FILE_ADDED, $t_file_name );
+		history_log_event_special( $p_key_id, FILE_ADDED, $t_file_name );
 	}
 }
 
@@ -836,27 +803,5 @@ function file_ensure_uploaded( $p_file ) {
 
 # Get extension given the filename or its full path.
 function file_get_extension( $p_filename ) {
-	$ext = '';
-	$dot_found = false;
-	$i = strlen( $p_filename ) - 1;
-	while( $i >= 0 ) {
-		if( '.' == $p_filename[$i] ) {
-			$dot_found = true;
-			break;
-		}
-
-		# foung a directoryarker before a period.
-		if(( $p_filename[$i] == "/" ) || ( $p_filename[$i] == "\\" ) ) {
-			return '';
-		}
-
-		$ext = $p_filename[$i] . $ext;
-		$i--;
-	}
-
-	if( $dot_found ) {
-		return $ext;
-	} else {
-		return '';
-	}
+	return pathinfo($p_filename, PATHINFO_EXTENSION);
 }
diff --git a/core/print_api.php b/core/print_api.php
index c2c4eea..7cb304b 100644
--- a/core/print_api.php
+++ b/core/print_api.php
@@ -146,22 +146,23 @@ function print_successful_redirect( $p_redirect_to ) {
 }
 
 # Print avatar image for the given user ID
-function print_avatar( $p_user_id, $p_size = 80 ) {
-	if( !user_exists( $p_user_id ) ) {
+function print_avatar( $p_user_id ) {
+	if ( !user_exists( $p_user_id ) ) {
 		return;
 	}
 
-	if( access_has_project_level( config_get( 'show_avatar_threshold' ), null, $p_user_id ) ) {
-		$t_avatar = user_get_avatar( $p_user_id, $p_size );
-		if( false !== $t_avatar ) {
+	if ( access_has_project_level( config_get( 'show_avatar_threshold' ), null, $p_user_id ) ) {
+		$t_avatar = user_get_avatar( $p_user_id );
+		if ( false !== $t_avatar ) {
 			$t_avatar_url = $t_avatar[0];
 			$t_width = $t_avatar[1];
 			$t_height = $t_avatar[2];
-			echo '<a rel="nofollow" href="http://site.gravatar.com">' . '<img class="avatar" src="' . $t_avatar_url . '" alt="User avatar"' . ' width="' . $t_width . '" height="' . $t_height . '" /></a>';
+			$t_href = $t_avatar[3];
+			echo '<a rel="nofollow" href="'.$t_href.'"><img class="avatar" src="'.$t_avatar_url.'" alt="User avatar" width="'.$t_width.'" height="'.$t_height.'" /></a>';
 		}
 	}
 }
-
+	
 # --------------------
 # prints the name of the user given the id.  also makes it an email link.
 function print_user( $p_user_id ) {
diff --git a/core/user_api.php b/core/user_api.php
index cb908fb..4569319 100644
--- a/core/user_api.php
+++ b/core/user_api.php
@@ -518,18 +518,16 @@ function user_signup( $p_username, $p_email = null ) {
 	return user_create( $p_username, $t_password, $p_email );
 }
 
-# --------------------
-# delete project-specific user access levels.
-# returns true when successfully deleted
-function user_delete_project_specific_access_levels( $p_user_id ) {
+function user_delete_from ( $p_user_id, $p_key_id, $p_table ) {
 	$c_user_id = db_prepare_int( $p_user_id );
 
 	user_ensure_unprotected( $p_user_id );
 
-	$t_project_user_list_table = db_get_table( 'mantis_project_user_list_table' );
+	$t_table = db_get_table( $p_table );
 
-	$query = "DELETE FROM $t_project_user_list_table
-				  WHERE user_id=" . db_param();
+	# Remove associated profiles
+	$query = "DELETE FROM $t_table
+				  WHERE '.$p_key_id.'=" . db_param();
 	db_query_bound( $query, Array( $c_user_id ) );
 
 	user_clear_cache( $p_user_id );
@@ -538,23 +536,26 @@ function user_delete_project_specific_access_levels( $p_user_id ) {
 }
 
 # --------------------
+# delete project-specific user access levels.
+# returns true when successfully deleted
+function user_delete_project_specific_access_levels( $p_user_id ) {
+	return user_delete_from ( $p_user_id, 'user_id', 'mantis_project_user_list_table' );
+}
+
+# --------------------
 # delete profiles for the specified user
 # returns true when successfully deleted
 function user_delete_profiles( $p_user_id ) {
-	$c_user_id = db_prepare_int( $p_user_id );
-
-	user_ensure_unprotected( $p_user_id );
-
-	$t_user_profile_table = db_get_table( 'mantis_user_profile_table' );
-
-	# Remove associated profiles
-	$query = "DELETE FROM $t_user_profile_table
-				  WHERE user_id=" . db_param();
-	db_query_bound( $query, Array( $c_user_id ) );
-
-	user_clear_cache( $p_user_id );
+	return user_delete_from ( $p_user_id, 'user_id', 'mantis_user_profile_table' );
+}
 
-	return true;
+# --------------------
+# delete avatar(s) for the specified user
+# returns true when successfully deleted
+function user_delete_avatar ( $p_avatar_id ) {
+	user_ensure_unprotected( $p_avatar_id );
+	file_delete_avatars ( $p_avatar_id );
+	return user_delete_from ( $p_avatar_id, 'avatar_id', 'mantis_avatar_profile_table' );
 }
 
 # --------------------
@@ -567,6 +568,9 @@ function user_delete( $p_user_id ) {
 	user_ensure_unprotected( $p_user_id );
 
 	# Remove associated profiles
+	user_delete_avatar( $p_user_id );
+	
+	# Remove associated profiles
 	user_delete_profiles( $p_user_id );
 
 	# Remove associated preferences
@@ -608,11 +612,9 @@ function user_delete( $p_user_id ) {
 # Data Access
 # ===================================
 # --------------------
-# get a user id from a username
-#  return false if the username does not exist
-function user_get_id_by_name( $p_username ) {
+function user_get_id_by ( $p_key, $p_value ) {
 	global $g_cache_user;
-	if( $t_user = user_search_cache( 'username', $p_username ) ) {
+	if( $t_user = user_search_cache( $p_key, $p_value ) ) {
 		return $t_user['id'];
 	}
 
@@ -620,8 +622,8 @@ function user_get_id_by_name( $p_username ) {
 
 	$query = "SELECT *
 				  FROM $t_user_table
-				  WHERE username=" . db_param();
-	$result = db_query_bound( $query, Array( $p_username ) );
+				  WHERE $p_key=" . db_param();
+	$result = db_query_bound( $query, Array( $p_value ) );
 
 	if( 0 == db_num_rows( $result ) ) {
 		return false;
@@ -632,50 +634,19 @@ function user_get_id_by_name( $p_username ) {
 	}
 }
 
-# Get a user id from an email address
-function user_get_id_by_email( $p_email ) {
-	global $g_cache_user;
-	if( $t_user = user_search_cache( 'email', $p_email ) ) {
-		return $t_user['id'];
-	}
-
-	$t_user_table = db_get_table( 'mantis_user_table' );
 
-	$query = "SELECT *
-				  FROM $t_user_table
-				  WHERE email=" . db_param();
-	$result = db_query_bound( $query, Array( $p_email ) );
+function user_get_id_by_name( $p_username ) {
+	return user_get_id_by ( 'username', $p_username );
+}
 
-	if( 0 == db_num_rows( $result ) ) {
-		return false;
-	} else {
-		$row = db_fetch_array( $result );
-		user_cache_database_result( $row );
-		return $row['id'];
-	}
+# Get a user id from an email address
+function user_get_id_by_email( $p_email ) {
+	return user_get_id_by ( 'email', $p_email );
 }
 
 # Get a user id from their real name
 function user_get_id_by_realname( $p_realname ) {
-	global $g_cache_user;
-	if( $t_user = user_search_cache( 'realname', $p_realname ) ) {
-		return $t_user['id'];
-	}
-
-	$t_user_table = db_get_table( 'mantis_user_table' );
-
-	$query = "SELECT *
-				  FROM $t_user_table
-				  WHERE realname=" . db_param();
-	$result = db_query_bound( $query, Array( $p_realname ) );
-
-	if( 0 == db_num_rows( $result ) ) {
-		return false;
-	} else {
-		$row = db_fetch_array( $result );
-		user_cache_database_result( $row );
-		return $row['id'];
-	}
+	return user_get_id_by ( 'realname', $p_realname );
 }
 
 # --------------------
@@ -770,30 +741,59 @@ function user_get_name( $p_user_id ) {
 * @return array|bool an array( URL, width, height ) or false when the given user has no avatar
 */
 function user_get_avatar( $p_user_id, $p_size = 80 ) {
-	$t_email = strtolower( user_get_email( $p_user_id ) );
-	if( is_blank( $t_email ) ) {
-		$t_result = false;
-	} else {
-		$t_default_image = config_get( 'default_avatar' );
-		$t_size = $p_size;
+	$t_avatar_type = strtolower ( config_get ( 'avatar_type' ) );
+	$t_found_local_avatar = false;
 
-		$t_use_ssl = false;
-		if( isset( $_SERVER['HTTPS'] ) && ( strtolower( $_SERVER['HTTPS'] ) != 'off' ) ) {
-			$t_use_ssl = true;
+	if ( $t_avatar_type == 'local' ) {
+		$c_user_id = db_prepare_int ( $p_user_id );
+		$t_avatar_table = db_get_table ( 'mantis_avatar_file_table' );
+		$query = "SELECT id
+				  FROM $t_avatar_table
+				  WHERE avatar_id='$c_user_id'";
+		$t_db_result = db_query ( $query );
+		/*
+		 * theoretically you could have more than one local avatar
+		 * but for now only one is allowed.
+		 */
+		if ( 1 == db_num_rows( $t_db_result )) {
+			$t_found_local_avatar = true;
+			$t_avatar_id = db_result ( $t_db_result );
+			$t_avatar_url = "file_download.php?type=avatar&amp;file_id=".$t_avatar_id;
+			$t_avatar_ref = "manage_user_edit_page.php?user_id=".$p_user_id;
+			$t_size = $p_size;
+			$t_result = array( $t_avatar_url, $t_size, $t_size, $t_avatar_ref );
 		}
+	}
 
-		if( !$t_use_ssl ) {
-			$t_gravatar_domain = 'http://www.gravatar.com/';
+	// if local avatar is disabled or not found check the gravatar
+	if ( ! $t_found_local_avatar ) {
+		// for gravatar you need a valid email
+		$t_email = strtolower( user_get_email( $p_user_id ) );
+		if( is_blank( $t_email ) ) {
+			$t_result = false;
 		} else {
-			$t_gravatar_domain = 'https://secure.gravatar.com/';
+			$t_default_image = config_get( 'default_avatar' );
+			$t_size = $p_size;
+	
+			$t_use_ssl = false;
+			if( isset( $_SERVER['HTTPS'] ) && ( strtolower( $_SERVER['HTTPS'] ) != 'off' ) ) {
+				$t_use_ssl = true;
+			}
+	
+			if( !$t_use_ssl ) {
+				$t_avatar_domain = 'http://www.gravatar.com/';
+			} else {
+				$t_avatar_domain = 'https://secure.gravatar.com/';
+			}
+	
+			$t_avatar_url = $t_avatar_domain . 'avatar.php?gravatar_id=' . md5( $t_email ) . '&amp;default=' . urlencode( $t_default_image ) . '&amp;size=' . $t_size . '&amp;rating=G';
+			$t_result = array(
+				$t_avatar_url,
+				$t_size,
+				$t_size,
+				$t_avatar_domain,
+			);
 		}
-
-		$t_avatar_url = $t_gravatar_domain . 'avatar.php?gravatar_id=' . md5( $t_email ) . '&amp;default=' . urlencode( $t_default_image ) . '&amp;size=' . $t_size . '&amp;rating=G';
-		$t_result = array(
-			$t_avatar_url,
-			$t_size,
-			$t_size,
-		);
 	}
 
 	return $t_result;
diff --git a/file_download.php b/file_download.php
index eec4d4d..9b4cd8a 100644
--- a/file_download.php
+++ b/file_download.php
@@ -34,54 +34,47 @@
 ?>
 <?php auth_ensure_user_authenticated() ?>
 <?php
+	$f_type	= gpc_get_string( 'type' );
+	$t_allowed_tables = array ( 'bug', 'doc', 'avatar' );
+	if ( ! in_array ($f_type, $t_allowed_tables) ) {
+		access_denied();
+	}
+	
+	if ( $f_type == 'doc' ) {
+		$f_type = 'project';
+	}
 	$f_file_id	= gpc_get_int( 'file_id' );
-	$f_type		= gpc_get_string( 'type' );
-
 	$c_file_id = (integer)$f_file_id;
 
 	# we handle the case where the file is attached to a bug
 	# or attached to a project as a project doc.
 	$query = '';
-	switch ( $f_type ) {
-		case 'bug':
-			$t_bug_file_table = db_get_table( 'mantis_bug_file_table' );
-			$query = "SELECT *
-				FROM $t_bug_file_table
-				WHERE id=" . db_param();
-			break;
-		case 'doc':
-			$t_project_file_table = db_get_table( 'mantis_project_file_table' );
-			$query = "SELECT *
-				FROM $t_project_file_table
-				WHERE id=" . db_param();
-			break;
-		default:
-			access_denied();
-	}
+	$t_file_table = db_get_table( 'mantis_'.$f_type.'_file_table' );
+	$query = "SELECT *
+		FROM $t_file_table
+		WHERE id=" . db_param();
 	$result = db_query_bound( $query, Array( $c_file_id ) );
 	$row = db_fetch_array( $result );
 	extract( $row, EXTR_PREFIX_ALL, 'v' );
 
-	if ( $f_type == 'bug' ) {
-		$t_project_id = bug_get_field( $v_bug_id, 'project_id' );
-	} else {
-		$t_project_id = $v_project_id;
-	}
-
 	# Check access rights
 	switch ( $f_type ) {
 		case 'bug':
 			if ( !file_can_download_bug_attachments( $v_bug_id ) ) {
 				access_denied();
 			}
+			$t_project_id = bug_get_field( $v_bug_id, 'project_id' );
 			break;
-		case 'doc':
+		case 'project':
 			# Check if project documentation feature is enabled.
 			if ( OFF == config_get( 'enable_project_documentation' ) ) {
 				access_denied();
 			}
-
 			access_ensure_project_level( config_get( 'view_proj_doc_threshold' ), $v_project_id );
+			$t_project_id = $v_project_id;
+			break;
+		case 'avatar':
+			$t_project_id = $v_avatar_id;
 			break;
 	}
 
diff --git a/manage_user_page.php b/manage_user_page.php
index b674dbd..e06a3f1 100644
--- a/manage_user_page.php
+++ b/manage_user_page.php
@@ -270,6 +270,7 @@
 		<?php print_manage_user_sort_link(  'manage_user_page.php', lang_get( 'last_visit' ), 'last_visit', $c_dir, $c_sort, $c_hide, $c_filter ) ?>
 		<?php print_sort_icon( $c_dir, $c_sort, 'last_visit' ) ?>
 	</td>
+	<td>Avatar</td>
 </tr>
 <?php
 	$t_date_format = config_get( 'normal_date_format' );
@@ -305,6 +306,9 @@
         </td>
 	<td><?php echo $u_date_created ?></td>
 	<td><?php echo $u_last_visit ?></td>
+	<?php if ( config_get( 'show_avatar' ) ) {?>
+	<td><?php print_avatar ( $u_id ); ?></td>
+	<?php }	?>
 </tr>
 <?php
 	}  # end for
-- 
1.6.2.msysgit.0.186.gf7512

0001-Loacal-avatar.patch (41,850 bytes)   
0001-Simple-local-avatar-feature.patch (13,434 bytes)   
From 39e79f97178c74591b84d6cbe952f7a182d19abe Mon Sep 17 00:00:00 2001
From: unknown <Peter@.(none)>
Date: Wed, 17 Nov 2010 11:59:03 +0100
Subject: [PATCH] Simple local avatar feature

---
 account_prefs_inc.php      |    3 ++
 avatar_file_add.php        |   67 ++++++++++++++++++++++++++++++++++
 avatar_file_delete.php     |   77 +++++++++++++++++++++++++++++++++++++++
 avatar_file_upload_inc.php |   85 ++++++++++++++++++++++++++++++++++++++++++++
 config_defaults_inc.php    |   22 +++++++++++
 file_download.php          |   47 ++++++++++++------------
 6 files changed, 277 insertions(+), 24 deletions(-)
 create mode 100644 avatar_file_add.php
 create mode 100644 avatar_file_delete.php
 create mode 100644 avatar_file_upload_inc.php

diff --git a/account_prefs_inc.php b/account_prefs_inc.php
index 36b9b33..47adf0f 100644
--- a/account_prefs_inc.php
+++ b/account_prefs_inc.php
@@ -186,6 +186,9 @@
 </tr>
 </table>
 </form>
+
+<?php 	include ( 'avatar_file_upload_inc.php' ); ?>
+
 </div>
 
 <br />
diff --git a/avatar_file_add.php b/avatar_file_add.php
new file mode 100644
index 0000000..736d227
--- /dev/null
+++ b/avatar_file_add.php
@@ -0,0 +1,67 @@
+<?php
+# MantisBT - a php based bugtracking system
+
+# 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/>.
+
+	/**
+	 * Add the image file to b used as avatar
+	 *
+	 * @package MantisBT
+	 * @copyright Copyright (C) 2000 - 2002  Kenzaburo Ito - kenito@300baud.org
+	 * @copyright Copyright (C) 2002 - 2010  MantisBT Team - mantisbt-dev@lists.sourceforge.net
+	 * @link http://www.mantisbt.org
+	 */
+	 /**
+	  * MantisBT Core API's
+	  */
+	require_once( 'core.php' );
+
+	require_once( 'file_api.php' );
+
+	$f_avatar_id = gpc_get_int ( 'avatar_id', -1 );
+	$f_file		 = gpc_get_file( 'file'     , -1 );
+
+	if ( $f_avatar_id == -1 && $f_file	== -1 ) {
+		# _POST/_FILES does not seem to get populated if you exceed size limit so check if avatar_id is -1
+		trigger_error( ERROR_FILE_TOO_BIG, ERROR );
+	}
+
+	form_security_validate( 'avatar_file_add' );
+
+	if ( !file_is_uploading_enabled() ) {
+		access_denied();
+	}
+
+	access_ensure_global_level( config_get( 'upload_avatar_file_threshold' ) );
+
+	file_add( $f_avatar_id, $f_file, 'avatar' );
+
+	form_security_purge( 'avatar_file_add' );
+
+	# Determine which view page to redirect back to.
+	$t_redirect_url = 'account_prefs_page.php';
+
+	html_page_top( null, $t_redirect_url );
+	
+?>
+<br />
+<div align="center">
+<?php
+	echo lang_get( 'operation_successful' ) . '<br />';
+	print_bracket_link( $t_redirect_url, lang_get( 'proceed' ) );
+?>
+</div>
+
+<?php
+	html_page_bottom();
diff --git a/avatar_file_delete.php b/avatar_file_delete.php
new file mode 100644
index 0000000..191eec1
--- /dev/null
+++ b/avatar_file_delete.php
@@ -0,0 +1,77 @@
+<?php
+# MantisBT - a php based bugtracking system
+
+# 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/>.
+
+	/**
+	 * Delete a file from a bug and then view the bug
+	 *
+	 * @package MantisBT
+	 * @copyright Copyright (C) 2000 - 2002  Kenzaburo Ito - kenito@300baud.org
+	 * @copyright Copyright (C) 2002 - 2010  MantisBT Team - mantisbt-dev@lists.sourceforge.net
+	 * @link http://www.mantisbt.org
+	 */
+	 /**
+	  * MantisBT Core API's
+	  */
+	require_once( 'core.php' );
+
+	require_once( 'file_api.php' );
+
+	/**
+	 * Get array of attachments associated with the specified avatar id.  The array will be
+	 * sorted in terms of date added (ASC).  The array will include the following fields:
+	 * id, title, diskfile, filename, filesize, file_type, date_added. For now one user has
+	 * only one avatar which has his avatar_id set equal to user_id.
+	 * @param int p_avatar_id integer representing avatar id
+	 * @return array array of results or null
+	 * @access public
+	 * @uses database_api.php
+	 * @uses file_api.php
+	 */
+	function get_avatar ( $p_avatar_id ) {
+		$c_avatar_id = db_prepare_int( $p_avatar_id );
+	
+		$t_avatar_file_table = db_get_table( 'mantis_avatar_file_table' );
+	
+		$query = "SELECT id, title, diskfile, filename, filesize, file_type, date_added
+			                FROM $t_avatar_file_table
+			                WHERE avatar_id=" . db_param() . "
+			                ORDER BY date_added";
+		$db_result = db_query_bound( $query, Array( $c_avatar_id ) );
+		$num_files = db_num_rows( $db_result );
+	
+		$t_result = array();
+	
+		for( $i = 0;$i < $num_files;$i++ ) {
+			$t_result[] = db_fetch_array( $db_result );
+		}
+	
+		return $t_result;
+	}
+		
+	form_security_validate( 'avatar_file_delete' );
+
+	$f_avatar_id = gpc_get_int( 'avatar_id' );
+	$f_file_id = get_avatar ( $f_avatar_id );
+	
+	access_ensure_global_level( config_get( 'update_avatar_threshold' ) );
+
+	helper_ensure_confirmed( lang_get( 'delete_attachment_sure_msg' ), lang_get( 'delete_attachment_button' ) );
+
+	file_delete( $f_file_id[0]['id'], 'avatar' );
+
+	form_security_purge( 'avatar_file_delete' );
+
+	print_header_redirect( 'account_prefs_page.php' );
diff --git a/avatar_file_upload_inc.php b/avatar_file_upload_inc.php
new file mode 100644
index 0000000..0b80285
--- /dev/null
+++ b/avatar_file_upload_inc.php
@@ -0,0 +1,85 @@
+<?php
+# MantisBT - a php based bugtracking system
+
+# 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/>.
+
+	/**
+	 * This include file prints out the avatar file upload form
+	 * It POSTs to avatar_file_add.php
+	 * @package MantisBT
+	 * @copyright Copyright (C) 2000 - 2002  Kenzaburo Ito - kenito@300baud.org
+	 * @copyright Copyright (C) 2002 - 2010  MantisBT Team - mantisbt-dev@lists.sourceforge.net
+	 * @link http://www.mantisbt.org
+	 */
+
+	require_once( 'file_api.php' );
+
+	# check if we can allow the upload... bail out if we can't
+	if ( !file_is_uploading_enabled() ) {
+		return false;
+	}
+
+	$t_max_file_size = (int)min( ini_get_number( 'upload_max_filesize' ), ini_get_number( 'post_max_size' ), config_get( 'max_file_size' ) );
+?>
+<br />
+
+<?php
+	collapse_open( 'upload_form' );
+?>
+<form method="post" enctype="multipart/form-data" action="avatar_file_add.php">
+<?php echo form_security_field( 'avatar_file_add' ) ?>
+<table class="width75" cellspacing="1">
+<tr>
+	<td class="form-title" colspan="2">
+<?php
+		collapse_icon( 'upload_form' );
+		echo lang_get( 'upload_file' ) ?>
+	</td>
+</tr>
+<tr class="row-1">
+	<td class="category" width="15%">
+		<?php echo lang_get( 'select_file' ) ?><br />
+		<?php echo '<span class="small">(' . lang_get( 'max_file_size' ) . ': ' . number_format( $t_max_file_size/1000 ) . 'k)</span>'?>
+	</td>
+	<td width="85%">
+		<input type="hidden" name="avatar_id" value="<?php echo $p_user_id ?>" />
+		<input type="hidden" name="max_file_size" value="<?php echo $t_max_file_size ?>" />
+		<input name="file" type="file" size="40" />
+		<input type="submit" class="button" value="<?php echo lang_get( 'upload_file_button' ) ?>" />
+<?php 
+if ( ($p_user_id == auth_get_current_user_id()) || user_is_administrator( $p_user_id ) ) {
+	echo '&#160;[';
+	print_link( 'avatar_file_delete.php?avatar_id=' . $p_user_id . form_security_param( 'avatar_file_delete' ), lang_get( 'delete_link' ), false, 'small' );
+	echo ']';
+}
+?>
+	</td>
+</tr>
+</table>
+</form>
+<?php
+	collapse_closed( 'upload_form' );
+?>
+<table class="width75" cellspacing="1">
+<tr>
+	<td class="form-title" colspan="2">
+		<?php
+			collapse_icon( 'upload_form' );
+			echo lang_get( 'upload_file' ) ?>
+	</td>
+</tr>
+</table>
+
+<?php
+	collapse_end( 'upload_form' );
diff --git a/config_defaults_inc.php b/config_defaults_inc.php
index b3f8bd8..cad1bda 100644
--- a/config_defaults_inc.php
+++ b/config_defaults_inc.php
@@ -943,6 +943,12 @@
 	$g_default_avatar = "%path%images/no_avatar.png";
 
 	/**
+	 * access level needed to update avatars
+	 * @global int $g_update_avatar_threshold
+	 */
+	$g_update_avatar_threshold	= DEVELOPER;
+	
+	/**
 	 * Show release dates on changelog
 	 * @global int $g_show_changelog_dates
 	 */
@@ -1571,6 +1577,14 @@
 	 */
 	$g_document_files_prefix = 'doc';
 
+	
+	/**
+	 * prefix to be used for the file system names of avatars uploaded to mantis.
+	 * Eg: avatar-015-face.png
+	 * @global string $g_document_files_prefix
+	 */
+	$g_avatar_files_prefix = 'avatar';
+	
 	/**
 	 * absolute path to the default upload folder.  Requires trailing / or \
 	 * @global string $g_absolute_path_default_upload_folder
@@ -2275,6 +2289,13 @@
 	$g_upload_bug_file_threshold	= REPORTER;
 
 	/**
+	 * access level needed to upload avatars
+	 *  if $g_allow_file_upload set to OFF then avatar upload is disabled
+	 * @global int $g_upload_avatar_file_threshold
+	 */
+	$g_upload_avatar_file_threshold	= DEVELOPER;
+	
+	/**
 	 * Add bugnote threshold
 	 * @global int $g_add_bugnote_threshold
 	 */
@@ -2868,6 +2889,7 @@
 	 * table names
 	 * @global array $g_db_table
 	 */
+	$g_db_table['mantis_avatar_file_table']				= '%db_table_prefix%_avatar_file%db_table_suffix%';
 	$g_db_table['mantis_bug_file_table']				= '%db_table_prefix%_bug_file%db_table_suffix%';
 	$g_db_table['mantis_bug_history_table']				= '%db_table_prefix%_bug_history%db_table_suffix%';
 	$g_db_table['mantis_bug_monitor_table']				= '%db_table_prefix%_bug_monitor%db_table_suffix%';
diff --git a/file_download.php b/file_download.php
index 6e750b5..282cb60 100644
--- a/file_download.php
+++ b/file_download.php
@@ -55,51 +55,50 @@
 	$f_file_id = gpc_get_int( 'file_id' );
 	$f_type = gpc_get_string( 'type' );
 
+	// allow only tables we can handle
+	$t_allowed_tables = array ( 'bug', 'doc', 'avatar' );
+	if ( ! in_array ($f_type, $t_allowed_tables) ) {
+		access_denied();
+	}
+	
+	// later on either change the table name mantis_project_file_table to
+	// mantis_doc_file_table or change the code on all places with file_download.php
+	// reference to use type='project' instead of type='doc'.
+	if ( $f_type == 'doc' ) {
+		$f_type = 'project';
+	}
+	
 	$c_file_id = (integer)$f_file_id;
 
 	# we handle the case where the file is attached to a bug
 	# or attached to a project as a project doc.
 	$query = '';
-	switch ( $f_type ) {
-		case 'bug':
-			$t_bug_file_table = db_get_table( 'mantis_bug_file_table' );
-			$query = "SELECT *
-				FROM $t_bug_file_table
-				WHERE id=" . db_param();
-			break;
-		case 'doc':
-			$t_project_file_table = db_get_table( 'mantis_project_file_table' );
-			$query = "SELECT *
-				FROM $t_project_file_table
-				WHERE id=" . db_param();
-			break;
-		default:
-			access_denied();
-	}
+	$t_file_table = db_get_table( 'mantis_'.$f_type.'_file_table' );
+	$query = "SELECT *
+		FROM $t_file_table
+		WHERE id=" . db_param();
 	$result = db_query_bound( $query, Array( $c_file_id ) );
 	$row = db_fetch_array( $result );
 	extract( $row, EXTR_PREFIX_ALL, 'v' );
 
-	if ( $f_type == 'bug' ) {
-		$t_project_id = bug_get_field( $v_bug_id, 'project_id' );
-	} else {
-		$t_project_id = $v_project_id;
-	}
-
 	# Check access rights
 	switch ( $f_type ) {
 		case 'bug':
 			if ( !file_can_download_bug_attachments( $v_bug_id ) ) {
 				access_denied();
 			}
+			$t_project_id = bug_get_field( $v_bug_id, 'project_id' );
 			break;
-		case 'doc':
+		case 'project':
 			# Check if project documentation feature is enabled.
 			if ( OFF == config_get( 'enable_project_documentation' ) ) {
 				access_denied();
 			}
-
 			access_ensure_project_level( config_get( 'view_proj_doc_threshold' ), $v_project_id );
+			$t_project_id = $v_project_id;
+			break;
+		case 'avatar':
+			$t_project_id = $v_avatar_id;
 			break;
 	}
 
-- 
1.6.2.msysgit.0.186.gf7512

0001-Simple-local-avatar-feature-in-core.patch (8,013 bytes)   
From d1d54004983e9ade0409ef5b5cc2034842a6ff4e Mon Sep 17 00:00:00 2001
From: unknown <Peter@.(none)>
Date: Wed, 17 Nov 2010 12:10:05 +0100
Subject: [PATCH] Simple local avatar feature in core

---
 core/file_api.php  |   47 +++++++++++++++++++++++++++-------------
 core/print_api.php |    3 +-
 core/user_api.php  |   60 ++++++++++++++++++++++++++++++++-------------------
 3 files changed, 72 insertions(+), 38 deletions(-)

diff --git a/core/file_api.php b/core/file_api.php
index b5b2e43..0759223 100644
--- a/core/file_api.php
+++ b/core/file_api.php
@@ -486,6 +486,8 @@ function file_delete( $p_file_id, $p_table = 'bug' ) {
 	if ( $p_table == 'bug' ) {
 		$t_bug_id = file_get_field( $p_file_id, 'bug_id', $p_table );
 		$t_project_id = bug_get_field( $t_bug_id, 'project_id' );
+	} elseif ( $p_table == 'avatar' ) {
+		$t_project_id = ALL_PROJECTS;
 	} else {
 		$t_project_id = file_get_field( $p_file_id, 'project_id', $p_table );
 	}
@@ -614,7 +616,7 @@ function file_is_name_unique( $p_name, $p_bug_id ) {
  * @param integer $p_bug_id the bug id
  * @param array $p_file the uploaded file info, as retrieved from gpc_get_file()
  */
-function file_add( $p_bug_id, $p_file, $p_table = 'bug', $p_title = '', $p_desc = '', $p_user_id = null ) {
+function file_add( $p_key_id, $p_file, $p_table = 'bug', $p_title = '', $p_desc = '', $p_user_id = null ) {
 
 	file_ensure_uploaded( $p_file );
 	$t_file_name = $p_file['name'];
@@ -624,16 +626,35 @@ function file_add( $p_bug_id, $p_file, $p_table = 'bug', $p_title = '', $p_desc
 		trigger_error( ERROR_FILE_NOT_ALLOWED, ERROR );
 	}
 
-	if( !file_is_name_unique( $t_file_name, $p_bug_id ) ) {
+	if( !file_is_name_unique( $t_file_name, $p_key_id ) ) {
 		trigger_error( ERROR_DUPLICATE_FILE, ERROR );
 	}
 
-	if( 'bug' == $p_table ) {
-		$t_project_id = bug_get_field( $p_bug_id, 'project_id' );
-		$t_bug_id = bug_format_id( $p_bug_id );
-	} else {
-		$t_project_id = helper_get_current_project();
-		$t_bug_id = 0;
+	# prepare variables for insertion
+	$c_key_id = db_prepare_int( $p_key_id );
+	
+	switch ( $p_table ) {
+		case 'bug':
+			$t_project_id = bug_get_field( $p_key_id, 'project_id' );
+			$c_project_id = db_prepare_int( $t_project_id );
+			$t_key_id     = bug_format_id( $p_key_id );
+			$t_file_hash  = $t_key_id;
+			$c_id         = $c_key_id;
+			break;
+		case 'avatar':
+			$t_project_id = ALL_PROJECTS;
+			$c_project_id = db_prepare_int( $t_project_id );
+			$t_key_id     = bug_format_id( $p_key_id );
+			$t_file_hash  = config_get( 'avatar_files_prefix' ) . '-' . $t_key_id;
+			$c_id         = $c_key_id;
+			break;
+		default:
+			$t_project_id = helper_get_current_project();
+			$c_project_id = db_prepare_int( $t_project_id );
+			$t_file_hash  = config_get( 'document_files_prefix' ) . '-' . $t_project_id;
+			$t_key_id     = 0;
+			$c_id         = $c_project_id;
+			break;
 	}
 
 	if( $p_user_id === null ) {
@@ -643,8 +664,6 @@ function file_add( $p_bug_id, $p_file, $p_table = 'bug', $p_title = '', $p_desc
 	}
 
 	# prepare variables for insertion
-	$c_bug_id = db_prepare_int( $p_bug_id );
-	$c_project_id = db_prepare_int( $t_project_id );
 	$c_file_type = db_prepare_string( $p_file['type'] );
 	$c_title = db_prepare_string( $p_title );
 	$c_desc = db_prepare_string( $p_desc );
@@ -657,10 +676,9 @@ function file_add( $p_bug_id, $p_file, $p_table = 'bug', $p_title = '', $p_desc
 			$t_file_path = config_get( 'absolute_path_default_upload_folder' );
 		}
 	}
+
 	$c_file_path = db_prepare_string( $t_file_path );
 	$c_new_file_name = db_prepare_string( $t_file_name );
-
-	$t_file_hash = ( 'bug' == $p_table ) ? $t_bug_id : config_get( 'document_files_prefix' ) . '-' . $t_project_id;
 	$t_unique_name = file_generate_unique_name( $t_file_hash . '-' . $t_file_name, $t_file_path );
 	$t_disk_file_name = $t_file_path . $t_unique_name;
 	$c_unique_name = db_prepare_string( $t_unique_name );
@@ -708,7 +726,6 @@ function file_add( $p_bug_id, $p_file, $p_table = 'bug', $p_title = '', $p_desc
 	}
 
 	$t_file_table = db_get_table( 'mantis_' . $p_table . '_file_table' );
-	$c_id = ( 'bug' == $p_table ) ? $c_bug_id : $c_project_id;
 
 	$query = "INSERT INTO $t_file_table
 						(" . $p_table . "_id, title, description, diskfile, filename, folder, filesize, file_type, date_added, content, user_id)
@@ -719,10 +736,10 @@ function file_add( $p_bug_id, $p_file, $p_table = 'bug', $p_title = '', $p_desc
 	if( 'bug' == $p_table ) {
 
 		# updated the last_updated date
-		$result = bug_update_date( $p_bug_id );
+		$result = bug_update_date( $p_key_id );
 
 		# log new bug
-		history_log_event_special( $p_bug_id, FILE_ADDED, $t_file_name );
+		history_log_event_special( $p_key_id, FILE_ADDED, $t_file_name );
 	}
 }
 
diff --git a/core/print_api.php b/core/print_api.php
index eaec5f2..c754d6f 100644
--- a/core/print_api.php
+++ b/core/print_api.php
@@ -152,7 +152,8 @@ function print_avatar( $p_user_id, $p_size = 80 ) {
 			$t_avatar_url = htmlspecialchars( $t_avatar[0] );
 			$t_width = $t_avatar[1];
 			$t_height = $t_avatar[2];
-			echo '<a rel="nofollow" href="http://site.gravatar.com"><img class="avatar" src="' . $t_avatar_url . '" alt="User avatar" width="' . $t_width . '" height="' . $t_height . '" /></a>';
+			$t_href = $t_avatar[3];
+			echo '<a rel="nofollow" href="'.$t_href.'"><img class="avatar" src="' . $t_avatar_url . '" alt="User avatar" width="' . $t_width . '" height="' . $t_height . '" /></a>';
 		}
 	}
 }
diff --git a/core/user_api.php b/core/user_api.php
index 1b3f1ac..343bacd 100644
--- a/core/user_api.php
+++ b/core/user_api.php
@@ -797,32 +797,48 @@ function user_get_name( $p_user_id ) {
 * @return array|bool an array( URL, width, height ) or false when the given user has no avatar
 */
 function user_get_avatar( $p_user_id, $p_size = 80 ) {
-	$t_email = utf8_strtolower( user_get_email( $p_user_id ) );
-	if( is_blank( $t_email ) ) {
-		$t_result = false;
-	} else {
-		$t_default_image = config_get( 'default_avatar' );
+	$c_user_id = db_prepare_int ( $p_user_id );
+	$t_avatar_table = db_get_table ( 'mantis_avatar_file_table' );
+	$query = "SELECT id
+			  FROM $t_avatar_table
+			  WHERE avatar_id='$c_user_id'";
+	$t_db_result = db_query ( $query );
+	if ( 1 == db_num_rows( $t_db_result )) {
+		$t_found_local_avatar = true;
+		$t_avatar_id = db_result ( $t_db_result );
+		$t_avatar_url = "file_download.php?type=avatar&file_id=".$t_avatar_id."&show_inline=1".form_security_param( 'file_show_inline' );
+		$t_avatar_ref = "manage_user_edit_page.php?user_id=".$p_user_id;
 		$t_size = $p_size;
-
-		$t_use_ssl = false;
-		if( isset( $_SERVER['HTTPS'] ) && ( utf8_strtolower( $_SERVER['HTTPS'] ) != 'off' ) ) {
-			$t_use_ssl = true;
-		}
-
-		if( !$t_use_ssl ) {
-			$t_gravatar_domain = 'http://www.gravatar.com/';
+		$t_result = array( $t_avatar_url, $t_size, $t_size, $t_avatar_ref );
+	} else {
+		$t_email = utf8_strtolower( user_get_email( $p_user_id ) );
+		if( is_blank( $t_email ) ) {
+			$t_result = false;
 		} else {
-			$t_gravatar_domain = 'https://secure.gravatar.com/';
+			$t_default_image = config_get( 'default_avatar' );
+			$t_size = $p_size;
+	
+			$t_use_ssl = false;
+			if( isset( $_SERVER['HTTPS'] ) && ( utf8_strtolower( $_SERVER['HTTPS'] ) != 'off' ) ) {
+				$t_use_ssl = true;
+			}
+	
+			if( !$t_use_ssl ) {
+				$t_gravatar_domain = 'http://www.gravatar.com/';
+			} else {
+				$t_gravatar_domain = 'https://secure.gravatar.com/';
+			}
+	
+			$t_avatar_url = $t_gravatar_domain . 'avatar.php?gravatar_id=' . md5( $t_email ) . '&default=' . urlencode( $t_default_image ) . '&size=' . $t_size . '&rating=G';
+			$t_result = array(
+				$t_avatar_url,
+				$t_size,
+				$t_size,
+				'http://site.gravatar.com'
+			);
 		}
-
-		$t_avatar_url = $t_gravatar_domain . 'avatar.php?gravatar_id=' . md5( $t_email ) . '&default=' . urlencode( $t_default_image ) . '&size=' . $t_size . '&rating=G';
-		$t_result = array(
-			$t_avatar_url,
-			$t_size,
-			$t_size,
-		);
 	}
-
+	
 	return $t_result;
 }
 
-- 
1.6.2.msysgit.0.186.gf7512

mantis_avatar_simple_patch.patch (21,623 bytes)   
diff -ruN mantisbt-1.2.4/account_prefs_inc.php mantis_patched/account_prefs_inc.php
--- mantisbt-1.2.4/account_prefs_inc.php	2010-12-15 03:26:31.000000000 +0100
+++ mantis_patched/account_prefs_inc.php	2011-02-03 15:54:46.000000000 +0100
@@ -290,6 +290,8 @@
 </tr>
 </table>
 </form>
+
+<?php   include ( 'avatar_file_upload_inc.php' ); ?>
 </div>
 
 <br />
diff -ruN mantisbt-1.2.4/avatar_file_add.php mantis_patched/avatar_file_add.php
--- mantisbt-1.2.4/avatar_file_add.php	1970-01-01 01:00:00.000000000 +0100
+++ mantis_patched/avatar_file_add.php	2011-02-03 15:54:51.000000000 +0100
@@ -0,0 +1,67 @@
+<?php
+# MantisBT - a php based bugtracking system
+
+# 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/>.
+
+   /**
+    * Add the image file to b used as avatar
+    *
+    * @package MantisBT
+    * @copyright Copyright (C) 2000 - 2002  Kenzaburo Ito - kenito@300baud.org
+    * @copyright Copyright (C) 2002 - 2010  MantisBT Team - mantisbt-dev@lists.sourceforge.net
+    * @link http://www.mantisbt.org
+    */
+    /**
+     * MantisBT Core API's
+     */
+   require_once( 'core.php' );
+
+   require_once( 'file_api.php' );
+
+   $f_avatar_id = gpc_get_int ( 'avatar_id', -1 );
+   $f_file      = gpc_get_file( 'file'     , -1 );
+
+   if ( $f_avatar_id == -1 && $f_file  == -1 ) {
+       # _POST/_FILES does not seem to get populated if you exceed size limit so check if avatar_id is -1
+       trigger_error( ERROR_FILE_TOO_BIG, ERROR );
+   }
+
+   form_security_validate( 'avatar_file_add' );
+
+   if ( !file_is_uploading_enabled() ) {
+       access_denied();
+   }
+
+   access_ensure_global_level( config_get( 'upload_avatar_file_threshold' ) );
+
+   file_add( $f_avatar_id, $f_file, 'avatar' );
+
+   form_security_purge( 'avatar_file_add' );
+
+   # Determine which view page to redirect back to.
+   $t_redirect_url = 'account_prefs_page.php';
+
+   html_page_top( null, $t_redirect_url );
+   
+?>
+<br />
+<div align="center">
+<?php
+   echo lang_get( 'operation_successful' ) . '<br />';
+   print_bracket_link( $t_redirect_url, lang_get( 'proceed' ) );
+?>
+</div>
+
+<?php
+   html_page_bottom();
diff -ruN mantisbt-1.2.4/avatar_file_delete.php mantis_patched/avatar_file_delete.php
--- mantisbt-1.2.4/avatar_file_delete.php	1970-01-01 01:00:00.000000000 +0100
+++ mantis_patched/avatar_file_delete.php	2011-02-03 15:54:51.000000000 +0100
@@ -0,0 +1,77 @@
+<?php
+# MantisBT - a php based bugtracking system
+
+# 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/>.
+
+   /**
+    * Delete a file from a bug and then view the bug
+    *
+    * @package MantisBT
+    * @copyright Copyright (C) 2000 - 2002  Kenzaburo Ito - kenito@300baud.org
+    * @copyright Copyright (C) 2002 - 2010  MantisBT Team - mantisbt-dev@lists.sourceforge.net
+    * @link http://www.mantisbt.org
+    */
+    /**
+     * MantisBT Core API's
+     */
+   require_once( 'core.php' );
+
+   require_once( 'file_api.php' );
+
+   /**
+    * Get array of attachments associated with the specified avatar id.  The array will be
+    * sorted in terms of date added (ASC).  The array will include the following fields:
+    * id, title, diskfile, filename, filesize, file_type, date_added. For now one user has
+    * only one avatar which has his avatar_id set equal to user_id.
+    * @param int p_avatar_id integer representing avatar id
+    * @return array array of results or null
+    * @access public
+    * @uses database_api.php
+    * @uses file_api.php
+    */
+   function get_avatar ( $p_avatar_id ) {
+       $c_avatar_id = db_prepare_int( $p_avatar_id );
+   
+       $t_avatar_file_table = db_get_table( 'mantis_avatar_file_table' );
+   
+       $query = "SELECT id, title, diskfile, filename, filesize, file_type, date_added
+                           FROM $t_avatar_file_table
+                           WHERE avatar_id=" . db_param() . "
+                           ORDER BY date_added";
+       $db_result = db_query_bound( $query, Array( $c_avatar_id ) );
+       $num_files = db_num_rows( $db_result );
+   
+       $t_result = array();
+   
+       for( $i = 0;$i < $num_files;$i++ ) {
+           $t_result[] = db_fetch_array( $db_result );
+       }
+   
+       return $t_result;
+   }
+       
+   form_security_validate( 'avatar_file_delete' );
+
+   $f_avatar_id = gpc_get_int( 'avatar_id' );
+   $f_file_id = get_avatar ( $f_avatar_id );
+   
+   access_ensure_global_level( config_get( 'update_avatar_threshold' ) );
+
+   helper_ensure_confirmed( lang_get( 'delete_attachment_sure_msg' ), lang_get( 'delete_attachment_button' ) );
+
+   file_delete( $f_file_id[0]['id'], 'avatar' );
+
+   form_security_purge( 'avatar_file_delete' );
+
+   print_header_redirect( 'account_prefs_page.php' );
diff -ruN mantisbt-1.2.4/avatar_file_upload_inc.php mantis_patched/avatar_file_upload_inc.php
--- mantisbt-1.2.4/avatar_file_upload_inc.php	1970-01-01 01:00:00.000000000 +0100
+++ mantis_patched/avatar_file_upload_inc.php	2011-02-03 15:54:51.000000000 +0100
@@ -0,0 +1,103 @@
+<?php
+# MantisBT - a php based bugtracking system
+
+# 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/>.
+
+   /**
+    * This include file prints out the avatar file upload form
+    * It POSTs to avatar_file_add.php
+    * @package MantisBT
+    * @copyright Copyright (C) 2000 - 2002  Kenzaburo Ito - kenito@300baud.org
+    * @copyright Copyright (C) 2002 - 2010  MantisBT Team - mantisbt-dev@lists.sourceforge.net
+    * @link http://www.mantisbt.org
+    */
+
+   require_once( 'file_api.php' );
+
+   # check if we can allow the upload... bail out if we can't
+   if ( !file_is_uploading_enabled() ) {
+       return false;
+   }
+
+   $t_max_file_size = (int)min( ini_get_number( 'upload_max_filesize' ), ini_get_number( 'post_max_size' ), config_get( 'max_file_size' ) );
+?>
+<br />
+
+<?php
+   collapse_open( 'upload_form' );
+?>
+<form method="post" enctype="multipart/form-data" action="avatar_file_add.php">
+<?php echo form_security_field( 'avatar_file_add' ) ?>
+<table class="width75" cellspacing="1">
+<tr>
+   <td class="form-title" colspan="2">
+<?php
+       collapse_icon( 'upload_form' );
+       echo lang_get( 'upload_file' ) ?>
+   </td>
+</tr>
+
+<tr class="row-1">
+   <td class="category" width="15%">
+        <?php if ( ON == config_get("show_avatar") ) echo "Current Avatar"; ?>
+   </td>
+   <td width="85%">
+    <table>
+      <tr>
+        <td with="30%">
+        <?php if ( ON  == config_get("show_avatar") ) print_avatar( $p_user_id ); ?>
+        </td>
+        <td with="70%">
+<?php 
+if ( ($p_user_id == auth_get_current_user_id()) || user_is_administrator( $p_user_id ) ) {
+   echo '&#160;[';
+   print_link( 'avatar_file_delete.php?avatar_id=' . $p_user_id . form_security_param( 'avatar_file_delete' ), lang_get( 'delete_link' ), false, 'small' );
+   echo ']';
+}
+?>
+       </td>
+      </tr>
+    </table>
+   </td>
+</tr>
+
+<tr class="row-1">
+   <td class="category" width="15%">
+       <?php echo lang_get( 'select_file' ) ?><br />
+       <?php echo '<span class="small">(' . lang_get( 'max_file_size' ) . ': ' . number_format( $t_max_file_size/1000 ) . 'k)</span>'?>
+   </td>
+   <td width="85%">
+       <input type="hidden" name="avatar_id" value="<?php echo $p_user_id ?>" />
+       <input type="hidden" name="max_file_size" value="<?php echo $t_max_file_size ?>" />
+       <input name="file" type="file" size="40" />
+       <input type="submit" class="button" value="<?php echo lang_get( 'upload_file_button' ) ?>" />
+   </td>
+</tr>
+</table>
+</form>
+<?php
+   collapse_closed( 'upload_form' );
+?>
+<table class="width75" cellspacing="1">
+<tr>
+   <td class="form-title" colspan="2">
+       <?php
+           collapse_icon( 'upload_form' );
+           echo lang_get( 'upload_file' ) ?>
+   </td>
+</tr>
+</table>
+
+<?php
+   collapse_end( 'upload_form' );
diff -ruN mantisbt-1.2.4/config_defaults_inc.php mantis_patched/config_defaults_inc.php
--- mantisbt-1.2.4/config_defaults_inc.php	2010-12-15 03:26:31.000000000 +0100
+++ mantis_patched/config_defaults_inc.php	2011-02-03 15:54:47.000000000 +0100
@@ -928,7 +928,7 @@
 	 * the updated gravatar images to show on sites
 	 * @global int $g_show_avatar
 	 */
-	$g_show_avatar = OFF;
+	$g_show_avatar = ON;
 
 	/**
 	 * Only users above this threshold will have their avatar shown
@@ -942,6 +942,24 @@
 	 */
 	$g_default_avatar = "%path%images/no_avatar.png";
 
+
+    /**
+     * prefix to be used for the file system names of avatars uploaded to mantis.
+     * Eg: avatar-015-face.png
+     * @global string $g_document_files_prefix
+     */
+    $g_avatar_files_prefix = 'avatar';
+
+    /**
+     * access level needed to upload avatars
+     *  if $g_allow_file_upload set to OFF then avatar upload is disabled
+     * @global int $g_upload_avatar_file_threshold
+     */
+    $g_upload_avatar_file_threshold = DEVELOPER;
+
+
+    $g_update_avatar_threshold  = DEVELOPER;
+
 	/**
 	 * Show release dates on changelog
 	 * @global int $g_show_changelog_dates
@@ -2868,6 +2886,7 @@
 	 * table names
 	 * @global array $g_db_table
 	 */
+    $g_db_table['mantis_avatar_file_table']             = '%db_table_prefix%_avatar_file%db_table_suffix%';
 	$g_db_table['mantis_bug_file_table']				= '%db_table_prefix%_bug_file%db_table_suffix%';
 	$g_db_table['mantis_bug_history_table']				= '%db_table_prefix%_bug_history%db_table_suffix%';
 	$g_db_table['mantis_bug_monitor_table']				= '%db_table_prefix%_bug_monitor%db_table_suffix%';
diff -ruN mantisbt-1.2.4/core/file_api.php mantis_patched/core/file_api.php
--- mantisbt-1.2.4/core/file_api.php	2010-12-15 03:26:31.000000000 +0100
+++ mantis_patched/core/file_api.php	2011-02-03 15:54:46.000000000 +0100
@@ -486,6 +486,8 @@
 	if ( $p_table == 'bug' ) {
 		$t_bug_id = file_get_field( $p_file_id, 'bug_id', $p_table );
 		$t_project_id = bug_get_field( $t_bug_id, 'project_id' );
+    } elseif ( $p_table == 'avatar' ) {
+        $t_project_id = ALL_PROJECTS;
 	} else {
 		$t_project_id = file_get_field( $p_file_id, 'project_id', $p_table );
 	}
@@ -614,7 +616,7 @@
  * @param integer $p_bug_id the bug id
  * @param array $p_file the uploaded file info, as retrieved from gpc_get_file()
  */
-function file_add( $p_bug_id, $p_file, $p_table = 'bug', $p_title = '', $p_desc = '', $p_user_id = null ) {
+function file_add( $p_key_id, $p_file, $p_table = 'bug', $p_title = '', $p_desc = '', $p_user_id = null ) {
 
 	file_ensure_uploaded( $p_file );
 	$t_file_name = $p_file['name'];
@@ -624,17 +626,36 @@
 		trigger_error( ERROR_FILE_NOT_ALLOWED, ERROR );
 	}
 
-	if( !file_is_name_unique( $t_file_name, $p_bug_id ) ) {
+	if( !file_is_name_unique( $t_file_name, $p_key_id ) ) {
 		trigger_error( ERROR_DUPLICATE_FILE, ERROR );
 	}
 
-	if( 'bug' == $p_table ) {
-		$t_project_id = bug_get_field( $p_bug_id, 'project_id' );
-		$t_bug_id = bug_format_id( $p_bug_id );
-	} else {
-		$t_project_id = helper_get_current_project();
-		$t_bug_id = 0;
-	}
+    # prepare variables for insertion
+    $c_key_id = db_prepare_int( $p_key_id );
+    
+    switch ( $p_table ) {
+        case 'bug':
+            $t_project_id = bug_get_field( $p_key_id, 'project_id' );
+            $c_project_id = db_prepare_int( $t_project_id );
+            $t_key_id     = bug_format_id( $p_key_id );
+            $t_file_hash  = $t_key_id;
+            $c_id         = $c_key_id;
+            break;
+        case 'avatar':
+            $t_project_id = ALL_PROJECTS;
+            $c_project_id = db_prepare_int( $t_project_id );
+            $t_key_id     = bug_format_id( $p_key_id );
+            $t_file_hash  = config_get( 'avatar_files_prefix' ) . '-' . $t_key_id;
+            $c_id         = $c_key_id;
+            break;
+        default:
+            $t_project_id = helper_get_current_project();
+            $c_project_id = db_prepare_int( $t_project_id );
+            $t_file_hash  = config_get( 'document_files_prefix' ) . '-' . $t_project_id;
+            $t_key_id     = 0;
+            $c_id         = $c_project_id;
+            break;
+    }
 
 	if( $p_user_id === null ) {
 		$c_user_id = auth_get_current_user_id();
@@ -643,8 +664,6 @@
 	}
 
 	# prepare variables for insertion
-	$c_bug_id = db_prepare_int( $p_bug_id );
-	$c_project_id = db_prepare_int( $t_project_id );
 	$c_file_type = db_prepare_string( $p_file['type'] );
 	$c_title = db_prepare_string( $p_title );
 	$c_desc = db_prepare_string( $p_desc );
@@ -657,10 +676,9 @@
 			$t_file_path = config_get( 'absolute_path_default_upload_folder' );
 		}
 	}
+
 	$c_file_path = db_prepare_string( $t_file_path );
 	$c_new_file_name = db_prepare_string( $t_file_name );
-
-	$t_file_hash = ( 'bug' == $p_table ) ? $t_bug_id : config_get( 'document_files_prefix' ) . '-' . $t_project_id;
 	$t_unique_name = file_generate_unique_name( $t_file_hash . '-' . $t_file_name, $t_file_path );
 	$t_disk_file_name = $t_file_path . $t_unique_name;
 	$c_unique_name = db_prepare_string( $t_unique_name );
@@ -708,7 +726,6 @@
 	}
 
 	$t_file_table = db_get_table( 'mantis_' . $p_table . '_file_table' );
-	$c_id = ( 'bug' == $p_table ) ? $c_bug_id : $c_project_id;
 
 	$query = "INSERT INTO $t_file_table
 						(" . $p_table . "_id, title, description, diskfile, filename, folder, filesize, file_type, date_added, content, user_id)
@@ -719,10 +736,10 @@
 	if( 'bug' == $p_table ) {
 
 		# updated the last_updated date
-		$result = bug_update_date( $p_bug_id );
+		$result = bug_update_date( $p_key_id );
 
 		# log new bug
-		history_log_event_special( $p_bug_id, FILE_ADDED, $t_file_name );
+		history_log_event_special( $p_key_id, FILE_ADDED, $t_file_name );
 	}
 }
 
diff -ruN mantisbt-1.2.4/core/print_api.php mantis_patched/core/print_api.php
--- mantisbt-1.2.4/core/print_api.php	2010-12-15 03:26:31.000000000 +0100
+++ mantis_patched/core/print_api.php	2011-02-03 15:54:46.000000000 +0100
@@ -152,7 +152,8 @@
 			$t_avatar_url = htmlspecialchars( $t_avatar[0] );
 			$t_width = $t_avatar[1];
 			$t_height = $t_avatar[2];
-			echo '<a rel="nofollow" href="http://site.gravatar.com"><img class="avatar" src="' . $t_avatar_url . '" alt="User avatar" width="' . $t_width . '" height="' . $t_height . '" /></a>';
+            $t_href = $t_avatar[3];
+            echo '<a rel="nofollow" href="'.$t_href.'"><img class="avatar" src="' . $t_avatar_url . '" alt="User avatar" width="' . $t_width . '" height="' . $t_height . '" /></a>';
 		}
 	}
 }
diff -ruN mantisbt-1.2.4/core/user_api.php mantis_patched/core/user_api.php
--- mantisbt-1.2.4/core/user_api.php	2010-12-15 03:26:31.000000000 +0100
+++ mantis_patched/core/user_api.php	2011-02-03 15:54:46.000000000 +0100
@@ -797,34 +797,50 @@
 * @return array|bool an array( URL, width, height ) or false when the given user has no avatar
 */
 function user_get_avatar( $p_user_id, $p_size = 80 ) {
-	$t_email = utf8_strtolower( user_get_email( $p_user_id ) );
-	if( is_blank( $t_email ) ) {
-		$t_result = false;
-	} else {
-		$t_default_image = config_get( 'default_avatar' );
-		$t_size = $p_size;
-
-		$t_use_ssl = false;
-		if( isset( $_SERVER['HTTPS'] ) && ( utf8_strtolower( $_SERVER['HTTPS'] ) != 'off' ) ) {
-			$t_use_ssl = true;
-		}
-
-		if( !$t_use_ssl ) {
-			$t_gravatar_domain = 'http://www.gravatar.com/';
-		} else {
-			$t_gravatar_domain = 'https://secure.gravatar.com/';
-		}
-
-		$t_avatar_url = $t_gravatar_domain . 'avatar.php?gravatar_id=' . md5( $t_email ) . '&default=' . urlencode( $t_default_image ) . '&size=' . $t_size . '&rating=G';
-		$t_result = array(
-			$t_avatar_url,
-			$t_size,
-			$t_size,
-		);
-	}
-
-	return $t_result;
-}
+    $c_user_id = db_prepare_int ( $p_user_id );
+    $t_avatar_table = db_get_table ( 'mantis_avatar_file_table' );
+    $query = "SELECT id
+              FROM $t_avatar_table
+              WHERE avatar_id='$c_user_id'";
+    $t_db_result = db_query ( $query );
+    if ( 1 == db_num_rows( $t_db_result )) {
+        $t_found_local_avatar = true;
+        $t_avatar_id = db_result ( $t_db_result );
+        $t_avatar_url = "file_download.php?type=avatar&file_id=".$t_avatar_id."&show_inline=1".form_security_param( 'file_show_inline' );
+        $t_avatar_ref = "manage_user_edit_page.php?user_id=".$p_user_id;
+        $t_size = $p_size;
+        $t_result = array( $t_avatar_url, $t_size, $t_size, $t_avatar_ref );
+    } else {
+        $t_email = utf8_strtolower( user_get_email( $p_user_id ) );
+        if( is_blank( $t_email ) ) {
+            $t_result = false;
+        } else {
+            $t_default_image = config_get( 'default_avatar' );
+            $t_size = $p_size;
+    
+            $t_use_ssl = false;
+            if( isset( $_SERVER['HTTPS'] ) && ( utf8_strtolower( $_SERVER['HTTPS'] ) != 'off' ) ) {
+                $t_use_ssl = true;
+            }
+    
+            if( !$t_use_ssl ) {
+                $t_gravatar_domain = 'http://www.gravatar.com/';
+            } else {
+                $t_gravatar_domain = 'https://secure.gravatar.com/';
+            }
+    
+            $t_avatar_url = $t_gravatar_domain . 'avatar.php?gravatar_id=' . md5( $t_email ) . '&default=' . urlencode( $t_default_image ) . '&size=' . $t_size . '&rating=G';
+            $t_result = array(
+                $t_avatar_url,
+                $t_size,
+                $t_size,
+                'http://site.gravatar.com'
+            );
+        }
+    }
+    
+    return $t_result;
+ }
 
 # --------------------
 # return the user's access level
diff -ruN mantisbt-1.2.4/file_download.php mantis_patched/file_download.php
--- mantisbt-1.2.4/file_download.php	2010-12-15 03:26:31.000000000 +0100
+++ mantis_patched/file_download.php	2011-02-03 15:54:46.000000000 +0100
@@ -55,51 +55,51 @@
 	$f_file_id = gpc_get_int( 'file_id' );
 	$f_type = gpc_get_string( 'type' );
 
+    // allow only tables we can handle
+    $t_allowed_tables = array ( 'bug', 'doc', 'avatar' );
+    if ( ! in_array ($f_type, $t_allowed_tables) ) {
+        access_denied();
+    }
+
+   // later on either change the table name mantis_project_file_table to
+    // mantis_doc_file_table or change the code on all places with file_download.php
+    // reference to use type='project' instead of type='doc'.
+    if ( $f_type == 'doc' ) {
+        $f_type = 'project';
+    }
+
 	$c_file_id = (integer)$f_file_id;
 
 	# we handle the case where the file is attached to a bug
 	# or attached to a project as a project doc.
 	$query = '';
-	switch ( $f_type ) {
-		case 'bug':
-			$t_bug_file_table = db_get_table( 'mantis_bug_file_table' );
-			$query = "SELECT *
-				FROM $t_bug_file_table
-				WHERE id=" . db_param();
-			break;
-		case 'doc':
-			$t_project_file_table = db_get_table( 'mantis_project_file_table' );
-			$query = "SELECT *
-				FROM $t_project_file_table
-				WHERE id=" . db_param();
-			break;
-		default:
-			access_denied();
-	}
+    $t_file_table = db_get_table( 'mantis_'.$f_type.'_file_table' );
+    $query = "SELECT *
+        FROM $t_file_table
+        WHERE id=" . db_param();
+
 	$result = db_query_bound( $query, Array( $c_file_id ) );
 	$row = db_fetch_array( $result );
 	extract( $row, EXTR_PREFIX_ALL, 'v' );
 
-	if ( $f_type == 'bug' ) {
-		$t_project_id = bug_get_field( $v_bug_id, 'project_id' );
-	} else {
-		$t_project_id = $v_project_id;
-	}
-
 	# Check access rights
 	switch ( $f_type ) {
 		case 'bug':
 			if ( !file_can_download_bug_attachments( $v_bug_id ) ) {
 				access_denied();
 			}
+            $t_project_id = bug_get_field( $v_bug_id, 'project_id' );
 			break;
-		case 'doc':
+        case 'project':
 			# Check if project documentation feature is enabled.
 			if ( OFF == config_get( 'enable_project_documentation' ) ) {
 				access_denied();
 			}
-
 			access_ensure_project_level( config_get( 'view_proj_doc_threshold' ), $v_project_id );
+            $t_project_id = $v_project_id;
+            break;
+        case 'avatar':
+            $t_project_id = $v_avatar_id;
 			break;
 	}
 

Relationships

related to 0019319 closedvboctor Add support for own gravatar site 
has duplicate 0011638 closedatrol Avatars feature without using external site 
has duplicate 0024550 closedatrol Avatars without using Gravatar 
has duplicate 0025978 closeddregad Local Avatar Support 
related to 0012785 closedvboctor Being able to use Gravatar when using internal email addresses 
related to 0016248 assignedvboctor Add avatar to User information page 
related to 0013788 closedvboctor Add EVENT_USER_DISPLAY_AVATAR to enable plugins to use LDAP and Social Networks 

Activities

giallu

giallu

2007-08-11 17:04

reporter   ~0015420

I would be glad to integrate your modifications into mantis, but before there are some issues I would like to see addressed: are you willing to help?

At a first glance:

  • the patch should be done against the latest release, or even better CVS HEAD. More info on this in: http://www.mantisbt.org/wiki/doku.php/mantisbt:howto_submit_patches

  • you should use tabs for indentation

  • IMHO the constrain on size should be instead on dimensions (width, height), 80x80 being a reasonable default

  • When the uploaded avatar is bigger than the preference, it should be resized to fit before saving on disk

  • the path for storing the avatar should be a configuration option

  • AFAICT, you are not using anymore the gravatars. I think we should let the user decide if he wants to use the local one or the gravatar one: I am going to attach a sample of what I have in mind.

mkornatzki

mkornatzki

2007-08-12 08:44

reporter   ~0015423

shure i will help if i can.

i made a patch against the cvs head.

now a user can confige the avatar in the account_page. you can decide if your image come from gravatar or form an uploaded file.
an administrator can also do the configuration in the manage_user_edit_page.

  • i used tabs
  • sorry i didn't do the resize on storing the file, because than i had to use a graphic-library (if that's not true you can mybe show me the way)
  • the image will be resized to fit $g_avatar_max_width and $g_avatar_max_height
  • the path is now stored in $g_directory_avatar
giallu

giallu

2007-08-12 11:28

reporter   ~0015425

Much better :)

About the resize, the same library you are using when you call getimagesize() should be able to do the trick; please check:

http://www.php.net/imagecopyresampled
and/or
http://www.php.net/imagecopyresized

DGtlRift

DGtlRift

2007-08-12 16:52

reporter   ~0015427

The patch should also allow for storing the image in the database or ftp server rather just to the local filesystem. See core/file_api.php

giallu

giallu

2007-08-12 17:26

reporter   ~0015428

Victor asked me explicitly to not involve the DB at this stage.

I liked the DB solution because some more work will be required if I decide to activate the feature in the Fedora RPM, but this way the implementation look simpler

mkornatzki

mkornatzki

2007-08-14 16:25

reporter   ~0015435

thank you for your advise.

it is now possible to configure ($g_resize_avatar_on_store) if the file should resize on store (default OFF).

the function for store and delete is in filter.api

pluntke

pluntke

2007-10-21 11:59

reporter   ~0015931

I would also like the local avatar solution, as I'm not very happy of the possibility to store every step I do in the web at gravatar (they get asked for a gravatar for my email, so even when I don't have one, they could track where my email/avatar request comes from - right?)

vboctor

vboctor

2007-10-21 19:37

manager   ~0015939

Looks like we are doing good work here. It would be great if you can create some functional description of what we are doing here in the Wiki. You can use the Wiki page associated with this issue. This will allow me (since I am not involved with the details of the patches) and others to look at it and provide feedback. The snapshots done so far will help :)

The wiki page should include:

  1. What are we trying to achive?
  2. Why?
  3. What are the admins options?
  4. What are the users options?
  5. Where do we store local avatars?
  6. Configuration Changes
  7. Database changes

Thanks a lot and keep up the good work.

giallu

giallu

2007-10-25 08:29

reporter   ~0015978

Victor, despite being a time consuming task, I'd love to use the associated wiki page but... 0008110

pluntke

pluntke

2008-01-18 07:40

reporter   ~0016714

which version is the latest patch for?
has anyone tested with 1.1.0 of mantis?
will it be implemented?
I would really like it

cheater

cheater

2008-02-01 03:47

reporter   ~0016903

There´s one bigger issue:
In the file /core/file_api.php
function: file_avatar_upload
you use the header-function "header('Content-type: ..."
This isn´t useful, because the script stops after saving the local avatar, because the browser gets the following output as an image.
After deleting this, the scripts works fine in 1.1.1

One small issues:

  • The UTF-8 Strings in lang/strings_german.txt aren´t corret (german Umlaute)
rady

rady

2008-02-25 03:33

reporter   ~0017190

Hi first of all. I'm interested in adding this patch to my mantis bug tracker, but i'm still very new to this, and i don't think i figured the way it is done. Can anyone help me out?

Thanks in advance!

mkornatzki

mkornatzki

2008-03-09 10:42

reporter   ~0017301

If i use the avatar-feature with a https-connection i get the following error "[function.getimagesize]: failed to open stream: Invalid argument"

You can fix the error if you change the following function in user.api

function user_get_local_avatar( $p_user_id ) {
    global $g_path;
    $t_avatar_exist = true;
    $avatar_dir = config_get('directory_avatar');
    $t_avatar_local_path = dirname( dirname( __FILE__ ) ) . DIRECTORY_SEPARATOR . $avatar_dir . DIRECTORY_SEPARATOR;

# default imagesize
$t_height = config_get('avatar_max_height');
$t_width = config_get('avatar_max_width');

    # if the variable $g_show_realname is on then user_get_name returns the realname.
    #$t_username = user_get_name( $p_user_id );
    #$t_row = user_cache_row( $p_user_id, false );
    #$t_username = $t_row['username'];
$t_username = user_get_field($p_user_id, 'username');

    $t_avatar_local = $t_avatar_local_path . $t_username . '.gif';
    $t_avatar_url = $g_path . $avatar_dir . '/' . $t_username . '.gif';
if (!file_exists($t_avatar_local)) {
  $t_avatar_local = $t_avatar_local_path . $t_username . '.jpg';
        $t_avatar_url = $g_path . $avatar_dir . '/' . $t_username . '.jpg';
  if (!file_exists($t_avatar_local)) {
    $t_avatar_exist = false;    
  }
}

if ($t_avatar_exist) {
  # get image dimensions
  list($width_orig, $height_orig) = getimagesize($t_avatar_local);

...

Maybe someone can find a better solution.

mkornatzki

mkornatzki

2008-05-31 08:53

reporter   ~0017971

Hi, i have made a patch (local_avatar.patch) against the actual trunk.

You have to crate a new Folder "avatar" to store the local images.

mthibeault

mthibeault

2008-12-01 12:16

reporter   ~0020174

Added a patch against the latest GIT. It has been in production environment for a couple months now. Added some resizing features and it is able to use ImageMagick if present (or rely on GD like the original one).
There is still only one issue where the user needs to reload the avatar before seeing the new one after changing it because I am using a single name for the file to prevent users from flooding the server with images.
The images are also resized (proportionally) to the necessary size to take less space on the server (or just more constant space with about 20-25k per avatar).

bartik

bartik

2009-03-29 04:48

reporter   ~0021259

Last edited: 2009-03-29 04:50

I have added another take on the local avatar. It uses the existing file_api.php to store the avatar (new table is added) that means you can use the database, ftp or disk. It uses file_download.php to actually show the picture. It will try to find the local avatar first if enabled and then it falls back to gravatar. The file_api.php got a small overhaul in the process. I have tested this only with the database storage. There is no image resizing. And you have to add the following variables to the config_inc.php :

$g_mantis_avatar_file_table = '%db_table_prefix%_avatar_file%db_table_suffix%';
$g_avatar_files_prefix = 'avatar';
$g_avatar_type = 'local';

and the changes are made for the english language only. Thanks for your effort.
And the diff is agains the 1.1.6 branch HEAD as of posting of this note.

giallu

giallu

2009-04-06 16:59

reporter   ~0021406

bartik, I definitely want to move on here, but we need to work on the git master branch, we can't add stuff to 1.1.6.

So, if any of is interested to help, what we need is one (or more) patches to apply on top of git master.

If some cleanup of file API can be done in the meanwhile, good; anyway, please try to provide it in a separate patchset (just store them ion your local branch, then "git format-patch" will be your friend)

thanks a lot

bartik

bartik

2009-04-11 20:21

reporter   ~0021475

I have attached the diff against the 1.2.x branch (I have a checkout from 7.4.2009 22:12) The added mantis_avatar_file_table is the same as for 1.1.6 I'm sorry but the file_api.php cleanup is also part of this diff and not a separate patch. I did some testing but a more detailed test would be in order. I have to get more familiar with git in the meantime perhaps. Thanks.

giallu

giallu

2009-04-14 11:24

reporter   ~0021527

bartik. thanks a lot.
I will retry to apply your patch and see if I can commit it as is, or be back at you with some more comments.

giallu

giallu

2009-04-15 17:54

reporter   ~0021567

bartik, is it possible you forgot to add to your patch the new file:
account_prefs_avatar_upload_inc.php
?

bartik

bartik

2009-04-16 00:56

reporter   ~0021568

Yes that is entirely possible given my relationship with git. I have now generated a patch which should contain also the missing files. I hope it works now. Thanks.

giallu

giallu

2009-04-16 02:47

reporter   ~0021569

eh eh, like in any other relationships, it takes time to really know each other ;)

borrmann

borrmann

2010-03-23 06:12

reporter   ~0024858

Hey
has someone a patch / diff for the current release 1.2.0?

djcarr

djcarr

2010-06-30 00:58

reporter   ~0025998

Last edited: 2010-07-14 22:07

I'm keen to see this feature too, because it allows admins and managers to set up avatars for users.

Also, I've found that with some Mantis users in China that they cannot retrieve the gravatars (probably due to firewalls) and the page takes forever to load.

Would it be suited to a plugin? I think it just needs two hook-in points (1) on the Edit User page and (2) in the avatar retrieval.

swordchanter

swordchanter

2010-09-27 00:41

reporter   ~0026866

I think we can consult bbs's avatar resolution.

bartik

bartik

2010-11-17 06:14

reporter   ~0027400

Last edited: 2010-11-17 06:15

The 0001-Simple-local-avatar-feature and 0001-Simple-local-avatar-feature-in-core is the minimalistic aproach to the avatar feature. As for making an avatar plugin. The gravatar feature should be moved also to the avatar plugin to make it clean. Beside the hook point (1) mentioned above (it does exist) the hook point (2) does not exist, at least not in 1.2.3 The user_get_avatar in user_api.php would need to have a hook. You need to create the mantis_avatar_file_table the sql is included and then apply the two patches 0001-Simple-local-avatar-feature.patch and 0001-Simple-local-avatar-feature-in-core.patch

kaner

kaner

2011-02-03 10:01

reporter   ~0028152

Hi, I've made a patch against the current stable release 1.2.4. The file is called 'mantis_avatar_simple_patch.patch' and its based on previous versions of patches. Needs some cleanups here and there, but seems to be working.

ibantxo28

ibantxo28

2011-04-15 03:25

reporter   ~0028628

Is there a patch against 1.2.5?

baamster

baamster

2012-04-13 08:49

reporter   ~0031652

I have no clue how to use the patch in Mantis? Why can this not be a plugin? Is much more user friendly I guess?

HiphopTech

HiphopTech

2012-05-25 03:01

reporter   ~0031900

Last edited: 2012-05-25 03:30

Tried running the cmd

patch file.php file.patch

it spits out some stuff and doesn't work. Can someone shed some more like as I'm using 1.2.8 version

vboctor

vboctor

2015-02-03 02:24

manager   ~0048772

Related pull request: https://github.com/mantisbt/mantisbt/pull/574

LewisR

LewisR

2015-02-03 11:56

reporter   ~0048778

@HiphopTech:

it spits out some stuff and doesn't work. Can someone shed some more like as I'm using 1.2.8 version

A full tutorial on diff/patch is beyond the scope of this bug, but assumign the underlying code hasn't changed too drastically, you might want to try increasing the fuzz factor for patch. The fuzz factor gets around strict line numbers (have a look at man patch). In extreme cases, you may have to open the patch file in your favorite editor/reader, and then open each referenced file individually, find where the relevant code should be applied, and copy/paste it manually (or remove, in such cases). As I say, a fuller description is beyond the scope, here.

If I get some time, I'll update the patch, as I'm looking at this myself.

@baamster:

Why can this not be a plugin?

Not everything is well implemented as a plugin, though it would be nice if the plugin functionality were expanded to allow for a wider range of enhancements. This could probably be done as a plugin, but in the meantime, this patch is the implementation available. ;-)

vboctor

vboctor

2016-01-24 21:39

manager   ~0052370

Here is a PR for adding plugin support for avatars. Would be nice to develop a local avatar plugin based on such model:

PR: https://github.com/mantisbt/mantisbt/pull/711

Skye

Skye

2019-08-06 19:32

reporter   ~0062525

Last edited: 2019-08-06 20:02

Since there isn't a local avatar plugin (yet), does that mean local avatars are no longer possible in Mantis 2.21.1...?

(Edit: Gravatar now requires users sign up for wordpress.com for the past few years, which is a bit inconvenient)

dregad

dregad

2019-08-08 05:49

developer   ~0062529

Not exactly a local storage, but this https://github.com/romaincabassot/LdapAvatar may be of interest as an alternative to Gravatar and an inspiration for someone to create a plugin.