sup 0.11 → 0.12

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of sup might be problematic. Click here for more details.

@@ -4,8 +4,9 @@ require 'rubygems'
4
4
  require 'uri'
5
5
  require 'tempfile'
6
6
  require 'trollop'
7
- require 'enumerator'
8
- require "sup"; Redwood::check_library_version_against "0.11"
7
+ require "sup"; Redwood::check_library_version_against "0.12"
8
+
9
+ fail "not working yet"
9
10
 
10
11
  ## save a message 'm' to an open file pointer 'fp'
11
12
  def save m, fp
@@ -17,7 +18,7 @@ def die msg
17
18
  end
18
19
  def has_any_from_source_with_label? index, source, label
19
20
  query = { :source_id => source.id, :label => label, :limit => 1, :load_spam => true, :load_deleted => true, :load_killed => true }
20
- not Enumerable::Enumerator.new(index, :each_id, query).map.empty?
21
+ index.num_results_for(query) != 0
21
22
  end
22
23
 
23
24
  opts = Trollop::options do
@@ -81,12 +82,12 @@ begin
81
82
 
82
83
  sources = ARGV.map do |uri|
83
84
  s = Redwood::SourceManager.source_for(uri) or die "unknown source: #{uri}. Did you add it with sup-add first?"
84
- s.is_a?(Redwood::MBox::Loader) or die "#{uri} is not an mbox source."
85
+ s.is_a?(Redwood::MBox) or die "#{uri} is not an mbox source."
85
86
  s
86
87
  end
87
88
 
88
89
  if sources.empty?
89
- sources = Redwood::SourceManager.usual_sources.select { |s| s.is_a? Redwood::MBox::Loader }
90
+ sources = Redwood::SourceManager.usual_sources.select { |s| s.is_a? Redwood::MBox }
90
91
  end
91
92
 
92
93
  unless sources.all? { |s| s.file_path.nil? } || File.executable?(dotlockfile) || opts[:dont_use_dotlockfile]
@@ -2,8 +2,7 @@
2
2
 
3
3
  require 'rubygems'
4
4
  require 'trollop'
5
- require 'enumerator'
6
- require "sup"; Redwood::check_library_version_against "0.11"
5
+ require "sup"; Redwood::check_library_version_against "0.12"
7
6
 
8
7
  class Float
9
8
  def to_s; sprintf '%.2f', self; end
@@ -74,18 +73,18 @@ begin
74
73
  end.map { |s| s.id }
75
74
  Trollop::die "nothing to do: no sources" if source_ids.empty?
76
75
 
77
- query = "+(" + source_ids.map { |id| "source_id:#{id}" }.join(" OR ") + ")"
76
+ query = "(" + source_ids.map { |id| "source_id:#{id}" }.join(" OR ") + ")"
78
77
  if add_labels.empty?
79
78
  ## if all we're doing is removing labels, we can further restrict the
80
79
  ## query to only messages with those labels
81
- query += " +(" + remove_labels.map { |l| "label:#{l}" }.join(" ") + ")"
80
+ query += " (" + remove_labels.map { |l| "label:#{l}" }.join(" OR ") + ")"
82
81
  end
83
82
  query += ' ' + opts[:query] if opts[:query]
84
83
 
85
84
  parsed_query = index.parse_query query
86
85
  parsed_query.merge! :load_spam => true, :load_deleted => true, :load_killed => true
87
- ids = Enumerable::Enumerator.new(index, :each_id, parsed_query).map
88
- num_total = ids.size
86
+ ids = Enumerator.new(index, :each_id, parsed_query)
87
+ num_total = index.num_results_for parsed_query
89
88
 
90
89
  $stderr.puts "Found #{num_total} documents across #{source_ids.length} sources. Scanning..."
91
90
 
data/lib/sup.rb CHANGED
@@ -5,6 +5,7 @@ require 'thread'
5
5
  require 'fileutils'
6
6
  require 'gettext'
7
7
  require 'curses'
8
+ require 'rmail'
8
9
  begin
9
10
  require 'fastthread'
10
11
  rescue LoadError
@@ -37,7 +38,7 @@ class Module
37
38
  end
38
39
 
39
40
  module Redwood
40
- VERSION = "0.11"
41
+ VERSION = "0.12"
41
42
 
42
43
  BASE_DIR = ENV["SUP_BASE"] || File.join(ENV["HOME"], ".sup")
43
44
  CONFIG_FN = File.join(BASE_DIR, "config.yaml")
@@ -51,6 +52,7 @@ module Redwood
51
52
  SUICIDE_FN = File.join(BASE_DIR, "please-kill-yourself")
52
53
  HOOK_DIR = File.join(BASE_DIR, "hooks")
53
54
  SEARCH_FN = File.join(BASE_DIR, "searches.txt")
55
+ LOG_FN = File.join(BASE_DIR, "log")
54
56
 
55
57
  YAML_DOMAIN = "masanjin.net"
56
58
  YAML_DATE = "2006-10-01"
@@ -119,26 +121,41 @@ module Redwood
119
121
  o
120
122
  end
121
123
 
124
+ def managers
125
+ %w(HookManager SentManager ContactManager LabelManager AccountManager
126
+ DraftManager UpdateManager PollManager CryptoManager UndoManager
127
+ SourceManager SearchManager IdleManager).map { |x| Redwood.const_get x.to_sym }
128
+ end
129
+
122
130
  def start
131
+ managers.each { |x| fail "#{x} already instantiated" if x.instantiated? }
132
+
133
+ FileUtils.mkdir_p Redwood::BASE_DIR
134
+ $config = load_config Redwood::CONFIG_FN
135
+ @log_io = File.open(Redwood::LOG_FN, 'a')
136
+ Redwood::Logger.add_sink @log_io
137
+ Redwood::HookManager.init Redwood::HOOK_DIR
123
138
  Redwood::SentManager.init $config[:sent_source] || 'sup://sent'
124
139
  Redwood::ContactManager.init Redwood::CONTACT_FN
125
140
  Redwood::LabelManager.init Redwood::LABEL_FN
126
141
  Redwood::AccountManager.init $config[:accounts]
127
142
  Redwood::DraftManager.init Redwood::DRAFT_DIR
128
- Redwood::UpdateManager.init
129
- Redwood::PollManager.init
130
- Redwood::CryptoManager.init
131
- Redwood::UndoManager.init
132
- Redwood::SourceManager.init
133
143
  Redwood::SearchManager.init Redwood::SEARCH_FN
134
- Redwood::IdleManager.init
144
+
145
+ managers.each { |x| x.init unless x.instantiated? }
135
146
  end
136
147
 
137
148
  def finish
138
149
  Redwood::LabelManager.save if Redwood::LabelManager.instantiated?
139
150
  Redwood::ContactManager.save if Redwood::ContactManager.instantiated?
140
- Redwood::BufferManager.deinstantiate! if Redwood::BufferManager.instantiated?
141
151
  Redwood::SearchManager.save if Redwood::SearchManager.instantiated?
152
+ Redwood::Logger.remove_sink @log_io
153
+
154
+ managers.each { |x| x.deinstantiate! if x.instantiated? }
155
+
156
+ @log_io.close
157
+ @log_io = nil
158
+ $config = nil
142
159
  end
143
160
 
144
161
  ## not really a good place for this, so I'll just dump it here.
@@ -220,81 +237,84 @@ EOS
220
237
  end
221
238
  end
222
239
 
223
- module_function :save_yaml_obj, :load_yaml_obj, :start, :finish,
224
- :report_broken_sources, :check_library_version_against
225
- end
226
-
227
- ## set up default configuration file
228
- if File.exists? Redwood::CONFIG_FN
229
- $config = Redwood::load_yaml_obj Redwood::CONFIG_FN
230
- abort "#{Redwood::CONFIG_FN} is not a valid configuration file (it's a #{$config.class}, not a hash)" unless $config.is_a?(Hash)
231
- else
232
- require 'etc'
233
- require 'socket'
234
- name = Etc.getpwnam(ENV["USER"]).gecos.split(/,/).first rescue nil
235
- name ||= ENV["USER"]
236
- email = ENV["USER"] + "@" +
237
- begin
238
- Socket.gethostbyname(Socket.gethostname).first
239
- rescue SocketError
240
- Socket.gethostname
241
- end
240
+ ## set up default configuration file
241
+ def load_config filename
242
+ if File.exists? filename
243
+ config = Redwood::load_yaml_obj filename
244
+ abort "#{filename} is not a valid configuration file (it's a #{config.class}, not a hash)" unless config.is_a?(Hash)
245
+ config
246
+ else
247
+ require 'etc'
248
+ require 'socket'
249
+ name = Etc.getpwnam(ENV["USER"]).gecos.split(/,/).first rescue nil
250
+ name ||= ENV["USER"]
251
+ email = ENV["USER"] + "@" +
252
+ begin
253
+ Socket.gethostbyname(Socket.gethostname).first
254
+ rescue SocketError
255
+ Socket.gethostname
256
+ end
242
257
 
243
- $config = {
244
- :accounts => {
245
- :default => {
246
- :name => name,
247
- :email => email,
248
- :alternates => [],
249
- :sendmail => "/usr/sbin/sendmail -oem -ti",
250
- :signature => File.join(ENV["HOME"], ".signature")
258
+ config = {
259
+ :accounts => {
260
+ :default => {
261
+ :name => name,
262
+ :email => email,
263
+ :alternates => [],
264
+ :sendmail => "/usr/sbin/sendmail -oem -ti",
265
+ :signature => File.join(ENV["HOME"], ".signature"),
266
+ :gpgkey => ""
267
+ }
268
+ },
269
+ :editor => ENV["EDITOR"] || "/usr/bin/vim -f -c 'setlocal spell spelllang=en_us' -c 'set filetype=mail'",
270
+ :thread_by_subject => false,
271
+ :edit_signature => false,
272
+ :ask_for_from => false,
273
+ :ask_for_to => true,
274
+ :ask_for_cc => true,
275
+ :ask_for_bcc => false,
276
+ :ask_for_subject => true,
277
+ :confirm_no_attachments => true,
278
+ :confirm_top_posting => true,
279
+ :jump_to_open_message => true,
280
+ :discard_snippets_from_encrypted_messages => false,
281
+ :default_attachment_save_dir => "",
282
+ :sent_source => "sup://sent",
283
+ :poll_interval => 300,
284
+ :wrap_width => 0,
285
+ :slip_rows => 0
251
286
  }
252
- },
253
- :editor => ENV["EDITOR"] || "/usr/bin/vim -f -c 'setlocal spell spelllang=en_us' -c 'set filetype=mail'",
254
- :thread_by_subject => false,
255
- :edit_signature => false,
256
- :ask_for_to => true,
257
- :ask_for_cc => true,
258
- :ask_for_bcc => false,
259
- :ask_for_subject => true,
260
- :confirm_no_attachments => true,
261
- :confirm_top_posting => true,
262
- :jump_to_open_message => true,
263
- :discard_snippets_from_encrypted_messages => false,
264
- :default_attachment_save_dir => "",
265
- :sent_source => "sup://sent",
266
- :poll_interval => 300,
267
- :wrap_width => 0
268
- }
269
- begin
270
- FileUtils.mkdir_p Redwood::BASE_DIR
271
- Redwood::save_yaml_obj $config, Redwood::CONFIG_FN
272
- rescue StandardError => e
273
- $stderr.puts "warning: #{e.message}"
287
+ begin
288
+ Redwood::save_yaml_obj config, filename
289
+ rescue StandardError => e
290
+ $stderr.puts "warning: #{e.message}"
291
+ end
292
+ config
293
+ end
274
294
  end
295
+
296
+ module_function :save_yaml_obj, :load_yaml_obj, :start, :finish,
297
+ :report_broken_sources, :check_library_version_against,
298
+ :load_config, :managers
275
299
  end
276
300
 
277
301
  require "sup/util"
278
302
  require "sup/hook"
279
303
 
280
- ## we have to initialize this guy first, because other classes must
281
- ## reference it in order to register hooks, and they do that at parse
282
- ## time.
283
- Redwood::HookManager.init Redwood::HOOK_DIR
284
-
285
304
  ## everything we need to get logging working
286
305
  require "sup/logger"
287
306
  Redwood::Logger.init.add_sink $stderr
288
307
  include Redwood::LogsStuff
289
308
 
290
309
  ## determine encoding and character set
291
- $encoding = Locale.current.charset
292
- if $encoding
293
- debug "using character set encoding #{$encoding.inspect}"
294
- else
295
- warn "can't find character set by using locale, defaulting to utf-8"
296
- $encoding = "UTF-8"
297
- end
310
+ $encoding = Locale.current.charset
311
+ $encoding = "UTF-8" if $encoding == "utf8"
312
+ if $encoding
313
+ debug "using character set encoding #{$encoding.inspect}"
314
+ else
315
+ warn "can't find character set by using locale, defaulting to utf-8"
316
+ $encoding = "UTF-8"
317
+ end
298
318
 
299
319
  require "sup/buffer"
300
320
  require "sup/keymap"
@@ -308,7 +328,6 @@ require "sup/message"
308
328
  require "sup/source"
309
329
  require "sup/mbox"
310
330
  require "sup/maildir"
311
- require "sup/imap"
312
331
  require "sup/person"
313
332
  require "sup/account"
314
333
  require "sup/thread"
@@ -348,7 +367,6 @@ require "sup/sent"
348
367
  require "sup/search"
349
368
  require "sup/modes/search-list-mode"
350
369
  require "sup/idle"
351
- require "sup/connection"
352
370
 
353
371
  $:.each do |base|
354
372
  d = File.join base, "sup/share/modes/"
@@ -1,7 +1,7 @@
1
1
  module Redwood
2
2
 
3
3
  class Account < Person
4
- attr_accessor :sendmail, :signature
4
+ attr_accessor :sendmail, :signature, :gpgkey
5
5
 
6
6
  def initialize h
7
7
  raise ArgumentError, "no name for account" unless h[:name]
@@ -9,6 +9,7 @@ class Account < Person
9
9
  super h[:name], h[:email]
10
10
  @sendmail = h[:sendmail]
11
11
  @signature = h[:signature]
12
+ @gpgkey = h[:gpgkey]
12
13
  end
13
14
 
14
15
  # Default sendmail command for bouncing mail,
@@ -46,7 +47,7 @@ class AccountManager
46
47
  def add_account hash, default=false
47
48
  raise ArgumentError, "no email specified for account" unless hash[:email]
48
49
  unless default
49
- [:name, :sendmail, :signature].each { |k| hash[k] ||= @default_account.send(k) }
50
+ [:name, :sendmail, :signature, :gpgkey].each { |k| hash[k] ||= @default_account.send(k) }
50
51
  end
51
52
  hash[:alternates] ||= []
52
53
 
@@ -100,7 +100,7 @@ class Buffer
100
100
 
101
101
  def redraw status
102
102
  if @dirty
103
- draw status
103
+ draw status
104
104
  else
105
105
  draw_status status
106
106
  end
@@ -130,15 +130,13 @@ class Buffer
130
130
  s ||= ""
131
131
  maxl = @width - x # maximum display width width
132
132
  stringl = maxl # string "length"
133
+
134
+ # fill up the line with blanks to overwrite old screen contents
135
+ @w.mvaddstr y, x, " " * maxl unless opts[:no_fill]
136
+
133
137
  ## the next horribleness is thanks to ruby's lack of widechar support
134
138
  stringl += 1 while stringl < s.length && s[0 ... stringl].display_length < maxl
135
139
  @w.mvaddstr y, x, s[0 ... stringl]
136
- unless opts[:no_fill]
137
- l = s.display_length
138
- unless l >= maxl
139
- @w.mvaddstr(y, x + l, " " * (maxl - l))
140
- end
141
- end
142
140
  end
143
141
 
144
142
  def clear
@@ -228,7 +226,7 @@ EOS
228
226
 
229
227
  def focus_on buf
230
228
  return unless @buffers.member? buf
231
- return if buf == @focus_buf
229
+ return if buf == @focus_buf
232
230
  @focus_buf.blur if @focus_buf
233
231
  @focus_buf = buf
234
232
  @focus_buf.focus
@@ -354,7 +352,7 @@ EOS
354
352
  ## creates a new buffer. returns two things: the buffer, and a boolean
355
353
  ## indicating whether it's a new buffer or not.
356
354
  def spawn_unless_exists title, opts={}
357
- new =
355
+ new =
358
356
  if @name_map.member? title
359
357
  raise_to_front @name_map[title] unless opts[:hidden]
360
358
  false
@@ -455,13 +453,14 @@ EOS
455
453
 
456
454
  def ask_with_completions domain, question, completions, default=nil
457
455
  ask domain, question, default do |s|
458
- completions.select { |x| x =~ /^#{Regexp::escape s}/i }.map { |x| [x, x] }
456
+ s.force_encoding 'UTF-8' if s.methods.include?(:encoding)
457
+ completions.select { |x| x =~ /^#{Regexp::escape s}/iu }.map { |x| [x, x] }
459
458
  end
460
459
  end
461
460
 
462
461
  def ask_many_with_completions domain, question, completions, default=nil
463
462
  ask domain, question, default do |partial|
464
- prefix, target =
463
+ prefix, target =
465
464
  case partial
466
465
  when /^\s*$/
467
466
  ["", ""]
@@ -471,6 +470,8 @@ EOS
471
470
  raise "william screwed up completion: #{partial.inspect}"
472
471
  end
473
472
 
473
+ prefix.force_encoding 'UTF-8' if prefix.methods.include?(:encoding)
474
+ target.force_encoding 'UTF-8' if target.methods.include?(:encoding)
474
475
  completions.select { |x| x =~ /^#{Regexp::escape target}/i }.map { |x| [prefix + x, x] }
475
476
  end
476
477
  end
@@ -479,7 +480,11 @@ EOS
479
480
  ask domain, question, default do |partial|
480
481
  prefix, target = partial.split_on_commas_with_remainder
481
482
  target ||= prefix.pop || ""
483
+ target.force_encoding 'UTF-8' if target.methods.include?(:encoding)
484
+
482
485
  prefix = prefix.join(", ") + (prefix.empty? ? "" : ", ")
486
+ prefix.force_encoding 'UTF-8' if prefix.methods.include?(:encoding)
487
+
483
488
  completions.select { |x| x =~ /^#{Regexp::escape target}/i }.sort_by { |c| [ContactManager.contact_for(c) ? 0 : 1, c] }.map { |x| [prefix + x, x] }
484
489
  end
485
490
  end
@@ -559,6 +564,13 @@ EOS
559
564
  end
560
565
  end
561
566
 
567
+ def ask_for_account domain, question
568
+ completions = AccountManager.user_emails
569
+ answer = BufferManager.ask_many_emails_with_completions domain, question, completions, ""
570
+ answer = AccountManager.default_account.email if answer == ""
571
+ AccountManager.account_for Person.from_address(answer).email if answer
572
+ end
573
+
562
574
  ## for simplicitly, we always place the question at the very bottom of the
563
575
  ## screen
564
576
  def ask domain, question, default=nil, &block
@@ -586,7 +598,7 @@ EOS
586
598
 
587
599
  if tf.new_completions?
588
600
  kill_buffer completion_buf if completion_buf
589
-
601
+
590
602
  shorts = tf.completions.map { |full, short| short }
591
603
  prefix_len = shorts.shared_prefix.length
592
604
 
@@ -603,7 +615,7 @@ EOS
603
615
 
604
616
  Ncurses.sync { Ncurses.refresh }
605
617
  end
606
-
618
+
607
619
  kill_buffer completion_buf if completion_buf
608
620
 
609
621
  @dirty = true
@@ -684,12 +696,12 @@ EOS
684
696
 
685
697
  def minibuf_lines
686
698
  @minibuf_mutex.synchronize do
687
- [(@flash ? 1 : 0) +
699
+ [(@flash ? 1 : 0) +
688
700
  (@asking ? 1 : 0) +
689
701
  @minibuf_stack.compact.size, 1].max
690
702
  end
691
703
  end
692
-
704
+
693
705
  def draw_minibuf opts={}
694
706
  m = nil
695
707
  @minibuf_mutex.synchronize do
@@ -791,7 +803,7 @@ private
791
803
 
792
804
  statusbar_text = HookManager.run("status-bar-text", opts) || default_status_bar(buf)
793
805
  term_title_text = HookManager.run("terminal-title-text", opts) || default_terminal_title(buf)
794
-
806
+
795
807
  [statusbar_text, term_title_text]
796
808
  end
797
809