sup 0.6 → 0.7

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.

data/lib/sup/label.rb CHANGED
@@ -78,7 +78,7 @@ class LabelManager
78
78
 
79
79
  def save
80
80
  return unless @modified
81
- File.open(@fn, "w") { |f| f.puts @labels.keys }
81
+ File.open(@fn, "w") { |f| f.puts @labels.keys.sort_by { |l| l.to_s } }
82
82
  end
83
83
  end
84
84
 
data/lib/sup/mbox.rb CHANGED
@@ -11,7 +11,7 @@ module Redwood
11
11
  ## TODO: move functionality to somewhere better, like message.rb
12
12
  module MBox
13
13
  BREAK_RE = /^From \S+/
14
- HEADER_RE = /\s*(.*?\S)\s*/
14
+ HEADER_RE = /\s*(.*?)\s*/
15
15
 
16
16
  def read_header f
17
17
  header = {}
@@ -21,6 +21,11 @@ module MBox
21
21
  ## when scanning over large mbox files.
22
22
  while(line = f.gets)
23
23
  case line
24
+ ## these three can occur multiple times, and we want the first one
25
+ when /^(Delivered-To):#{HEADER_RE}$/i,
26
+ /^(X-Original-To):#{HEADER_RE}$/i,
27
+ /^(Envelope-To):#{HEADER_RE}$/i: header[last = $1] ||= $2
28
+
24
29
  when /^(From):#{HEADER_RE}$/i,
25
30
  /^(To):#{HEADER_RE}$/i,
26
31
  /^(Cc):#{HEADER_RE}$/i,
@@ -33,15 +38,10 @@ module MBox
33
38
  /^(List-Post):#{HEADER_RE}$/i,
34
39
  /^(List-Subscribe):#{HEADER_RE}$/i,
35
40
  /^(List-Unsubscribe):#{HEADER_RE}$/i,
36
- /^(Status):#{HEADER_RE}$/i: header[last = $1] = $2
41
+ /^(Status):#{HEADER_RE}$/i,
42
+ /^(X-\S+):#{HEADER_RE}$/: header[last = $1] = $2
37
43
  when /^(Message-Id):#{HEADER_RE}$/i: header[mid_field = last = $1] = $2
38
44
 
39
- ## these next three can occur multiple times, and we want the
40
- ## first one
41
- when /^(Delivered-To):#{HEADER_RE}$/i,
42
- /^(X-Original-To):#{HEADER_RE}$/i,
43
- /^(Envelope-To):#{HEADER_RE}$/i: header[last = $1] ||= $2
44
-
45
45
  when /^\r*$/: break
46
46
  when /^\S+:/: last = nil # some other header we don't care about
47
47
  else
@@ -41,6 +41,8 @@ end
41
41
 
42
42
  module Redwood
43
43
  module Chunk
44
+ WRAP_LEN = 80 # wrap messages and text attachments at this width
45
+
44
46
  class Attachment
45
47
  HookManager.register "mime-decode", <<EOS
46
48
  Executes when decoding a MIME attachment.
@@ -95,6 +97,7 @@ EOS
95
97
  @lines = nil
96
98
  if text
97
99
  @lines = text.gsub("\r\n", "\n").gsub(/\t/, " ").gsub(/\r/, "").split("\n")
100
+ @lines = lines.map {|l| l.chomp.wrap WRAP_LEN}.flatten
98
101
  @quotable = true
99
102
  end
100
103
  end
@@ -116,7 +119,7 @@ EOS
116
119
  def initial_state; :open end
117
120
  def viewable?; @lines.nil? end
118
121
  def view_default! path
119
- cmd = "/usr/bin/run-mailcap --action=view '#{@content_type}:#{path}' > /dev/null 2> /dev/null"
122
+ cmd = "/usr/bin/run-mailcap --action=view '#{@content_type}:#{path}' 2>/dev/null"
120
123
  Redwood::log "running: #{cmd.inspect}"
121
124
  system cmd
122
125
  $? == 0
@@ -143,7 +146,6 @@ EOS
143
146
  end
144
147
 
145
148
  class Text
146
- WRAP_LEN = 80 # wrap at this width
147
149
 
148
150
  attr_reader :lines
149
151
  def initialize lines
@@ -206,7 +208,7 @@ EOS
206
208
  def inlineable?; false end
207
209
  def quotable?; false end
208
210
  def expandable?; true end
209
- def initial_state; :open end
211
+ def initial_state; :closed end
210
212
  def viewable?; false end
211
213
 
212
214
  def patina_color; :generic_notice_patina_color end
data/lib/sup/message.rb CHANGED
@@ -64,7 +64,7 @@ class Message
64
64
  end
65
65
 
66
66
  def parse_header header
67
- header.each { |k, v| header[k.downcase] = v }
67
+ header.keys.each { |k| header[k.downcase] = header[k] } # canonicalize
68
68
 
69
69
  fakeid = nil
70
70
  fakename = nil
@@ -392,7 +392,8 @@ private
392
392
  payload = RMail::Parser.read(m.body)
393
393
  from = payload.header.from.first
394
394
  from_person = from ? PersonManager.person_for(from.format) : nil
395
- [Chunk::EnclosedMessage.new(from_person, payload.to_s)]
395
+ [Chunk::EnclosedMessage.new(from_person, payload.to_s)] +
396
+ message_to_chunks(payload, encrypted)
396
397
  else
397
398
  filename =
398
399
  ## first, paw through the headers looking for a filename
@@ -433,11 +434,10 @@ private
433
434
  end
434
435
 
435
436
  def self.convert_from body, charset
436
- charset = "utf-8" if charset =~ /UTF_?8/i
437
437
  begin
438
438
  raise MessageFormatError, "RubyMail decode returned a null body" unless body
439
439
  return body unless charset
440
- Iconv.iconv($encoding + "//IGNORE", charset, body + " ").join[0 .. -2]
440
+ Iconv.easy_decode($encoding, charset, body)
441
441
  rescue Errno::EINVAL, Iconv::InvalidEncoding, Iconv::IllegalSequence, MessageFormatError => e
442
442
  Redwood::log "warning: error (#{e.class.name}) decoding message body from #{charset}: #{e.message}"
443
443
  File.open(File.join(BASE_DIR,"unable-to-decode.txt"), "w") { |f| f.write body }
@@ -386,6 +386,7 @@ EOS
386
386
  end
387
387
 
388
388
  def save
389
+ BufferManager.say("Saving contacts...") { ContactManager.instance.save }
389
390
  dirty_threads = @mutex.synchronize { (@threads + @hidden_threads.keys).select { |t| t.dirty? } }
390
391
  return if dirty_threads.empty?
391
392
 
@@ -566,7 +567,7 @@ protected
566
567
  def add_or_unhide m
567
568
  @ts_mutex.synchronize do
568
569
  if (is_relevant?(m) || @ts.is_relevant?(m)) && !@ts.contains?(m)
569
- @ts.load_thread_for_message m
570
+ @ts.load_thread_for_message m, @load_thread_opts
570
571
  end
571
572
 
572
573
  @hidden_threads.delete @ts.thread_for(m)
@@ -30,6 +30,7 @@ EOS
30
30
  k.add :activate_chunk, "Expand/collapse or activate item", :enter
31
31
  k.add :expand_all_messages, "Expand/collapse all messages", 'E'
32
32
  k.add :edit_draft, "Edit draft", 'e'
33
+ k.add :send_draft, "Send draft", 'y'
33
34
  k.add :edit_labels, "Edit or add labels for a thread", 'l'
34
35
  k.add :expand_all_quotes, "Expand/collapse all quotes in a message", 'o'
35
36
  k.add :jump_to_next_open, "Jump to next open message", 'n'
@@ -259,7 +260,8 @@ EOS
259
260
  chunk = @chunk_lines[curpos] or return
260
261
  case chunk
261
262
  when Chunk::Attachment
262
- fn = BufferManager.ask_for_filename :filename, "Save attachment to file: ", chunk.filename
263
+ default_dir = File.join(($config[:default_attachment_save_dir] || "."), chunk.filename)
264
+ fn = BufferManager.ask_for_filename :filename, "Save attachment to file: ", default_dir
263
265
  save_to_file(fn) { |f| f.print chunk.raw_content } if fn
264
266
  else
265
267
  m = @message_lines[curpos]
@@ -283,6 +285,18 @@ EOS
283
285
  end
284
286
  end
285
287
 
288
+ def send_draft
289
+ m = @message_lines[curpos] or return
290
+ if m.is_draft?
291
+ mode = ResumeMode.new m
292
+ BufferManager.spawn "Send message", mode
293
+ BufferManager.kill_buffer self.buffer
294
+ mode.send_message
295
+ else
296
+ BufferManager.flash "Not a draft message!"
297
+ end
298
+ end
299
+
286
300
  def jump_to_first_open loose_alignment=false
287
301
  m = @message_lines[0] or return
288
302
  if @layout[m].state != :closed
@@ -642,7 +656,7 @@ private
642
656
  [[[:missing_message_color, "#{prefix}<an unreceived message>"]]]
643
657
  when Message
644
658
  message_patina_lines(chunk, state, start, parent, prefix, color, star_color) +
645
- (chunk.is_draft? ? [[[:draft_notification_color, prefix + " >>> This message is a draft. To edit, hit 'e'. <<<"]]] : [])
659
+ (chunk.is_draft? ? [[[:draft_notification_color, prefix + " >>> This message is a draft. Hit 'e' to edit, 'y' to send. <<<"]]] : [])
646
660
 
647
661
  else
648
662
  raise "Bad chunk: #{chunk.inspect}" unless chunk.respond_to?(:inlineable?) ## debugging
data/lib/sup/rfc2047.rb CHANGED
@@ -52,13 +52,8 @@ module Rfc2047
52
52
  # WORD.
53
53
  end
54
54
 
55
- charset = "utf-8" if charset =~ /UTF_?8/i
56
-
57
- # Convert:
58
- #
59
- # Remember - Iconv.open(to, from)!
60
55
  begin
61
- text = Iconv.iconv(target + "//IGNORE", charset, text + " ").join[0 .. -2]
56
+ Iconv.easy_decode(target, charset, text)
62
57
  rescue Iconv::InvalidCharacter
63
58
  text
64
59
  end
data/lib/sup/textfield.rb CHANGED
@@ -33,7 +33,7 @@ class TextField
33
33
  @w, @y, @x, @width = window, y, x, width
34
34
  @question = question
35
35
  @completion_block = block
36
- @field = Ncurses::Form.new_field 1, @width - question.length, @y, @x + question.length, 0, 0
36
+ @field = Ncurses::Form.new_field 1, @width - question.length, @y, @x + question.length, 256, 0
37
37
  @form = Ncurses::Form.new_form [@field]
38
38
  @value = default
39
39
  Ncurses::Form.post_form @form
data/lib/sup/util.rb CHANGED
@@ -617,3 +617,20 @@ class FinishLine
617
617
  @m.synchronize { !@over && @over = true }
618
618
  end
619
619
  end
620
+
621
+ class Iconv
622
+ def self.easy_decode target, charset, text
623
+ return text if charset =~ /^(x-unknown|unknown[-_]?8bit|ascii[-_]?7[-_]?bit)$/i
624
+ charset = case charset
625
+ when /UTF[-_]?8/i: "utf-8"
626
+ when /(iso[-_])?latin[-_]?1$/i: "ISO-8859-1"
627
+ when /unicode[-_]1[-_]1[-_]utf[-_]7/i: "utf-7"
628
+ else charset
629
+ end
630
+
631
+ # Convert:
632
+ #
633
+ # Remember - Iconv.open(to, from)!
634
+ Iconv.iconv(target + "//IGNORE", charset, text + " ").join[0 .. -2]
635
+ end
636
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sup
3
3
  version: !ruby/object:Gem::Version
4
- version: "0.6"
4
+ version: "0.7"
5
5
  platform: ruby
6
6
  authors:
7
7
  - William Morgan
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-08-03 00:00:00 -07:00
12
+ date: 2009-03-25 06:21:53 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -20,7 +20,7 @@ dependencies:
20
20
  requirements:
21
21
  - - ">="
22
22
  - !ruby/object:Gem::Version
23
- version: 0.10.13
23
+ version: 0.11.6
24
24
  version:
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: ncurses
@@ -70,7 +70,7 @@ dependencies:
70
70
  requirements:
71
71
  - - ">="
72
72
  - !ruby/object:Gem::Version
73
- version: "1.7"
73
+ version: "1.12"
74
74
  version:
75
75
  - !ruby/object:Gem::Dependency
76
76
  name: lockfile
@@ -88,9 +88,9 @@ dependencies:
88
88
  version_requirement:
89
89
  version_requirements: !ruby/object:Gem::Requirement
90
90
  requirements:
91
- - - ">="
91
+ - - ~>
92
92
  - !ruby/object:Gem::Version
93
- version: "0"
93
+ version: "1"
94
94
  version:
95
95
  - !ruby/object:Gem::Dependency
96
96
  name: gettext
@@ -112,16 +112,6 @@ dependencies:
112
112
  - !ruby/object:Gem::Version
113
113
  version: "0"
114
114
  version:
115
- - !ruby/object:Gem::Dependency
116
- name: hoe
117
- type: :development
118
- version_requirement:
119
- version_requirements: !ruby/object:Gem::Requirement
120
- requirements:
121
- - - ">="
122
- - !ruby/object:Gem::Version
123
- version: 1.7.0
124
- version:
125
115
  description: "Sup is a console-based email client for people with a lot of email. It supports tagging, very fast full-text search, automatic contact-list management, and more. If you're the type of person who treats email as an extension of your long-term memory, Sup is for you. Sup makes it easy to: - Handle massive amounts of email. - Mix email from different sources: mbox files (even across different machines), Maildir directories, IMAP folders, POP accounts, and GMail accounts. - Instantaneously search over your entire email collection. Search over body text, or use a query language to combine search predicates in any way. - Handle multiple accounts. Replying to email sent to a particular account will use the correct SMTP server, signature, and from address. - Add custom code to handle certain types of messages or to handle certain types of text within messages. - Organize email with user-defined labels, automatically track recent contacts, and much more! The goal of Sup is to become the email client of choice for nerds everywhere."
126
116
  email: wmorgan-sup@masanjin.net
127
117
  executables:
@@ -135,22 +125,13 @@ executables:
135
125
  - sup-tweak-labels
136
126
  extensions: []
137
127
 
138
- extra_rdoc_files:
139
- - History.txt
140
- - Manifest.txt
141
- - README.txt
142
- - doc/FAQ.txt
143
- - doc/Hooks.txt
144
- - doc/NewUserGuide.txt
145
- - doc/Philosophy.txt
128
+ extra_rdoc_files: []
129
+
146
130
  files:
147
131
  - CONTRIBUTORS
148
- - HACKING
149
- - History.txt
150
- - LICENSE
151
- - Manifest.txt
152
132
  - README.txt
153
- - Rakefile
133
+ - LICENSE
134
+ - History.txt
154
135
  - ReleaseNotes
155
136
  - bin/sup
156
137
  - bin/sup-add
@@ -160,71 +141,66 @@ files:
160
141
  - bin/sup-sync
161
142
  - bin/sup-sync-back
162
143
  - bin/sup-tweak-labels
163
- - doc/FAQ.txt
164
- - doc/Hooks.txt
165
- - doc/NewUserGuide.txt
166
- - doc/Philosophy.txt
167
144
  - lib/sup.rb
145
+ - lib/sup/draft.rb
146
+ - lib/sup/imap.rb
147
+ - lib/sup/thread.rb
148
+ - lib/sup/logger.rb
149
+ - lib/sup/person.rb
150
+ - lib/sup/rfc2047.rb
168
151
  - lib/sup/account.rb
169
152
  - lib/sup/buffer.rb
153
+ - lib/sup/horizontal-selector.rb
154
+ - lib/sup/textfield.rb
155
+ - lib/sup/source.rb
156
+ - lib/sup/suicide.rb
157
+ - lib/sup/maildir.rb
158
+ - lib/sup/tagger.rb
170
159
  - lib/sup/colormap.rb
171
- - lib/sup/contact.rb
172
- - lib/sup/crypto.rb
173
- - lib/sup/draft.rb
174
160
  - lib/sup/hook.rb
175
- - lib/sup/horizontal-selector.rb
176
- - lib/sup/imap.rb
177
161
  - lib/sup/index.rb
178
- - lib/sup/keymap.rb
162
+ - lib/sup/update.rb
163
+ - lib/sup/util.rb
164
+ - lib/sup/message-chunks.rb
179
165
  - lib/sup/label.rb
180
- - lib/sup/logger.rb
181
- - lib/sup/maildir.rb
182
166
  - lib/sup/mbox.rb
183
- - lib/sup/mbox/loader.rb
184
- - lib/sup/mbox/ssh-file.rb
185
- - lib/sup/mbox/ssh-loader.rb
186
- - lib/sup/message-chunks.rb
167
+ - lib/sup/poll.rb
187
168
  - lib/sup/message.rb
169
+ - lib/sup/crypto.rb
170
+ - lib/sup/sent.rb
188
171
  - lib/sup/mode.rb
189
- - lib/sup/modes/buffer-list-mode.rb
190
- - lib/sup/modes/completion-mode.rb
191
- - lib/sup/modes/compose-mode.rb
192
- - lib/sup/modes/contact-list-mode.rb
193
- - lib/sup/modes/edit-message-mode.rb
194
- - lib/sup/modes/file-browser-mode.rb
195
- - lib/sup/modes/forward-mode.rb
196
- - lib/sup/modes/help-mode.rb
197
- - lib/sup/modes/inbox-mode.rb
198
- - lib/sup/modes/label-list-mode.rb
172
+ - lib/sup/contact.rb
173
+ - lib/sup/keymap.rb
174
+ - lib/sup/modes/resume-mode.rb
175
+ - lib/sup/modes/poll-mode.rb
176
+ - lib/sup/modes/thread-view-mode.rb
199
177
  - lib/sup/modes/label-search-results-mode.rb
200
- - lib/sup/modes/line-cursor-mode.rb
178
+ - lib/sup/modes/label-list-mode.rb
179
+ - lib/sup/modes/help-mode.rb
201
180
  - lib/sup/modes/log-mode.rb
181
+ - lib/sup/modes/edit-message-mode.rb
182
+ - lib/sup/modes/forward-mode.rb
202
183
  - lib/sup/modes/person-search-results-mode.rb
203
- - lib/sup/modes/poll-mode.rb
204
- - lib/sup/modes/reply-mode.rb
205
- - lib/sup/modes/resume-mode.rb
184
+ - lib/sup/modes/inbox-mode.rb
185
+ - lib/sup/modes/buffer-list-mode.rb
206
186
  - lib/sup/modes/scroll-mode.rb
207
187
  - lib/sup/modes/search-results-mode.rb
208
- - lib/sup/modes/text-mode.rb
188
+ - lib/sup/modes/compose-mode.rb
189
+ - lib/sup/modes/line-cursor-mode.rb
209
190
  - lib/sup/modes/thread-index-mode.rb
210
- - lib/sup/modes/thread-view-mode.rb
211
- - lib/sup/person.rb
212
- - lib/sup/poll.rb
213
- - lib/sup/rfc2047.rb
214
- - lib/sup/sent.rb
215
- - lib/sup/source.rb
216
- - lib/sup/suicide.rb
217
- - lib/sup/tagger.rb
218
- - lib/sup/textfield.rb
219
- - lib/sup/thread.rb
220
- - lib/sup/update.rb
221
- - lib/sup/util.rb
222
- has_rdoc: true
223
- homepage: http://sup.rubyforge.org
191
+ - lib/sup/modes/contact-list-mode.rb
192
+ - lib/sup/modes/completion-mode.rb
193
+ - lib/sup/modes/file-browser-mode.rb
194
+ - lib/sup/modes/reply-mode.rb
195
+ - lib/sup/modes/text-mode.rb
196
+ - lib/sup/mbox/ssh-loader.rb
197
+ - lib/sup/mbox/loader.rb
198
+ - lib/sup/mbox/ssh-file.rb
199
+ has_rdoc: false
200
+ homepage: http://sup.rubyforge.org/
224
201
  post_install_message:
225
- rdoc_options:
226
- - --main
227
- - README.txt
202
+ rdoc_options: []
203
+
228
204
  require_paths:
229
205
  - lib
230
206
  required_ruby_version: !ruby/object:Gem::Requirement
@@ -241,11 +217,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
241
217
  version:
242
218
  requirements: []
243
219
 
244
- rubyforge_project: sup
220
+ rubyforge_project:
245
221
  rubygems_version: 1.2.0
246
222
  signing_key:
247
223
  specification_version: 2
248
224
  summary: A console-based email client with the best features of GMail, mutt, and emacs. Features full text search, labels, tagged operations, multiple buffers, recent contacts, and more.
249
- test_files:
250
- - test/test_message.rb
251
- - test/test_mbox_parsing.rb
225
+ test_files: []
226
+