]> git.cworth.org Git - sup/blob - lib/sup.rb
notify user of source errors on startup and on poll
[sup] / lib / sup.rb
1 require 'rubygems'
2 require 'yaml'
3 require 'zlib'
4 require 'thread'
5 require 'fileutils'
6
7 class Object
8   ## this is for debugging purposes because i keep calling #id on the
9   ## wrong object and i want it to throw an exception
10   def id
11     raise "wrong id called on #{self.inspect}"
12   end
13 end
14
15 module Redwood
16   VERSION = "0.0.7"
17
18   BASE_DIR   = ENV["SUP_BASE"] || File.join(ENV["HOME"], ".sup")
19   CONFIG_FN  = File.join(BASE_DIR, "config.yaml")
20   SOURCE_FN  = File.join(BASE_DIR, "sources.yaml")
21   LABEL_FN   = File.join(BASE_DIR, "labels.txt")
22   PERSON_FN  = File.join(BASE_DIR, "people.txt")
23   CONTACT_FN = File.join(BASE_DIR, "contacts.txt")
24   DRAFT_DIR  = File.join(BASE_DIR, "drafts")
25   SENT_FN    = File.join(BASE_DIR, "sent.mbox")
26
27   YAML_DOMAIN = "masanjin.net"
28   YAML_DATE = "2006-10-01"
29
30 ## record exceptions thrown in threads nicely
31   $exception = nil
32   def reporting_thread
33     ::Thread.new do
34       begin
35         yield
36       rescue Exception => e
37         File.open("sup-exception-log.txt", "w") do |f|
38           f.puts "--- #{e.class.name} at #{Time.now}"
39           f.puts e.message, e.backtrace
40         end
41         $exception ||= e
42         raise
43       end
44     end
45   end
46   module_function :reporting_thread
47
48 ## one-stop shop for yamliciousness
49   def register_yaml klass, props
50     vars = props.map { |p| "@#{p}" }
51     path = klass.name.gsub(/::/, "/")
52     
53     klass.instance_eval do
54       define_method(:to_yaml_properties) { vars }
55       define_method(:to_yaml_type) { "!#{YAML_DOMAIN},#{YAML_DATE}/#{path}" }
56     end
57
58     YAML.add_domain_type("#{YAML_DOMAIN},#{YAML_DATE}", path) do |type, val|
59       klass.new(*props.map { |p| val[p] })
60     end
61   end
62
63   def save_yaml_obj object, fn, compress=false
64     if compress
65       Zlib::GzipWriter.open(fn) { |f| f.puts object.to_yaml }
66     else
67       File.open(fn, "w") { |f| f.puts object.to_yaml }
68     end
69   end
70
71   def load_yaml_obj fn, compress=false
72     if File.exists? fn
73       if compress
74         Zlib::GzipReader.open(fn) { |f| YAML::load f }
75       else
76         YAML::load_file fn
77       end
78     end
79   end
80
81   def start
82     Redwood::PersonManager.new Redwood::PERSON_FN
83     Redwood::SentManager.new Redwood::SENT_FN
84     Redwood::ContactManager.new Redwood::CONTACT_FN
85     Redwood::LabelManager.new Redwood::LABEL_FN
86     Redwood::AccountManager.new $config[:accounts]
87     Redwood::DraftManager.new Redwood::DRAFT_DIR
88     Redwood::UpdateManager.new
89     Redwood::PollManager.new
90   end
91
92   def finish
93     Redwood::LabelManager.save
94     Redwood::ContactManager.save
95     Redwood::PersonManager.save
96   end
97
98   ## not really a good place for this, so I'll just dump it here.
99   def report_broken_sources
100     broken_sources = Index.usual_sources.select { |s| s.broken? }
101     unless broken_sources.empty?
102       BufferManager.spawn "Broken source report", TextMode.new(<<EOM)
103 Broken source report
104 --------------------
105
106 The following message sources reported errors. Until these errors are
107 corrected, messages from these sources cannot be viewed, and new messages
108 will not be detected.
109
110 #{broken_sources.map { |s| "Source: " + s.to_s + "\n Error: " + s.broken_msg.wrap(70).join("\n        ") }.join('\n\n')}
111 EOM
112     end
113   end
114
115   module_function :register_yaml, :save_yaml_obj, :load_yaml_obj, :start, :finish, :report_broken_sources
116 end
117
118 ## set up default configuration file
119 if File.exists? Redwood::CONFIG_FN
120   $config = Redwood::load_yaml_obj Redwood::CONFIG_FN
121 else
122   $config = {
123     :accounts => {
124       :default => {
125         :name => "Your Name Here",
126         :email => "your.email.here@domain.tld",
127         :alternates => [],
128         :sendmail => "/usr/sbin/sendmail -oem -ti",
129         :signature => File.join(ENV["HOME"], ".signature")
130       }
131     },
132     :editor => ENV["EDITOR"] || "/usr/bin/vi",
133   }
134   begin
135     FileUtils.mkdir_p Redwood::BASE_DIR
136     Redwood::save_yaml_obj $config, Redwood::CONFIG_FN
137   rescue StandardError => e
138     $stderr.puts "warning: #{e.message}"
139   end
140 end
141
142 require "sup/util"
143 require "sup/update"
144 require "sup/message"
145 require "sup/source"
146 require "sup/mbox"
147 require "sup/maildir"
148 require "sup/imap"
149 require "sup/person"
150 require "sup/account"
151 require "sup/thread"
152 require "sup/index"
153 require "sup/textfield"
154 require "sup/buffer"
155 require "sup/keymap"
156 require "sup/mode"
157 require "sup/colormap"
158 require "sup/label"
159 require "sup/contact"
160 require "sup/tagger"
161 require "sup/draft"
162 require "sup/poll"
163 require "sup/modes/scroll-mode"
164 require "sup/modes/text-mode"
165 require "sup/modes/line-cursor-mode"
166 require "sup/modes/help-mode"
167 require "sup/modes/edit-message-mode"
168 require "sup/modes/compose-mode"
169 require "sup/modes/resume-mode"
170 require "sup/modes/forward-mode"
171 require "sup/modes/reply-mode"
172 require "sup/modes/label-list-mode"
173 require "sup/modes/contact-list-mode"
174 require "sup/modes/thread-view-mode"
175 require "sup/modes/thread-index-mode"
176 require "sup/modes/label-search-results-mode"
177 require "sup/modes/search-results-mode"
178 require "sup/modes/person-search-results-mode"
179 require "sup/modes/inbox-mode"
180 require "sup/modes/buffer-list-mode"
181 require "sup/modes/log-mode"
182 require "sup/modes/poll-mode"
183 require "sup/logger"
184 require "sup/sent"
185
186 module Redwood
187   def log s; Logger.log s; end
188   module_function :log
189 end
190
191 $:.each do |base|
192   d = File.join base, "sup/share/modes/"
193   Redwood::Mode.load_all_modes d if File.directory? d
194 end