1 --- cvsspam-0.2.11/cvsspam.rb 2005-02-21 21:52:45.000000000 +0200
2 +++ cvsspam-0.2.11.patched/cvsspam.rb 2005-02-21 21:52:18.000000000 +0200
4 # long values with header continuation lines as needed
5 def rfc2047_encode_quoted(io, start, rest)
6 raise "no charset" if @charset.nil?
7 - code_begin = "=?#{@charset}?#{@encoding}?"
8 + code_begin = marker_start_quoted
10 - rest.each_byte do |b|
11 - code = if b>126 || b==UNDERSCORE || b==TAB
19 + each_char_encoded(rest) do |code|
20 if start.length+code.length+2 > @right_margin
21 - io.puts(start + "?=")
22 + io.puts(start + marker_end_quoted)
23 start = " " + code_begin
27 - io.puts(start + "?=")
28 + io.puts(start + marker_end_quoted)
31 + # return a string representing the given character-code in quoted-printable
33 + def quoted_encode_char(b)
34 + if b>126 || b==UNDERSCORE || b==TAB
45 + # yields a quoted-printable version of each byte in the given string
46 + def each_char_encoded(text)
47 + text.each_byte do |b|
48 + yield quoted_encode_char(b)
52 + # gives the string "?=",which is used to mark the end of a quoted-printable
53 + # characte rsequence
54 + def marker_end_quoted
58 + # gives a string starting "=?", and including a charset specification, that
59 + # marks the start of a quoted-printable character sequence
60 + def marker_start_quoted
61 + "=?#{@charset}?#{@encoding}?"
64 # test to see of the given string contains non-ASCII characters
65 @@ -1145,6 +1170,60 @@
69 +# an RFC 822 email address
71 + def initialize(text)
72 + if text =~ /^\s*([^<]+?)\s*<\s*([^>]+?)\s*>\s*$/
76 + @personal_name = nil
81 + attr_accessor :personal_name, :address
83 + def has_personal_name?
84 + return !@personal_name.nil?
88 + if has_personal_name?
89 + "#{encoded_personal_name} <#{address}>"
96 + if has_personal_name?
97 + "#{personal_name} <#{address}>"
105 + def encoded_personal_name
106 + personal_name.split(" ").map{|word| encode_word(word)}.join(" ")
109 + # rfc2047 encode the word, if it contains non-ASCII characters
110 + def encode_word(word)
111 + if $encoder.requires_rfc2047?(word)
112 + encoded = $encoder.marker_start_quoted
113 + $encoder.each_char_encoded(word) do |code|
116 + encoded << $encoder.marker_end_quoted
124 cvsroot_dir = "#{ENV['CVSROOT']}/CVSROOT"
125 $config = "#{cvsroot_dir}/cvsspam.conf"
126 @@ -1183,10 +1262,10 @@
129 opts.each do |opt, arg|
130 - $recipients << arg if opt=="--to"
131 + $recipients << EmailAddress.new(arg) if opt=="--to"
132 $config = arg if opt=="--config"
133 $debug = true if opt=="--debug"
134 - $from_address = arg if opt=="--from"
135 + $from_address = EmailAddress.new(arg) if opt=="--from"
136 # must use different variable as the config is readed later.
137 $arg_charset = arg if opt == "--charset"
139 @@ -1218,7 +1297,7 @@
141 # helper function called from the 'config file'
142 def addRecipient(email)
143 - $recipients << email
144 + $recipients << EmailAddress.new(email)
146 # 'constant' used from the 'config file'
148 @@ -1333,6 +1412,7 @@
151 $encoder = HeaderEncoder.new
152 +# TODO: maybe we should use the system-default value instead of ISO Latin 1?
153 $encoder.charset = $charset.nil? ? "ISO-8859-1" : $charset
156 @@ -1572,19 +1652,19 @@
157 # Tries to look up an 'alias' email address for the given string in the
158 # CVSROOT/users file, if the file exists. The argument is returned unchanged
159 # if no alias is found.
160 -def sender_alias(address)
161 +def sender_alias(email)
162 if File.exists?($users_file)
163 File.open($users_file) do |io|
164 io.each_line do |line|
165 if line =~ /^([^:]+)\s*:\s*(['"]?)([^\n\r]+)(\2)/
168 + if email.address == $1
169 + return EmailAddress.new($3)
179 # A handle for code that needs to add headers and a body to an email being
180 @@ -1628,8 +1708,8 @@
181 blah("invoking '#{cmd}'")
182 IO.popen(cmd, "w") do |mail|
183 ctx = MailContext.new(mail)
184 - ctx.header("To", recipients.join(','))
185 - ctx.header("From", from) if from
186 + ctx.header("To", recipients.map{|addr| addr.encoded}.join(','))
187 + ctx.header("From", from.encoded) if from
191 @@ -1657,18 +1737,18 @@
193 def send(from, recipients)
195 - from = ENV['USER'] || ENV['USERNAME'] || 'cvsspam'
196 + from = EmailAddress.new(ENV['USER'] || ENV['USERNAME'] || 'cvsspam')
199 - from = "#{from}@#{ENV['HOSTNAME']||'localhost'}"
200 + unless from.address =~ /@/
201 + from.address = "#{from.address}@#{ENV['HOSTNAME']||'localhost'}"
203 smtp = Net::SMTP.new(@smtp_host)
204 blah("connecting to '#{@smtp_host}'")
206 - smtp.ready(from, recipients) do |mail|
207 + smtp.ready(from.address, recipients.map{|addr| addr.address}) do |mail|
208 ctx = MailContext.new(IOAdapter.new(mail))
209 - ctx.header("To", recipients.join(','))
210 - ctx.header("From", from) if from
211 + ctx.header("To", recipients.map{|addr| addr.encoded}.join(','))
212 + ctx.header("From", from.encoded) if from
213 ctx.header("Date", Time.now.utc.strftime(DATE_HEADER_FORMAT))