module Redwood
fucking imap fucking sucks. what the FUCK kind of committee of dunces designed this shit.
imap talks about 'unique ids' for messages, to be used for cross-session identification. great—just what sup needs! except it turns out the uids can be invalidated every time the 'uidvalidity' value changes on the server, and 'uidvalidity' can change without restriction. it can change any time you log in. it can change EVERY time you log in. of course the imap spec “strongly recommends” that it never change, but there's nothing to stop people from just setting it to the current timestamp, and in fact that's EXACTLY what the one imap server i have at my disposal does. thus the so-called uids are absolutely useless and imap provides no cross-session way of uniquely identifying a message. but thanks for the “strong recommendation”, guys!
so right now i'm using the 'internal date' and the size of each message to uniquely identify it, and i scan over the entire mailbox each time i open it to map those things to message ids. that can be slow for large mailboxes, and we'll just have to hope that there are no collisions. ho ho! a perfectly reasonable solution!
and here's another thing. check out RFC2060 2.2.2 paragraph 5:
A client MUST be prepared to accept any server response at all times. This includes server data that was not requested.
yeah. that totally makes a lot of sense. and once again, the idiocy of the spec actually happens in practice. you'll request flags for one message, and get it interspersed with a random bunch of flags for some other messages, including a different set of flags for the same message! totally ok by the imap spec. totally retarded by any other metric.
fuck you, imap committee. you managed to design something nearly as shitty as mbox but goddamn THIRTY YEARS LATER.
Constants
- BASE_DIR
- COLOR_FN
- CONFIG_FN
- CONTACT_FN
- DEFAULT_NEW_INDEX_TYPE
- DRAFT_DIR
- HOOK_DIR
- LABEL_FN
- LOCK_FN
- SENT_FN
- SOURCE_FN
- SUICIDE_FN
- VERSION
- YAML_DATE
- YAML_DOMAIN
Attributes
Public Class Methods
to be called by entry points in bin/, to ensure that their versions match up against the library versions.
this is a perennial source of bug reports from people who both use git and have a gem version installed.
# File lib/sup.rb, line 196 def check_library_version_against v unless Redwood::VERSION == v $stderr.puts <<EOS Error: version mismatch! The sup executable is at version #{v.inspect}. The sup libraries are at version #{Redwood::VERSION.inspect}. Your development environment may be picking up code from a rubygems installation of sup. If you're running from git with a commandline like ruby -Ilib #{$0} try this instead: RUBY_INVOCATION="ruby -Ilib" ruby -Ilib #{$0} You can also try `gem uninstall sup` and removing all Sup rubygems. EOS abort end end
# File lib/sup.rb, line 136 def finish Redwood::LabelManager.save if Redwood::LabelManager.instantiated? Redwood::ContactManager.save if Redwood::ContactManager.instantiated? Redwood::BufferManager.deinstantiate! if Redwood::BufferManager.instantiated? end
# File lib/sup.rb, line 107 def load_yaml_obj fn, compress=false o = if File.exists? fn if compress Zlib::GzipReader.open(fn) { |f| YAML::load f } else YAML::load_file fn end end if o.is_a?(Array) o.each { |x| x.after_unmarshal! if x.respond_to?(:after_unmarshal!) } else o.after_unmarshal! if o.respond_to?(:after_unmarshal!) end o end
# File lib/sup.rb, line 64 def record_exception e, name @exception_mutex.synchronize do @exceptions ||= [] @exceptions << [e, name] end end
not really a good place for this, so I'll just dump it here.
a source error is either a FatalSourceError or an OutOfSyncSourceError. the superclass SourceError is just a generic.
# File lib/sup.rb, line 146 def report_broken_sources opts={} return unless BufferManager.instantiated? broken_sources = SourceManager.sources.select { |s| s.error.is_a? FatalSourceError } unless broken_sources.empty? BufferManager.spawn_unless_exists("Broken source notification for #{broken_sources.join(',')}", opts) do TextMode.new("Source error notification ------------------------- Hi there. It looks like one or more message sources is reporting errors. Until this is corrected, messages from these sources cannot be viewed, and new messages will not be detected. #{broken_sources.map { |s| "Source: " + s.to_s + "\n Error: " + s.error.message.wrap(70).join("\n ")}.join("\n\n")} ") #' stupid ruby-mode end end desynced_sources = SourceManager.sources.select { |s| s.error.is_a? OutOfSyncSourceError } unless desynced_sources.empty? BufferManager.spawn_unless_exists("Out-of-sync source notification for #{broken_sources.join(',')}", opts) do TextMode.new("Out-of-sync source notification ------------------------------- Hi there. It looks like one or more sources has fallen out of sync with my index. This can happen when you modify these sources with other email clients. (Sorry, I don't play well with others.) Until this is corrected, messages from these sources cannot be viewed, and new messages will not be detected. Luckily, this is easy to correct! #{desynced_sources.map do |s| "Source: " + s.to_s + "\n Error: " + s.error.message.wrap(70).join("\n ") + "\n Fix: sup-sync --changed #{s.to_s}" end} ") #' stupid ruby-mode end end end
# File lib/sup.rb, line 71 def reporting_thread name if $opts[:no_threads] yield else ::Thread.new do begin yield rescue Exception => e record_exception e, name end end end end
one-stop shop for yamliciousness
# File lib/sup.rb, line 88 def save_yaml_obj o, fn, safe=false o = if o.is_a?(Array) o.map { |x| (x.respond_to?(:before_marshal) && x.before_marshal) || x } elsif o.respond_to? :before_marshal o.before_marshal else o end if safe safe_fn = "#{File.dirname fn}/safe_#{File.basename fn}" mode = File.stat(fn).mode if File.exists? fn File.open(safe_fn, "w", mode) { |f| f.puts o.to_yaml } FileUtils.mv safe_fn, fn else File.open(fn, "w") { |f| f.puts o.to_yaml } end end
# File lib/sup.rb, line 123 def start Redwood::SentManager.init $config[:sent_source] || 'sup://sent' Redwood::ContactManager.init Redwood::CONTACT_FN Redwood::LabelManager.init Redwood::LABEL_FN Redwood::AccountManager.init $config[:accounts] Redwood::DraftManager.init Redwood::DRAFT_DIR Redwood::UpdateManager.init Redwood::PollManager.init Redwood::CryptoManager.init Redwood::UndoManager.init Redwood::SourceManager.init end
Private Instance Methods
to be called by entry points in bin/, to ensure that their versions match up against the library versions.
this is a perennial source of bug reports from people who both use git and have a gem version installed.
# File lib/sup.rb, line 196 def check_library_version_against v unless Redwood::VERSION == v $stderr.puts <<EOS Error: version mismatch! The sup executable is at version #{v.inspect}. The sup libraries are at version #{Redwood::VERSION.inspect}. Your development environment may be picking up code from a rubygems installation of sup. If you're running from git with a commandline like ruby -Ilib #{$0} try this instead: RUBY_INVOCATION="ruby -Ilib" ruby -Ilib #{$0} You can also try `gem uninstall sup` and removing all Sup rubygems. EOS abort end end
# File lib/sup.rb, line 136 def finish Redwood::LabelManager.save if Redwood::LabelManager.instantiated? Redwood::ContactManager.save if Redwood::ContactManager.instantiated? Redwood::BufferManager.deinstantiate! if Redwood::BufferManager.instantiated? end
# File lib/sup.rb, line 107 def load_yaml_obj fn, compress=false o = if File.exists? fn if compress Zlib::GzipReader.open(fn) { |f| YAML::load f } else YAML::load_file fn end end if o.is_a?(Array) o.each { |x| x.after_unmarshal! if x.respond_to?(:after_unmarshal!) } else o.after_unmarshal! if o.respond_to?(:after_unmarshal!) end o end
# File lib/sup.rb, line 64 def record_exception e, name @exception_mutex.synchronize do @exceptions ||= [] @exceptions << [e, name] end end
not really a good place for this, so I'll just dump it here.
a source error is either a FatalSourceError or an OutOfSyncSourceError. the superclass SourceError is just a generic.
# File lib/sup.rb, line 146 def report_broken_sources opts={} return unless BufferManager.instantiated? broken_sources = SourceManager.sources.select { |s| s.error.is_a? FatalSourceError } unless broken_sources.empty? BufferManager.spawn_unless_exists("Broken source notification for #{broken_sources.join(',')}", opts) do TextMode.new("Source error notification ------------------------- Hi there. It looks like one or more message sources is reporting errors. Until this is corrected, messages from these sources cannot be viewed, and new messages will not be detected. #{broken_sources.map { |s| "Source: " + s.to_s + "\n Error: " + s.error.message.wrap(70).join("\n ")}.join("\n\n")} ") #' stupid ruby-mode end end desynced_sources = SourceManager.sources.select { |s| s.error.is_a? OutOfSyncSourceError } unless desynced_sources.empty? BufferManager.spawn_unless_exists("Out-of-sync source notification for #{broken_sources.join(',')}", opts) do TextMode.new("Out-of-sync source notification ------------------------------- Hi there. It looks like one or more sources has fallen out of sync with my index. This can happen when you modify these sources with other email clients. (Sorry, I don't play well with others.) Until this is corrected, messages from these sources cannot be viewed, and new messages will not be detected. Luckily, this is easy to correct! #{desynced_sources.map do |s| "Source: " + s.to_s + "\n Error: " + s.error.message.wrap(70).join("\n ") + "\n Fix: sup-sync --changed #{s.to_s}" end} ") #' stupid ruby-mode end end end
# File lib/sup.rb, line 71 def reporting_thread name if $opts[:no_threads] yield else ::Thread.new do begin yield rescue Exception => e record_exception e, name end end end end
one-stop shop for yamliciousness
# File lib/sup.rb, line 88 def save_yaml_obj o, fn, safe=false o = if o.is_a?(Array) o.map { |x| (x.respond_to?(:before_marshal) && x.before_marshal) || x } elsif o.respond_to? :before_marshal o.before_marshal else o end if safe safe_fn = "#{File.dirname fn}/safe_#{File.basename fn}" mode = File.stat(fn).mode if File.exists? fn File.open(safe_fn, "w", mode) { |f| f.puts o.to_yaml } FileUtils.mv safe_fn, fn else File.open(fn, "w") { |f| f.puts o.to_yaml } end end
# File lib/sup.rb, line 123 def start Redwood::SentManager.init $config[:sent_source] || 'sup://sent' Redwood::ContactManager.init Redwood::CONTACT_FN Redwood::LabelManager.init Redwood::LABEL_FN Redwood::AccountManager.init $config[:accounts] Redwood::DraftManager.init Redwood::DRAFT_DIR Redwood::UpdateManager.init Redwood::PollManager.init Redwood::CryptoManager.init Redwood::UndoManager.init Redwood::SourceManager.init end