##// END OF EJS Templates
Adds a User-Agent header to Redmine mailhandler requests (#7318)....
Jean-Philippe Lang -
r4605:ced782ecb21c
parent child
Show More
@@ -1,165 +1,168
1 #!/usr/bin/env ruby
1 #!/usr/bin/env ruby
2
2
3 # == Synopsis
3 # == Synopsis
4 #
4 #
5 # Reads an email from standard input and forward it to a Redmine server
5 # Reads an email from standard input and forward it to a Redmine server
6 # through a HTTP request.
6 # through a HTTP request.
7 #
7 #
8 # == Usage
8 # == Usage
9 #
9 #
10 # rdm-mailhandler [options] --url=<Redmine URL> --key=<API key>
10 # rdm-mailhandler [options] --url=<Redmine URL> --key=<API key>
11 #
11 #
12 # == Arguments
12 # == Arguments
13 #
13 #
14 # -u, --url URL of the Redmine server
14 # -u, --url URL of the Redmine server
15 # -k, --key Redmine API key
15 # -k, --key Redmine API key
16 #
16 #
17 # General options:
17 # General options:
18 # --unknown-user=ACTION how to handle emails from an unknown user
18 # --unknown-user=ACTION how to handle emails from an unknown user
19 # ACTION can be one of the following values:
19 # ACTION can be one of the following values:
20 # ignore: email is ignored (default)
20 # ignore: email is ignored (default)
21 # accept: accept as anonymous user
21 # accept: accept as anonymous user
22 # create: create a user account
22 # create: create a user account
23 # --no-permission-check disable permission checking when receiving
23 # --no-permission-check disable permission checking when receiving
24 # the email
24 # the email
25 # -h, --help show this help
25 # -h, --help show this help
26 # -v, --verbose show extra information
26 # -v, --verbose show extra information
27 # -V, --version show version information and exit
27 # -V, --version show version information and exit
28 #
28 #
29 # Issue attributes control options:
29 # Issue attributes control options:
30 # -p, --project=PROJECT identifier of the target project
30 # -p, --project=PROJECT identifier of the target project
31 # -s, --status=STATUS name of the target status
31 # -s, --status=STATUS name of the target status
32 # -t, --tracker=TRACKER name of the target tracker
32 # -t, --tracker=TRACKER name of the target tracker
33 # --category=CATEGORY name of the target category
33 # --category=CATEGORY name of the target category
34 # --priority=PRIORITY name of the target priority
34 # --priority=PRIORITY name of the target priority
35 # -o, --allow-override=ATTRS allow email content to override attributes
35 # -o, --allow-override=ATTRS allow email content to override attributes
36 # specified by previous options
36 # specified by previous options
37 # ATTRS is a comma separated list of attributes
37 # ATTRS is a comma separated list of attributes
38 #
38 #
39 # == Examples
39 # == Examples
40 # No project specified. Emails MUST contain the 'Project' keyword:
40 # No project specified. Emails MUST contain the 'Project' keyword:
41 #
41 #
42 # rdm-mailhandler --url http://redmine.domain.foo --key secret
42 # rdm-mailhandler --url http://redmine.domain.foo --key secret
43 #
43 #
44 # Fixed project and default tracker specified, but emails can override
44 # Fixed project and default tracker specified, but emails can override
45 # both tracker and priority attributes using keywords:
45 # both tracker and priority attributes using keywords:
46 #
46 #
47 # rdm-mailhandler --url https://domain.foo/redmine --key secret \\
47 # rdm-mailhandler --url https://domain.foo/redmine --key secret \\
48 # --project foo \\
48 # --project foo \\
49 # --tracker bug \\
49 # --tracker bug \\
50 # --allow-override tracker,priority
50 # --allow-override tracker,priority
51
51
52 require 'net/http'
52 require 'net/http'
53 require 'net/https'
53 require 'net/https'
54 require 'uri'
54 require 'uri'
55 require 'getoptlong'
55 require 'getoptlong'
56 require 'rdoc/usage'
56 require 'rdoc/usage'
57
57
58 module Net
58 module Net
59 class HTTPS < HTTP
59 class HTTPS < HTTP
60 def self.post_form(url, params)
60 def self.post_form(url, params, headers)
61 request = Post.new(url.path)
61 request = Post.new(url.path)
62 request.form_data = params
62 request.form_data = params
63 request.basic_auth url.user, url.password if url.user
63 request.basic_auth url.user, url.password if url.user
64 request.initialize_http_header(headers)
64 http = new(url.host, url.port)
65 http = new(url.host, url.port)
65 http.use_ssl = (url.scheme == 'https')
66 http.use_ssl = (url.scheme == 'https')
66 http.start {|h| h.request(request) }
67 http.start {|h| h.request(request) }
67 end
68 end
68 end
69 end
69 end
70 end
70
71
71 class RedmineMailHandler
72 class RedmineMailHandler
72 VERSION = '0.1'
73 VERSION = '0.1'
73
74
74 attr_accessor :verbose, :issue_attributes, :allow_override, :unknown_user, :no_permission_check, :url, :key
75 attr_accessor :verbose, :issue_attributes, :allow_override, :unknown_user, :no_permission_check, :url, :key
75
76
76 def initialize
77 def initialize
77 self.issue_attributes = {}
78 self.issue_attributes = {}
78
79
79 opts = GetoptLong.new(
80 opts = GetoptLong.new(
80 [ '--help', '-h', GetoptLong::NO_ARGUMENT ],
81 [ '--help', '-h', GetoptLong::NO_ARGUMENT ],
81 [ '--version', '-V', GetoptLong::NO_ARGUMENT ],
82 [ '--version', '-V', GetoptLong::NO_ARGUMENT ],
82 [ '--verbose', '-v', GetoptLong::NO_ARGUMENT ],
83 [ '--verbose', '-v', GetoptLong::NO_ARGUMENT ],
83 [ '--url', '-u', GetoptLong::REQUIRED_ARGUMENT ],
84 [ '--url', '-u', GetoptLong::REQUIRED_ARGUMENT ],
84 [ '--key', '-k', GetoptLong::REQUIRED_ARGUMENT],
85 [ '--key', '-k', GetoptLong::REQUIRED_ARGUMENT],
85 [ '--project', '-p', GetoptLong::REQUIRED_ARGUMENT ],
86 [ '--project', '-p', GetoptLong::REQUIRED_ARGUMENT ],
86 [ '--status', '-s', GetoptLong::REQUIRED_ARGUMENT ],
87 [ '--status', '-s', GetoptLong::REQUIRED_ARGUMENT ],
87 [ '--tracker', '-t', GetoptLong::REQUIRED_ARGUMENT],
88 [ '--tracker', '-t', GetoptLong::REQUIRED_ARGUMENT],
88 [ '--category', GetoptLong::REQUIRED_ARGUMENT],
89 [ '--category', GetoptLong::REQUIRED_ARGUMENT],
89 [ '--priority', GetoptLong::REQUIRED_ARGUMENT],
90 [ '--priority', GetoptLong::REQUIRED_ARGUMENT],
90 [ '--allow-override', '-o', GetoptLong::REQUIRED_ARGUMENT],
91 [ '--allow-override', '-o', GetoptLong::REQUIRED_ARGUMENT],
91 [ '--unknown-user', GetoptLong::REQUIRED_ARGUMENT],
92 [ '--unknown-user', GetoptLong::REQUIRED_ARGUMENT],
92 [ '--no-permission-check', GetoptLong::NO_ARGUMENT]
93 [ '--no-permission-check', GetoptLong::NO_ARGUMENT]
93 )
94 )
94
95
95 opts.each do |opt, arg|
96 opts.each do |opt, arg|
96 case opt
97 case opt
97 when '--url'
98 when '--url'
98 self.url = arg.dup
99 self.url = arg.dup
99 when '--key'
100 when '--key'
100 self.key = arg.dup
101 self.key = arg.dup
101 when '--help'
102 when '--help'
102 usage
103 usage
103 when '--verbose'
104 when '--verbose'
104 self.verbose = true
105 self.verbose = true
105 when '--version'
106 when '--version'
106 puts VERSION; exit
107 puts VERSION; exit
107 when '--project', '--status', '--tracker', '--category', '--priority'
108 when '--project', '--status', '--tracker', '--category', '--priority'
108 self.issue_attributes[opt.gsub(%r{^\-\-}, '')] = arg.dup
109 self.issue_attributes[opt.gsub(%r{^\-\-}, '')] = arg.dup
109 when '--allow-override'
110 when '--allow-override'
110 self.allow_override = arg.dup
111 self.allow_override = arg.dup
111 when '--unknown-user'
112 when '--unknown-user'
112 self.unknown_user = arg.dup
113 self.unknown_user = arg.dup
113 when '--no-permission-check'
114 when '--no-permission-check'
114 self.no_permission_check = '1'
115 self.no_permission_check = '1'
115 end
116 end
116 end
117 end
117
118
118 RDoc.usage if url.nil?
119 RDoc.usage if url.nil?
119 end
120 end
120
121
121 def submit(email)
122 def submit(email)
122 uri = url.gsub(%r{/*$}, '') + '/mail_handler'
123 uri = url.gsub(%r{/*$}, '') + '/mail_handler'
123
124
125 headers = { 'User-Agent' => "Redmine mail handler/#{VERSION}" }
126
124 data = { 'key' => key, 'email' => email,
127 data = { 'key' => key, 'email' => email,
125 'allow_override' => allow_override,
128 'allow_override' => allow_override,
126 'unknown_user' => unknown_user,
129 'unknown_user' => unknown_user,
127 'no_permission_check' => no_permission_check}
130 'no_permission_check' => no_permission_check}
128 issue_attributes.each { |attr, value| data["issue[#{attr}]"] = value }
131 issue_attributes.each { |attr, value| data["issue[#{attr}]"] = value }
129
132
130 debug "Posting to #{uri}..."
133 debug "Posting to #{uri}..."
131 response = Net::HTTPS.post_form(URI.parse(uri), data)
134 response = Net::HTTPS.post_form(URI.parse(uri), data, headers)
132 debug "Response received: #{response.code}"
135 debug "Response received: #{response.code}"
133
136
134 case response.code.to_i
137 case response.code.to_i
135 when 403
138 when 403
136 warn "Request was denied by your Redmine server. " +
139 warn "Request was denied by your Redmine server. " +
137 "Make sure that 'WS for incoming emails' is enabled in application settings and that you provided the correct API key."
140 "Make sure that 'WS for incoming emails' is enabled in application settings and that you provided the correct API key."
138 return 77
141 return 77
139 when 422
142 when 422
140 warn "Request was denied by your Redmine server. " +
143 warn "Request was denied by your Redmine server. " +
141 "Possible reasons: email is sent from an invalid email address or is missing some information."
144 "Possible reasons: email is sent from an invalid email address or is missing some information."
142 return 77
145 return 77
143 when 400..499
146 when 400..499
144 warn "Request was denied by your Redmine server (#{response.code})."
147 warn "Request was denied by your Redmine server (#{response.code})."
145 return 77
148 return 77
146 when 500..599
149 when 500..599
147 warn "Failed to contact your Redmine server (#{response.code})."
150 warn "Failed to contact your Redmine server (#{response.code})."
148 return 75
151 return 75
149 when 201
152 when 201
150 debug "Proccessed successfully"
153 debug "Proccessed successfully"
151 return 0
154 return 0
152 else
155 else
153 return 1
156 return 1
154 end
157 end
155 end
158 end
156
159
157 private
160 private
158
161
159 def debug(msg)
162 def debug(msg)
160 puts msg if verbose
163 puts msg if verbose
161 end
164 end
162 end
165 end
163
166
164 handler = RedmineMailHandler.new
167 handler = RedmineMailHandler.new
165 exit(handler.submit(STDIN.read))
168 exit(handler.submit(STDIN.read))
General Comments 0
You need to be logged in to leave comments. Login now