Class: Redwood::Source
Direct Known Subclasses
Instance Attribute Summary collapse
-
#id ⇒ Object
Returns the value of attribute id.
-
#poll_lock ⇒ Object
Returns the value of attribute poll_lock.
-
#uri ⇒ Object
readonly
Returns the value of attribute uri.
Class Method Summary collapse
-
.parse_raw_email_header(f) ⇒ Object
utility method to read a raw email header from an IO stream and turn it into a hash of key-value pairs.
Instance Method Summary collapse
- #==(o) ⇒ Object
-
#file_path ⇒ Object
overwrite me if you have a disk incarnation (currently used only for sup-sync-back).
-
#go_idle ⇒ Object
release resources that are easy to reacquire.
-
#initialize(uri, usual = true, archived = false, id = nil) ⇒ Source
constructor
A new instance of Source.
- #is_source_for?(uri) ⇒ Boolean
-
#poll ⇒ Object
Yields values of the form [Symbol, Hash] add: info, labels, progress delete: info, progress.
- #read? ⇒ Boolean
- #to_s ⇒ Object
-
#usual ⇒ Object
Implementing a new source should be easy, because Sup only needs to be able to: 1.
- #valid?(info) ⇒ Boolean
Constructor Details
#initialize(uri, usual = true, archived = false, id = nil) ⇒ Source
Returns a new instance of Source.
59 60 61 62 63 64 65 66 67 68 |
# File 'lib/sup/source.rb', line 59 def initialize uri, usual=true, archived=false, id=nil raise ArgumentError, "id must be an integer: #{id.inspect}" unless id.is_a? Fixnum if id @uri = uri @usual = usual @archived = archived @id = id @poll_lock = Mutex.new end |
Instance Attribute Details
#id ⇒ Object
Returns the value of attribute id.
57 58 59 |
# File 'lib/sup/source.rb', line 57 def id @id end |
#poll_lock ⇒ Object
Returns the value of attribute poll_lock.
57 58 59 |
# File 'lib/sup/source.rb', line 57 def poll_lock @poll_lock end |
#uri ⇒ Object (readonly)
Returns the value of attribute uri.
56 57 58 |
# File 'lib/sup/source.rb', line 56 def uri @uri end |
Class Method Details
.parse_raw_email_header(f) ⇒ Object
utility method to read a raw email header from an IO stream and turn it into a hash of key-value pairs. minor special semantics for certain headers.
THIS IS A SPEED-CRITICAL SECTION. Everything you do here will have a significant effect on Sup’s processing speed of email from ALL sources. Little things like string interpolation, regexp interpolation, += vs <<, all have DRAMATIC effects. BE CAREFUL WHAT YOU DO!
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'lib/sup/source.rb', line 102 def self.parse_raw_email_header f header = {} last = nil while(line = f.gets) case line ## these three can occur multiple times, and we want the first one when /^(Delivered-To|X-Original-To|Envelope-To):\s*(.*?)\s*$/i; header[last = $1.downcase] ||= $2 ## regular header: overwrite (not that we should see more than one) ## TODO: figure out whether just using the first occurrence changes ## anything (which would simplify the logic slightly) when /^([^:\s]+):\s*(.*?)\s*$/i; header[last = $1.downcase] = $2 when /^\r*$/; break # blank line signifies end of header else if last header[last] << " " unless header[last].empty? header[last] << line.strip end end end %w(subject from to cc bcc).each do |k| v = header[k] or next next unless Rfc2047.is_encoded? v header[k] = begin Rfc2047.decode_to $encoding, v rescue Errno::EINVAL, Iconv::InvalidEncoding, Iconv::IllegalSequence => e #debug "warning: error decoding RFC 2047 header (#{e.class.name}): #{e.message}" v end end header end |
Instance Method Details
#==(o) ⇒ Object
74 |
# File 'lib/sup/source.rb', line 74 def == o; o.uri == uri; end |
#file_path ⇒ Object
overwrite me if you have a disk incarnation (currently used only for sup-sync-back)
71 |
# File 'lib/sup/source.rb', line 71 def file_path; nil end |
#go_idle ⇒ Object
release resources that are easy to reacquire. it is called after processing a source (e.g. polling) to prevent resource leaks (esp. file descriptors).
82 |
# File 'lib/sup/source.rb', line 82 def go_idle; end |
#is_source_for?(uri) ⇒ Boolean
75 |
# File 'lib/sup/source.rb', line 75 def is_source_for? uri; uri == @uri; end |
#poll ⇒ Object
Yields values of the form [Symbol, Hash] add: info, labels, progress delete: info, progress
87 88 89 |
# File 'lib/sup/source.rb', line 87 def poll unimplemented end |
#read? ⇒ Boolean
77 |
# File 'lib/sup/source.rb', line 77 def read?; false; end |
#to_s ⇒ Object
73 |
# File 'lib/sup/source.rb', line 73 def to_s; @uri.to_s; end |
#usual ⇒ Object
Implementing a new source should be easy, because Sup only needs to be able to:
1. See how many messages it contains
2. Get an arbitrary message
3. (optional) see whether the source has marked it read or not
In particular, Sup doesn’t need to move messages, mark them as read, delete them, or anything else. (Well, it’s nice to be able to delete them, but that is optional.)
Messages are identified internally based on the message id, and stored with an unique document id. Along with the message, source information that can contain arbitrary fields (set up by the source) is stored. This information will be passed back to the source when a message in the index (Sup database) needs to be identified to its source, e.g. when re-reading or modifying a unique message.
To write a new source, subclass this class, and implement:
-
initialize
-
load_header offset
-
load_message offset
-
raw_header offset
-
raw_message offset
-
store_message (optional)
-
poll (loads new messages)
-
go_idle (optional)
All exceptions relating to accessing the source must be caught and rethrown as FatalSourceErrors or OutOfSyncSourceErrors. OutOfSyncSourceErrors should be used for problems that a call to sup-sync will fix (namely someone’s been playing with the source from another client); FatalSourceErrors can be used for anything else (e.g. the imap server is down or the maildir is missing.)
Finally, be sure the source is thread-safe, since it WILL be pummelled from multiple threads at once.
Examples for you to look at: mbox.rb and maildir.rb.
55 |
# File 'lib/sup/source.rb', line 55 bool_accessor :usual, :archived |
#valid?(info) ⇒ Boolean
91 92 93 |
# File 'lib/sup/source.rb', line 91 def valid? info true end |