gurgitate-mail 1.10.9 → 1.10.10

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,167 @@
1
+ #!/opt/bin/ruby -w
2
+ # -*- encoding : utf-8 -*-
3
+
4
+ require "gurgitate/headers"
5
+
6
+ module Gurgitate
7
+ class IllegalHeader < RuntimeError ; end
8
+
9
+ # ========================================================================
10
+
11
+ # A slightly bigger class for all of a message's headers
12
+ class MailHeaders < Headers
13
+
14
+ private
15
+
16
+ # Figures out whether the first line of a mail message is an
17
+ # mbox-style "From " line (say, if you get this from sendmail),
18
+ # or whether it's just a normal header.
19
+ # --
20
+ # If you run "fetchmail" with the -m option to feed the
21
+ # mail message straight to gurgitate, skipping the "local
22
+ # MTA" step, then it doesn't have a "From " line. So I
23
+ # have to deal with that by hand. First, check to see if
24
+ # there's a "From " line present in the first place.
25
+ def figure_out_from_line(headertext)
26
+ (unix_from,normal_headers) = headertext.split(/\n/,2)
27
+
28
+ if unix_from =~ /^From / then
29
+ headertext=normal_headers
30
+ unix_from=unix_from
31
+ else
32
+ # If there isn't, then deal with it after we've
33
+ # worried about the rest of the headers, 'cos we'll
34
+ # have to make our own.
35
+ unix_from=nil
36
+ end
37
+ return unix_from, headertext
38
+ end
39
+
40
+ # Get the envelope From information. This comes with a
41
+ # whole category of rants: this information is absurdly hard
42
+ # to get your hands on. The best you can manage is a sort
43
+ # of educated guess. Thus, this horrible glob of hackiness.
44
+ # I don't recommend looking too closely at this code if you
45
+ # can avoid it, and further I recommend making sure to
46
+ # configure your MTA so that it sends proper sender and
47
+ # recipient information to gurgitate so that this code never
48
+ # has to be run at all.
49
+ def guess_sender
50
+ # Start by worrying about the "From foo@bar" line. If it's
51
+ # not there, then make one up from the Return-Path: header.
52
+ # If there isn't a "Return-Path:" header (then I suspect we
53
+ # have bigger problems, but still) then use From: as a wild
54
+ # guess. If I hope that this entire lot of code doesn't get
55
+ # used, then I _particularly_ hope that things never get so
56
+ # bad that poor gurgitate has to use the From: header as a
57
+ # source of authoritative information on anything.
58
+ #
59
+ # And then after all that fuss, if we're delivering to a
60
+ # Maildir, I have to get rid of it. And sometimes the MTA
61
+ # gives me a mbox-style From line and sometimes it doesn't.
62
+ # It's annoying, but I have no choice but to Just Deal With
63
+ # It.
64
+ if @unix_from then
65
+ # If it is there, then grab the email address in it and
66
+ # use that as our official "from".
67
+ fromregex=/^From ([^ ]+@[^ ]+) /
68
+ fromregex.match(@unix_from)
69
+ @from=$+
70
+
71
+ # or maybe it's local
72
+ if @from == nil then
73
+ @unix_from =~ /^From (\S+) /
74
+ @from=$+
75
+ end
76
+ else
77
+ fromregex=/([^ ]+@[^ ]+) \(.*\)|[^<]*[<](.*@.*)[>]|([^ ]+@[^ ]+)/
78
+ if self["Return-Path"] != nil then
79
+ fromregex.match(self["Return-Path"][0].contents)
80
+ else
81
+ if self["From"] != nil then
82
+ fromregex.match(self["From"][0].contents)
83
+ end
84
+ end
85
+ address_candidate=$+
86
+
87
+ # If there STILL isn't a match, then it's probably safe to
88
+ # assume that it's local mail, and doesn't have an @ in its
89
+ # address.
90
+ unless address_candidate
91
+ if self["Return-Path"] != nil then
92
+ self["Return-Path"][0].contents =~ /(\S+)/
93
+ address_candidate=$+
94
+ else
95
+ self["From"][0].contents =~ /(\S+)/
96
+ address_candidate=$+
97
+ end
98
+ end
99
+
100
+ @from=address_candidate
101
+
102
+ @unix_from="From "+self.from+" "+Time.new.to_s
103
+ end
104
+ end
105
+
106
+ public
107
+
108
+ # Creates a MailHeaders object.
109
+ # headertext::
110
+ # The text of the message headers.
111
+ def initialize(headertext=nil, sender=nil, recipient=nil)
112
+ @from = sender
113
+ @to = recipient
114
+ @headers = Hash.new(nil)
115
+
116
+ if Hash === headertext
117
+ @headers_changed = true
118
+ headertext.each_key do |key|
119
+
120
+ headername = key.to_s.gsub("_","-")
121
+
122
+ header=Header.new(headername, headertext[key])
123
+ @headers[header.name] ||= HeaderBag.new
124
+ @headers[header.name].push(header)
125
+ end
126
+ else
127
+ if headertext
128
+ @unix_from, @headertext = figure_out_from_line headertext
129
+ parse_headers if @headertext
130
+
131
+ if sender # then don't believe the mbox separator
132
+ @from = sender
133
+ @unix_from="From "+self.from+" "+Time.new.to_s
134
+ else
135
+ guess_sender
136
+ end
137
+ end
138
+ end
139
+ end
140
+
141
+ # Who the message is to (the envelope to)
142
+ #
143
+ # Yet another bucket of rants. Unix mail sucks.
144
+ def to
145
+ return @to || @headers["X-Original-To"] || nil
146
+ end
147
+
148
+ # Who the message is from (the envelope from)
149
+ def from
150
+ return @from || ""
151
+ end
152
+
153
+ # Change the envelope from line to whatever you want. This might
154
+ # not be particularly neighborly, but oh well.
155
+ # newfrom:: An email address
156
+ def from=(newfrom)
157
+ @from=newfrom
158
+ @unix_from="From "+self.from+" "+Time.new.to_s
159
+ end
160
+
161
+ # Returns the headers properly formatted for an mbox-format
162
+ # email message.
163
+ def to_mbox
164
+ return @unix_from+"\n"+to_s
165
+ end
166
+ end
167
+ end
@@ -0,0 +1,142 @@
1
+ # -*- encoding : utf-8 -*-
2
+ # Contains the class Gurgitate::Mailmessage, used to handle the parsing
3
+ # of existing messages and the creation of new messages.
4
+
5
+ require 'gurgitate/headers'
6
+ require 'gurgitate/message'
7
+
8
+ module Gurgitate
9
+
10
+ # A complete mail message. This is the base class for
11
+ # gurgitate-mail itself: if you want to use gurgitate-mail to create
12
+ # new messages, this is what you want to use.
13
+ class Mailmessage < Message
14
+
15
+ Fromregex=/([^ ]+@[^ ]+) \(.*\)|[^<][<](.*@.*)[>]|([^ ]+@[^ ]+)/;
16
+
17
+ # The envelope sender and recipient, if anyone thought to
18
+ # mention them to us.
19
+ attr_accessor :sender
20
+ attr_accessor :recipient
21
+
22
+ # Creates a new mail message from the options hash, and the body of the
23
+ # message in a string.
24
+ #
25
+ # This can actually be invoked in several ways:
26
+ #
27
+ # Gurgitate::Mailmessage.create "This is the message body",
28
+ # :from => "from_address@example.com",
29
+ # :to => "to_address@example.com",
30
+ # :subject => "This is the message subject"
31
+ #
32
+ # This results in an email message that, when rendered via to_s, will
33
+ # look like this:
34
+ #
35
+ # From: from_address@example.com
36
+ # To: to_address@example.com
37
+ # Subject: This is the message subject
38
+ #
39
+ # This is the message body
40
+ #
41
+ # If you prefer to do things entirely by options hashes, as some do,
42
+ # you can substitute a :body key for the first argument:
43
+ #
44
+ # Gurgitate::Mailmessage.create(
45
+ # :body => "This is the message body",
46
+ # :from => "from_address@example.com",
47
+ # :to => "to_address@example.com",
48
+ # :subject => "This is the message subject"
49
+ # )
50
+ #
51
+ # There are two other special options you can use: :sender and
52
+ # :recipient. These are used to specify the sender and recipient of
53
+ # email messages, when the message is sent via SMTP.
54
+ #
55
+ def self.create(*args)
56
+ options = body = nil
57
+
58
+ if String === args[0]
59
+ options = args[1]
60
+ body = args[0]
61
+ elsif Hash === args[0]
62
+ options = args[0]
63
+ else
64
+ options = {}
65
+ end
66
+
67
+ message = self.new
68
+
69
+ message.instance_eval do
70
+ if body
71
+ @body=body
72
+ end
73
+
74
+ %w/sender recipient body/.each do |key|
75
+ if options.has_key? key.to_sym
76
+ instance_variable_set("@#{key}", options[key.to_sym])
77
+ options.delete key.to_sym
78
+ end
79
+ end
80
+
81
+ @headers = MailHeaders.new(options)
82
+ end
83
+
84
+ message
85
+ end
86
+
87
+ def initialize(text=nil, recipient=nil, sender=nil)
88
+
89
+ @recipient = recipient
90
+ @sender = sender
91
+
92
+ begin
93
+ # ASCII_8BIT is what Ruby 1.9 and up calls
94
+ # "binary stream of unknown encoding".
95
+ #
96
+ # At least it treats the ASCII characters
97
+ # as strings, so I can do regex things
98
+ # with them
99
+ text.force_encoding(Encoding::ASCII_8BIT)
100
+ rescue NameError # Ruby 1.9 and up
101
+ true
102
+ end
103
+
104
+ if text
105
+ (@headertext,@body)=text.split(/\n\n/m,2)
106
+ @headers=MailHeaders.new(@headertext);
107
+ Fromregex.match(
108
+ if @headers["From"] then
109
+ @headers["From"][0].contents
110
+ else
111
+ ""
112
+ end);
113
+ @from=$+
114
+ else
115
+ super(text)
116
+ end
117
+ end
118
+
119
+ # custom accessors
120
+
121
+ # Returns the message's sender
122
+ def from; @sender || @headers.from; end
123
+
124
+ # Returns all the candidates for a recipient
125
+ def to
126
+ if @recipient
127
+ then @recipient
128
+ elsif @headers["To"]
129
+ then @headers["To"][0].contents
130
+ elsif @headers["Cc"]
131
+ then @headers["Cc"][0].contents
132
+ elsif @headers["X-Original-To"]
133
+ then @headers["X-Original-To"][0].contents
134
+ else
135
+ ""
136
+ end
137
+ end
138
+
139
+ # Returns the mail message formatted for mbox
140
+ def to_mbox; @headers.to_mbox + "\n\n" + @body; end
141
+ end
142
+ end
@@ -0,0 +1,114 @@
1
+ #!/opt/bin/ruby -w
2
+ # -*- encoding : utf-8 -*-
3
+
4
+ #------------------------------------------------------------------------
5
+ # Handles a complete mail message
6
+ #------------------------------------------------------------------------
7
+
8
+ require 'gurgitate/mail_headers'
9
+
10
+ module Gurgitate
11
+
12
+ # A complete mail message.
13
+ class Message
14
+
15
+ # The headers of the message
16
+ attr_reader :headers
17
+ # The body of the message
18
+ attr_accessor :body
19
+
20
+ # Creates a new message from the options hash, and the body of the
21
+ # message in a string.
22
+ #
23
+ # This can actually be invoked in several ways:
24
+ #
25
+ # Gurgitate::Mailmessage.create "This is the message body",
26
+ # :from => "from_address@example.com",
27
+ # :to => "to_address@example.com",
28
+ # :subject => "This is the message subject"
29
+ #
30
+ # This results in an email message that, when rendered via to_s, will
31
+ # look like this:
32
+ #
33
+ # From: from_address@example.com
34
+ # To: to_address@example.com
35
+ # Subject: This is the message subject
36
+ #
37
+ # This is the message body
38
+ #
39
+ # If you prefer to do things entirely by options hashes, as some do,
40
+ # you can substitute a :body key for the first argument:
41
+ #
42
+ # Gurgitate::Mailmessage.create(
43
+ # :body => "This is the message body",
44
+ # :from => "from_address@example.com",
45
+ # :to => "to_address@example.com",
46
+ # :subject => "This is the message subject"
47
+ # )
48
+ #
49
+ # There are two other special options you can use: :sender and
50
+ # :recipient. These are used to specify the sender and recipient of
51
+ # email messages, when the message is sent via SMTP.
52
+ #
53
+ def self.create(*args)
54
+ options = body = nil
55
+
56
+ if String === args[0]
57
+ options = args[1]
58
+ body = args[0]
59
+ elsif Hash === args[0]
60
+ options = args[0]
61
+ else
62
+ options = {}
63
+ end
64
+
65
+ message = self.new
66
+
67
+ message.instance_eval do
68
+ if body
69
+ @body=body
70
+ end
71
+
72
+ @headers = Headers.new(options)
73
+ end
74
+
75
+ message
76
+ end
77
+
78
+ # Creates a new Gurgitate message from a pre-existing message.
79
+ # This is what is used when gurgitate-mail is used as a mail filter.
80
+ #
81
+ # ARGUMENTS::
82
+ # +text+ :: An RFC822-formatted message.
83
+ # +recipient+ :: The recipient of the email message, from the MTA
84
+ # +sender+ :: The sender of the email message, also from the MTA
85
+ #
86
+ # All of its arguments can be nil: if called with no arguments,
87
+ # it simply returns an empty email message, which can be populated
88
+ # after the fact.
89
+ def initialize(text=nil)
90
+ if text
91
+ (@headertext,@body)=text.split(/\n\n/,2)
92
+ @headers=Headers.new(@headertext);
93
+ else
94
+ @headers = Headers.new
95
+ @body = ""
96
+ end
97
+ end
98
+
99
+ # Returns the header +name+, which is, note, a HeaderBag of all
100
+ # headers by that name, not just a single header.
101
+ #
102
+ # If you want the text of the header, then you have to coerce it to a
103
+ # string:
104
+ #
105
+ # header("name").to_s
106
+ #
107
+ def header(name)
108
+ @headers[name].each { |h| h.contents }.join(", ")
109
+ end
110
+
111
+ # Returns the formatted mail message
112
+ def to_s; @headers.to_s + "\n\n" + ( @body || ""); end
113
+ end
114
+ end
@@ -163,7 +163,7 @@ class TC_Delivery < GurgitateTest
163
163
  end
164
164
  system("ls -ld #{@spoolfile}")
165
165
  end
166
-
166
+
167
167
  end
168
168
 
169
169
  def test_mailbox_heuristics_mbox
metadata CHANGED
@@ -1,98 +1,91 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: gurgitate-mail
3
- version: !ruby/object:Gem::Version
4
- hash: 45
5
- prerelease:
6
- segments:
7
- - 1
8
- - 10
9
- - 9
10
- version: 1.10.9
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.10.10
11
5
  platform: ruby
12
- authors:
6
+ authors:
13
7
  - Dave Brown
14
8
  autorequire:
15
9
  bindir: bin
16
10
  cert_chain: []
17
-
18
- date: 2013-06-04 00:00:00 Z
11
+ date: 2015-02-05 00:00:00.000000000 Z
19
12
  dependencies: []
20
-
21
- description: " gurgitate-mail is a mail filter. It can be used as a module or\n as a standalone application.\n"
13
+ description: |2
14
+ gurgitate-mail is a mail filter. It can be used as a module or
15
+ as a standalone application.
22
16
  email: gurgitate-mail@dagbrown.com
23
- executables:
17
+ executables:
24
18
  - gurgitate-mail
25
19
  extensions: []
26
-
27
20
  extra_rdoc_files: []
28
-
29
- files:
21
+ files:
22
+ - ".gemtest"
23
+ - Rakefile
24
+ - bin/gurgitate-mail
25
+ - lib/gurgitate-mail.rb
26
+ - lib/gurgitate/deliver.rb
27
+ - lib/gurgitate/deliver/maildir.rb
28
+ - lib/gurgitate/deliver/mbox.rb
29
+ - lib/gurgitate/deliver/mh.rb
30
+ - lib/gurgitate/header.rb
31
+ - lib/gurgitate/headers.rb
32
+ - lib/gurgitate/mail_headers.rb
33
+ - lib/gurgitate/mailmessage.rb
34
+ - lib/gurgitate/message.rb
35
+ - test/gurgitate-test.rb
30
36
  - test/runtests.rb
31
- - test/test_writing.rb
32
- - test/test_rules.rb
33
- - test/test_header.rb
34
- - test/test_gurgitate_delivery.rb
35
- - test/test_process.rb
36
- - test/test_deliver.rb
37
37
  - test/test_configuration.rb
38
- - test/gurgitate-test.rb
39
- - test/test_mail_headers.rb
38
+ - test/test_deliver.rb
40
39
  - test/test_delivery.rb
41
- - test/test_headers_creating_from_hash.rb
42
- - test/test_headers_meddling_with_headers.rb
43
40
  - test/test_execute_rules.rb
41
+ - test/test_gurgitate_delivery.rb
42
+ - test/test_header.rb
44
43
  - test/test_headers.rb
44
+ - test/test_headers_creating_from_hash.rb
45
+ - test/test_headers_meddling_with_headers.rb
46
+ - test/test_mail_headers.rb
45
47
  - test/test_mail_headers_meddling_with_headers.rb
46
- - .gemtest
47
- - Rakefile
48
- - bin/gurgitate-mail
49
- homepage: http://www.rubyforge.org/projects/gurgitate-mail/
50
- licenses: []
51
-
48
+ - test/test_process.rb
49
+ - test/test_rules.rb
50
+ - test/test_writing.rb
51
+ homepage: http://www.github.com/dagbrown/gurgitate-mail/
52
+ licenses:
53
+ - GPL-2.0
54
+ metadata: {}
52
55
  post_install_message:
53
56
  rdoc_options: []
54
-
55
- require_paths:
57
+ require_paths:
56
58
  - lib
57
- required_ruby_version: !ruby/object:Gem::Requirement
58
- none: false
59
- requirements:
59
+ required_ruby_version: !ruby/object:Gem::Requirement
60
+ requirements:
60
61
  - - ">="
61
- - !ruby/object:Gem::Version
62
- hash: 3
63
- segments:
64
- - 0
65
- version: "0"
66
- required_rubygems_version: !ruby/object:Gem::Requirement
67
- none: false
68
- requirements:
62
+ - !ruby/object:Gem::Version
63
+ version: '0'
64
+ required_rubygems_version: !ruby/object:Gem::Requirement
65
+ requirements:
69
66
  - - ">="
70
- - !ruby/object:Gem::Version
71
- hash: 3
72
- segments:
73
- - 0
74
- version: "0"
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
75
69
  requirements: []
76
-
77
- rubyforge_project: gurgitate-mail
78
- rubygems_version: 1.8.24
70
+ rubyforge_project:
71
+ rubygems_version: 2.4.5
79
72
  signing_key:
80
- specification_version: 3
73
+ specification_version: 4
81
74
  summary: gurgitate-mail is a mail filter (and a mail-delivery agent)
82
- test_files:
83
- - test/runtests.rb
75
+ test_files:
84
76
  - test/test_writing.rb
77
+ - test/test_headers_meddling_with_headers.rb
85
78
  - test/test_rules.rb
86
- - test/test_header.rb
79
+ - test/test_execute_rules.rb
80
+ - test/test_mail_headers.rb
87
81
  - test/test_gurgitate_delivery.rb
88
- - test/test_process.rb
82
+ - test/runtests.rb
89
83
  - test/test_deliver.rb
84
+ - test/test_process.rb
85
+ - test/test_mail_headers_meddling_with_headers.rb
90
86
  - test/test_configuration.rb
91
- - test/gurgitate-test.rb
92
- - test/test_mail_headers.rb
87
+ - test/test_header.rb
93
88
  - test/test_delivery.rb
94
89
  - test/test_headers_creating_from_hash.rb
95
- - test/test_headers_meddling_with_headers.rb
96
- - test/test_execute_rules.rb
90
+ - test/gurgitate-test.rb
97
91
  - test/test_headers.rb
98
- - test/test_mail_headers_meddling_with_headers.rb