Module: MIME::ContentFormats::TextFlowed

Defined in:
lib/mime/content_formats/text_flowed.rb

Overview

Minimal implementation of RFC 2646: The Text/Plain Format Parameter

tools.ietf.org/html/rfc2646

Excerpts from RFC

This memo proposes a new parameter to be used with Text/Plain, and, in the presence of this parameter, the use of trailing whitespace to indicate flowed lines. This results in an encoding which appears as normal Text/Plain in older implementations, since it is in fact normal Text/Plain.

Each paragraph is displayed, starting at the left margin (or paragraph indent), and continuing to the right until a word is encountered which does not fit in the remaining display width. This word is displayed at the left margin of the next line. This continues until the paragraph ends (a CRLF is seen).

MIME format parameter to the text/plain media type

Name:  Format
Value: Fixed, Flowed
Example: Content-Type: text/plain; charset=iso-8859-1; format=flowed

TODO

  • Implement RFC 3676, which obsoletes RFC 2646.

  • Usenet signature convention (section 4.3)

  • Space-Stuffing (section 4.4)

  • Quoting (section 4.5)

  • Perhaps this should be subsumed into the MIME project.

Constant Summary collapse

MAX_FLOWED_LINE =
79

Class Method Summary collapse

Class Method Details

.decode(text) ⇒ Object

Decode flowed plain text.

Raises:

  • (NotImplementedError)


122
123
124
# File 'lib/mime/content_formats/text_flowed.rb', line 122

def self.decode(text)
  raise NotImplementedError
end

.encode(text, max = MAX_FLOWED_LINE) ⇒ Object

Encode plain text into flowed format, reducing long lines to max characters or less using soft line breaks (i.e., SPACE+CRLF).

According to the RFC, the max flowed line length is 79 characters. Line lengths of 66 and 72 characters are common.

The features of RFC 2646, such as line quoting and space-stuffing, are not implemented.



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/mime/content_formats/text_flowed.rb', line 57

def self.encode(text, max = MAX_FLOWED_LINE)
  if max > MAX_FLOWED_LINE
    raise ArgumentError, "flowed lines must be #{MAX_FLOWED_LINE} characters or less"
  end

  out = []
  text.split(/\r\n|\n/).each do |paragraph|
    # tab use is discouraged
    # http://tools.ietf.org/html/rfc822#section-3.4.2 
    paragraph.gsub!(/\t/, ' '*4)

    # trim spaces before hard break
    # http://tools.ietf.org/html/rfc2646#section-4.1
    paragraph.rstrip!

    if paragraph.length <= max
      out << paragraph
    else # flow text
      line = ''
      word = ''

      paragraph.each_char do |char|
        if char == ' '
          # Omit spaces after soft break to prevent stuffing on next line.
          next if word.empty? && (line.size == 0 || line.size == max)

          if (line.size + word.size) < max
            line << word + char
          else # soft break situation
            unless line.empty?
              out << line.dup
              line.clear
            end
            if word.size < max
              line << word + char
            else
              word.scan(/.{1,#{MIME::MAX_LINE_LENGTH}}/) {|s| out << s }
            end
          end
          word.clear
        else  # accumulate non-space characters in buffer
          word += char
        end
      end

      # flush buffers in an orderly fashion
      if ! word.empty?
        if (line.size + word.size) <= max
          out << line + word
        else
          out << line unless line.empty?
          word.scan(/.{1,#{MIME::MAX_LINE_LENGTH}}/) {|s| out << s }
        end
      elsif ! line.empty?
        out << line
      end
    end
  end

  out.join("\r\n")
end