--- /dev/null
+# redMine - project management software
+# Copyright (C) 2006-2008 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 MailHandlerController < ActionController::Base
+ before_filter :check_credential
+
+ verify :method => :post,
+ :only => :index,
+ :render => { :nothing => true, :status => 405 }
+
+ # Submits an incoming email to MailHandler
+ def index
+ options = params.dup
+ email = options.delete(:email)
+ if MailHandler.receive(email, options)
+ render :nothing => true, :status => :created
+ else
+ render :nothing => true, :status => :unprocessable_entity
+ end
+ end
+
+ private
+
+ def check_credential
+ User.current = nil
+ unless Setting.mail_handler_api_enabled? && params[:key] == Setting.mail_handler_api_key
+ render :nothing => true, :status => 403
+ end
+ end
+end
--- /dev/null
+# redMine - project management software
+# Copyright (C) 2006-2008 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 MailHandlerHelper
+end
{:name => 'authentication', :partial => 'settings/authentication', :label => :label_authentication},
{:name => 'issues', :partial => 'settings/issues', :label => :label_issue_tracking},
{:name => 'notifications', :partial => 'settings/notifications', :label => l(:field_mail_notification)},
+ {:name => 'mail_handler', :partial => 'settings/mail_handler', :label => l(:label_incoming_emails)},
{:name => 'repositories', :partial => 'settings/repositories', :label => :label_repository_plural}
]
end
# TODO: other ways to specify project:
# * parse the email To field
# * specific project (eg. Setting.mail_handler_target_project)
- identifier = if @@handler_options[:project]
+ identifier = if !@@handler_options[:project].blank?
@@handler_options[:project]
elsif email.plain_text_body =~ %r{^Project:[ \t]*(.+)$}i
$1
--- /dev/null
+<% form_tag({:action => 'edit', :tab => 'mail_handler'}) do %>
+
+<div class="box tabular settings">
+<p><label><%= l(:setting_mail_handler_api_enabled) %></label>
+<%= check_box_tag 'settings[mail_handler_api_enabled]', 1, Setting.mail_handler_api_enabled?,
+ :onclick => "if (this.checked) { Form.Element.enable('settings_mail_handler_api_key'); } else { Form.Element.disable('settings_mail_handler_api_key'); }" %>
+<%= hidden_field_tag 'settings[mail_handler_api_enabled]', 0 %></p>
+
+<p><label><%= l(:setting_mail_handler_api_key) %></label>
+<%= text_field_tag 'settings[mail_handler_api_key]', Setting.mail_handler_api_key,
+ :size => 30,
+ :id => 'settings_mail_handler_api_key',
+ :disabled => !Setting.mail_handler_api_enabled? %>
+<%= link_to_function l(:label_generate_key), "if ($('settings_mail_handler_api_key').disabled == false) { $('settings_mail_handler_api_key').value = randomKey(20) }" %></p>
+</div>
+
+<%= submit_tag l(:button_save) %>
+<% end %>
default:
- issue_added
- issue_updated
+mail_handler_api_enabled:
+ default: 0
+mail_handler_api_key:
+ default:
issue_list_default_columns:
serialized: true
default:
--- /dev/null
+#!/usr/bin/ruby
+
+# rdm-mailhandler
+# Reads an email from standard input and forward it to a Redmine server
+# Can be used from a remote mail server
+
+require 'net/http'
+require 'net/https'
+require 'uri'
+require 'getoptlong'
+
+class RedmineMailHandler
+ VERSION = '0.1'
+
+ attr_accessor :verbose, :project, :url, :key
+
+ def initialize
+ opts = GetoptLong.new(
+ [ '--help', '-h', GetoptLong::NO_ARGUMENT ],
+ [ '--version', '-V', GetoptLong::NO_ARGUMENT ],
+ [ '--verbose', '-v', GetoptLong::NO_ARGUMENT ],
+ [ '--url', '-u', GetoptLong::REQUIRED_ARGUMENT ],
+ [ '--key', '-k', GetoptLong::REQUIRED_ARGUMENT],
+ [ '--project', '-p', GetoptLong::REQUIRED_ARGUMENT ]
+ )
+
+ opts.each do |opt, arg|
+ case opt
+ when '--url'
+ self.url = arg.dup
+ when '--key'
+ self.key = arg.dup
+ when '--help'
+ usage
+ when '--verbose'
+ self.verbose = true
+ when '--version'
+ puts VERSION; exit
+ when '--project'
+ self.project = arg.dup
+ end
+ end
+
+ usage if url.nil?
+ end
+
+ def submit(email)
+ uri = url.gsub(%r{/*$}, '') + '/mail_handler'
+ debug "Posting to #{uri}..."
+ data = { 'key' => key, 'project' => project, 'email' => email }
+ response = Net::HTTP.post_form(URI.parse(uri), data)
+ debug "Response received: #{response.code}"
+ response.code == 201 ? 0 : 1
+ end
+
+ private
+
+ def usage
+ puts "Usage: rdm-mailhandler [options] --url=<Redmine URL> --key=<API key>"
+ puts "Reads an email from standard input and forward it to a Redmine server"
+ puts
+ puts "Options:"
+ puts " --help show this help"
+ puts " --verbose show extra information"
+ puts " --project identifier of the target project"
+ puts
+ puts "Examples:"
+ puts " rdm-mailhandler --url http://redmine.domain.foo --key secret"
+ puts " rdm-mailhandler --url https://redmine.domain.foo --key secret --project foo"
+ exit
+ end
+
+ def debug(msg)
+ puts msg if verbose
+ end
+end
+
+handler = RedmineMailHandler.new
+handler.submit(STDIN.read)
setting_enabled_scm: Enabled SCM
text_enumeration_category_reassign_to: 'Reassign them to this value:'
text_enumeration_destroy_question: '%d objects are assigned to this value.'
+label_incoming_emails: Incoming emails
+label_generate_key: Generate a key
+setting_mail_handler_api_enabled: Enable WS for incoming emails
+setting_mail_handler_api_key: API key
setting_enabled_scm: Enabled SCM
text_enumeration_category_reassign_to: 'Reassign them to this value:'
text_enumeration_destroy_question: '%d objects are assigned to this value.'
+label_incoming_emails: Incoming emails
+label_generate_key: Generate a key
+setting_mail_handler_api_enabled: Enable WS for incoming emails
+setting_mail_handler_api_key: API key
setting_enabled_scm: Enabled SCM
text_enumeration_category_reassign_to: 'Reassign them to this value:'
text_enumeration_destroy_question: '%d objects are assigned to this value.'
+label_incoming_emails: Incoming emails
+label_generate_key: Generate a key
+setting_mail_handler_api_enabled: Enable WS for incoming emails
+setting_mail_handler_api_key: API key
setting_enabled_scm: Enabled SCM
text_enumeration_category_reassign_to: 'Reassign them to this value:'
text_enumeration_destroy_question: '%d objects are assigned to this value.'
+label_incoming_emails: Incoming emails
+label_generate_key: Generate a key
+setting_mail_handler_api_enabled: Enable WS for incoming emails
+setting_mail_handler_api_key: API key
setting_activity_days_default: Days displayed on project activity
setting_display_subprojects_issues: Display subprojects issues on main projects by default
setting_enabled_scm: Enabled SCM
+setting_mail_handler_api_enabled: Enable WS for incoming emails
+setting_mail_handler_api_key: API key
project_module_issue_tracking: Issue tracking
project_module_time_tracking: Time tracking
label_chronological_order: In chronological order
label_reverse_chronological_order: In reverse chronological order
label_planning: Planning
+label_incoming_emails: Incoming emails
+label_generate_key: Generate a key
button_login: Login
button_submit: Submit
setting_enabled_scm: Enabled SCM
text_enumeration_category_reassign_to: 'Reassign them to this value:'
text_enumeration_destroy_question: '%d objects are assigned to this value.'
+label_incoming_emails: Incoming emails
+label_generate_key: Generate a key
+setting_mail_handler_api_enabled: Enable WS for incoming emails
+setting_mail_handler_api_key: API key
setting_enabled_scm: Enabled SCM
text_enumeration_category_reassign_to: 'Reassign them to this value:'
text_enumeration_destroy_question: '%d objects are assigned to this value.'
+label_incoming_emails: Incoming emails
+label_generate_key: Generate a key
+setting_mail_handler_api_enabled: Enable WS for incoming emails
+setting_mail_handler_api_key: API key
setting_activity_days_default: Nombre de jours affichés sur l'activité des projets
setting_display_subprojects_issues: Afficher par défaut les demandes des sous-projets sur les projets principaux
setting_enabled_scm: SCM activés
+setting_mail_handler_api_enabled: "Activer le WS pour la réception d'emails"
+setting_mail_handler_api_key: Clé de protection de l'API
project_module_issue_tracking: Suivi des demandes
project_module_time_tracking: Suivi du temps passé
label_chronological_order: Dans l'ordre chronologique
label_reverse_chronological_order: Dans l'ordre chronologique inverse
label_planning: Planning
+label_incoming_emails: Emails entrants
+label_generate_key: Générer une clé
button_login: Connexion
button_submit: Soumettre
setting_enabled_scm: Enabled SCM
text_enumeration_category_reassign_to: 'Reassign them to this value:'
text_enumeration_destroy_question: '%d objects are assigned to this value.'
+label_incoming_emails: Incoming emails
+label_generate_key: Generate a key
+setting_mail_handler_api_enabled: Enable WS for incoming emails
+setting_mail_handler_api_key: API key
setting_enabled_scm: Forráskódkezelő (SCM) engedélyezése
text_enumeration_category_reassign_to: 'Reassign them to this value:'
text_enumeration_destroy_question: '%d objects are assigned to this value.'
+label_incoming_emails: Incoming emails
+label_generate_key: Generate a key
+setting_mail_handler_api_enabled: Enable WS for incoming emails
+setting_mail_handler_api_key: API key
setting_enabled_scm: Enabled SCM
text_enumeration_category_reassign_to: 'Reassign them to this value:'
text_enumeration_destroy_question: '%d objects are assigned to this value.'
+label_incoming_emails: Incoming emails
+label_generate_key: Generate a key
+setting_mail_handler_api_enabled: Enable WS for incoming emails
+setting_mail_handler_api_key: API key
setting_enabled_scm: Enabled SCM
text_enumeration_category_reassign_to: 'Reassign them to this value:'
text_enumeration_destroy_question: '%d objects are assigned to this value.'
+label_incoming_emails: Incoming emails
+label_generate_key: Generate a key
+setting_mail_handler_api_enabled: Enable WS for incoming emails
+setting_mail_handler_api_key: API key
setting_enabled_scm: Enabled SCM
text_enumeration_category_reassign_to: 'Reassign them to this value:'
text_enumeration_destroy_question: '%d objects are assigned to this value.'
+label_incoming_emails: Incoming emails
+label_generate_key: Generate a key
+setting_mail_handler_api_enabled: Enable WS for incoming emails
+setting_mail_handler_api_key: API key
setting_enabled_scm: Enabled SCM
text_enumeration_category_reassign_to: 'Reassign them to this value:'
text_enumeration_destroy_question: '%d objects are assigned to this value.'
+label_incoming_emails: Incoming emails
+label_generate_key: Generate a key
+setting_mail_handler_api_enabled: Enable WS for incoming emails
+setting_mail_handler_api_key: API key
setting_enabled_scm: Enabled SCM
text_enumeration_category_reassign_to: 'Reassign them to this value:'
text_enumeration_destroy_question: '%d objects are assigned to this value.'
+label_incoming_emails: Incoming emails
+label_generate_key: Generate a key
+setting_mail_handler_api_enabled: Enable WS for incoming emails
+setting_mail_handler_api_key: API key
enumeration_activities: Aktiviteter (tidssporing)
text_enumeration_category_reassign_to: 'Reassign them to this value:'
text_enumeration_destroy_question: '%d objects are assigned to this value.'
+label_incoming_emails: Incoming emails
+label_generate_key: Generate a key
+setting_mail_handler_api_enabled: Enable WS for incoming emails
+setting_mail_handler_api_key: API key
setting_enabled_scm: Enabled SCM
text_enumeration_category_reassign_to: 'Reassign them to this value:'
text_enumeration_destroy_question: '%d objects are assigned to this value.'
+label_incoming_emails: Incoming emails
+label_generate_key: Generate a key
+setting_mail_handler_api_enabled: Enable WS for incoming emails
+setting_mail_handler_api_key: API key
setting_enabled_scm: Enabled SCM\r
text_enumeration_category_reassign_to: 'Reassign them to this value:'\r
text_enumeration_destroy_question: '%d objects are assigned to this value.'\r
+label_incoming_emails: Incoming emails\r
+label_generate_key: Generate a key\r
+setting_mail_handler_api_enabled: Enable WS for incoming emails\r
+setting_mail_handler_api_key: API key\r
setting_enabled_scm: Enabled SCM
text_enumeration_category_reassign_to: 'Reassign them to this value:'
text_enumeration_destroy_question: '%d objects are assigned to this value.'
+label_incoming_emails: Incoming emails
+label_generate_key: Generate a key
+setting_mail_handler_api_enabled: Enable WS for incoming emails
+setting_mail_handler_api_key: API key
setting_enabled_scm: Enabled SCM
text_enumeration_category_reassign_to: 'Reassign them to this value:'
text_enumeration_destroy_question: '%d objects are assigned to this value.'
+label_incoming_emails: Incoming emails
+label_generate_key: Generate a key
+setting_mail_handler_api_enabled: Enable WS for incoming emails
+setting_mail_handler_api_key: API key
setting_enabled_scm: Enabled SCM
text_enumeration_category_reassign_to: 'Reassign them to this value:'
text_enumeration_destroy_question: '%d objects are assigned to this value.'
+label_incoming_emails: Incoming emails
+label_generate_key: Generate a key
+setting_mail_handler_api_enabled: Enable WS for incoming emails
+setting_mail_handler_api_key: API key
setting_enabled_scm: Enabled SCM
text_enumeration_category_reassign_to: 'Reassign them to this value:'
text_enumeration_destroy_question: '%d objects are assigned to this value.'
+label_incoming_emails: Incoming emails
+label_generate_key: Generate a key
+setting_mail_handler_api_enabled: Enable WS for incoming emails
+setting_mail_handler_api_key: API key
setting_enabled_scm: Enabled SCM
text_enumeration_category_reassign_to: 'Reassign them to this value:'
text_enumeration_destroy_question: '%d objects are assigned to this value.'
+label_incoming_emails: Incoming emails
+label_generate_key: Generate a key
+setting_mail_handler_api_enabled: Enable WS for incoming emails
+setting_mail_handler_api_key: API key
setting_enabled_scm: Enabled SCM
text_enumeration_category_reassign_to: 'Reassign them to this value:'
text_enumeration_destroy_question: '%d objects are assigned to this value.'
+label_incoming_emails: Incoming emails
+label_generate_key: Generate a key
+setting_mail_handler_api_enabled: Enable WS for incoming emails
+setting_mail_handler_api_key: API key
setting_enabled_scm: Enabled SCM
text_enumeration_category_reassign_to: 'Reassign them to this value:'
text_enumeration_destroy_question: '%d objects are assigned to this value.'
+label_incoming_emails: Incoming emails
+label_generate_key: Generate a key
+setting_mail_handler_api_enabled: Enable WS for incoming emails
+setting_mail_handler_api_key: API key
enumeration_activities: 活動 (時間追蹤)
text_enumeration_category_reassign_to: 'Reassign them to this value:'
text_enumeration_destroy_question: '%d objects are assigned to this value.'
+label_incoming_emails: Incoming emails
+label_generate_key: Generate a key
+setting_mail_handler_api_enabled: Enable WS for incoming emails
+setting_mail_handler_api_key: API key
enumeration_activities: 活动(时间跟踪)
text_enumeration_category_reassign_to: 'Reassign them to this value:'
text_enumeration_destroy_question: '%d objects are assigned to this value.'
+label_incoming_emails: Incoming emails
+label_generate_key: Generate a key
+setting_mail_handler_api_enabled: Enable WS for incoming emails
+setting_mail_handler_api_key: API key
Element.removeClassName(id, 'loading');
}
+function randomKey(size) {
+ var chars = new Array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z');
+ var key = '';
+ for (i = 0; i < size; i++) {
+ key += chars[Math.floor(Math.random() * chars.length)];
+ }
+ return key;
+}
+
/* shows and hides ajax indicator */
Ajax.Responders.register({
onCreate: function(){
--- /dev/null
+# redMine - project management software
+# Copyright (C) 2006-2008 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'
+require 'mail_handler_controller'
+
+# Re-raise errors caught by the controller.
+class MailHandlerController; def rescue_action(e) raise e end; end
+
+class MailHandlerControllerTest < Test::Unit::TestCase
+ fixtures :users, :projects, :enabled_modules, :roles, :members, :issues, :issue_statuses, :trackers, :enumerations
+
+ FIXTURES_PATH = File.dirname(__FILE__) + '/../fixtures/mail_handler'
+
+ def setup
+ @controller = MailHandlerController.new
+ @request = ActionController::TestRequest.new
+ @response = ActionController::TestResponse.new
+ User.current = nil
+ end
+
+ def test_should_create_issue
+ # Enable API and set a key
+ Setting.mail_handler_api_enabled = 1
+ Setting.mail_handler_api_key = 'secret'
+
+ post :index, :key => 'secret', :email => IO.read(File.join(FIXTURES_PATH, 'ticket_on_given_project.eml'))
+ assert_response 201
+ end
+
+ def test_should_not_allow
+ # Disable API
+ Setting.mail_handler_api_enabled = 0
+ Setting.mail_handler_api_key = 'secret'
+
+ post :index, :key => 'secret', :email => IO.read(File.join(FIXTURES_PATH, 'ticket_on_given_project.eml'))
+ assert_response 403
+ end
+end