To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.

Statistics Download as Zip
| Branch: | Tag: | Revision:

root / .svn / pristine / 19 / 196c7c4e4ef7e50cda7944736d264f90424a0cab.svn-base @ 1297:0a574315af3e

History | View | Annotate | Download (6.34 KB)

1 1296:038ba2d95de8 Chris
#!/usr/bin/env ruby
2
3
require 'net/http'
4
require 'net/https'
5
require 'uri'
6
require 'optparse'
7
8
module Net
9
  class HTTPS < HTTP
10
    def self.post_form(url, params, headers, options={})
11
      request = Post.new(url.path)
12
      request.form_data = params
13
      request.initialize_http_header(headers)
14
      request.basic_auth url.user, url.password if url.user
15
      http = new(url.host, url.port)
16
      http.use_ssl = (url.scheme == 'https')
17
      if options[:no_check_certificate]
18
        http.verify_mode = OpenSSL::SSL::VERIFY_NONE
19
      end
20
      http.start {|h| h.request(request) }
21
    end
22
  end
23
end
24
25
class RedmineMailHandler
26
  VERSION = '0.2.1'
27
28
  attr_accessor :verbose, :issue_attributes, :allow_override, :unknown_user, :no_permission_check, :url, :key, :no_check_certificate
29
30
  def initialize
31
    self.issue_attributes = {}
32
33
    optparse = OptionParser.new do |opts|
34
      opts.banner = "Usage: rdm-mailhandler.rb [options] --url=<Redmine URL> --key=<API key>"
35
      opts.separator("")
36
      opts.separator("Reads an email from standard input and forward it to a Redmine server through a HTTP request.")
37
      opts.separator("")
38
      opts.separator("Required arguments:")
39
      opts.on("-u", "--url URL",              "URL of the Redmine server") {|v| self.url = v}
40
      opts.on("-k", "--key KEY",              "Redmine API key") {|v| self.key = v}
41
      opts.separator("")
42
      opts.separator("General options:")
43
      opts.on("--unknown-user ACTION",        "how to handle emails from an unknown user",
44
                                              "ACTION can be one of the following values:",
45
                                              "* ignore: email is ignored (default)",
46
                                              "* accept: accept as anonymous user",
47
                                              "* create: create a user account") {|v| self.unknown_user = v}
48
      opts.on("--no-permission-check",        "disable permission checking when receiving",
49
                                              "the email") {self.no_permission_check = '1'}
50
      opts.on("--key-file FILE",              "path to a file that contains the Redmine",
51
                                              "API key (use this option instead of --key",
52
                                              "if you don't the key to appear in the",
53
                                              "command line)") {|v| read_key_from_file(v)}
54
      opts.on("--no-check-certificate",       "do not check server certificate") {self.no_check_certificate = true}
55
      opts.on("-h", "--help",                 "show this help") {puts opts; exit 1}
56
      opts.on("-v", "--verbose",              "show extra information") {self.verbose = true}
57
      opts.on("-V", "--version",              "show version information and exit") {puts VERSION; exit}
58
      opts.separator("")
59
      opts.separator("Issue attributes control options:")
60
      opts.on("-p", "--project PROJECT",      "identifier of the target project") {|v| self.issue_attributes['project'] = v}
61
      opts.on("-s", "--status STATUS",        "name of the target status") {|v| self.issue_attributes['status'] = v}
62
      opts.on("-t", "--tracker TRACKER",      "name of the target tracker") {|v| self.issue_attributes['tracker'] = v}
63
      opts.on(      "--category CATEGORY",    "name of the target category") {|v| self.issue_attributes['category'] = v}
64
      opts.on(      "--priority PRIORITY",    "name of the target priority") {|v| self.issue_attributes['priority'] = v}
65
      opts.on("-o", "--allow-override ATTRS", "allow email content to override attributes",
66
                                              "specified by previous options",
67
                                              "ATTRS is a comma separated list of attributes") {|v| self.allow_override = v}
68
      opts.separator("")
69
      opts.separator("Examples:")
70
      opts.separator("No project specified. Emails MUST contain the 'Project' keyword:")
71
      opts.separator("  rdm-mailhandler.rb --url http://redmine.domain.foo --key secret")
72
      opts.separator("")
73
      opts.separator("Fixed project and default tracker specified, but emails can override")
74
      opts.separator("both tracker and priority attributes using keywords:")
75
      opts.separator("  rdm-mailhandler.rb --url https://domain.foo/redmine --key secret \\")
76
      opts.separator("    --project foo \\")
77
      opts.separator("    --tracker bug \\")
78
      opts.separator("    --allow-override tracker,priority")
79
80
      opts.summary_width = 27
81
    end
82
    optparse.parse!
83
84
    unless url && key
85
      puts "Some arguments are missing. Use `rdm-mailhandler.rb --help` for getting help."
86
      exit 1
87
    end
88
  end
89
90
  def submit(email)
91
    uri = url.gsub(%r{/*$}, '') + '/mail_handler'
92
93
    headers = { 'User-Agent' => "Redmine mail handler/#{VERSION}" }
94
95
    data = { 'key' => key, 'email' => email,
96
                           'allow_override' => allow_override,
97
                           'unknown_user' => unknown_user,
98
                           'no_permission_check' => no_permission_check}
99
    issue_attributes.each { |attr, value| data["issue[#{attr}]"] = value }
100
101
    debug "Posting to #{uri}..."
102
    response = Net::HTTPS.post_form(URI.parse(uri), data, headers, :no_check_certificate => no_check_certificate)
103
    debug "Response received: #{response.code}"
104
105
    case response.code.to_i
106
      when 403
107
        warn "Request was denied by your Redmine server. " +
108
             "Make sure that 'WS for incoming emails' is enabled in application settings and that you provided the correct API key."
109
        return 77
110
      when 422
111
        warn "Request was denied by your Redmine server. " +
112
             "Possible reasons: email is sent from an invalid email address or is missing some information."
113
        return 77
114
      when 400..499
115
        warn "Request was denied by your Redmine server (#{response.code})."
116
        return 77
117
      when 500..599
118
        warn "Failed to contact your Redmine server (#{response.code})."
119
        return 75
120
      when 201
121
        debug "Proccessed successfully"
122
        return 0
123
      else
124
        return 1
125
    end
126
  end
127
128
  private
129
130
  def debug(msg)
131
    puts msg if verbose
132
  end
133
134
  def read_key_from_file(filename)
135
    begin
136
      self.key = File.read(filename).strip
137
    rescue Exception => e
138
      $stderr.puts "Unable to read the key from #{filename}:\n#{e.message}"
139
      exit 1
140
    end
141
  end
142
end
143
144
handler = RedmineMailHandler.new
145
exit(handler.submit(STDIN.read))