diff --git a/app/controllers/watchers_controller.rb b/app/controllers/watchers_controller.rb
new file mode 100644
index 0000000000000000000000000000000000000000..09ec5bcd7fdd80224533b40832f36c90366fa614
--- /dev/null
+++ b/app/controllers/watchers_controller.rb
@@ -0,0 +1,38 @@
+# redMine - project management software
+# Copyright (C) 2006-2007  Jean-Philippe Lang
+#
+# This program 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.
+# 
+# This program 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 this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+class WatchersController < ApplicationController
+  layout 'base'
+  before_filter :require_login, :find_project, :check_project_privacy
+  
+  def add
+    @issue.add_watcher(logged_in_user)
+    redirect_to :controller => 'issues', :action => 'show', :id => @issue
+  end
+  
+  def remove
+    @issue.remove_watcher(logged_in_user)
+    redirect_to :controller => 'issues', :action => 'show', :id => @issue
+  end
+
+private
+
+  def find_project
+    @issue = Issue.find(params[:issue_id])
+    @project = @issue.project
+  end
+end
diff --git a/app/helpers/watchers_helper.rb b/app/helpers/watchers_helper.rb
new file mode 100644
index 0000000000000000000000000000000000000000..23f7676117ef292174c5467d9e4103f1a565c595
--- /dev/null
+++ b/app/helpers/watchers_helper.rb
@@ -0,0 +1,19 @@
+# redMine - project management software
+# Copyright (C) 2006-2007  Jean-Philippe Lang
+#
+# This program 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.
+# 
+# This program 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 this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+module WatchersHelper
+end
diff --git a/app/models/issue.rb b/app/models/issue.rb
index bb7797c402246aa139723dc8492df7796718c757..0f44cdd3025ca28e9c1ebfd2fc0b24d84313cff9 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -32,6 +32,8 @@ class Issue < ActiveRecord::Base
   has_many :custom_values, :dependent => :delete_all, :as => :customized
   has_many :custom_fields, :through => :custom_values
 
+  acts_as_watchable
+  
   validates_presence_of :subject, :description, :priority, :tracker, :author, :status
   validates_inclusion_of :done_ratio, :in => 0..100
   validates_associated :custom_values, :on => :update
diff --git a/app/models/mailer.rb b/app/models/mailer.rb
index 36bcddc2a6cfd2de06d26852f34d9c8124f0f180..5d835289aae962b2240a93b769fe5582dfcfcf23 100644
--- a/app/models/mailer.rb
+++ b/app/models/mailer.rb
@@ -32,6 +32,8 @@ class Mailer < ActionMailer::Base
     # Sends to all project members
     issue = journal.journalized
     @recipients     = issue.project.members.collect { |m| m.user.mail if m.user.mail_notification }.compact
+    # Watchers in cc
+    @cc             = issue.watcher_recipients - @recipients
     @from           = Setting.mail_from
     @subject        = "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] #{issue.status.name} - #{issue.subject}"
     @body['issue']  = issue
diff --git a/app/models/watcher.rb b/app/models/watcher.rb
new file mode 100644
index 0000000000000000000000000000000000000000..cb6ff52eaaaabc870b7932c5aff155bca7cd4528
--- /dev/null
+++ b/app/models/watcher.rb
@@ -0,0 +1,23 @@
+# redMine - project management software
+# Copyright (C) 2006-2007  Jean-Philippe Lang
+#
+# This program 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.
+# 
+# This program 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 this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+class Watcher < ActiveRecord::Base
+  belongs_to :watchable, :polymorphic => true
+  belongs_to :user
+  
+  validates_uniqueness_of :user_id, :scope => [:watchable_type, :watchable_id]
+end
diff --git a/app/views/issues/show.rhtml b/app/views/issues/show.rhtml
index a5569c9d4d495f6c98c3ce5f9a1abb0d5ceaa442..3c1ac0e2ec09006c0463a8a8f712f27ebbffe191 100644
--- a/app/views/issues/show.rhtml
+++ b/app/views/issues/show.rhtml
@@ -53,6 +53,13 @@ end %>
 <div class="contextual">
 <%= link_to_if_authorized l(:button_edit), {:controller => 'issues', :action => 'edit', :id => @issue}, :class => 'icon icon-edit' %>
 <%= link_to_if_authorized l(:button_log_time), {:controller => 'timelog', :action => 'edit', :issue_id => @issue}, :class => 'icon icon-time' %>
+<% if @logged_in_user %>
+  <% if @issue.watched_by?(@logged_in_user) %>
+<%= link_to l(:button_unwatch), {:controller => 'watchers', :action => 'remove', :issue_id => @issue}, :class => 'icon icon-fav' %>
+  <% else %>
+<%= link_to l(:button_watch), {:controller => 'watchers', :action => 'add', :issue_id => @issue}, :class => 'icon icon-fav' %>
+  <% end %>
+<% end %>
 <%= link_to_if_authorized l(:button_move), {:controller => 'projects', :action => 'move_issues', :id => @project, "issue_ids[]" => @issue.id }, :class => 'icon icon-move' %>
 <%= link_to_if_authorized l(:button_delete), {:controller => 'issues', :action => 'destroy', :id => @issue}, :confirm => l(:text_are_you_sure), :method => :post, :class => 'icon icon-del' %>
 </div>
diff --git a/config/environment.rb b/config/environment.rb
index a73dc9a4c41c7b8ad7cc8dd3f2cbba8bb95c5562..8ff43e0ac88eb4446dfd7d0491ede4a3dfca7e8f 100644
--- a/config/environment.rb
+++ b/config/environment.rb
@@ -82,4 +82,5 @@ GLoc.set_kcode
 GLoc.load_localized_strings
 GLoc.set_config(:raise_string_not_found_errors => false)
 
+require 'redmine'
 
diff --git a/lang/de.yml b/lang/de.yml
index 95ae4a635428e24570899bd95987edc821b84e9a..590e5e0d5605737a00c941bb4e35db451c4c723b 100644
--- a/lang/de.yml
+++ b/lang/de.yml
@@ -383,6 +383,8 @@ button_activate: Aktivieren
 button_sort: Sortieren
 button_log_time: Log time
 button_rollback: Rollback to this version
+button_watch: Watch
+button_unwatch: Unwatch
 
 status_active: aktiv
 status_registered: angemeldet
diff --git a/lang/en.yml b/lang/en.yml
index 0e66a1faf693ab8087ee69f0ada2d779089b7fdb..e40c915f2bd7c4c6fc9d87846cb1d189f02a7dbd 100644
--- a/lang/en.yml
+++ b/lang/en.yml
@@ -383,6 +383,8 @@ button_activate: Activate
 button_sort: Sort
 button_log_time: Log time
 button_rollback: Rollback to this version
+button_watch: Watch
+button_unwatch: Unwatch
 
 status_active: active
 status_registered: registered
diff --git a/lang/es.yml b/lang/es.yml
index a245d05fbf740d3f5d83228e4d239efcf7f07787..103c399c0e4f7e540ac964e6c2cd2e6fe1ad7f2d 100644
--- a/lang/es.yml
+++ b/lang/es.yml
@@ -383,6 +383,8 @@ button_activate: Activar
 button_sort: Clasificar
 button_log_time: Log time
 button_rollback: Rollback to this version
+button_watch: Watch
+button_unwatch: Unwatch
 
 status_active: active
 status_registered: registered
diff --git a/lang/fr.yml b/lang/fr.yml
index 5cc05ef64c1b808372bcda46c9447a523fddddc0..d6666169c4c76ffdc160183a39a1979469df7d28 100644
--- a/lang/fr.yml
+++ b/lang/fr.yml
@@ -383,6 +383,8 @@ button_activate: Activer
 button_sort: Trier
 button_log_time: Saisir temps
 button_rollback: Revenir à cette version
+button_watch: Surveiller
+button_unwatch: Ne plus surveiller
 
 status_active: actif
 status_registered: enregistré
diff --git a/lang/it.yml b/lang/it.yml
index 6beb963ed76c145966cf3e53f2ca0cf423e83954..6af04b2f4695e1e2a43dd0213b0c21d4de79276b 100644
--- a/lang/it.yml
+++ b/lang/it.yml
@@ -383,6 +383,8 @@ button_activate: Attiva
 button_sort: Ordina
 button_log_time: Log time
 button_rollback: Rollback to this version
+button_watch: Watch
+button_unwatch: Unwatch
 
 status_active: active
 status_registered: registered
diff --git a/lang/ja.yml b/lang/ja.yml
index 8bcf77fe36a1953d41d770ef6c5db4d95ac429bc..5cc9bb907631ddbf49db3bc076eb58a1e53e2ce9 100644
--- a/lang/ja.yml
+++ b/lang/ja.yml
@@ -384,6 +384,8 @@ button_activate: 有効にする
 button_sort: ソート
 button_log_time: 時間を記録
 button_rollback: このバージョンにロールバック
+button_watch: Watch
+button_unwatch: Unwatch
 
 status_active: 有効
 status_registered: 登録
diff --git a/lang/zh.yml b/lang/zh.yml
index be1c91f8a1db73c4b682af204a18e2e3e656dde2..78e093d59b4d8fc9e70fc6e10fe6188fb4801e4b 100644
--- a/lang/zh.yml
+++ b/lang/zh.yml
@@ -386,6 +386,8 @@ button_activate: 激活
 button_sort: 排序
 button_log_time: 登记工时
 button_rollback: Rollback to this version
+button_watch: Watch
+button_unwatch: Unwatch
 
 status_active: 激活
 status_registered: 已注册
diff --git a/lib/redmine.rb b/lib/redmine.rb
index 20b30c037e1fad15429e0c42b2c964fd06e44259..cfcccccf925a8fa942ca95cd491f29abc036757f 100644
--- a/lib/redmine.rb
+++ b/lib/redmine.rb
@@ -1,11 +1,2 @@
-module Redmine
-  module VERSION #:nodoc:
-    MAJOR = 0
-    MINOR = 5
-    TINY  = 0
-
-    STRING= [MAJOR, MINOR, TINY].join('.')
-    
-    def self.to_s; STRING end    
-  end
-end
\ No newline at end of file
+require 'redmine/version'
+require 'redmine/acts_as_watchable/init'
diff --git a/lib/redmine/acts_as_watchable/init.rb b/lib/redmine/acts_as_watchable/init.rb
new file mode 100644
index 0000000000000000000000000000000000000000..f39cc7d189af2906779a7953677b67b3b8f19459
--- /dev/null
+++ b/lib/redmine/acts_as_watchable/init.rb
@@ -0,0 +1,3 @@
+# Include hook code here
+require File.dirname(__FILE__) + '/lib/acts_as_watchable'
+ActiveRecord::Base.send(:include, Redmine::Acts::Watchable)
diff --git a/lib/redmine/acts_as_watchable/lib/acts_as_watchable.rb b/lib/redmine/acts_as_watchable/lib/acts_as_watchable.rb
new file mode 100644
index 0000000000000000000000000000000000000000..d62742cacba08ad2fdf3a0b28fa64f196cd2ac2a
--- /dev/null
+++ b/lib/redmine/acts_as_watchable/lib/acts_as_watchable.rb
@@ -0,0 +1,53 @@
+# ActsAsWatchable
+module Redmine
+  module Acts
+    module Watchable
+      def self.included(base) 
+        base.extend ClassMethods
+      end 
+
+      module ClassMethods
+        def acts_as_watchable(options = {})
+          return if self.included_modules.include?(Redmine::Acts::Watchable::InstanceMethods)          
+          send :include, Redmine::Acts::Watchable::InstanceMethods
+          
+          class_eval do
+            has_many :watchers, :as => :watchable, :dependent => :delete_all
+          end
+        end
+      end
+
+      module InstanceMethods
+        def self.included(base)
+          base.extend ClassMethods
+        end
+        
+        def add_watcher(user)
+          self.watchers << Watcher.new(:user => user)
+        end
+        
+        def remove_watcher(user)
+          return nil unless user && user.is_a?(User)
+          Watcher.delete_all "watchable_type = '#{self.class}' AND watchable_id = #{self.id} AND user_id = #{user.id}"
+        end
+        
+        def watched_by?(user)
+          !self.watchers.find(:first,
+                              :conditions => ["#{Watcher.table_name}.user_id = ?", user.id]).nil?
+        end
+        
+        def watcher_recipients
+          self.watchers.collect { |w| w.user.mail if w.user.mail_notification }.compact
+        end
+
+        module ClassMethods
+          def watched_by(user)
+            find(:all, 
+                 :include => :watchers,
+                 :conditions => ["#{Watcher.table_name}.user_id = ?", user.id])
+          end
+        end
+      end
+    end
+  end
+end 
\ No newline at end of file
diff --git a/lib/redmine/version.rb b/lib/redmine/version.rb
new file mode 100644
index 0000000000000000000000000000000000000000..630fb1ff8086cff37dc26f3f0dcdfd4d521481ab
--- /dev/null
+++ b/lib/redmine/version.rb
@@ -0,0 +1,11 @@
+module Redmine
+  module VERSION #:nodoc:
+    MAJOR = 0
+    MINOR = 5
+    TINY  = 0
+
+    STRING= [MAJOR, MINOR, TINY].join('.')
+    
+    def self.to_s; STRING end    
+  end
+end
diff --git a/public/images/fav.png b/public/images/fav.png
new file mode 100644
index 0000000000000000000000000000000000000000..49c0f473a139665cfd4bb148bbe58833c79d4f59
Binary files /dev/null and b/public/images/fav.png differ
diff --git a/public/stylesheets/application.css b/public/stylesheets/application.css
index 7461c74a3bbb0cc90e9248a121963aa7ab20c492..ced43768d3b2904ba870f42e38bc31f96229580f 100644
--- a/public/stylesheets/application.css
+++ b/public/stylesheets/application.css
@@ -158,6 +158,7 @@ vertical-align: middle;
 .icon-time  { background-image: url(../images/time.png); }
 .icon-stats  { background-image: url(../images/stats.png); }
 .icon-warning  { background-image: url(../images/warning.png); }
+.icon-fav  { background-image: url(../images/fav.png); }
 
 .icon22-projects { background-image: url(../images/22x22/projects.png); }
 .icon22-users { background-image: url(../images/22x22/users.png); }
diff --git a/test/unit/watcher_test.rb b/test/unit/watcher_test.rb
new file mode 100644
index 0000000000000000000000000000000000000000..b8a095426dd12730afff9469e1c5cf95b77b7633
--- /dev/null
+++ b/test/unit/watcher_test.rb
@@ -0,0 +1,69 @@
+# redMine - project management software
+# Copyright (C) 2006-2007  Jean-Philippe Lang
+#
+# This program 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.
+# 
+# This program 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 this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+require File.dirname(__FILE__) + '/../test_helper'
+
+class WatcherTest < Test::Unit::TestCase
+  fixtures :issues, :users
+
+  def setup
+    @user = User.find(1)
+    @issue = Issue.find(1)
+  end
+  
+  def test_watch
+    assert @issue.add_watcher(@user)
+    @issue.reload
+    assert @issue.watchers.detect { |w| w.user == @user }
+  end
+  
+  def test_cant_watch_twice
+    assert @issue.add_watcher(@user)
+    assert !@issue.add_watcher(@user)
+  end
+  
+  def test_watched_by
+    assert @issue.add_watcher(@user)
+    @issue.reload
+    assert @issue.watched_by?(@user)
+    assert Issue.watched_by(@user).include?(@issue)
+  end
+  
+  def test_recipients
+    @issue.watchers.delete_all
+    @issue.reload
+    
+    assert @issue.watcher_recipients.empty?
+    assert @issue.add_watcher(@user)
+
+    @user.mail_notification = true
+    @user.save    
+    @issue.reload
+    assert @issue.watcher_recipients.include?(@user.mail)
+
+    @user.mail_notification = false
+    @user.save    
+    @issue.reload
+    assert !@issue.watcher_recipients.include?(@user.mail)
+  end
+  
+  def test_unwatch
+    assert @issue.add_watcher(@user)
+    @issue.reload
+    assert_equal 1, @issue.remove_watcher(@user)  
+  end
+end