sup 0.0.7 → 0.0.8
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/History.txt +14 -1
- data/Manifest.txt +4 -1
- data/README.txt +13 -7
- data/Rakefile +3 -3
- data/bin/sup +17 -8
- data/bin/sup-add +20 -14
- data/bin/sup-config +222 -0
- data/bin/sup-dump +31 -0
- data/bin/sup-sync +235 -0
- data/doc/FAQ.txt +52 -25
- data/doc/Philosophy.txt +19 -19
- data/doc/TODO +37 -11
- data/doc/UserGuide.txt +42 -41
- data/lib/sup.rb +48 -4
- data/lib/sup/buffer.rb +22 -5
- data/lib/sup/draft.rb +2 -2
- data/lib/sup/imap.rb +20 -30
- data/lib/sup/index.rb +42 -54
- data/lib/sup/logger.rb +1 -1
- data/lib/sup/maildir.rb +127 -0
- data/lib/sup/mbox/loader.rb +40 -38
- data/lib/sup/mbox/ssh-file.rb +16 -25
- data/lib/sup/mbox/ssh-loader.rb +2 -11
- data/lib/sup/message.rb +14 -8
- data/lib/sup/mode.rb +1 -1
- data/lib/sup/modes/edit-message-mode.rb +1 -1
- data/lib/sup/modes/inbox-mode.rb +4 -1
- data/lib/sup/modes/line-cursor-mode.rb +3 -2
- data/lib/sup/modes/reply-mode.rb +1 -1
- data/lib/sup/modes/thread-index-mode.rb +6 -6
- data/lib/sup/modes/thread-view-mode.rb +24 -11
- data/lib/sup/poll.rb +45 -36
- data/lib/sup/sent.rb +3 -3
- data/lib/sup/source.rb +29 -47
- data/lib/sup/thread.rb +1 -1
- data/lib/sup/util.rb +30 -5
- metadata +12 -7
- data/bin/sup-import +0 -159
data/doc/TODO
CHANGED
@@ -1,29 +1,53 @@
|
|
1
1
|
for 0.0.8
|
2
2
|
---------
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
3
|
+
x nice little startup config program
|
4
|
+
x bugfix: triggering a pageup when cursor scrolling up jumps to the
|
5
|
+
bottom of the page rather than the next line
|
6
|
+
x bugfix: final logging messages to stdout?
|
7
|
+
x bugfix: mbox directory shouldn't generate an exception, just an error
|
8
|
+
x bugfix: m in thread-view-mode when a person is not selected should open up a
|
9
|
+
blank compose-mode rather than do nothing
|
10
|
+
x bugfix: stars on messages with blue backgrounds still have green bgs
|
11
|
+
x ferret upgrade script (dump & restore)
|
12
|
+
x bugfix: mark messages as read immediately when t-v-m is opened
|
13
|
+
x compose in thread-view-mode auto-fills in person
|
14
|
+
x bugfix: 'N' in thread-view-mode (expand only new messages) crashes
|
15
|
+
x bugfix: detect source corruption at startup
|
16
|
+
x maildir
|
17
|
+
x bugfix: single-line messages come empty upon reply
|
7
18
|
|
8
|
-
|
19
|
+
next release
|
20
|
+
------------
|
21
|
+
_ bugfix: when one new message comes into an imap folder, we don't
|
22
|
+
catch it until a reload (sometimes?)
|
23
|
+
_ bugfix: add new message counts until keypress
|
24
|
+
_ bugfix: attachment filenames sometimes not detected (filename=)
|
25
|
+
_ split out threading & message chunk parsing to a separate library
|
26
|
+
|
27
|
+
near future
|
9
28
|
---------
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
29
|
+
_ Net::SMTP support (cuz I'm going to need it soon)
|
30
|
+
_ create attachments
|
31
|
+
_ forward attachments
|
32
|
+
_ select all, starred, to me, etc
|
33
|
+
_ undo
|
34
|
+
_ gmail
|
35
|
+
_ warnings: top-posting, missing attachment, ruby-talk:XXXX detection
|
36
|
+
_ mboxz, mboxbz
|
14
37
|
|
15
38
|
future
|
16
39
|
------
|
40
|
+
search results: highlight relevant snippets and open to relevant portion of thread
|
41
|
+
email address to name mapping needs some work. automatic email addresses (noreply@...) are often assigned to something screwy.
|
17
42
|
decode RFC 2047 ("encoded word") headers
|
18
43
|
- see: http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/101949, http://dev.rubyonrails.org/ticket/6807
|
19
44
|
swappable keymappings
|
20
45
|
within-buffer search
|
21
46
|
bugfix: when returning from a shelling out, ncurses is crazy
|
22
|
-
|
47
|
+
more control character support in buffer line editing
|
23
48
|
wide character support
|
24
49
|
i18n support
|
25
50
|
batch deletion
|
26
|
-
support for message-content modules such as ruby-talk:XXXXX detection
|
27
51
|
tab completion on labels, contacts
|
28
52
|
contact selector in edit-message-mode
|
29
53
|
maybe: filters
|
@@ -33,6 +57,7 @@ pop
|
|
33
57
|
be able to mark individual messages as spam in thread-view-mode
|
34
58
|
toggle wrapping
|
35
59
|
maybe: de-archived messages auto-added to inbox
|
60
|
+
prune old entries from contacts.txt so that it doesn't arbitrarily
|
36
61
|
|
37
62
|
done
|
38
63
|
----
|
@@ -82,3 +107,4 @@ x highlighting/different color stuff
|
|
82
107
|
x config: your email, sendmail, etc
|
83
108
|
x status: to/from_you, cc_you_others
|
84
109
|
x status: new/not, important
|
110
|
+
x bugfix: miscellaneous weirdnesses in buffer line editing
|
data/doc/UserGuide.txt
CHANGED
@@ -26,12 +26,21 @@ for messages or view your inbox, Sup talks only to the index (stored
|
|
26
26
|
locally on disk). When you view a thread, Sup requests the full
|
27
27
|
content of all the messages from the source.
|
28
28
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
29
|
+
The easiest way to set up all your sources is to run "sup-config".
|
30
|
+
This will interactively walk you through some basic configuration,
|
31
|
+
prompt you for all the sources you need, and optionally import
|
32
|
+
messages from them.
|
33
|
+
|
34
|
+
sup-config works by calling sup-add and sup-sync with the right
|
35
|
+
arguments. If you have a non-trivial setup, you may need to run
|
36
|
+
sup-add and sup-sync manually.
|
37
|
+
|
38
|
+
You can manually add a source to Sup's source list by running
|
39
|
+
'sup-add' with a URI pointing to it. The URI should be of the form:
|
40
|
+
- mbox://path/to/a/filename, for an mbox file on disk.
|
41
|
+
- maildir://path/to/a/filename, for an maildir directory on disk.
|
42
|
+
- imap://imap.server/folder for an unsecure IMAP folder.
|
43
|
+
- imaps://secure.imap.server/folder for a secure IMAP folder.
|
35
44
|
- mbox+ssh://remote.machine/path/to/a/filename for a remote mbox file.
|
36
45
|
|
37
46
|
Before you add the source, you need make two decisions. The first is
|
@@ -46,39 +55,33 @@ inbox, but will be found when you search. (Your inbox in Sup is, by
|
|
46
55
|
definition, the set of all all non-archived messages). Specify
|
47
56
|
--archive to automatically archive all messages from the source. This
|
48
57
|
is useful for sources that contain, for example, high-traffic mailing
|
49
|
-
lists that you don't want
|
58
|
+
lists that you don't want polluting your inbox.
|
50
59
|
|
51
60
|
If Sup requires account information, e.g. for IMAP servers and remote
|
52
61
|
mbox files, sup-add will ask for it.
|
53
62
|
|
54
63
|
Now that you've added the source, let's import all the current
|
55
|
-
messages from it, by running sup-
|
64
|
+
messages from it, by running sup-sync with the source URI. You can
|
56
65
|
specify --archive to automatically archive all messages in this
|
57
66
|
import; typically you'll want to specify this for every source you
|
58
67
|
import except your actual inbox. You can also specify --read to mark
|
59
68
|
all imported messages as read; the default is to preserve the
|
60
69
|
read/unread status from the source.
|
61
70
|
|
62
|
-
sup-
|
71
|
+
sup-sync will now load all the messages from the source into the
|
63
72
|
index. Depending on the size of the source, this may take a
|
64
73
|
while. Don't panic! It's a one-time process.
|
65
74
|
|
66
|
-
We're almost ready. But before we run 'sup' again, take a moment to
|
67
|
-
edit your ~/.sup/config.yaml file. Replace "Your Name Here" with your
|
68
|
-
name, "your.email.here@domain.tld" with your email address, and fill
|
69
|
-
in your .signature file if you choose. You can also set the default
|
70
|
-
editor.
|
71
|
-
|
72
75
|
Ok, now run 'sup'. You should see the most recent unarchived messages
|
73
76
|
appear in your inbox. Congratulations, you've got Sup working!
|
74
77
|
|
75
|
-
If you're coming from the world of traditional
|
78
|
+
If you're coming from the world of traditional MUAs, there are a
|
76
79
|
couple differences you should be aware of at this point. First, Sup
|
77
80
|
does not use folders. Instead, you organize and find messages by a
|
78
81
|
combination of search and labels (knowns as 'tags' everywhere else in
|
79
|
-
the world). I
|
82
|
+
the world). I claim that 95% of the functionality of folders is
|
80
83
|
superceded by a quick, easy-to-access, and powerful search mechanism,
|
81
|
-
and the other 5% by labels. (The Sup
|
84
|
+
and the other 5% by labels. (The Sup philosophical treatise has a
|
82
85
|
little more on this.)
|
83
86
|
|
84
87
|
Search and labels are an integral part of Sup because in Sup, rather
|
@@ -96,18 +99,18 @@ life can be easier than that if you just trust the search engine, and
|
|
96
99
|
use labels judiciously for things that are too hard to find with
|
97
100
|
search.
|
98
101
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
102
|
+
Now let's take a look at your inbox. You'll see that Sup groups
|
103
|
+
messages together into threads: each line in the inbox is a thread,
|
104
|
+
and the number in parentheses is the number of messages in that
|
105
|
+
thread. (If there's no number, there's just one message.) In Sup, most
|
106
|
+
operations are on threads, not individual messages. The idea is that
|
107
|
+
you rarely want to operate on a message independent of its context.
|
108
|
+
You typically want to view, archive, kill, or label all the messages
|
109
|
+
in a thread at one time.
|
107
110
|
|
108
111
|
Use the up and down arrows to highlight a thread. ('j' and 'k' do the
|
109
112
|
same thing, and 'J' and 'K' will scroll the whole window. Even the
|
110
|
-
left and right arrow keys work
|
113
|
+
left and right arrow keys work.) By default, Sup only loads as many
|
111
114
|
threads as it takes to fill the window; if you'd like to load more,
|
112
115
|
press 'M'. You can hit tab to cycle between only threads with new
|
113
116
|
messages.
|
@@ -122,19 +125,18 @@ to expand or collapse all messages or 'N' to expand only the new
|
|
122
125
|
messages. You'll also notice that Sup hides quoted text and
|
123
126
|
signatures. If you highlight a particular hidden chunk, you can press
|
124
127
|
enter to expand it, or you can press 'o' to toggle every hidden chunk
|
125
|
-
in a particular message. (
|
126
|
-
|
127
|
-
any point.)
|
128
|
+
in a particular message. (You can hit '?' to see the full list of
|
129
|
+
keyboard commands at any point.)
|
128
130
|
|
129
131
|
A few other useful commands while viewing a thread. Press 'd' to
|
130
132
|
toggle a detailed header fpr a message. If you've scrolled too far to
|
131
133
|
the right, press '[' to jump all the way to the left. Finally, you can
|
132
134
|
press 'n' and 'p' to jump forward and backward between open
|
133
|
-
messages
|
135
|
+
messages, aligning the display as necessary.
|
134
136
|
|
135
137
|
Now press 'x' to kill the thread view buffer. You should see the inbox
|
136
138
|
again. If you don't, you can cycle through the buffers by pressing
|
137
|
-
'b', or you can press '
|
139
|
+
'b', or you can press 'B' to see a list of all buffers and simply
|
138
140
|
select the inbox.
|
139
141
|
|
140
142
|
There are many operations you can perform on threads beyond viewing
|
@@ -190,11 +192,11 @@ details on more sophisticated queries (date ranges, "within n words",
|
|
190
192
|
etc.)
|
191
193
|
|
192
194
|
At this point, you're well on your way to figuring out all the cool
|
193
|
-
things Sup can do. By repeated
|
195
|
+
things Sup can do. By repeated application of the '?' key, see if you
|
194
196
|
can figure out how to:
|
195
197
|
- List some recent contacts
|
196
198
|
- Easily search for all mail from a recent contact
|
197
|
-
- Easily search for all mail from several recent contacts
|
199
|
+
- Easily search for all mail from several recent contacts
|
198
200
|
- Add someone to your address book
|
199
201
|
- Postpone a message (i.e., save a draft)
|
200
202
|
- Quickly re-edit a just-saved draft message
|
@@ -203,11 +205,10 @@ can figure out how to:
|
|
203
205
|
|
204
206
|
There's one last thing to be aware of when using Sup: how it interacts
|
205
207
|
with other email programs. Sup stores data about messages in the
|
206
|
-
index
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
be unable to operate on that source.
|
208
|
+
index, but doesn't duplicate the message contents themselves. The
|
209
|
+
messages remain on the source. If the index and the source every fall
|
210
|
+
out of sync, e.g. due to another email client modifying the source,
|
211
|
+
then Sup will be unable to operate on that source.
|
211
212
|
|
212
213
|
For example, for mbox files, Sup stores a byte offset into the file
|
213
214
|
for each message. If a message deleted from that file by another
|
@@ -216,8 +217,8 @@ offsets will be wrong.
|
|
216
217
|
|
217
218
|
That's the bad news. The good news is that Sup is fairly good at being
|
218
219
|
able to detect this type of situation, and fixing it is just a matter
|
219
|
-
of running sup-
|
220
|
-
how to invoke sup-
|
220
|
+
of running sup-sync --changed on the source. Sup will even tell you
|
221
|
+
how to invoke sup-sync when it detects a problem. This is a
|
221
222
|
complication you will almost certainly run in to if you use both Sup
|
222
223
|
and another MUA on the same source, so it's good to be aware of it.
|
223
224
|
|
data/lib/sup.rb
CHANGED
@@ -13,7 +13,7 @@ class Object
|
|
13
13
|
end
|
14
14
|
|
15
15
|
module Redwood
|
16
|
-
VERSION = "0.0.
|
16
|
+
VERSION = "0.0.8"
|
17
17
|
|
18
18
|
BASE_DIR = ENV["SUP_BASE"] || File.join(ENV["HOME"], ".sup")
|
19
19
|
CONFIG_FN = File.join(BASE_DIR, "config.yaml")
|
@@ -93,9 +93,52 @@ module Redwood
|
|
93
93
|
Redwood::LabelManager.save
|
94
94
|
Redwood::ContactManager.save
|
95
95
|
Redwood::PersonManager.save
|
96
|
+
Redwood::BufferManager.deinstantiate!
|
96
97
|
end
|
97
98
|
|
98
|
-
|
99
|
+
## not really a good place for this, so I'll just dump it here.
|
100
|
+
def report_broken_sources opts={}
|
101
|
+
return unless BufferManager.instantiated?
|
102
|
+
|
103
|
+
broken_sources = Index.usual_sources.select { |s| s.error.is_a? FatalSourceError }
|
104
|
+
unless broken_sources.empty?
|
105
|
+
BufferManager.spawn "Broken source notification", TextMode.new(<<EOM), opts
|
106
|
+
Source error notification
|
107
|
+
-------------------------
|
108
|
+
|
109
|
+
Hi there. It looks like one or more message sources is reporting
|
110
|
+
errors. Until this is corrected, messages from these sources cannot
|
111
|
+
be viewed, and new messages will not be detected.
|
112
|
+
|
113
|
+
#{broken_sources.map { |s| "Source: " + s.to_s + "\n Error: " + s.error.message.wrap(70).join("\n ")}.join('\n\n')}
|
114
|
+
EOM
|
115
|
+
#' stupid ruby-mode
|
116
|
+
end
|
117
|
+
|
118
|
+
desynced_sources = Index.usual_sources.select { |s| s.error.is_a? OutOfSyncSourceError }
|
119
|
+
unless desynced_sources.empty?
|
120
|
+
BufferManager.spawn "Out-of-sync source notification", TextMode.new(<<EOM), opts
|
121
|
+
Out-of-sync source notification
|
122
|
+
-------------------------------
|
123
|
+
|
124
|
+
Hi there. It looks like one or more sources has fallen out of sync
|
125
|
+
with my index. This can happen when you modify these sources with
|
126
|
+
other email clients. (Sorry, I don't play well with others.)
|
127
|
+
|
128
|
+
Until this is corrected, messages from these sources cannot be viewed,
|
129
|
+
and new messages will not be detected. Luckily, this is easy to correct!
|
130
|
+
|
131
|
+
#{desynced_sources.map do |s|
|
132
|
+
"Source: " + s.to_s +
|
133
|
+
"\n Error: " + s.error.message.wrap(70).join("\n ") +
|
134
|
+
"\n Fix: sup-sync --changed #{s.to_s}"
|
135
|
+
end}
|
136
|
+
EOM
|
137
|
+
#' stupid ruby-mode
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
module_function :register_yaml, :save_yaml_obj, :load_yaml_obj, :start, :finish, :report_broken_sources
|
99
142
|
end
|
100
143
|
|
101
144
|
## set up default configuration file
|
@@ -105,8 +148,8 @@ else
|
|
105
148
|
$config = {
|
106
149
|
:accounts => {
|
107
150
|
:default => {
|
108
|
-
:name => "
|
109
|
-
:email => "
|
151
|
+
:name => "Sup Rocks",
|
152
|
+
:email => "sup-rocks@reading-my-emails",
|
110
153
|
:alternates => [],
|
111
154
|
:sendmail => "/usr/sbin/sendmail -oem -ti",
|
112
155
|
:signature => File.join(ENV["HOME"], ".signature")
|
@@ -127,6 +170,7 @@ require "sup/update"
|
|
127
170
|
require "sup/message"
|
128
171
|
require "sup/source"
|
129
172
|
require "sup/mbox"
|
173
|
+
require "sup/maildir"
|
130
174
|
require "sup/imap"
|
131
175
|
require "sup/person"
|
132
176
|
require "sup/account"
|
data/lib/sup/buffer.rb
CHANGED
@@ -50,6 +50,7 @@ module Redwood
|
|
50
50
|
class Buffer
|
51
51
|
attr_reader :mode, :x, :y, :width, :height, :title
|
52
52
|
bool_reader :dirty
|
53
|
+
bool_accessor :force_to_top
|
53
54
|
|
54
55
|
def initialize window, mode, width, height, opts={}
|
55
56
|
@w = window
|
@@ -57,6 +58,7 @@ class Buffer
|
|
57
58
|
@dirty = true
|
58
59
|
@focus = false
|
59
60
|
@title = opts[:title] || ""
|
61
|
+
@force_to_top = opts[:force_to_top] || false
|
60
62
|
@x, @y, @width, @height = 0, 0, width, height
|
61
63
|
end
|
62
64
|
|
@@ -156,18 +158,33 @@ class BufferManager
|
|
156
158
|
|
157
159
|
def raise_to_front buf
|
158
160
|
raise ArgumentError, "buffer not on stack: #{buf.inspect}" unless @buffers.member? buf
|
161
|
+
|
159
162
|
@buffers.delete buf
|
160
|
-
@buffers.
|
161
|
-
|
163
|
+
if @buffers.length > 0 && @buffers.last.force_to_top?
|
164
|
+
@buffers.insert(-2, buf)
|
165
|
+
else
|
166
|
+
@buffers.push buf
|
167
|
+
focus_on buf
|
168
|
+
end
|
162
169
|
@dirty = true
|
163
170
|
end
|
164
171
|
|
172
|
+
## we reset force_to_top when rolling buffers. this is so that the
|
173
|
+
## human can actually still move buffers around, while still
|
174
|
+
## programmatically being able to pop stuff up in the middle of
|
175
|
+
## drawing a window without worrying about covering it up.
|
176
|
+
##
|
177
|
+
## if we ever start calling roll_buffers programmatically, we will
|
178
|
+
## have to change this. but it's not clear that we will ever actually
|
179
|
+
## do that.
|
165
180
|
def roll_buffers
|
181
|
+
@buffers.last.force_to_top = false
|
166
182
|
raise_to_front @buffers.first
|
167
183
|
end
|
168
184
|
|
169
185
|
def roll_buffers_backwards
|
170
186
|
return unless @buffers.length > 1
|
187
|
+
@buffers.last.force_to_top = false
|
171
188
|
raise_to_front @buffers[@buffers.length - 2]
|
172
189
|
end
|
173
190
|
|
@@ -258,14 +275,14 @@ class BufferManager
|
|
258
275
|
## w = Ncurses::WINDOW.new(height, width, (opts[:top] || 0),
|
259
276
|
## (opts[:left] || 0))
|
260
277
|
w = Ncurses.stdscr
|
261
|
-
b = Buffer.new w, mode, width, height, :title => realtitle
|
278
|
+
b = Buffer.new w, mode, width, height, :title => realtitle, :force_to_top => (opts[:force_to_top] || false)
|
262
279
|
mode.buffer = b
|
263
280
|
@name_map[realtitle] = b
|
281
|
+
|
282
|
+
@buffers.unshift b
|
264
283
|
if opts[:hidden]
|
265
|
-
@buffers.unshift b
|
266
284
|
focus_on b unless @focus_buf
|
267
285
|
else
|
268
|
-
@buffers.push b
|
269
286
|
raise_to_front b
|
270
287
|
end
|
271
288
|
b
|
data/lib/sup/draft.rb
CHANGED
@@ -12,7 +12,7 @@ class DraftManager
|
|
12
12
|
|
13
13
|
def self.source_name; "sup://drafts"; end
|
14
14
|
def self.source_id; 9999; end
|
15
|
-
def new_source; @source = DraftLoader.new; end
|
15
|
+
def new_source; @source = Recoverable.new DraftLoader.new; end
|
16
16
|
|
17
17
|
def write_draft
|
18
18
|
offset = @source.gen_offset
|
@@ -22,7 +22,7 @@ class DraftManager
|
|
22
22
|
my_message = nil
|
23
23
|
@source.each do |thisoffset, theselabels|
|
24
24
|
m = Message.new :source => @source, :source_info => thisoffset, :labels => theselabels
|
25
|
-
Index.
|
25
|
+
Index.sync_message m
|
26
26
|
UpdateManager.relay self, :add, m
|
27
27
|
my_message = m if thisoffset == offset
|
28
28
|
end
|
data/lib/sup/imap.rb
CHANGED
@@ -2,6 +2,7 @@ require 'uri'
|
|
2
2
|
require 'net/imap'
|
3
3
|
require 'stringio'
|
4
4
|
require 'time'
|
5
|
+
require 'rmail'
|
5
6
|
|
6
7
|
## fucking imap fucking sucks. what the FUCK kind of committee of
|
7
8
|
## dunces designed this shit.
|
@@ -35,7 +36,6 @@ class IMAP < Source
|
|
35
36
|
## upon these errors we'll try to rereconnect a few times
|
36
37
|
RECOVERABLE_ERRORS = [ Errno::EPIPE, Errno::ETIMEDOUT ]
|
37
38
|
|
38
|
-
attr_reader_cloned :labels
|
39
39
|
attr_accessor :username, :password
|
40
40
|
|
41
41
|
def initialize uri, username, password, last_idate=nil, usual=true, archived=false, id=nil
|
@@ -52,7 +52,6 @@ class IMAP < Source
|
|
52
52
|
@ids = []
|
53
53
|
@last_scan = nil
|
54
54
|
@labels = [:unread]
|
55
|
-
@labels << :inbox unless archived?
|
56
55
|
@labels << mailbox.intern unless mailbox =~ /inbox/i
|
57
56
|
@mutex = Mutex.new
|
58
57
|
end
|
@@ -64,6 +63,18 @@ class IMAP < Source
|
|
64
63
|
x.nil? || x.empty? ? 'INBOX' : x
|
65
64
|
end
|
66
65
|
def ssl?; @parsed_uri.scheme == 'imaps' end
|
66
|
+
|
67
|
+
def check
|
68
|
+
ids =
|
69
|
+
@mutex.synchronize do
|
70
|
+
unsynchronized_scan_mailbox
|
71
|
+
@ids
|
72
|
+
end
|
73
|
+
|
74
|
+
start = ids.index(cur_offset || start_offset) or raise OutOfSyncSourceError, "Unknown message id #{cur_offset || start_offset}."
|
75
|
+
end
|
76
|
+
|
77
|
+
## is this necessary? TODO: remove maybe
|
67
78
|
def == o; o.is_a?(IMAP) && o.uri == self.uri && o.username == self.username; end
|
68
79
|
|
69
80
|
def load_header id
|
@@ -89,7 +100,7 @@ class IMAP < Source
|
|
89
100
|
synchronized :raw_full_message
|
90
101
|
|
91
102
|
def connect
|
92
|
-
return if
|
103
|
+
return if @imap
|
93
104
|
safely { } # do nothing!
|
94
105
|
end
|
95
106
|
synchronized :connect
|
@@ -121,12 +132,12 @@ class IMAP < Source
|
|
121
132
|
@ids
|
122
133
|
end
|
123
134
|
|
124
|
-
start = ids.index(cur_offset || start_offset) or
|
135
|
+
start = ids.index(cur_offset || start_offset) or raise OutOfSyncSourceError, "Unknown message id #{cur_offset || start_offset}."
|
125
136
|
|
126
137
|
start.upto(ids.length - 1) do |i|
|
127
138
|
id = ids[i]
|
128
139
|
self.cur_offset = id
|
129
|
-
yield id, labels
|
140
|
+
yield id, @labels.clone
|
130
141
|
end
|
131
142
|
end
|
132
143
|
|
@@ -196,26 +207,6 @@ private
|
|
196
207
|
@say_id = nil
|
197
208
|
end
|
198
209
|
|
199
|
-
def die_from e, opts={}
|
200
|
-
@imap = nil
|
201
|
-
|
202
|
-
message =
|
203
|
-
case e
|
204
|
-
when Exception
|
205
|
-
"Error while #{opts[:while]}: #{e.message.chomp} (#{e.class.name})."
|
206
|
-
when String
|
207
|
-
e
|
208
|
-
end
|
209
|
-
|
210
|
-
message += " It is likely that messages have been deleted from this IMAP mailbox. Please run sup-import --rebuild #{to_s} to correct this problem." if opts[:suggest_rebuild]
|
211
|
-
|
212
|
-
self.broken_msg = message
|
213
|
-
Redwood::log message
|
214
|
-
BufferManager.flash "Error communicating with IMAP server. See log for details." if BufferManager.instantiated?
|
215
|
-
raise SourceError, message
|
216
|
-
end
|
217
|
-
|
218
|
-
## build a fake unique id
|
219
210
|
def make_id imap_stuff
|
220
211
|
# use 7 digits for the size. why 7? seems nice.
|
221
212
|
msize, mdate = imap_stuff.attr['RFC822.SIZE'] % 10000000, Time.parse(imap_stuff.attr["INTERNALDATE"])
|
@@ -223,13 +214,12 @@ private
|
|
223
214
|
end
|
224
215
|
|
225
216
|
def get_imap_fields id, *fields
|
226
|
-
raise
|
227
|
-
imap_id = @imap_ids[id] or die_from "Unknown message id #{id}.", :suggest_rebuild => true
|
217
|
+
imap_id = @imap_ids[id] or raise OutOfSyncSourceError, "Unknown message id #{id}"
|
228
218
|
|
229
219
|
retried = false
|
230
220
|
results = safely { @imap.fetch imap_id, (fields + ['RFC822.SIZE', 'INTERNALDATE']).uniq }.first
|
231
221
|
got_id = make_id results
|
232
|
-
|
222
|
+
raise OutOfSyncSourceError, "IMAP message mismatch: requested #{id}, got #{got_id}." unless got_id == id
|
233
223
|
|
234
224
|
fields.map { |f| results.attr[f] }
|
235
225
|
end
|
@@ -250,8 +240,8 @@ private
|
|
250
240
|
end
|
251
241
|
raise
|
252
242
|
end
|
253
|
-
rescue
|
254
|
-
|
243
|
+
rescue SocketError, Net::IMAP::Error, SystemCallError, IOError => e
|
244
|
+
raise FatalSourceError, "While communicating with IMAP server: #{e.message}"
|
255
245
|
end
|
256
246
|
end
|
257
247
|
|