#!/usr/bin/ruby -w require 'cgi' def formatChanges(changes) body = "" changes.each { |line| line = CGI.escapeHTML(line) color = "black" if line =~ /^Modified: / next elsif line =~ /^Added: / next elsif line =~ /^@@ / color = "gray" elsif line =~ /^-/ color = "red" elsif line =~ /^\+/ color = "blue" end if line =~ /^(---|\+\+\+)(.*)$/ # Use for ---/+++ so they line up, and use distinctive background # colors. We can't use "---" and "+++" as class names, sadly. class_name = ($1 == "---" ? "triple-minus-line" : "triple-plus-line") body << "
#$1#$2
" next end body << "" # Write the per-line prefix characters in fixed width line.gsub!(/^([-+ ])/) { |prefix| "#{prefix.gsub(' ', ' ')}" } # Don't collapse indentation line.gsub!(/( {2,})/) { |s| s.gsub(' ', ' ') } line.gsub!(/\t/, '    ') body << "#{line}
\n" } return body end def sanitizeChanges(changes) # I don't think there's any source in the jessies code with more than the 2778 lines of ectags/c.c. # man-summary only has 4152 lines but it's uselessly boring to scroll through in an email. # The 533 lines of TerminatorMenuBar.java seems a more likely maximum for source that's likely to appear at once, # but we can conservatively set the limit higher. # Evergreen refused to load files larger than a megabyte at some stage (the limit's half a gig now). if changes.length() > 1000 || changes.join("\n").length() > 1024 * 1024 patchHeader = changes.slice(0, 3) errorMessage = "(truncated due to fear of email breakage - this patch was too large to be a plausible manual change)" return patchHeader << errorMessage end return changes end def outputFormattedChanges(asciiArt, changes) changes = sanitizeChanges(changes) body = "" if asciiArt body << "" body << formatChanges(changes) body << "" else body << formatChanges(changes) end return body end def patchToHtml(subject, preamble, changes) body = "" body << "" body << "" body << "\n" body << "\n" body << " #{subject}\n" body << " \n" body << " \n" body << "\n" body << preamble # Determine if we should output it in a fixed width font asciiArt = false changesSoFar = Array.new changes.each() { |line| line = line.chomp() if line =~ /^=====/ body << outputFormattedChanges(asciiArt, changesSoFar) asciiArt = false changesSoFar = Array.new next end # ETextArea says 3 spaces and you're art if line =~ /^.\s*\S.*\s{3,}/ asciiArt = true end changesSoFar.push(line) } body << outputFormattedChanges(asciiArt, changesSoFar) body << "" return body end def sendHtmlEmail(from_address, to_address, reply_to_address, subject, preamble, changes) body = patchToHtml(subject, preamble, changes) # Write the header. header = "" header << "To: #{to_address}\n" header << "From: #{from_address}\n" header << "Subject: #{subject}\n" header << "Reply-to: #{reply_to_address}\n" if reply_to_address != nil header << "MIME-Version: 1.0\n" header << "Content-Type: text/html; charset=UTF-8\n" header << "Content-Transfer-Encoding: 8bit\n" header << "\n" sendmail="/usr/sbin/sendmail" IO.popen("#{sendmail} #{to_address}", "w") { |fd| fd.print(header) # The hope is that this would be bigger than anyone would read while being small enough # to avoid hard mail size limits - so we get to see there was a problem - and small enough # not to cause performance problems. maximumMailSize = 2 * 1024 * 1024 fd.print(body.slice(0, maximumMailSize)) } end # Work as a filter if we're run as a program rather than used as a library. if __FILE__ == $0 puts(patchToHtml("", "", ARGF.readlines())) end