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