]> code.delx.au - offlineimap/blob - src/Data/Syncable.hs
Cleaned up findDeleted fix
[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 ++
87 (map CopyItem .
88 findAdded childstate masterstate $ lastchildstate)
89 childchanges = (map DeleteItem .
90 findDeleted masterstate childstate $ lastchildstate)
91 ++
92 (map CopyItem .
93 findAdded masterstate childstate $ lastchildstate)
94
95 {- | Returns a list of keys that exist in state2 and lastchildstate
96 but not in state1 -}
97 findDeleted :: Ord k =>
98 SyncCollection k -> SyncCollection k -> SyncCollection k ->
99 [k]
100 findDeleted state1 state2 lastchildstate =
101 Map.keys . Map.difference (Map.intersection state2 lastchildstate) $ state1
102
103 {- | Returns a list of keys that exist in state1 but in neither
104 state2 nor lastchildstate -}
105 findAdded :: (Ord k, Eq k) =>
106 SyncCollection k -> SyncCollection k -> SyncCollection k ->
107 [k]
108 findAdded state1 state2 lastchildstate =
109 Map.keys . Map.difference state1 . Map.union state2 $ lastchildstate
110
111 {- | Returns a list of keys that exist in the passed state -}
112 filterKeys :: (Ord k) =>
113 SyncCollection k -> [k] -> [k]
114 filterKeys state keylist =
115 concatMap keyfunc keylist
116 where keyfunc k =
117 case Map.lookup k state of
118 Nothing -> []
119 Just _ -> [k]