##// END OF EJS Templates
Adds copyright....
Jean-Philippe Lang -
r11293:c4cf97dea5dd
parent child
Show More
@@ -1,155 +1,171
1 1 #!/usr/bin/env ruby
2 # Redmine - project management software
3 # Copyright (C) 2006-2013 Jean-Philippe Lang
4 #
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; either version 2
8 # of the License, or (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
2 18
3 19 require 'net/http'
4 20 require 'net/https'
5 21 require 'uri'
6 22 require 'optparse'
7 23
8 24 module Net
9 25 class HTTPS < HTTP
10 26 def self.post_form(url, params, headers, options={})
11 27 request = Post.new(url.path)
12 28 request.form_data = params
13 29 request.initialize_http_header(headers)
14 30 request.basic_auth url.user, url.password if url.user
15 31 http = new(url.host, url.port)
16 32 http.use_ssl = (url.scheme == 'https')
17 33 if options[:no_check_certificate]
18 34 http.verify_mode = OpenSSL::SSL::VERIFY_NONE
19 35 end
20 36 http.start {|h| h.request(request) }
21 37 end
22 38 end
23 39 end
24 40
25 41 class RedmineMailHandler
26 42 VERSION = '0.2.2'
27 43
28 44 attr_accessor :verbose, :issue_attributes, :allow_override, :unknown_user, :default_group, :no_permission_check, :url, :key, :no_check_certificate
29 45
30 46 def initialize
31 47 self.issue_attributes = {}
32 48
33 49 optparse = OptionParser.new do |opts|
34 50 opts.banner = "Usage: rdm-mailhandler.rb [options] --url=<Redmine URL> --key=<API key>"
35 51 opts.separator("")
36 52 opts.separator("Reads an email from standard input and forward it to a Redmine server through a HTTP request.")
37 53 opts.separator("")
38 54 opts.separator("Required arguments:")
39 55 opts.on("-u", "--url URL", "URL of the Redmine server") {|v| self.url = v}
40 56 opts.on("-k", "--key KEY", "Redmine API key") {|v| self.key = v}
41 57 opts.separator("")
42 58 opts.separator("General options:")
43 59 opts.on("--no-permission-check", "disable permission checking when receiving",
44 60 "the email") {self.no_permission_check = '1'}
45 61 opts.on("--key-file FILE", "path to a file that contains the Redmine",
46 62 "API key (use this option instead of --key",
47 63 "if you don't the key to appear in the",
48 64 "command line)") {|v| read_key_from_file(v)}
49 65 opts.on("--no-check-certificate", "do not check server certificate") {self.no_check_certificate = true}
50 66 opts.on("-h", "--help", "show this help") {puts opts; exit 1}
51 67 opts.on("-v", "--verbose", "show extra information") {self.verbose = true}
52 68 opts.on("-V", "--version", "show version information and exit") {puts VERSION; exit}
53 69 opts.separator("")
54 70 opts.separator("User creation options:")
55 71 opts.on("--unknown-user ACTION", "how to handle emails from an unknown user",
56 72 "ACTION can be one of the following values:",
57 73 "* ignore: email is ignored (default)",
58 74 "* accept: accept as anonymous user",
59 75 "* create: create a user account") {|v| self.unknown_user = v}
60 76 opts.on("--default-group GROUP", "add created user to GROUP (none by default)",
61 77 "GROUP can be a comma separated list of groups") { |v| self.default_group = v}
62 78 opts.separator("")
63 79 opts.separator("Issue attributes control options:")
64 80 opts.on("-p", "--project PROJECT", "identifier of the target project") {|v| self.issue_attributes['project'] = v}
65 81 opts.on("-s", "--status STATUS", "name of the target status") {|v| self.issue_attributes['status'] = v}
66 82 opts.on("-t", "--tracker TRACKER", "name of the target tracker") {|v| self.issue_attributes['tracker'] = v}
67 83 opts.on( "--category CATEGORY", "name of the target category") {|v| self.issue_attributes['category'] = v}
68 84 opts.on( "--priority PRIORITY", "name of the target priority") {|v| self.issue_attributes['priority'] = v}
69 85 opts.on("-o", "--allow-override ATTRS", "allow email content to override attributes",
70 86 "specified by previous options",
71 87 "ATTRS is a comma separated list of attributes") {|v| self.allow_override = v}
72 88 opts.separator("")
73 89 opts.separator("Examples:")
74 90 opts.separator("No project specified. Emails MUST contain the 'Project' keyword:")
75 91 opts.separator(" rdm-mailhandler.rb --url http://redmine.domain.foo --key secret")
76 92 opts.separator("")
77 93 opts.separator("Fixed project and default tracker specified, but emails can override")
78 94 opts.separator("both tracker and priority attributes using keywords:")
79 95 opts.separator(" rdm-mailhandler.rb --url https://domain.foo/redmine --key secret \\")
80 96 opts.separator(" --project foo \\")
81 97 opts.separator(" --tracker bug \\")
82 98 opts.separator(" --allow-override tracker,priority")
83 99
84 100 opts.summary_width = 27
85 101 end
86 102 optparse.parse!
87 103
88 104 unless url && key
89 105 puts "Some arguments are missing. Use `rdm-mailhandler.rb --help` for getting help."
90 106 exit 1
91 107 end
92 108 end
93 109
94 110 def submit(email)
95 111 uri = url.gsub(%r{/*$}, '') + '/mail_handler'
96 112
97 113 headers = { 'User-Agent' => "Redmine mail handler/#{VERSION}" }
98 114
99 115 data = { 'key' => key, 'email' => email,
100 116 'allow_override' => allow_override,
101 117 'unknown_user' => unknown_user,
102 118 'default_group' => default_group,
103 119 'no_permission_check' => no_permission_check}
104 120 issue_attributes.each { |attr, value| data["issue[#{attr}]"] = value }
105 121
106 122 debug "Posting to #{uri}..."
107 123 begin
108 124 response = Net::HTTPS.post_form(URI.parse(uri), data, headers, :no_check_certificate => no_check_certificate)
109 125 rescue SystemCallError => e # connection refused, etc.
110 126 warn "An error occured while contacting your Redmine server: #{e.message}"
111 127 return 75 # temporary failure
112 128 end
113 129 debug "Response received: #{response.code}"
114 130
115 131 case response.code.to_i
116 132 when 403
117 133 warn "Request was denied by your Redmine server. " +
118 134 "Make sure that 'WS for incoming emails' is enabled in application settings and that you provided the correct API key."
119 135 return 77
120 136 when 422
121 137 warn "Request was denied by your Redmine server. " +
122 138 "Possible reasons: email is sent from an invalid email address or is missing some information."
123 139 return 77
124 140 when 400..499
125 141 warn "Request was denied by your Redmine server (#{response.code})."
126 142 return 77
127 143 when 500..599
128 144 warn "Failed to contact your Redmine server (#{response.code})."
129 145 return 75
130 146 when 201
131 147 debug "Proccessed successfully"
132 148 return 0
133 149 else
134 150 return 1
135 151 end
136 152 end
137 153
138 154 private
139 155
140 156 def debug(msg)
141 157 puts msg if verbose
142 158 end
143 159
144 160 def read_key_from_file(filename)
145 161 begin
146 162 self.key = File.read(filename).strip
147 163 rescue Exception => e
148 164 $stderr.puts "Unable to read the key from #{filename}:\n#{e.message}"
149 165 exit 1
150 166 end
151 167 end
152 168 end
153 169
154 170 handler = RedmineMailHandler.new
155 171 exit(handler.submit(STDIN.read))
General Comments 0
You need to be logged in to leave comments. Login now