Class: Redwood::Message
Overview
a Message is what’s threaded.
it is also where the parsing for quotes and signatures is done, but that should be moved out to a separate class at some point (because i would like, for example, to be able to add in a ruby-talk specific module that would detect and link to /ruby-talk:d+/ sequences in the text of an email. (how sweet would that be?)
this class cathces all source exceptions. if the underlying source throws an error, it is caught and handled.
Constant Summary collapse
- SNIPPET_LEN =
80- RE_PATTERN =
/^((re|re[\[\(]\d[\]\)]):\s*)+/i- QUOTE_PATTERN =
/^\s{0,4}[>|\}]/- BLOCK_QUOTE_PATTERN =
/^-----\s*Original Message\s*----+$/- QUOTE_START_PATTERN =
/(^\s*Excerpts from)|(^\s*In message )|(^\s*In article )|(^\s*Quoting )|((wrote|writes|said|says)\s*:\s*$)/- SIG_PATTERN =
/(^-- ?$)|(^\s*----------+\s*$)|(^\s*_________+\s*$)|(^\s*--~--~-)|(^\s*--\+\+\*\*==)/- MAX_SIG_DISTANCE =
lines from the end
15- DEFAULT_SUBJECT =
""- DEFAULT_SENDER =
"(missing sender)"
Instance Attribute Summary collapse
-
#bcc ⇒ Object
readonly
Returns the value of attribute bcc.
-
#cc ⇒ Object
readonly
Returns the value of attribute cc.
-
#chunks ⇒ Object
readonly
Returns the value of attribute chunks.
-
#date ⇒ Object
readonly
Returns the value of attribute date.
-
#from ⇒ Object
readonly
Returns the value of attribute from.
-
#id ⇒ Object
readonly
Returns the value of attribute id.
-
#labels ⇒ Object
Returns the value of attribute labels.
-
#list_address ⇒ Object
readonly
Returns the value of attribute list_address.
-
#list_subscribe ⇒ Object
readonly
Returns the value of attribute list_subscribe.
-
#list_unsubscribe ⇒ Object
readonly
Returns the value of attribute list_unsubscribe.
-
#recipient_email ⇒ Object
readonly
Returns the value of attribute recipient_email.
-
#refs ⇒ Object
readonly
Returns the value of attribute refs.
-
#replyto ⇒ Object
readonly
Returns the value of attribute replyto.
-
#replytos ⇒ Object
readonly
Returns the value of attribute replytos.
-
#source ⇒ Object
readonly
Returns the value of attribute source.
-
#source_info ⇒ Object
readonly
Returns the value of attribute source_info.
-
#subj ⇒ Object
readonly
Returns the value of attribute subj.
-
#to ⇒ Object
readonly
Returns the value of attribute to.
Class Method Summary collapse
Instance Method Summary collapse
- #add_label(t) ⇒ Object
- #content ⇒ Object
- #draft_filename ⇒ Object
-
#each_raw_message_line(&b) ⇒ Object
much faster than raw_message.
- #error_message(msg) ⇒ Object
- #has_label?(t) ⇒ Boolean
-
#initialize(opts) ⇒ Message
constructor
if you specify a :header, will use values from that.
- #is_draft? ⇒ Boolean
- #is_list_message? ⇒ Boolean
-
#load_from_source! ⇒ Object
this is called when the message body needs to actually be loaded.
- #quotable_body_lines ⇒ Object
- #quotable_header_lines ⇒ Object
- #raw_header ⇒ Object
- #raw_message ⇒ Object
- #recipients ⇒ Object
- #remove_label(t) ⇒ Object
- #sanitize_message_id(mid) ⇒ Object
- #save(index) ⇒ Object
- #snippet ⇒ Object
-
#with_source_errors_handled ⇒ Object
wrap any source methods that might throw sourceerrors.
Constructor Details
#initialize(opts) ⇒ Message
if you specify a :header, will use values from that. otherwise, will try and load the header from the source.
48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/sup/message.rb', line 48 def initialize opts @source = opts[:source] or raise ArgumentError, "source can't be nil" @source_info = opts[:source_info] or raise ArgumentError, "source_info can't be nil" @snippet = opts[:snippet] || "" @have_snippet = !opts[:snippet].nil? @labels = [] + (opts[:labels] || []) @dirty = false @chunks = nil parse_header(opts[:header] || @source.load_header(@source_info)) end |
Instance Attribute Details
#bcc ⇒ Object (readonly)
Returns the value of attribute bcc.
40 41 42 |
# File 'lib/sup/message.rb', line 40 def bcc @bcc end |
#cc ⇒ Object (readonly)
Returns the value of attribute cc.
40 41 42 |
# File 'lib/sup/message.rb', line 40 def cc @cc end |
#chunks ⇒ Object (readonly)
Returns the value of attribute chunks.
40 41 42 |
# File 'lib/sup/message.rb', line 40 def chunks @chunks end |
#date ⇒ Object (readonly)
Returns the value of attribute date.
40 41 42 |
# File 'lib/sup/message.rb', line 40 def date @date end |
#from ⇒ Object (readonly)
Returns the value of attribute from.
40 41 42 |
# File 'lib/sup/message.rb', line 40 def from @from end |
#id ⇒ Object (readonly)
Returns the value of attribute id.
40 41 42 |
# File 'lib/sup/message.rb', line 40 def id @id end |
#labels ⇒ Object
Returns the value of attribute labels.
40 41 42 |
# File 'lib/sup/message.rb', line 40 def labels @labels end |
#list_address ⇒ Object (readonly)
Returns the value of attribute list_address.
40 41 42 |
# File 'lib/sup/message.rb', line 40 def list_address @list_address end |
#list_subscribe ⇒ Object (readonly)
Returns the value of attribute list_subscribe.
40 41 42 |
# File 'lib/sup/message.rb', line 40 def list_subscribe @list_subscribe end |
#list_unsubscribe ⇒ Object (readonly)
Returns the value of attribute list_unsubscribe.
40 41 42 |
# File 'lib/sup/message.rb', line 40 def list_unsubscribe @list_unsubscribe end |
#recipient_email ⇒ Object (readonly)
Returns the value of attribute recipient_email.
40 41 42 |
# File 'lib/sup/message.rb', line 40 def recipient_email @recipient_email end |
#refs ⇒ Object (readonly)
Returns the value of attribute refs.
40 41 42 |
# File 'lib/sup/message.rb', line 40 def refs @refs end |
#replyto ⇒ Object (readonly)
Returns the value of attribute replyto.
40 41 42 |
# File 'lib/sup/message.rb', line 40 def replyto @replyto end |
#replytos ⇒ Object (readonly)
Returns the value of attribute replytos.
40 41 42 |
# File 'lib/sup/message.rb', line 40 def replytos @replytos end |
#source ⇒ Object (readonly)
Returns the value of attribute source.
40 41 42 |
# File 'lib/sup/message.rb', line 40 def source @source end |
#source_info ⇒ Object (readonly)
Returns the value of attribute source_info.
40 41 42 |
# File 'lib/sup/message.rb', line 40 def source_info @source_info end |
#subj ⇒ Object (readonly)
Returns the value of attribute subj.
40 41 42 |
# File 'lib/sup/message.rb', line 40 def subj @subj end |
#to ⇒ Object (readonly)
Returns the value of attribute to.
40 41 42 |
# File 'lib/sup/message.rb', line 40 def to @to end |
Class Method Details
.normalize_subj(s) ⇒ Object
26 |
# File 'lib/sup/message.rb', line 26 def normalize_subj s; s.gsub(RE_PATTERN, ""); end |
.reify_subj(s) ⇒ Object
28 |
# File 'lib/sup/message.rb', line 28 def reify_subj s; subj_is_reply?(s) ? s : "Re: " + s; end |
.subj_is_reply?(s) ⇒ Boolean
27 |
# File 'lib/sup/message.rb', line 27 def subj_is_reply? s; s =~ RE_PATTERN; end |
Instance Method Details
#add_label(t) ⇒ Object
135 136 137 138 139 |
# File 'lib/sup/message.rb', line 135 def add_label t return if @labels.member? t @labels.push t @dirty = true end |
#content ⇒ Object
227 228 229 230 231 232 233 234 235 236 237 |
# File 'lib/sup/message.rb', line 227 def content load_from_source! [ from && "#{from.name} #{from.email}", to.map { |p| "#{p.name} #{p.email}" }, cc.map { |p| "#{p.name} #{p.email}" }, bcc.map { |p| "#{p.name} #{p.email}" }, chunks.select { |c| c.is_a? Chunk::Text }.map { |c| c.lines }, Message.normalize_subj(subj), ].flatten.compact.join " " end |
#draft_filename ⇒ Object
122 123 124 125 |
# File 'lib/sup/message.rb', line 122 def draft_filename raise "not a draft" unless is_draft? @source.fn_for_offset @source_info end |
#each_raw_message_line(&b) ⇒ Object
much faster than raw_message
223 224 225 |
# File 'lib/sup/message.rb', line 223 def &b with_source_errors_handled { @source.(@source_info, &b) } end |
#error_message(msg) ⇒ Object
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 |
# File 'lib/sup/message.rb', line 183 def msg "\#@snippet...\n\n***********************************************************************\n An error occurred while loading this message. It is possible that\n the source has changed, or (in the case of remote sources) is down.\n You can check the log for errors, though hopefully an error window\n should have popped up at some point.\n\n The message location was:\n \#@source#\#@source_info\n***********************************************************************\n\nThe error message was:\n\#{msg}\n" end |
#has_label?(t) ⇒ Boolean
134 |
# File 'lib/sup/message.rb', line 134 def has_label? t; @labels.member? t; end |
#is_draft? ⇒ Boolean
121 |
# File 'lib/sup/message.rb', line 121 def is_draft?; @source.is_a? DraftLoader; end |
#is_list_message? ⇒ Boolean
120 |
# File 'lib/sup/message.rb', line 120 def ; !@list_address.nil?; end |
#load_from_source! ⇒ Object
this is called when the message body needs to actually be loaded.
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 |
# File 'lib/sup/message.rb', line 156 def load_from_source! @chunks ||= if @source.has_errors? [Chunk::Text.new((@source.error..split("\n")))] else begin ## we need to re-read the header because it contains information ## that we don't store in the index. actually i think it's just ## the mailing list address (if any), so this is kinda overkill. ## i could just store that in the index, but i think there might ## be other things like that in the future, and i'd rather not ## bloat the index. ## actually, it's also the differentiation between to/cc/bcc, ## so i will keep this. parse_header @source.load_header(@source_info) @source.(@source_info) rescue SourceError, SocketError, MessageFormatError => e Redwood::log "problem getting messages from #{@source}: #{e.message}" ## we need force_to_top here otherwise this window will cover ## up the error message one @source.error ||= e Redwood::report_broken_sources :force_to_top => true [Chunk::Text.new((e.))] end end end |
#quotable_body_lines ⇒ Object
239 240 241 |
# File 'lib/sup/message.rb', line 239 def quotable_body_lines chunks.find_all { |c| c.quotable? }.map { |c| c.lines }.flatten end |
#quotable_header_lines ⇒ Object
243 244 245 246 247 248 249 250 |
# File 'lib/sup/message.rb', line 243 def quotable_header_lines ["From: #{@from.full_address}"] + (@to.empty? ? [] : ["To: " + @to.map { |p| p.full_address }.join(", ")]) + (@cc.empty? ? [] : ["Cc: " + @cc.map { |p| p.full_address }.join(", ")]) + (@bcc.empty? ? [] : ["Bcc: " + @bcc.map { |p| p.full_address }.join(", ")]) + ["Date: #{@date.rfc822}", "Subject: #{@subj}"] end |
#raw_header ⇒ Object
214 215 216 |
# File 'lib/sup/message.rb', line 214 def raw_header with_source_errors_handled { @source.raw_header @source_info } end |
#raw_message ⇒ Object
218 219 220 |
# File 'lib/sup/message.rb', line 218 def with_source_errors_handled { @source. @source_info } end |
#recipients ⇒ Object
146 147 148 |
# File 'lib/sup/message.rb', line 146 def recipients @to + @cc + @bcc end |
#remove_label(t) ⇒ Object
140 141 142 143 144 |
# File 'lib/sup/message.rb', line 140 def remove_label t return unless @labels.member? t @labels.delete t @dirty = true end |
#sanitize_message_id(mid) ⇒ Object
127 |
# File 'lib/sup/message.rb', line 127 def mid; mid.gsub(/\s/, "") end |
#save(index) ⇒ Object
129 130 131 132 |
# File 'lib/sup/message.rb', line 129 def save index index. self if @dirty @dirty = false end |
#snippet ⇒ Object
119 |
# File 'lib/sup/message.rb', line 119 def snippet; @snippet || chunks && @snippet; end |
#with_source_errors_handled ⇒ Object
wrap any source methods that might throw sourceerrors
203 204 205 206 207 208 209 210 211 212 |
# File 'lib/sup/message.rb', line 203 def with_source_errors_handled begin yield rescue SourceError => e Redwood::log "problem getting messages from #{@source}: #{e.message}" @source.error ||= e Redwood::report_broken_sources :force_to_top => true e. end end |