]> code.delx.au - offlineimap/blob - src/Data/Syncable.hs
Added masterchanges start
[offlineimap] / src / Data / Syncable.hs
1 {- offlineimap component
2 Copyright (C) 2002-2008 John Goerzen <jgoerzen@complete.org>
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 -}
18
19 {-
20 The OfflineIMAP v6 algorithm worked like this:
21
22 call remoterepos.syncfoldersto(localrepos, [statusrepos])
23
24 for each folder, call
25 syncfolder(remotename, remoterepos, remotefolder, localrepos, statusrepos, quick)
26 this:
27 sets localfolder = local folder
28 adds localfolder to mbnames
29 sets statusfolder = status folder
30 if localfolder.getuidvalidity() == None, removes anything in statusfolder
31
32 statusfolder.cachemessagelist()
33
34 localfolder.cachemessagelist()
35
36 Check UID validity
37 Save UID validity
38
39 remotefolder.cachemessagelist()
40
41 if not statusfolder.isnewfolder():
42 # Delete local copies of remote messages. This way,
43 # if a message's flag is modified locally but it has been
44 # deleted remotely, we'll delete it locally. Otherwise, we
45 # try to modify a deleted message's flags! This step
46 # need only be taken if a statusfolder is present; otherwise,
47 # there is no action taken *to* the remote repository.
48 remotefolder.syncmessagesto_delete(localfolder, [localfolder,
49 statusfolder])
50 localfolder.syncmessagesto(statusfolder, [remotefolder, statusfolder])
51
52 # Synchroonize remote changes
53 remotefolder.syncmessagesto(localfolder, [localfolder, statusfolder])
54
55 # Make sure the status folder is up-to-date.
56 ui.syncingmessages(localrepos, localfolder, statusrepos, statusfolder)
57 localfolder.syncmessagesto(statusfolder)
58 statusfolder.save()
59 localrepos.restore_atime()
60
61
62
63 call forgetfolders on local and remote
64 -}
65
66 module Data.Syncable where
67 import qualified Data.Map as Map
68
69 type SyncCollection k = Map.Map k ()
70
71 data (Eq k, Ord k, Show k) =>
72 SyncCommand k =
73 DeleteItem k
74 | CopyItem k
75 deriving (Eq, Ord, Show)
76
77 syncThem :: (Ord k, Show k) =>
78 SyncCollection k -- ^ Present state of master
79 -> SyncCollection k -- ^ Present state of child
80 -> SyncCollection k -- ^ Last state of child
81 -> ([SyncCommand k], [SyncCommand k]) -- ^ Changes to make to (master, child)
82 syncThem masterstate childstate lastchildstate =
83 (masterchanges, childchanges)
84 where masterchanges = map DeleteItem .
85 findDeleted childstate masterstate $ lastchildstate
86 childchanges = map DeleteItem .
87 findDeleted masterstate childstate $ lastchildstate
88
89 {- | Returns a list of keys that exist in state1 and lastchildstate
90 but not in state2 -}
91 findDeleted :: Ord k =>
92 SyncCollection k -> SyncCollection k -> SyncCollection k ->
93 [k]
94 findDeleted state1 state2 lastchildstate =
95 Map.keys . Map.difference state2 . Map.difference state1 $ lastchildstate
96
97 {- | Returns a list of keys that exist in the passed state -}
98 filterKeys :: (Ord k) =>
99 SyncCollection k -> [k] -> [k]
100 filterKeys state keylist =
101 concatMap keyfunc keylist
102 where keyfunc k =
103 case Map.lookup k state of
104 Nothing -> []
105 Just _ -> [k]