Index: common/attachment.php
===================================================================
--- common/attachment.php	(revision 1155)
+++ common/attachment.php	(working copy)
@@ -177,7 +177,9 @@
             // reset palette and transparent color to that of the original file
             $trans_col = imagecolortransparent($image);
             imagepalettecopy($image_resized, $image);
-            imagefill($image_resized, 0, 0, $trans_col);
+            if ($trans_col != -1) {
+                imagefill($image_resized, 0, 0, $trans_col);
+            }
             imagecolortransparent($image_resized, $trans_col);
             imagecopyresampled($image_resized, $image, 0, 0, 0, 0,
                     $new_image_width, $new_image_height, $image_width,
Index: common/avatar.php
===================================================================
--- common/avatar.php	(revision 1155)
+++ common/avatar.php	(working copy)
@@ -6,9 +6,51 @@
 require_once(IA_ROOT_DIR.'common/db/attachment.php');
 require_once(IA_ROOT_DIR.'www/controllers/account_validator.php');
 require_once(IA_ROOT_DIR.'common/common.php');
+require_once(IA_ROOT_DIR.'www/config.php');
 require_once(IA_ROOT_DIR.'common/attachment.php');
 
 /**
+ * Returns whether the attachment of the given page is an avatar attachment
+ * @param  string  $attachment_name
+ * @param  string  $page_name
+ * @return bool
+ */
+function is_avatar_attachment($attachment_name, $page_name) {
+    $matches = get_page_user_name($page_name);
+
+    if ($attachment_name === 'avatar' && $matches) {
+        return true;
+    }
+
+    return false;
+}
+
+/**
+ * Resizes a newly uploaded avatar and returns errors if any
+ * @param  string  $temporary_name
+ * @param  string  $filepath          The filepath where to copy the attachment
+ * @param  string  $username
+ * @return mixed   Error message or null on success
+ */
+function avatar_update($temporary_name, $filepath, $username) {
+    // resize the avatar if it has a correct mime-type
+    $avatar_mime_types = array('image/gif', 'image/jpeg', 'image/png');
+    $image_info = getimagesize($temporary_name);
+    if (!in_array($image_info['mime'], $avatar_mime_types)) {
+        return 'Fisierul nu este o imagine acceptata pe site. ' .
+                'Utilizati doar imagini GIF, JPEG sau PNG.';
+    }
+
+    // write the file on disk.
+    if (!move_uploaded_file($temporary_name, $filepath)) {
+        return 'Fisierul nu a putut fi incarcat pe server.';
+    }
+    // resize the avatar
+    avatar_cache_resized($filepath, $image_info, "a".$username);
+    return null;
+}
+
+/**
  * It takes an avatar image file given by it's filepath and resizes it in the
  * sizes necessary on the site.
  *
@@ -20,8 +62,16 @@
     $resize_sizes = array('L16x16' => 'tiny/', 'L32x32' => 'small/',
             'L50x50' => 'normal/' , '75x75'=> 'forum/', '150x150' => 'big/');
 
-    // Copying the original image
-    copy($filepath, IA_AVATAR_FOLDER.'full/'.$new_filename);
+    // Hardlink / Copy the original image
+    $new_filepath = IA_AVATAR_FOLDER . 'full/' . $new_filename;
+    if (is_file($new_filepath) || is_link($new_filepath)) {
+        unlink($new_filepath);
+    }
+    if (!link($filepath, $new_filepath)) {
+        if (!copy($filepath, $new_filepath)) {
+            log_error('Unable to copy user avatar into avatar folder');
+        }
+    }
 
     list($image_width, $image_height, $image_type, $image_attribute) =
             $image_info;
@@ -36,4 +86,27 @@
     }
 }
 
+/**
+ * Delete's an user avatar, the rest is done from the attachment page
+ *
+ * @param  string  $username
+ */
+function avatar_delete($username) {
+    $resize_folders = array('tiny/', 'small/', 'normal/', 'forum/', 'big/');
+
+    // Unlink the hardlinked full-sized image
+    $filepath = IA_AVATAR_FOLDER . 'full/a' . $username;
+    if (is_file($filepath) || is_link($filepath)) {
+        unlink($filepath);
+    }
+
+    // Delete the resized ones
+    foreach ($resize_folders as $resize_folder) {
+        $filepath = IA_AVATAR_FOLDER . $resize_folder . 'a'
+                . $username;
+        if (is_file($filepath) || is_link($filepath)) {
+            unlink($filepath);
+        }
+    }
+}
 ?>
Index: common/common.php
===================================================================
--- common/common.php	(revision 1155)
+++ common/common.php	(working copy)
@@ -155,6 +155,20 @@
     return preg_match('/^'.IA_RE_PAGE_NAME.'$/xi', $page_name);
 }
 
+/**
+ * Validates user page name
+ *
+ * @param  string  $page_name
+ * @return array                returns an array containing the matched user
+ */
+function get_page_user_name($page_name) {
+    preg_match("/^ ".
+                preg_quote(IA_USER_TEXTBLOCK_PREFIX, '/').
+                '('.IA_RE_USER_NAME.") (\/?.*) $/xi",
+                $page_name, $matches);
+    return $matches;
+}
+
 // returns boolean whether specified attach name is valid
 // NOTE: We hereby limit file names. No spaces, please. Not that we have
 // a problem with spaces inside URLs. Everything should be (and hopefully is)
Index: common/security.php
===================================================================
--- common/security.php	(revision 1155)
+++ common/security.php	(working copy)
@@ -192,10 +192,7 @@
 
     // HACK: Forward security to user.
     // HACK: based on name
-    if (preg_match("/^ ".
-                preg_quote(IA_USER_TEXTBLOCK_PREFIX, '/').
-                '('.IA_RE_USER_NAME.") (\/?.*) $/xi",
-                $textblock['name'], $matches)) {
+    if (count($matches = get_page_user_name($textblock['name'])) > 0) {
         require_once(IA_ROOT_DIR . "common/db/user.php");
         $ouser = user_get_by_username($matches[1]);
         if ($ouser === null) {
@@ -204,9 +201,6 @@
         }
         // This is a horrible hack to prevent deleting or moving an user page.
         // This is pure evil.
-        if ($matches[2] != '') {
-            return false;
-        }
         if ($action == 'textblock-delete' || $action == 'textblock-move') {
             $action = 'simple-critical';
         }
Index: scripts/make-avatar-folder
===================================================================
--- scripts/make-avatar-folder	(revision 1155)
+++ scripts/make-avatar-folder	(working copy)
@@ -1,21 +1,22 @@
 #! /usr/bin/env php
 <?php
 
-require_once(dirname($argv[0])."/utilities.php");
-require_once(IA_ROOT_DIR.'common/db/db.php');
-require_once(IA_ROOT_DIR.'www/controllers/attachment.php');
-require_once(IA_ROOT_DIR.'www/controllers/image_attachment.php');
-require_once(IA_ROOT_DIR.'common/db/attachment.php');
-require_once(IA_ROOT_DIR.'common/cache.php');
-require_once(IA_ROOT_DIR.'common/db/user.php');
-require_once(IA_ROOT_DIR.'common/avatar.php');
-require_once(IA_ROOT_DIR.'common/db/textblock.php');
+require_once(dirname($argv[0]) . '/utilities.php');
+require_once(IA_ROOT_DIR . 'common/db/db.php');
+require_once(IA_ROOT_DIR . 'www/controllers/attachment.php');
+require_once(IA_ROOT_DIR . 'www/controllers/image_attachment.php');
+require_once(IA_ROOT_DIR . 'common/db/attachment.php');
+require_once(IA_ROOT_DIR . 'common/cache.php');
+require_once(IA_ROOT_DIR . 'common/db/user.php');
+require_once(IA_ROOT_DIR . 'common/avatar.php');
+require_once(IA_ROOT_DIR . 'common/db/textblock.php');
 
 // Database connect
 db_connect();
+$verbose = getattr($argv, 1, false) === '-v';
 
 // Managing the userinfo template from the textblock table
-if (read_bool("Do you want to change the template/userinfo textblock?",
+if (read_bool('Do you want to change the template/userinfo textblock?',
         false)) {
     $textfortextblock = "table(compact). |=/5. ==UserImage".
     "(user=\"%user%\" size=\"big\")==\r\n{'Vezi solutiile trimise':monitor?use".
@@ -27,7 +28,7 @@
     "==SmfLink(user=\"%user%\" link=\"stats\" caption=\"vezi activitate\")== |".
     "\r\n\r\n\r\n";
     textblock_add_revision('template/userinfo', 'template/userinfo',
-            $textfortextblock, 1, "protected");
+            $textfortextblock, 1, 'protected');
 }
 
 // getting the user list
@@ -39,11 +40,11 @@
 // creating the avatar folder if it does not exists, and grant it permissions
 if (file_exists(IA_AVATAR_FOLDER) == false) {
     mkdir(IA_AVATAR_FOLDER, 0777);
-    $size_types = array("tiny", "small", "normal", "forum", "big", "full");
-    foreach ($size_types as $size) {
-        if (file_exists(IA_AVATAR_FOLDER."/".$size) == false) {
-            mkdir(IA_AVATAR_FOLDER."/".$size, 0777);
-        }
+}
+$size_types = array('tiny', 'small', 'normal', 'forum', 'big', 'full');
+foreach ($size_types as $size) {
+    if (file_exists(IA_AVATAR_FOLDER . '/' . $size) == false) {
+        mkdir(IA_AVATAR_FOLDER . '/' . $size, 0777);
     }
 }
 
@@ -53,14 +54,19 @@
 
 // Going through all the users
 foreach ($userlist as $user) {
-    $attach = attachment_get('avatar', 'utilizator/'.$user);
+    if (!is_user_name($user)) {
+        log_warn('Invalid username: ' . $user);
+        continue;
+    }
+    $attach = attachment_get('avatar', 'utilizator/' . $user);
     $found = !is_null($attach);
 
     if ($found) {
         $real_name = attachment_get_filepath($attach);
         $found = file_exists($real_name);
-        if (!$found)
-            log_warn("File does not exists but it is in the Database.");
+        if (!$found) {
+            log_warn('File does not exists but it is in the Database.');
+        }
     }
 
     if (!$found) {
@@ -73,6 +79,9 @@
     }
 
     // The user has a valid image, resizing it, but keeping the attachment
+    if ($verbose) {
+        log_print('Processing user: ' . $user);
+    }
     avatar_cache_resized($real_name, $img_info, "a".$user);
 }
 
Index: scripts/setup
===================================================================
--- scripts/setup	(revision 1155)
+++ scripts/setup	(working copy)
@@ -229,7 +229,6 @@
     $sitename = read_line("Site name?", $sitename);
     system("chmod g+ws {$ia_root}attach");
     system("chmod g+ws {$ia_root}cache");
-    system("chmod g+ws {$ia_root}www/static/images/avatar");
     system("chmod g+ws {$ia_root}www/static/images/tmp");
     system("chmod g+ws {$ia_root}www/static/images/latex");
 
@@ -268,6 +267,8 @@
     }
 }
 
+// Running scripts to keep things simple for new developers
+system("./{$ia_root}scripts/make-avatar-folder");
 // FIXME: configure forum
 if (read_bool("Should I try to configure the forum (ugly db stuff)?", true)) {
     system("{$ia_root}scripts/forum-fix");
Index: www/controllers/account.php
===================================================================
--- www/controllers/account.php	(revision 1155)
+++ www/controllers/account.php	(working copy)
@@ -6,6 +6,7 @@
 require_once(IA_ROOT_DIR."common/avatar.php");
 require_once(IA_ROOT_DIR."www/controllers/account_validator.php");
 require_once(IA_ROOT_DIR."www/config.php");
+require_once(IA_ROOT_DIR."common/avatar.php");
 
 // identify target user and check permission to edit profile
 // Yields flash_error & redirect when username invalid or security error
@@ -128,20 +129,9 @@
                 // write the file on disk.
                 if (!$errors) {
                     $disk_name = attachment_get_filepath($attach);
-                    if (!move_uploaded_file($_FILES['avatar']['tmp_name'],
-                                            $disk_name)) {
-                        $errors['avatar'] = 'Fisierul nu a putut fi incarcat '
-                                            .'pe server.';
-                    } else {
-                        // resize the avatar if it is a correct mime-type
-                        global $IA_SAFE_MIME_TYPES;
-                        $img_info = getimagesize($disk_name);
-                        // check if mime-type is from accepted ones
-                        if (in_array($img_info['mime'], $IA_SAFE_MIME_TYPES)) {
-                            avatar_cache_resized($disk_name, $img_info,
-                                    "a".$user['username']);
-                        }
-                    }
+                    $errors['avatar'] = avatar_update(
+                            $_FILES['avatar']['tmp_name'], $disk_name,
+                            $user['username']);
                 }
             }
 
@@ -211,6 +201,8 @@
     $view['form_errors'] = $errors;
     $view['form_values'] = $data;
     $view['action'] = url_account($user['username']);
+    $view['avatar_exists'] = attachment_get('avatar', IA_USER_TEXTBLOCK_PREFIX .
+            $user['username']);
     if ($ownprofile) {
         $view['topnav_select'] = 'profile';
     }
Index: www/controllers/attachment.php
===================================================================
--- www/controllers/attachment.php	(revision 1155)
+++ www/controllers/attachment.php	(working copy)
@@ -5,6 +5,7 @@
 require_once(IA_ROOT_DIR."common/db/attachment.php");
 require_once(IA_ROOT_DIR.'www/controllers/zip_attachment.php');
 require_once(IA_ROOT_DIR."common/external_libs/zipfile.php");
+require_once(IA_ROOT_DIR."common/avatar.php");
 
 // Try to get the textblock model for a certain page.
 // If it fails it will flash and redirect
@@ -108,21 +109,24 @@
     $attachments = array();
     if (!$form_errors) {
         if ($autoextract) {
-            $zip_files = get_zipped_attachments($_FILES['file_name']['tmp_name']);
+            $zip_files = get_zipped_attachments(
+                    $_FILES['file_name']['tmp_name']);
 
             if (false === $zip_files) {
-                $form_errors['file_name'] = 'Arhiva ZIP este invalida sau nu poate fi recunoscuta';
+                $form_errors['file_name'] = 'Arhiva ZIP este invalida sau nu '
+                        . 'poate fi recunoscuta';
             } else {
                 $attachments = $zip_files['attachments'];
-                $skipped_files = $zip_files['total_files'] - count($attachments);
+                $skipped_files = $zip_files['total_files'] -
+                        count($attachments);
             }
         }
         else {
             // simple (single) file attachment
             $attachments = array(
-                array('name' => $form_values['file_name'], 'size' => $form_values['file_size'],
-                      'disk_name' => $_FILES['file_name']['tmp_name'])
-            );
+                array('name' => $form_values['file_name'],
+                        'size' => $form_values['file_size'],
+                        'disk_name' => $_FILES['file_name']['tmp_name']));
         }
     }
 
@@ -140,7 +144,8 @@
             // extract archived file to a tempory file on disk
             $tmpname = tempnam(IA_ROOT_DIR . 'attach/', 'iatmp');
             log_assert($tmpname);
-            $res = extract_zipped_attachment($ziparchive, $att['zipindex'], $tmpname);
+            $res = extract_zipped_attachment($ziparchive, $att['zipindex'],
+                    $tmpname);
             if ($res) {
                 $att['disk_name'] = $tmpname;
                 $extract_okcount++;
@@ -164,6 +169,7 @@
     // Create database entries
     $rewrite_count = 0;
     $attach_okcount = 0;
+    $extra_errors = '';
     if (!$form_errors) {
         for ($i = 0; $i < count($attachments); $i++) {
             $file_att =& $attachments[$i];
@@ -181,6 +187,16 @@
                 $file_att['size'] = filesize($file_att['disk_name']);
             }
 
+            if (is_avatar_attachment($file_att['name'], $page_name)) {
+                if (isset($skipped_files)) {
+                    $skipped_files++;
+                }
+                $extra_errors .= ' A fost intalnit un fisier cu numele avatar' .
+                        '. Pentru a va modifica imaginea de profil va rugam ' .
+                        'folositi pagina "Contul meu".';
+                 continue;
+            }
+
             $attach = attachment_get($file_att['name'], $page_name);
             if ($attach) {
                 // Attachment already exists, overwrite.
@@ -215,7 +231,8 @@
             }
             $disk_name = attachment_get_filepath($file_att['attach_obj']);
             if (is_uploaded_file($file_att['disk_name'])) {
-                $move_ok = move_uploaded_file($file_att['disk_name'], $disk_name);
+                $move_ok = move_uploaded_file($file_att['disk_name'],
+                        $disk_name);
             } else {
                 $move_ok = @rename($file_att['disk_name'], $disk_name);
             }
@@ -231,44 +248,52 @@
     }
 
     // custom error message for simple (single) file uploads
-    if (!$form_errors && !$autoextract && 0 >= $attach_okcount) {
-        $form_errors['file_name'] = 'Fisierul nu a putut fi atasat! Eroare necunoscuta ...';
+    if (!$form_errors && !$autoextract && 0 >= $attach_okcount &&
+                !$extra_errors) {
+        $form_errors['file_name'] = 'Fisierul nu a putut fi atasat! Eroare ' .
+                'necunoscuta ...';
     }
 
     // display error/confirmation message
     if (!$form_errors) {
         if ($autoextract) {
             if ($attach_okcount == 1) {
-                $msg = "Am extras si incarcat un fisier.";
+                $msg = 'Am extras si incarcat un fisier.';
             } else {
                 $msg = "Am extras si incarcat {$attach_okcount} fisiere.";
             }
 
             if ($rewrite_count == 1) {
-                $msg .= " Un fisier mai vechi a fost rescris.";
+                $msg .= ' Un fisier mai vechi a fost rescris.';
             } else if ($rewrite_count > 1) {
                 $msg .= " {$rewrite_count} fisiere mai vechi au fost rescrise.";
             }
 
             if ($skipped_files == 1) {
-                $msg .= " Un fisier nu a fost dezarhivat deoarece era prea mare sau era invalid.";
+                $msg .= ' Un fisier nu a fost dezarhivat deoarece era prea ' .
+                        'mare sau era invalid.';
             } else if ($skipped_files > 1) {
-                $msg .= " {$skipped_files} fisiere nu au fost dezarhivate deoarece erau prea mari sau erau invalide.";
+                $msg .= " {$skipped_files} fisiere nu au fost dezarhivate " .
+                        'deoarece erau prea mari sau erau invalide.';
             }
+            $msg .= $extra_errors;
         }
         else {
-            if ($rewrite_count) {
-                $msg = "Fisierul trimis a fost atasat cu succes. Un atasamant mai vechi a fost rescris.";
+            if ($extra_errors) {
+                $msg = $extra_errors;
+            } else if($rewrite_count) {
+                $msg = 'Fisierul trimis a fost atasat cu succes. Un atasament' .
+                        'mai vechi a fost rescris.';
+            } else {
+                $msg = 'Fisierul trimis a fost atasat cu succes.';
             }
-            else {
-                $msg = "Fisierul trimis a fost atasat cu succes.";
-            }
         }
 
         flash($msg);
         redirect(url_textblock($page_name));
     }
 
+    $form_errors['file_name'] .= $extra_errors;
     // Errors, print view template.
     $view['form_errors'] = $form_errors;
     $view['form_values'] = $form_values;
@@ -300,6 +325,11 @@
         redirect(url_textblock($page_name));
     }
 
+    // Delete the resizedimages in case the page is an avatar
+    $matches = get_page_user_name($page_name);
+    if (is_avatar_attachment($file_name, $page_name)) {
+        avatar_delete($matches[1]);
+    }
     // We've got big balls.
 
     if(!$more_files) {
@@ -343,6 +373,18 @@
         redirect(url_attachment_list($page_name));
     }
 
+    if (is_avatar_attachment($old_name, $page_name)) {
+        flash_error('Atasamentul "avatar" nu poate fi redenumit.');
+        redirect(url_textblock($page_name));
+    }
+
+    if (is_avatar_attachment($new_name, $page_name)) {
+        flash_error('Nu puteti numi un atasament "avatar". Pentru '
+                . 'a va modifica imaginea de profil va rugam folositi '
+                . 'pagina "Contul meu".');
+        redirect(url_textblock($page_name));
+    }
+
     $old_attach = attachment_get($old_name, $page_name);
     identity_require('attach-rename', $old_attach);
     if (!$old_attach) {
Index: www/index.php
===================================================================
--- www/index.php	(revision 1155)
+++ www/index.php	(working copy)
@@ -279,7 +279,7 @@
         controller_attachment_download($page, request('file'), request('safe_only', false) == 'true');
     }
 }
-else if ($action == 'download-zip') {
+else if ($action == 'attach-bulk-action') {
     require_once(IA_ROOT_DIR.'www/controllers/attachment.php');
     if(request('download')) {
         controller_attachment_download_zip($page, request_args());
Index: www/views/account.php
===================================================================
--- www/views/account.php	(revision 1155)
+++ www/views/account.php	(working copy)
@@ -96,6 +96,16 @@
             ?>
         </li>
         <li>
+            <?php
+                if ($view['avatar_exists']) {
+                    echo format_post_link(url_attachment_delete(
+                                IA_USER_TEXTBLOCK_PREFIX . $user['username'],
+                                'avatar'), "Sterge Avatar", array(), true,
+                                array('onclick' => "return confirm('Aceasta " .
+                                        'actiune este ireversibila! Doresti ' .
+                                        "sa continui?')"));
+                }
+            ?>
             <label for="form_avatar">Avatar nou</label>
             <?= ferr_span('avatar') ?>
             <input type="file" name="avatar" id="form_avatar" />
Index: www/views/listattach.php
===================================================================
--- www/views/listattach.php	(revision 1155)
+++ www/views/listattach.php	(working copy)
@@ -36,7 +36,7 @@
 
 function format_attach_name($row) {
     global $page_name;
-    
+
     $attachurl = '<span id="rename_'.$row['id'].'" style="display: none">';
     $attachurl .= '<form action="'.url_attachment_rename($page_name).'" method="post">';
     $attachurl .= '<input type="hidden" name="old_name" value="'.$row['name'].'"/>';
@@ -125,8 +125,8 @@
     ),
 );
 ?>
-    <form method = 'post' action = ''> 
-    <input type = 'hidden' name = 'action' value = 'download-zip'>
+    <form method = 'post' action = ''>
+    <input type = 'hidden' name = 'action' value = 'attach-bulk-action'>
     <h1>Atasamente pentru pagina <?= format_link(url_textblock($view['page_name']), $view['page_name']) ?></h1>
     <?php
         $options = array(
