sup

A curses threads-with-tags style email client

sup-website.git

git clone https://supmua.dev/git/sup-website/

community/pipermail-archives/sup-devel/2012-08.txt (36263B) - raw

      1 From ezyang@MIT.EDU  Tue Aug 21 14:35:45 2012
      2 From: ezyang@MIT.EDU (Edward Z. Yang)
      3 Date: Tue, 21 Aug 2012 10:35:45 -0400
      4 Subject: [sup-devel] Maildir synchronizing other labels
      5 Message-ID: <1345559230-sup-5105@javelin>
      6 
      7 I think it would be nice if we at least support the :inbox label,
      8 so that we can keep our inboxes tidy and our OfflineIMAP sync
      9 times down.
     10 
     11 Proposed implementation strategy:
     12 
     13     - Define a label/source mapping, as well as a default source for
     14       unrecognized labels and an ordering on labels if there is
     15       a conflict.  (Each Maildir folder is its own source.)
     16 
     17     - Implement moving messages between Maildir sources in Sup.
     18       Probably the easiest way is to do this:
     19 
     20         1. Copy message form old Maildir to new Maildir
     21         2. Add new Maildir copy to index (with all other tags
     22            and metadata added on)
     23         3. Delete old Maildir copy from index
     24 
     25       OfflineIMAP will then DTRT as long as SEARCH is supported,
     26       I think.
     27 
     28     - Hook in this behavior on the right places (label change,
     29       after message add)
     30 
     31     - Implement a script to go through old mail and move it.
     32 
     33 Edward
     34 
     35 From ezyang@MIT.EDU  Tue Aug 21 15:17:32 2012
     36 From: ezyang@MIT.EDU (Edward Z. Yang)
     37 Date: Tue, 21 Aug 2012 11:17:32 -0400
     38 Subject: [sup-devel] inotify support for Maildir mailboxes
     39 Message-ID: <1345562202-sup-2266@javelin>
     40 
     41 I'm planning on adding inotify support for Maildir mailboxes.
     42 This would mean we no longer need to 'poll' to find new messages;
     43 they show up instantly.  Let me know if you're interested and willing
     44 to help test.
     45 
     46 Cheers,
     47 Edward
     48 
     49 From alvherre@alvh.no-ip.org  Tue Aug 21 16:00:31 2012
     50 From: alvherre@alvh.no-ip.org (Alvaro Herrera)
     51 Date: Tue, 21 Aug 2012 12:00:31 -0400
     52 Subject: [sup-devel] inotify support for Maildir mailboxes
     53 In-Reply-To: <1345562202-sup-2266@javelin>
     54 References: <1345562202-sup-2266@javelin>
     55 Message-ID: <1345564795-sup-3898@alvh.no-ip.org>
     56 
     57 Excerpts from Edward Z. Yang's message of mar ago 21 11:17:32 -0400 2012:
     58 > I'm planning on adding inotify support for Maildir mailboxes.
     59 > This would mean we no longer need to 'poll' to find new messages;
     60 > they show up instantly.  Let me know if you're interested and willing
     61 > to help test.
     62 
     63 I definitely am interested and willing to test.
     64 
     65 -- 
     66 ?lvaro Herrera <alvherre at alvh.no-ip.org>
     67 
     68 From ezyang@MIT.EDU  Tue Aug 21 19:19:56 2012
     69 From: ezyang@MIT.EDU (Edward Z. Yang)
     70 Date: Tue, 21 Aug 2012 15:19:56 -0400
     71 Subject: [sup-devel] [PATCH] Sync and update other threads when Maildir
     72 	sync-back changes location.
     73 Message-ID: <1345576796-31445-1-git-send-email-ezyang@mit.edu>
     74 
     75 From: "Edward Z. Yang" <ezyang at mit.edu>
     76 
     77 Signed-off-by: Edward Z. Yang <ezyang at mit.edu>
     78 ---
     79  lib/sup/maildir.rb | 2 +-
     80  lib/sup/message.rb | 6 +++++-
     81  2 files changed, 6 insertions(+), 2 deletions(-)
     82 
     83 diff --git a/lib/sup/maildir.rb b/lib/sup/maildir.rb
     84 index 0c8c563..050cfaf 100644
     85 --- a/lib/sup/maildir.rb
     86 +++ b/lib/sup/maildir.rb
     87 @@ -226,7 +226,7 @@ private
     88        new_base = (flags.include?("S")) ? "cur" : "new"
     89        md_base, md_ver, md_flags = maildir_data orig_path
     90  
     91 -      return orig_path if md_flags == flags
     92 +      return if md_flags == flags
     93  
     94        new_loc = File.join new_base, "#{md_base}:#{md_ver},#{flags}"
     95        orig_path = File.join @dir, orig_path
     96 diff --git a/lib/sup/message.rb b/lib/sup/message.rb
     97 index 0616f75..cd9226e 100644
     98 --- a/lib/sup/message.rb
     99 +++ b/lib/sup/message.rb
    100 @@ -288,7 +288,11 @@ EOS
    101    def sync_back
    102      @locations.each do |l|
    103        if l.valid?
    104 -        l.sync_back @labels if $config[:sync_back_to_maildir] and l.source.is_a? Maildir
    105 +        r = l.sync_back @labels if $config[:sync_back_to_maildir] and l.source.is_a? Maildir
    106 +        if r
    107 +          Index.sync_message self, true
    108 +          UpdateManager.relay self, :updated, self
    109 +        end
    110        end
    111      end
    112    end
    113 -- 
    114 1.7.11.3
    115 
    116 
    117 From ezyang@MIT.EDU  Tue Aug 21 19:25:41 2012
    118 From: ezyang@MIT.EDU (Edward Z. Yang)
    119 Date: Tue, 21 Aug 2012 15:25:41 -0400
    120 Subject: [sup-devel] [PATCH] Sync and update other threads when Maildir
    121 	sync-back changes location.
    122 In-Reply-To: <1345576796-31445-1-git-send-email-ezyang@mit.edu>
    123 References: <1345576796-31445-1-git-send-email-ezyang@mit.edu>
    124 Message-ID: <1345577064-sup-4877@javelin>
    125 
    126 This fixes the "I changed a message from unread to read in one list (e.g. 'U')
    127 and now when I open the message from inbox it can't find it" bug.
    128 
    129 Here is a version that is theoretically more efficient, though God
    130 help you if you have more than one location per message.
    131 
    132 commit ca5b02b8ff88412f92984d6b9176ff1876886cc6
    133 Author: Edward Z. Yang <ezyang at mit.edu>
    134 Date:   Tue Aug 21 15:19:11 2012 -0400
    135 
    136     Sync and update other threads when Maildir sync-back changes location.
    137     
    138     Signed-off-by: Edward Z. Yang <ezyang at mit.edu>
    139 
    140 diff --git a/lib/sup/maildir.rb b/lib/sup/maildir.rb
    141 index 0c8c563..050cfaf 100644
    142 --- a/lib/sup/maildir.rb
    143 +++ b/lib/sup/maildir.rb
    144 @@ -226,7 +226,7 @@ private
    145        new_base = (flags.include?("S")) ? "cur" : "new"
    146        md_base, md_ver, md_flags = maildir_data orig_path
    147  
    148 -      return orig_path if md_flags == flags
    149 +      return if md_flags == flags
    150  
    151        new_loc = File.join new_base, "#{md_base}:#{md_ver},#{flags}"
    152        orig_path = File.join @dir, orig_path
    153 diff --git a/lib/sup/message.rb b/lib/sup/message.rb
    154 index 0616f75..9af847d 100644
    155 --- a/lib/sup/message.rb
    156 +++ b/lib/sup/message.rb
    157 @@ -286,11 +286,16 @@ EOS
    158    end
    159  
    160    def sync_back
    161 +    r = nil
    162      @locations.each do |l|
    163        if l.valid?
    164 -        l.sync_back @labels if $config[:sync_back_to_maildir] and l.source.is_a? Maildir
    165 +        r ||= l.sync_back @labels if $config[:sync_back_to_maildir] and l.source.is_a? Maildir
    166        end
    167      end
    168 +    if r
    169 +      Index.sync_message self, true
    170 +      UpdateManager.relay self, :updated, self
    171 +    end
    172    end
    173  
    174    def merge_labels_from_locations merge_labels
    175 
    176 Excerpts from Edward Z. Yang's message of Tue Aug 21 15:19:56 -0400 2012:
    177 > From: "Edward Z. Yang" <ezyang at mit.edu>
    178 > 
    179 > Signed-off-by: Edward Z. Yang <ezyang at mit.edu>
    180 > ---
    181 >  lib/sup/maildir.rb | 2 +-
    182 >  lib/sup/message.rb | 6 +++++-
    183 >  2 files changed, 6 insertions(+), 2 deletions(-)
    184 > 
    185 > diff --git a/lib/sup/maildir.rb b/lib/sup/maildir.rb
    186 > index 0c8c563..050cfaf 100644
    187 > --- a/lib/sup/maildir.rb
    188 > +++ b/lib/sup/maildir.rb
    189 > @@ -226,7 +226,7 @@ private
    190 >        new_base = (flags.include?("S")) ? "cur" : "new"
    191 >        md_base, md_ver, md_flags = maildir_data orig_path
    192 >  
    193 > -      return orig_path if md_flags == flags
    194 > +      return if md_flags == flags
    195 >  
    196 >        new_loc = File.join new_base, "#{md_base}:#{md_ver},#{flags}"
    197 >        orig_path = File.join @dir, orig_path
    198 > diff --git a/lib/sup/message.rb b/lib/sup/message.rb
    199 > index 0616f75..cd9226e 100644
    200 > --- a/lib/sup/message.rb
    201 > +++ b/lib/sup/message.rb
    202 > @@ -288,7 +288,11 @@ EOS
    203 >    def sync_back
    204 >      @locations.each do |l|
    205 >        if l.valid?
    206 > -        l.sync_back @labels if $config[:sync_back_to_maildir] and l.source.is_a? Maildir
    207 > +        r = l.sync_back @labels if $config[:sync_back_to_maildir] and l.source.is_a? Maildir
    208 > +        if r
    209 > +          Index.sync_message self, true
    210 > +          UpdateManager.relay self, :updated, self
    211 > +        end
    212 >        end
    213 >      end
    214 >    end
    215 
    216 From ezyang@MIT.EDU  Tue Aug 21 19:43:47 2012
    217 From: ezyang@MIT.EDU (Edward Z. Yang)
    218 Date: Tue, 21 Aug 2012 15:43:47 -0400
    219 Subject: [sup-devel] [PATCH] Sync and update other threads when Maildir
    220 	sync-back changes location.
    221 In-Reply-To: <1345577064-sup-4877@javelin>
    222 References: <1345576796-31445-1-git-send-email-ezyang@mit.edu>
    223 	<1345577064-sup-4877@javelin>
    224 Message-ID: <1345578187-sup-5921@javelin>
    225 
    226 Aaand here's an even prettier version.
    227 
    228 commit f7d30410d946418a885929f20a498c10e4058243
    229 Author: Edward Z. Yang <ezyang at mit.edu>
    230 Date:   Tue Aug 21 15:19:11 2012 -0400
    231 
    232     Sync and update other threads when Maildir sync-back changes location.
    233     
    234     Signed-off-by: Edward Z. Yang <ezyang at mit.edu>
    235 
    236 diff --git a/lib/sup/maildir.rb b/lib/sup/maildir.rb
    237 index 0c8c563..050cfaf 100644
    238 --- a/lib/sup/maildir.rb
    239 +++ b/lib/sup/maildir.rb
    240 @@ -226,7 +226,7 @@ private
    241        new_base = (flags.include?("S")) ? "cur" : "new"
    242        md_base, md_ver, md_flags = maildir_data orig_path
    243  
    244 -      return orig_path if md_flags == flags
    245 +      return if md_flags == flags
    246  
    247        new_loc = File.join new_base, "#{md_base}:#{md_ver},#{flags}"
    248        orig_path = File.join @dir, orig_path
    249 diff --git a/lib/sup/message.rb b/lib/sup/message.rb
    250 index 0616f75..3eeea66 100644
    251 --- a/lib/sup/message.rb
    252 +++ b/lib/sup/message.rb
    253 @@ -286,10 +286,11 @@ EOS
    254    end
    255  
    256    def sync_back
    257 -    @locations.each do |l|
    258 -      if l.valid?
    259 -        l.sync_back @labels if $config[:sync_back_to_maildir] and l.source.is_a? Maildir
    260 -      end
    261 +    if @locations.map { |l|
    262 +      l.sync_back @labels if l.valid? and $config[:sync_back_to_maildir] and l.source.is_a? Maildir
    263 +    }.any?
    264 +      Index.sync_message self, true
    265 +      UpdateManager.relay self, :updated, self
    266      end
    267    end
    268  
    269 
    270 From ezyang@MIT.EDU  Wed Aug 22 05:45:31 2012
    271 From: ezyang@MIT.EDU (Edward Z. Yang)
    272 Date: Wed, 22 Aug 2012 01:45:31 -0400
    273 Subject: [sup-devel] [PATCH] Implement moving message between Maildir
    274 	sources based on label.
    275 In-Reply-To: <1345559230-sup-5105@javelin>
    276 References: <1345559230-sup-5105@javelin>
    277 Message-ID: <1345614331-17294-1-git-send-email-ezyang@mit.edu>
    278 
    279 From: "Edward Z. Yang" <ezyang at mit.edu>
    280 
    281 Signed-off-by: Edward Z. Yang <ezyang at mit.edu>
    282 ---
    283  lib/sup/maildir.rb | 28 ++++++++++++++++++++++------
    284  lib/sup/message.rb |  9 +++++++--
    285  2 files changed, 29 insertions(+), 8 deletions(-)
    286 
    287 diff --git a/lib/sup/maildir.rb b/lib/sup/maildir.rb
    288 index 95305c2..ff8da23 100644
    289 --- a/lib/sup/maildir.rb
    290 +++ b/lib/sup/maildir.rb
    291 @@ -77,8 +77,17 @@ class Maildir < Source
    292    end
    293  
    294    def sync_back id, labels
    295 +    new_source = @id
    296 +    $config[:maildir_labels].each do |k,v|
    297 +      v.each do |lbl,i|
    298 +        if lbl.nil? or labels.member? lbl
    299 +          new_source = i
    300 +          break
    301 +        end
    302 +      end if v.any? { |lbl,i| i == @id }
    303 +    end if $config[:maildir_labels]
    304      flags = maildir_reconcile_flags id, labels
    305 -    maildir_mark_file id, flags
    306 +    maildir_move_file id, new_source, flags
    307    end
    308  
    309    def raw_header id
    310 @@ -221,24 +230,31 @@ private
    311        new_flags.to_a.sort.join
    312    end
    313  
    314 -  def maildir_mark_file orig_path, flags
    315 +  def maildir_move_file orig_path, new_source_id, flags
    316      @mutex.synchronize do
    317        new_base = (flags.include?("S")) ? "cur" : "new"
    318        md_base, md_ver, md_flags = maildir_data orig_path
    319  
    320 -      return if md_flags == flags
    321 +      return if md_flags == flags and new_source_id == @id
    322 +
    323 +      new_source = SourceManager[new_source_id]
    324  
    325        new_loc = File.join new_base, "#{md_base}:#{md_ver},#{flags}"
    326        orig_path = File.join @dir, orig_path
    327 -      new_path  = File.join @dir, new_loc
    328 +      new_path  = File.join new_source.file_path, new_loc
    329        tmp_path  = File.join @dir, "tmp", "#{md_base}:#{md_ver},#{flags}"
    330  
    331        File.link orig_path, tmp_path
    332        File.unlink orig_path
    333 -      File.link tmp_path, new_path
    334 +      begin
    335 +        File.link tmp_path, new_path
    336 +      rescue SystemCallError
    337 +        File.unlink new_path # XXX kinda unsafe eh
    338 +        File.link tmp_path, new_path
    339 +      end
    340        File.unlink tmp_path
    341  
    342 -      new_loc
    343 +      [new_source, new_loc]
    344      end
    345    end
    346  end
    347 diff --git a/lib/sup/message.rb b/lib/sup/message.rb
    348 index 3eeea66..d6016df 100644
    349 --- a/lib/sup/message.rb
    350 +++ b/lib/sup/message.rb
    351 @@ -726,8 +726,13 @@ class Location
    352    end
    353  
    354    def sync_back labels
    355 -    new_info = source.sync_back(@info, labels) if source.respond_to? :sync_back
    356 -    @info = new_info if new_info
    357 +    pair = source.sync_back(@info, labels) if source.respond_to? :sync_back
    358 +    if pair
    359 +      new_source, new_info = pair
    360 +      @source = new_source if new_source
    361 +      @info = new_info if new_info
    362 +    end
    363 +    pair
    364    end
    365  
    366    ## much faster than raw_message
    367 -- 
    368 1.7.11.3
    369 
    370 
    371 From ezyang@MIT.EDU  Wed Aug 22 05:54:15 2012
    372 From: ezyang@MIT.EDU (Edward Z. Yang)
    373 Date: Wed, 22 Aug 2012 01:54:15 -0400
    374 Subject: [sup-devel] [PATCH] Implement moving message between Maildir
    375 	sources based on label.
    376 In-Reply-To: <1345614331-17294-1-git-send-email-ezyang@mit.edu>
    377 References: <1345559230-sup-5105@javelin>
    378 	<1345614331-17294-1-git-send-email-ezyang@mit.edu>
    379 Message-ID: <1345614564-sup-5523@javelin>
    380 
    381 Usage instructions:
    382 
    383 In config.yaml, you need to add a new option :maildir_labels:
    384 
    385     :maildir_labels:
    386       :stanford: [[:inbox, 4], [null, 6]]
    387 
    388 Maildir labels is a dictionary of "accounts" to lists of precedences.
    389 Read it as follows:
    390 
    391     For messages in source 4 or source 6 (consult sources.yaml),
    392     if the message has the :inbox tag, move it to source 4, otherwise
    393     move it to source 6.
    394 
    395 So in this case, 6 would be some sort of Archive folder, and 4 would be INBOX.
    396 If you want "export-only" folders, just tack them on after the null entry;
    397 the labels are checked *in order*.  Multiple accounts are supported, but
    398 these should be disjoint sets of sources.
    399 
    400 This will automatically start working for any new mail you change the labels of.
    401 In order to apply this to old mail, you need to run sup-sync-back-maildir.
    402 OfflineIMAP will shit its pants [1] if you move too much mail, so I recommend
    403 holding on until I implement the companion patch for OfflineIMAP if you have
    404 a lot of mail.
    405 
    406 Edward
    407 
    408 [1] Namely, it will reupload every single article of mail, and if you get
    409 unlucky and "Archive" is sorted before "INBOX", it will probably run you out
    410 of quota too.  If you arrange to delete everything from INBOX first, and then
    411 sync Archive, it will probably just spend a lot of time uploading.
    412 
    413 Excerpts from Edward Z. Yang's message of Wed Aug 22 01:45:31 -0400 2012:
    414 > From: "Edward Z. Yang" <ezyang at mit.edu>
    415 > 
    416 > Signed-off-by: Edward Z. Yang <ezyang at mit.edu>
    417 > ---
    418 >  lib/sup/maildir.rb | 28 ++++++++++++++++++++++------
    419 >  lib/sup/message.rb |  9 +++++++--
    420 >  2 files changed, 29 insertions(+), 8 deletions(-)
    421 > 
    422 > diff --git a/lib/sup/maildir.rb b/lib/sup/maildir.rb
    423 > index 95305c2..ff8da23 100644
    424 > --- a/lib/sup/maildir.rb
    425 > +++ b/lib/sup/maildir.rb
    426 > @@ -77,8 +77,17 @@ class Maildir < Source
    427 >    end
    428 >  
    429 >    def sync_back id, labels
    430 > +    new_source = @id
    431 > +    $config[:maildir_labels].each do |k,v|
    432 > +      v.each do |lbl,i|
    433 > +        if lbl.nil? or labels.member? lbl
    434 > +          new_source = i
    435 > +          break
    436 > +        end
    437 > +      end if v.any? { |lbl,i| i == @id }
    438 > +    end if $config[:maildir_labels]
    439 >      flags = maildir_reconcile_flags id, labels
    440 > -    maildir_mark_file id, flags
    441 > +    maildir_move_file id, new_source, flags
    442 >    end
    443 >  
    444 >    def raw_header id
    445 > @@ -221,24 +230,31 @@ private
    446 >        new_flags.to_a.sort.join
    447 >    end
    448 >  
    449 > -  def maildir_mark_file orig_path, flags
    450 > +  def maildir_move_file orig_path, new_source_id, flags
    451 >      @mutex.synchronize do
    452 >        new_base = (flags.include?("S")) ? "cur" : "new"
    453 >        md_base, md_ver, md_flags = maildir_data orig_path
    454 >  
    455 > -      return if md_flags == flags
    456 > +      return if md_flags == flags and new_source_id == @id
    457 > +
    458 > +      new_source = SourceManager[new_source_id]
    459 >  
    460 >        new_loc = File.join new_base, "#{md_base}:#{md_ver},#{flags}"
    461 >        orig_path = File.join @dir, orig_path
    462 > -      new_path  = File.join @dir, new_loc
    463 > +      new_path  = File.join new_source.file_path, new_loc
    464 >        tmp_path  = File.join @dir, "tmp", "#{md_base}:#{md_ver},#{flags}"
    465 >  
    466 >        File.link orig_path, tmp_path
    467 >        File.unlink orig_path
    468 > -      File.link tmp_path, new_path
    469 > +      begin
    470 > +        File.link tmp_path, new_path
    471 > +      rescue SystemCallError
    472 > +        File.unlink new_path # XXX kinda unsafe eh
    473 > +        File.link tmp_path, new_path
    474 > +      end
    475 >        File.unlink tmp_path
    476 >  
    477 > -      new_loc
    478 > +      [new_source, new_loc]
    479 >      end
    480 >    end
    481 >  end
    482 > diff --git a/lib/sup/message.rb b/lib/sup/message.rb
    483 > index 3eeea66..d6016df 100644
    484 > --- a/lib/sup/message.rb
    485 > +++ b/lib/sup/message.rb
    486 > @@ -726,8 +726,13 @@ class Location
    487 >    end
    488 >  
    489 >    def sync_back labels
    490 > -    new_info = source.sync_back(@info, labels) if source.respond_to? :sync_back
    491 > -    @info = new_info if new_info
    492 > +    pair = source.sync_back(@info, labels) if source.respond_to? :sync_back
    493 > +    if pair
    494 > +      new_source, new_info = pair
    495 > +      @source = new_source if new_source
    496 > +      @info = new_info if new_info
    497 > +    end
    498 > +    pair
    499 >    end
    500 >  
    501 >    ## much faster than raw_message
    502 
    503 From ezyang@MIT.EDU  Wed Aug 22 20:09:40 2012
    504 From: ezyang@MIT.EDU (Edward Z. Yang)
    505 Date: Wed, 22 Aug 2012 16:09:40 -0400
    506 Subject: [sup-devel] [PATCH] Implement moving message between Maildir
    507 	sources based on label.
    508 In-Reply-To: <1345614564-sup-5523@javelin>
    509 References: <1345559230-sup-5105@javelin>
    510 	<1345614331-17294-1-git-send-email-ezyang@mit.edu>
    511 	<1345614564-sup-5523@javelin>
    512 Message-ID: <1345665956-sup-4988@javelin>
    513 
    514 Here is an improved version that handles the thread/message distinction
    515 better; previously, if you archived something, it's possible only some of
    516 the messages got moved if you hadn't run sup-sync-back-maildir.
    517 
    518 commit a25c345c15c8859a041cc9dc13090d7b8feb3d58
    519 Author: Edward Z. Yang <ezyang at mit.edu>
    520 Date:   Tue Aug 21 23:40:03 2012 -0400
    521 
    522     Implement moving message between Maildir sources based on label.
    523     
    524     Signed-off-by: Edward Z. Yang <ezyang at mit.edu>
    525 
    526 diff --git a/lib/sup/maildir.rb b/lib/sup/maildir.rb
    527 index 95305c2..a7bf567 100644
    528 --- a/lib/sup/maildir.rb
    529 +++ b/lib/sup/maildir.rb
    530 @@ -76,9 +76,23 @@ class Maildir < Source
    531      with_file_for(id) { |f| RMail::Parser.read f }
    532    end
    533  
    534 +  def wrong_source? labels
    535 +    new_source = nil
    536 +    $config[:maildir_labels].each do |k,v|
    537 +      v.each do |lbl,i|
    538 +        if lbl.nil? or labels.member? lbl
    539 +          new_source = i
    540 +          break
    541 +        end
    542 +      end if v.any? { |lbl,i| i == @id }
    543 +    end if $config[:maildir_labels]
    544 +    new_source
    545 +  end
    546 +
    547    def sync_back id, labels
    548 +    new_source = wrong_source? labels || @id
    549      flags = maildir_reconcile_flags id, labels
    550 -    maildir_mark_file id, flags
    551 +    maildir_move_file id, new_source, flags
    552    end
    553  
    554    def raw_header id
    555 @@ -221,24 +235,31 @@ private
    556        new_flags.to_a.sort.join
    557    end
    558  
    559 -  def maildir_mark_file orig_path, flags
    560 +  def maildir_move_file orig_path, new_source_id, flags
    561      @mutex.synchronize do
    562        new_base = (flags.include?("S")) ? "cur" : "new"
    563        md_base, md_ver, md_flags = maildir_data orig_path
    564  
    565 -      return if md_flags == flags
    566 +      return if md_flags == flags and new_source_id == @id
    567 +
    568 +      new_source = SourceManager[new_source_id]
    569  
    570        new_loc = File.join new_base, "#{md_base}:#{md_ver},#{flags}"
    571        orig_path = File.join @dir, orig_path
    572 -      new_path  = File.join @dir, new_loc
    573 +      new_path  = File.join new_source.file_path, new_loc
    574        tmp_path  = File.join @dir, "tmp", "#{md_base}:#{md_ver},#{flags}"
    575  
    576        File.link orig_path, tmp_path
    577        File.unlink orig_path
    578 -      File.link tmp_path, new_path
    579 +      begin
    580 +        File.link tmp_path, new_path
    581 +      rescue SystemCallError
    582 +        File.unlink new_path # XXX kinda unsafe eh
    583 +        File.link tmp_path, new_path
    584 +      end
    585        File.unlink tmp_path
    586  
    587 -      new_loc
    588 +      [new_source, new_loc]
    589      end
    590    end
    591  end
    592 diff --git a/lib/sup/message.rb b/lib/sup/message.rb
    593 index 3eeea66..4139f3e 100644
    594 --- a/lib/sup/message.rb
    595 +++ b/lib/sup/message.rb
    596 @@ -285,6 +285,10 @@ EOS
    597      location.each_raw_message_line &b
    598    end
    599  
    600 +  def wrong_source?
    601 +    $config[:sync_back_to_maildir] and @locations.any? { |l| l.valid? and l.source.is_a? Maildir and l.wrong_source? @labels}
    602 +  end
    603 +
    604    def sync_back
    605      if @locations.map { |l|
    606        l.sync_back @labels if l.valid? and $config[:sync_back_to_maildir] and l.source.is_a? Maildir
    607 @@ -726,8 +730,17 @@ class Location
    608    end
    609  
    610    def sync_back labels
    611 -    new_info = source.sync_back(@info, labels) if source.respond_to? :sync_back
    612 -    @info = new_info if new_info
    613 +    pair = source.sync_back(@info, labels) if source.respond_to? :sync_back
    614 +    if pair
    615 +      new_source, new_info = pair
    616 +      @source = new_source if new_source
    617 +      @info = new_info if new_info
    618 +    end
    619 +    pair
    620 +  end
    621 +
    622 +  def wrong_source? labels
    623 +    source.wrong_source? labels if source.respond_to? :wrong_source
    624    end
    625  
    626    ## much faster than raw_message
    627 diff --git a/lib/sup/thread.rb b/lib/sup/thread.rb
    628 index b08bae2..c1e4b40 100644
    629 --- a/lib/sup/thread.rb
    630 +++ b/lib/sup/thread.rb
    631 @@ -113,7 +113,7 @@ class Thread
    632  
    633    def set_labels l; each { |m, *o| m && m.labels = l }; end
    634    def has_label? t; any? { |m, *o| m && m.has_label?(t) }; end
    635 -  def each_dirty_message; each { |m, *o| m && m.dirty? && yield(m) }; end
    636 +  def each_dirty_message; each { |m, *o| m && (m.dirty? || m.wrong_source?) && yield(m) }; end
    637  
    638    def direct_participants
    639      map { |m, *o| [m.from] + m.to if m }.flatten.compact.uniq
    640 
    641 From ezyang@MIT.EDU  Thu Aug 23 14:40:22 2012
    642 From: ezyang@MIT.EDU (Edward Z. Yang)
    643 Date: Thu, 23 Aug 2012 10:40:22 -0400
    644 Subject: [sup-devel] [PATCH] Implement moving message between Maildir
    645 	sources based on label.
    646 In-Reply-To: <1345665956-sup-4988@javelin>
    647 References: <1345559230-sup-5105@javelin>
    648 	<1345614331-17294-1-git-send-email-ezyang@mit.edu>
    649 	<1345614564-sup-5523@javelin> <1345665956-sup-4988@javelin>
    650 Message-ID: <1345732781-sup-2983@javelin>
    651 
    652 It looks like the current patchset will *destroy* all labels you have
    653 on messages, so be careful! (This was masked for me since most of my
    654 labels are from before-add-message.rb, and that hook gets reapplied)
    655 
    656 Edward
    657 
    658 Excerpts from Edward Z. Yang's message of Wed Aug 22 16:09:40 -0400 2012:
    659 > Here is an improved version that handles the thread/message distinction
    660 > better; previously, if you archived something, it's possible only some of
    661 > the messages got moved if you hadn't run sup-sync-back-maildir.
    662 > 
    663 > commit a25c345c15c8859a041cc9dc13090d7b8feb3d58
    664 > Author: Edward Z. Yang <ezyang at mit.edu>
    665 > Date:   Tue Aug 21 23:40:03 2012 -0400
    666 > 
    667 >     Implement moving message between Maildir sources based on label.
    668 >     
    669 >     Signed-off-by: Edward Z. Yang <ezyang at mit.edu>
    670 > 
    671 > diff --git a/lib/sup/maildir.rb b/lib/sup/maildir.rb
    672 > index 95305c2..a7bf567 100644
    673 > --- a/lib/sup/maildir.rb
    674 > +++ b/lib/sup/maildir.rb
    675 > @@ -76,9 +76,23 @@ class Maildir < Source
    676 >      with_file_for(id) { |f| RMail::Parser.read f }
    677 >    end
    678 >  
    679 > +  def wrong_source? labels
    680 > +    new_source = nil
    681 > +    $config[:maildir_labels].each do |k,v|
    682 > +      v.each do |lbl,i|
    683 > +        if lbl.nil? or labels.member? lbl
    684 > +          new_source = i
    685 > +          break
    686 > +        end
    687 > +      end if v.any? { |lbl,i| i == @id }
    688 > +    end if $config[:maildir_labels]
    689 > +    new_source
    690 > +  end
    691 > +
    692 >    def sync_back id, labels
    693 > +    new_source = wrong_source? labels || @id
    694 >      flags = maildir_reconcile_flags id, labels
    695 > -    maildir_mark_file id, flags
    696 > +    maildir_move_file id, new_source, flags
    697 >    end
    698 >  
    699 >    def raw_header id
    700 > @@ -221,24 +235,31 @@ private
    701 >        new_flags.to_a.sort.join
    702 >    end
    703 >  
    704 > -  def maildir_mark_file orig_path, flags
    705 > +  def maildir_move_file orig_path, new_source_id, flags
    706 >      @mutex.synchronize do
    707 >        new_base = (flags.include?("S")) ? "cur" : "new"
    708 >        md_base, md_ver, md_flags = maildir_data orig_path
    709 >  
    710 > -      return if md_flags == flags
    711 > +      return if md_flags == flags and new_source_id == @id
    712 > +
    713 > +      new_source = SourceManager[new_source_id]
    714 >  
    715 >        new_loc = File.join new_base, "#{md_base}:#{md_ver},#{flags}"
    716 >        orig_path = File.join @dir, orig_path
    717 > -      new_path  = File.join @dir, new_loc
    718 > +      new_path  = File.join new_source.file_path, new_loc
    719 >        tmp_path  = File.join @dir, "tmp", "#{md_base}:#{md_ver},#{flags}"
    720 >  
    721 >        File.link orig_path, tmp_path
    722 >        File.unlink orig_path
    723 > -      File.link tmp_path, new_path
    724 > +      begin
    725 > +        File.link tmp_path, new_path
    726 > +      rescue SystemCallError
    727 > +        File.unlink new_path # XXX kinda unsafe eh
    728 > +        File.link tmp_path, new_path
    729 > +      end
    730 >        File.unlink tmp_path
    731 >  
    732 > -      new_loc
    733 > +      [new_source, new_loc]
    734 >      end
    735 >    end
    736 >  end
    737 > diff --git a/lib/sup/message.rb b/lib/sup/message.rb
    738 > index 3eeea66..4139f3e 100644
    739 > --- a/lib/sup/message.rb
    740 > +++ b/lib/sup/message.rb
    741 > @@ -285,6 +285,10 @@ EOS
    742 >      location.each_raw_message_line &b
    743 >    end
    744 >  
    745 > +  def wrong_source?
    746 > +    $config[:sync_back_to_maildir] and @locations.any? { |l| l.valid? and l.source.is_a? Maildir and l.wrong_source? @labels}
    747 > +  end
    748 > +
    749 >    def sync_back
    750 >      if @locations.map { |l|
    751 >        l.sync_back @labels if l.valid? and $config[:sync_back_to_maildir] and l.source.is_a? Maildir
    752 > @@ -726,8 +730,17 @@ class Location
    753 >    end
    754 >  
    755 >    def sync_back labels
    756 > -    new_info = source.sync_back(@info, labels) if source.respond_to? :sync_back
    757 > -    @info = new_info if new_info
    758 > +    pair = source.sync_back(@info, labels) if source.respond_to? :sync_back
    759 > +    if pair
    760 > +      new_source, new_info = pair
    761 > +      @source = new_source if new_source
    762 > +      @info = new_info if new_info
    763 > +    end
    764 > +    pair
    765 > +  end
    766 > +
    767 > +  def wrong_source? labels
    768 > +    source.wrong_source? labels if source.respond_to? :wrong_source
    769 >    end
    770 >  
    771 >    ## much faster than raw_message
    772 > diff --git a/lib/sup/thread.rb b/lib/sup/thread.rb
    773 > index b08bae2..c1e4b40 100644
    774 > --- a/lib/sup/thread.rb
    775 > +++ b/lib/sup/thread.rb
    776 > @@ -113,7 +113,7 @@ class Thread
    777 >  
    778 >    def set_labels l; each { |m, *o| m && m.labels = l }; end
    779 >    def has_label? t; any? { |m, *o| m && m.has_label?(t) }; end
    780 > -  def each_dirty_message; each { |m, *o| m && m.dirty? && yield(m) }; end
    781 > +  def each_dirty_message; each { |m, *o| m && (m.dirty? || m.wrong_source?) && yield(m) }; end
    782 >  
    783 >    def direct_participants
    784 >      map { |m, *o| [m.from] + m.to if m }.flatten.compact.uniq
    785 
    786 From alvherre@alvh.no-ip.org  Thu Aug 23 14:52:21 2012
    787 From: alvherre@alvh.no-ip.org (Alvaro Herrera)
    788 Date: Thu, 23 Aug 2012 10:52:21 -0400
    789 Subject: [sup-devel] [PATCH] Implement moving message between Maildir
    790 	sources based on label.
    791 In-Reply-To: <1345732781-sup-2983@javelin>
    792 References: <1345559230-sup-5105@javelin>
    793 	<1345614331-17294-1-git-send-email-ezyang@mit.edu>
    794 	<1345614564-sup-5523@javelin> <1345665956-sup-4988@javelin>
    795 	<1345732781-sup-2983@javelin>
    796 Message-ID: <1345733453-sup-9957@alvh.no-ip.org>
    797 
    798 Excerpts from Edward Z. Yang's message of jue ago 23 10:40:22 -0400 2012:
    799 > It looks like the current patchset will *destroy* all labels you have
    800 > on messages, so be careful! (This was masked for me since most of my
    801 > labels are from before-add-message.rb, and that hook gets reapplied)
    802 
    803 Thanks for the notice.  Most of my labels come from that hook too, but a
    804 few do not, so I could easily lose some!  I was planning on trying out
    805 your patch, but with this caveat I'm likely to refrain.  Are you
    806 planning on submitting a fixed version?
    807 
    808 -- 
    809 ?lvaro Herrera <alvherre at alvh.no-ip.org>
    810 
    811 From ezyang@MIT.EDU  Thu Aug 23 15:28:22 2012
    812 From: ezyang@MIT.EDU (Edward Z. Yang)
    813 Date: Thu, 23 Aug 2012 11:28:22 -0400
    814 Subject: [sup-devel] [PATCH] Implement moving message between Maildir
    815 	sources based on label.
    816 In-Reply-To: <1345733453-sup-9957@alvh.no-ip.org>
    817 References: <1345559230-sup-5105@javelin>
    818 	<1345614331-17294-1-git-send-email-ezyang@mit.edu>
    819 	<1345614564-sup-5523@javelin> <1345665956-sup-4988@javelin>
    820 	<1345732781-sup-2983@javelin> <1345733453-sup-9957@alvh.no-ip.org>
    821 Message-ID: <1345735597-sup-2272@javelin>
    822 
    823 Yes. The current plan is to snoop the message ID of newly added messages
    824 in maildirs, and do moved message detection based on that.  If you have a
    825 better idea I'm all ears. (Another possibility is to add sha1sum to the
    826 index and compare that.)
    827 
    828 Also note that it won't destroy the labels *unless you run OfflineIMAP*.
    829 The trouble is OfflineIMAP reuploads your message and then reassigns
    830 the UID based on the IMAP server, but doesn't communicate this back to Sup.
    831 
    832 Edward
    833 
    834 Excerpts from Alvaro Herrera's message of Thu Aug 23 10:52:21 -0400 2012:
    835 > Excerpts from Edward Z. Yang's message of jue ago 23 10:40:22 -0400 2012:
    836 > > It looks like the current patchset will *destroy* all labels you have
    837 > > on messages, so be careful! (This was masked for me since most of my
    838 > > labels are from before-add-message.rb, and that hook gets reapplied)
    839 > 
    840 > Thanks for the notice.  Most of my labels come from that hook too, but a
    841 > few do not, so I could easily lose some!  I was planning on trying out
    842 > your patch, but with this caveat I'm likely to refrain.  Are you
    843 > planning on submitting a fixed version?
    844 > 
    845 
    846 From ezyang@MIT.EDU  Thu Aug 23 18:20:18 2012
    847 From: ezyang@MIT.EDU (Edward Z. Yang)
    848 Date: Thu, 23 Aug 2012 14:20:18 -0400
    849 Subject: [sup-devel] [PATCH] Implement moving message between Maildir
    850 	sources based on label.
    851 In-Reply-To: <1345733453-sup-9957@alvh.no-ip.org>
    852 References: <1345559230-sup-5105@javelin>
    853 	<1345614331-17294-1-git-send-email-ezyang@mit.edu>
    854 	<1345614564-sup-5523@javelin> <1345665956-sup-4988@javelin>
    855 	<1345732781-sup-2983@javelin> <1345733453-sup-9957@alvh.no-ip.org>
    856 Message-ID: <1345745979-sup-7676@javelin>
    857 
    858 With pleasure, I report that Sup is actually doing this!  So solving
    859 the "hooks run too many times" is as easy as this:
    860 
    861 commit ec3afe7ac01741bc67f68009193d2d2e73f05529
    862 Author: Edward Z. Yang <ezyang at mit.edu>
    863 Date:   Thu Aug 23 14:19:24 2012 -0400
    864 
    865     Don't run before-add-message hook for messages already in index.
    866     
    867     Signed-off-by: Edward Z. Yang <ezyang at mit.edu>
    868 
    869 diff --git a/lib/sup/poll.rb b/lib/sup/poll.rb
    870 index 1b64098..7d5aaa2 100644
    871 --- a/lib/sup/poll.rb
    872 +++ b/lib/sup/poll.rb
    873 @@ -184,7 +184,7 @@ EOS
    874            m.labels.each { |l| LabelManager << l }
    875            m.labels = old_m.labels + (m.labels - [:unread, :inbox]) if old_m
    876            m.locations = old_m.locations + m.locations if old_m
    877 -          HookManager.run "before-add-message", :message => m
    878 +          HookManager.run "before-add-message", :message => m if not old_m
    879            yield :add, m, old_m, args[:progress] if block_given?
    880            Index.sync_message m, true
    881  
    882 
    883 
    884 Excerpts from Alvaro Herrera's message of Thu Aug 23 10:52:21 -0400 2012:
    885 > Excerpts from Edward Z. Yang's message of jue ago 23 10:40:22 -0400 2012:
    886 > > It looks like the current patchset will *destroy* all labels you have
    887 > > on messages, so be careful! (This was masked for me since most of my
    888 > > labels are from before-add-message.rb, and that hook gets reapplied)
    889 > 
    890 > Thanks for the notice.  Most of my labels come from that hook too, but a
    891 > few do not, so I could easily lose some!  I was planning on trying out
    892 > your patch, but with this caveat I'm likely to refrain.  Are you
    893 > planning on submitting a fixed version?
    894 > 
    895 
    896 From ezyang@MIT.EDU  Wed Aug 29 00:35:01 2012
    897 From: ezyang@MIT.EDU (Edward Z. Yang)
    898 Date: Tue, 28 Aug 2012 20:35:01 -0400
    899 Subject: [sup-devel] [PATCH] Handle drafts with high ID numbers.
    900 Message-ID: <1346200502-27650-1-git-send-email-ezyang@mit.edu>
    901 
    902 From: "Edward Z. Yang" <ezyang at mit.edu>
    903 
    904 Signed-off-by: Edward Z. Yang <ezyang at mit.edu>
    905 ---
    906  lib/sup/draft.rb | 16 +++++++---------
    907  1 file changed, 7 insertions(+), 9 deletions(-)
    908 
    909 diff --git a/lib/sup/draft.rb b/lib/sup/draft.rb
    910 index 58c45db..1f33dc1 100644
    911 --- a/lib/sup/draft.rb
    912 +++ b/lib/sup/draft.rb
    913 @@ -37,7 +37,6 @@ class DraftLoader < Source
    914      Dir.mkdir dir unless File.exists? dir
    915      super DraftManager.source_name, true, false
    916      @dir = dir
    917 -    @cur_offset = 0
    918    end
    919  
    920    def id; DraftManager.source_id; end
    921 @@ -46,14 +45,13 @@ class DraftLoader < Source
    922  
    923    def poll
    924      ids = get_ids
    925 -    ids.each do |id|
    926 -      if id >= @cur_offset
    927 -        @cur_offset = id + 1
    928 -        yield :add,
    929 -          :info => id,
    930 -          :labels => [:draft, :inbox],
    931 -          :progress => 0.0
    932 -      end
    933 +    old_ids = Enumerator.new(Index.instance, :each_source_info, self.id).to_a
    934 +    new_ids = ids - old_ids
    935 +    new_ids.each do |id|
    936 +      yield :add,
    937 +        :info => id,
    938 +        :labels => [:draft, :inbox],
    939 +        :progress => 0.0
    940      end
    941    end
    942  
    943 -- 
    944 1.7.11.3
    945 
    946 
    947 From ezyang@MIT.EDU  Wed Aug 29 00:41:15 2012
    948 From: ezyang@MIT.EDU (Edward Z. Yang)
    949 Date: Tue, 28 Aug 2012 20:41:15 -0400
    950 Subject: [sup-devel] [PATCH] Handle drafts with high ID numbers.
    951 In-Reply-To: <1346200502-27650-1-git-send-email-ezyang@mit.edu>
    952 References: <1346200502-27650-1-git-send-email-ezyang@mit.edu>
    953 Message-ID: <1346200850-sup-3549@javelin>
    954 
    955 If you've ever suffered from saving a draft message, and then
    956 suddenly asking, "Where did it go?" because it didn't show up
    957 in your INBOX, try this patch.
    958 
    959 Edward
    960 
    961 Excerpts from Edward Z. Yang's message of Tue Aug 28 20:35:01 -0400 2012:
    962 > From: "Edward Z. Yang" <ezyang at mit.edu>
    963 > 
    964 > Signed-off-by: Edward Z. Yang <ezyang at mit.edu>
    965 > ---
    966 >  lib/sup/draft.rb | 16 +++++++---------
    967 >  1 file changed, 7 insertions(+), 9 deletions(-)
    968 > 
    969 > diff --git a/lib/sup/draft.rb b/lib/sup/draft.rb
    970 > index 58c45db..1f33dc1 100644
    971 > --- a/lib/sup/draft.rb
    972 > +++ b/lib/sup/draft.rb
    973 > @@ -37,7 +37,6 @@ class DraftLoader < Source
    974 >      Dir.mkdir dir unless File.exists? dir
    975 >      super DraftManager.source_name, true, false
    976 >      @dir = dir
    977 > -    @cur_offset = 0
    978 >    end
    979 >  
    980 >    def id; DraftManager.source_id; end
    981 > @@ -46,14 +45,13 @@ class DraftLoader < Source
    982 >  
    983 >    def poll
    984 >      ids = get_ids
    985 > -    ids.each do |id|
    986 > -      if id >= @cur_offset
    987 > -        @cur_offset = id + 1
    988 > -        yield :add,
    989 > -          :info => id,
    990 > -          :labels => [:draft, :inbox],
    991 > -          :progress => 0.0
    992 > -      end
    993 > +    old_ids = Enumerator.new(Index.instance, :each_source_info, self.id).to_a
    994 > +    new_ids = ids - old_ids
    995 > +    new_ids.each do |id|
    996 > +      yield :add,
    997 > +        :info => id,
    998 > +        :labels => [:draft, :inbox],
    999 > +        :progress => 0.0
   1000 >      end
   1001 >    end
   1002 >  
   1003 
   1004 From ezyang@MIT.EDU  Wed Aug 29 01:42:10 2012
   1005 From: ezyang@MIT.EDU (Edward Z. Yang)
   1006 Date: Tue, 28 Aug 2012 21:42:10 -0400
   1007 Subject: [sup-devel] [PATCH] Add sent-save-to hook.
   1008 Message-ID: <1346204530-30793-1-git-send-email-ezyang@mit.edu>
   1009 
   1010 From: "Edward Z. Yang" <ezyang at mit.edu>
   1011 
   1012 Signed-off-by: Edward Z. Yang <ezyang at mit.edu>
   1013 ---
   1014  lib/sup/modes/edit-message-mode.rb | 13 ++++++++++++-
   1015  lib/sup/sent.rb                    |  7 ++++---
   1016  2 files changed, 16 insertions(+), 4 deletions(-)
   1017 
   1018 diff --git a/lib/sup/modes/edit-message-mode.rb b/lib/sup/modes/edit-message-mode.rb
   1019 index 5947ffd..2daffaf 100644
   1020 --- a/lib/sup/modes/edit-message-mode.rb
   1021 +++ b/lib/sup/modes/edit-message-mode.rb
   1022 @@ -69,6 +69,16 @@ Return value:
   1023       True if mail has been sent successfully, false otherwise.
   1024  EOS
   1025  
   1026 +  HookManager.register "sent-save-to", <<EOS
   1027 +Configures where to save sent mail to. If this hook doesn't exist,
   1028 +the global sent setting will be used (possibly defaulting to sup://sent)
   1029 +Variables:
   1030 +    message: RMail::Message instance of the mail to send.
   1031 +    account: Account instance matching the From address
   1032 +Return value:
   1033 +     Source to save mail to, nil to use default
   1034 +EOS
   1035 +
   1036    attr_reader :status
   1037    attr_accessor :body, :header
   1038    bool_reader :edited
   1039 @@ -456,7 +466,8 @@ protected
   1040          raise SendmailCommandFailed, "Couldn't execute #{acct.sendmail}" unless $? == 0
   1041        end
   1042  
   1043 -      SentManager.write_sent_message(date, from_email) { |f| f.puts sanitize_body(m.to_s) }
   1044 +      SentManager.write_sent_message(HookManager.run("sent-save-to", :message => m, :account => acct),
   1045 +                                     date, from_email) { |f| f.puts sanitize_body(m.to_s) }
   1046        BufferManager.kill_buffer buffer
   1047        BufferManager.flash "Message sent!"
   1048        true
   1049 diff --git a/lib/sup/sent.rb b/lib/sup/sent.rb
   1050 index 0ca1fb1..e712dad 100644
   1051 --- a/lib/sup/sent.rb
   1052 +++ b/lib/sup/sent.rb
   1053 @@ -24,9 +24,10 @@ class SentManager
   1054      @source
   1055    end
   1056  
   1057 -  def write_sent_message date, from_email, &block
   1058 -    @source.store_message date, from_email, &block
   1059 -    PollManager.poll_from @source
   1060 +  def write_sent_message src, date, from_email, &block
   1061 +    use_src = src || @source
   1062 +    use_src.store_message date, from_email, &block
   1063 +    PollManager.poll_from use_src
   1064    end
   1065  end
   1066  
   1067 -- 
   1068 1.7.11.3
   1069 
   1070