CVS Web Frontends
Index: cvsspam.rb
===================================================================
--- cvsspam.rb (revision 223)
+++ cvsspam.rb (revision 253)
@@ -20,6 +20,7 @@
$version = "0.2.12"
+require 'time'
$maxSubjectLength = 200
$maxLinesPerDiff = 1000
@@ -35,10 +36,6 @@
a126 || b==UNDERSCORE || b==TAB
+ if b>126 || b==UNDERSCORE || b==TAB || b==HOOK || b==EQUALS
sprintf("=%02x", b)
elsif b == SPACE
"_"
@@ -388,6 +387,7 @@
class FileEntry
def initialize(path)
@path = path
+ @fromVer = @toVer = nil
@lineAdditions = @lineRemovals = 0
@repository = Repository.get(path)
@repository.merge_common_prefix(basedir())
@@ -533,6 +533,14 @@
# TODO: consolidate these into a nicer framework,
mailSub = proc { |match| "#{match}" }
urlSub = proc { |match| "#{match}" }
+gforgeTaskSub = proc { |match|
+ match =~ /([0-9]+)/
+ "#{match}"
+}
+gforgeBugSub = proc { |match|
+ match =~ /([0-9]+)/
+ "#{match}"
+}
bugzillaSub = proc { |match|
match =~ /([0-9]+)/
"#{match}"
@@ -544,11 +552,27 @@
match =~ /([0-9]+)/
"#{match}"
}
+issueSub = proc { |match|
+ match =~ /([0-9]+)/
+ "#{match}"
+}
wikiSub = proc { |match|
- match =~ /\[\[(.*)\]\]/
+ match =~ /\[\[(.*?)\]\]/
raw = $1
"[[#{raw}]]"
}
+xplannerIterationSub = proc { |match|
+ match =~ /([0-9]+)/
+ "#{match}"
+}
+xplannerProjectSub = proc { |match|
+ match =~ /([0-9]+)/
+ "#{match}"
+}
+xplannerStorySub = proc { |match|
+ match =~ /([0-9]+)/
+ "#{match}"
+}
commentSubstitutions = {
'(?:mailto:)?[\w\.\-\+\=]+\@[\w\-]+(?:\.[\w\-]+)+\b' => mailSub,
'\b(?:http|https|ftp):[^ \t\n<>"]+[\w/]' => urlSub
@@ -670,6 +694,12 @@
def diff(file)
'->'
end
+
+ # may be overridden by subclasses that are able to make a hyperlink to a
+ # history log for a file
+ def log(file)
+ ''
+ end
end
# Superclass for objects that can link to CVS frontends on the web (ViewCVS,
@@ -710,6 +740,14 @@
"#{super(file)}"
end
+ def log(file)
+ link = log_url(file)
+ if link
+ return "(log)"
+ end
+ return nil
+ end
+
protected
def add_repo(url)
if @repository_name
@@ -722,6 +760,10 @@
url
end
end
+
+ def log_url(file)
+ nil
+ end
end
# Link to ViewCVS
@@ -745,6 +787,15 @@
def diff_url(file)
add_repo("#{@base_url}#{urlEncode(file.path)}.diff?r1=#{file.fromVer}&r2=#{file.toVer}")
end
+
+ def log_url(file)
+ if file.toVer
+ log_anchor = "#rev#{file.toVer}"
+ else
+ log_anchor = ""
+ end
+ add_repo("#{@base_url}#{urlEncode(file.path)}#{log_anchor}")
+ end
end
# Link to Chora, from the Horde framework
@@ -767,9 +818,9 @@
class CVSwebFrontend < WebFrontend
def path_url(path, tag)
if tag == nil
- add_repo(@base_url + urlEncode(path))
+ add_repo(@base_url + urlEncode(path) + "/")
else
- add_repo("#{@base_url}#{urlEncode(path)}?only_with_tag=#{urlEncode(tag)}")
+ add_repo("#{@base_url}#{urlEncode(path)}/?only_with_tag=#{urlEncode(tag)}")
end
end
@@ -780,6 +831,17 @@
def diff_url(file)
add_repo("#{@base_url}#{urlEncode(file.path)}.diff?r1=text&tr1=#{file.fromVer}&r2=text&tr2=#{file.toVer}&f=h")
end
+
+ protected
+
+ def log_url(file)
+ if file.toVer
+ log_anchor = "#rev#{file.toVer}"
+ else
+ log_anchor = ""
+ end
+ add_repo("#{@base_url}#{urlEncode(file.path)}#{log_anchor}")
+ end
end
@@ -958,7 +1020,7 @@
end
shift(nil)
if @truncatedLineCount>0
- println("[Note: Some over-long lines of diff output only partialy shown]")
+ println("[Note: Some over-long lines of diff output only partially shown]")
end
end
@@ -1247,10 +1309,16 @@
$no_diff = false
$task_keywords = ['TODO', 'FIXME']
$bugzillaURL = nil
+$gforgeBugURL = nil
+$gforgeTaskURL = nil
$wikiURL = nil
$jiraURL = nil
$ticketURL = nil
+$issueURL = nil
$viewcvsURL = nil
+$xplannerIterationURL = nil
+$xplannerProjectURL = nil
+$xplannerStoryURL = nil
$choraURL = nil
$cvswebURL = nil
$from_address = nil
@@ -1261,6 +1329,7 @@
# 2MiB limit on attached diffs,
$mail_size_limit = 1024 * 1024 * 2
$arg_charset = nil
+$cvsroot_email_header = false
require 'getoptlong'
@@ -1353,17 +1422,35 @@
if $bugzillaURL != nil
- commentSubstitutions['\b[Bb][Uu][Gg]\s*#?[0-9]+'] = bugzillaSub
+ commentSubstitutions['\b[Bb]([Uu][Gg])?\s*[#:]?\s*\[?[0-9]+\]?'] = bugzillaSub
end
+if $gforgeBugURL != nil
+ commentSubstitutions['\B\[#[0-9]+\]'] = gforgeBugSub
+end
+if $gforgeTaskURL != nil
+ commentSubstitutions['\B\[[Tt][0-9]+\]'] = gforgeTaskSub
+end
if $jiraURL != nil
commentSubstitutions['\b[a-zA-Z]+-[0-9]+\b'] = jiraSub
end
if $ticketURL != nil
commentSubstitutions['\b[Tt][Ii][Cc][Kk][Ee][Tt]\s*#?[0-9]+\b'] = ticketSub
end
+if $issueURL != nil
+ commentSubstitutions['\b[Ii][Ss][Ss][Uu][Ee]\s*#?[0-9]+\b'] = issueSub
+end
if $wikiURL != nil
commentSubstitutions['\[\[.+\]\]'] = wikiSub
end
+if $xplannerIterationURL != nil
+ commentSubstitutions['\bXI\[?[0-9]+\]?'] = xplannerIterationSub
+end
+if $xplannerProjectURL != nil
+ commentSubstitutions['\bXP\[?[0-9]+\]?'] = xplannerProjectSub
+end
+if $xplannerStoryURL != nil
+ commentSubstitutions['\bXS\[?[0-9]+\]?'] = xplannerStorySub
+end
$commentEncoder = MultiSub.new(commentSubstitutions)
@@ -1546,11 +1633,14 @@
elsif file.removal?
name = "#{name}"
end
+ mail.print("")
if file.has_diff?
- mail.print(" | #{prefix}#{name} | ")
+ mail.print("#{prefix}#{name}")
else
- mail.print("#{prefix}#{name} | ")
+ mail.print("#{prefix}#{name}")
end
+ mail.print(" #{$frontend.log(file)}")
+ mail.print("")
if file.isEmpty
mail.print("[empty] | ")
elsif file.isBinary
@@ -1686,6 +1776,8 @@
# sensible header formatting, and for ensuring that the body is seperated
# from the message headers by a blank line (as it is required to be).
class MailContext
+ ENCODE_HEADERS = ["Subject", "X-CVSspam-Module-Path"]
+
def initialize(io)
@done_headers = false
@io = io
@@ -1695,8 +1787,8 @@
# called
def header(name, value)
raise "headers already commited" if @done_headers
- if name == "Subject"
- $encoder.encode_header(@io, "Subject", value)
+ if ENCODE_HEADERS.include?(name)
+ $encoder.encode_header(@io, name, value)
else
@io.puts("#{name}: #{value}")
end
@@ -1769,7 +1861,7 @@
ctx.header("To", recipients.map{|addr| addr.encoded}.join(','))
blah("Mail From: <#{from}>")
ctx.header("From", from.encoded) if from
- ctx.header("Date", Time.now.utc.strftime(DATE_HEADER_FORMAT))
+ ctx.header("Date", Time.now.rfc2822)
yield ctx
end
end
@@ -1800,10 +1892,10 @@
return unless $fileEntries.length == 1
file = $fileEntries[0]
name = zap_header_special_chars(file.path)
- unless file.fromVer == "NONE"
+ if file.fromVer
mail.header("References", make_msg_id("#{name}.#{file.fromVer}", $hostname))
end
- unless file.toVer == "NONE"
+ if file.toVer
mail.header("Message-ID", make_msg_id("#{name}.#{file.toVer}", $hostname))
end
end
@@ -1834,6 +1926,14 @@
end
end
mail.header("X-Mailer", "CVSspam #{$version} ")
+ if $cvsroot_email_header
+ mod = '/'
+ if Repository.count == 1
+ rep = Repository.array.first
+ mod << rep.common_prefix
+ end
+ mail.header("X-CVSspam-Module-Path", mod)
+ end
mail.body do |body|
make_html_email(body)