summaryrefslogtreecommitdiff
path: root/src/Network/Tox/ContactInfo.hs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Network/Tox/ContactInfo.hs')
-rw-r--r--src/Network/Tox/ContactInfo.hs130
1 files changed, 63 insertions, 67 deletions
diff --git a/src/Network/Tox/ContactInfo.hs b/src/Network/Tox/ContactInfo.hs
index df3365a2..7f74caff 100644
--- a/src/Network/Tox/ContactInfo.hs
+++ b/src/Network/Tox/ContactInfo.hs
@@ -35,55 +35,24 @@ data ContactEvent = OnionRouted { contact :: PublicKey, onionRouted :: OnionDat
35 | AddrChange { contact :: PublicKey, addrChange :: SockAddr } 35 | AddrChange { contact :: PublicKey, addrChange :: SockAddr }
36 36
37data Contact = Contact 37data Contact = Contact
38 { contactKeyPacket :: Maybe (DHT.DHTPublicKey) 38 { contactKeyPacket :: TVar (Maybe (DHT.DHTPublicKey))
39 , contactLastSeenAddr :: Maybe SockAddr 39 , contactLastSeenAddr :: TVar (Maybe SockAddr)
40 , contactFriendRequest :: Maybe (DHT.FriendRequest) 40 , contactFriendRequest :: TVar (Maybe (DHT.FriendRequest))
41 , contactPolicy :: Maybe (Connection.Policy) 41 , contactPolicy :: TVar (Maybe (Connection.Policy))
42 -- Possible semantics 42 -- Possible semantics
43 -- RefusingToConnect : rejected friend-request or blocked or unknown. 43 -- RefusingToConnect : rejected friend-request or blocked or unknown.
44 -- OpenToConnect : pending friend-request. 44 -- OpenToConnect : pending friend-request.
45 -- TryingToConnect : roster entry. 45 -- TryingToConnect : roster entry.
46 } 46 }
47 47
48nullContact :: Contact
49nullContact = Contact
50 { contactKeyPacket = Nothing
51 , contactLastSeenAddr = Nothing
52 , contactFriendRequest = Nothing
53 , contactPolicy = Nothing
54 }
55
56mergeContact :: Contact -> Maybe Contact -> Maybe Contact
57mergeContact (Contact newk news newf newp) (Just (Contact oldk olds oldf oldp)) =
58 Just $ Contact mergek -- Prefer newer public key packet as long as its stamp
59 -- is later than the stored one.
60 (mplus news olds) -- Prefer newer last-seen
61 (mplus newf oldf) -- Prefer newer friend request.
62 (mplus newp oldp) -- Prefer newer connection policy.
63 where
64 mergek = flip mplus oldk $ do
65 n <- newk
66 stamp <- fmap DHT.dhtpkNonce oldk `mplus` return minBound
67 guard (stamp <= DHT.dhtpkNonce n)
68 return n
69
70mergeContact new Nothing = Just new
71
72newContactInfo :: IO ContactInfo 48newContactInfo :: IO ContactInfo
73newContactInfo = atomically $ ContactInfo <$> newTVar HashMap.empty 49newContactInfo = atomically $ ContactInfo <$> newTVar HashMap.empty
74 50
75newAccount :: SecretKey -> STM Account 51myKeyPairs :: ContactInfo -> STM [(SecretKey,PublicKey)]
76newAccount sk = Account sk <$> newTVar HashMap.empty 52myKeyPairs (ContactInfo accounts) = do
77 <*> newTVar Set.empty 53 acnts <- readTVar accounts
78 <*> newBroadcastTChan 54 forM (HashMap.toList acnts) $ \(nid, Account{userSecret}) -> do
79 55 return (userSecret,id2key nid)
80addContactInfo :: ContactInfo -> SecretKey -> STM ()
81addContactInfo (ContactInfo as) sk = do
82 a <- newAccount sk
83 modifyTVar' as $ HashMap.insert (key2id $ toPublic sk) a
84
85delContactInfo :: ContactInfo -> PublicKey -> STM ()
86delContactInfo (ContactInfo as) pk = modifyTVar' as $ HashMap.delete (key2id pk)
87 56
88updateContactInfo :: ContactInfo -> Onion.AnnouncedRendezvous -> (PublicKey,Onion.OnionData) -> IO () 57updateContactInfo :: ContactInfo -> Onion.AnnouncedRendezvous -> (PublicKey,Onion.OnionData) -> IO ()
89updateContactInfo roster Onion.AnnouncedRendezvous{remoteUserKey} (localUserKey,omsg) = do 58updateContactInfo roster Onion.AnnouncedRendezvous{remoteUserKey} (localUserKey,omsg) = do
@@ -94,44 +63,76 @@ updateContactInfo roster Onion.AnnouncedRendezvous{remoteUserKey} (localUserKey,
94 (updateAccount remoteUserKey omsg) 63 (updateAccount remoteUserKey omsg)
95 $ HashMap.lookup (key2id localUserKey) as 64 $ HashMap.lookup (key2id localUserKey) as
96 65
97 66initContact :: STM Contact
98onionUpdate :: OnionData -> Maybe Contact -> Maybe Contact 67initContact = Contact <$> newTVar Nothing
99onionUpdate (Onion.OnionDHTPublicKey dhtpk) 68 <*> newTVar Nothing
100 = mergeContact nullContact { contactKeyPacket = Just dhtpk } 69 <*> newTVar Nothing
101onionUpdate (Onion.OnionFriendRequest fr) 70 <*> newTVar Nothing
102 = mergeContact nullContact { contactFriendRequest = Just fr } 71
103 72updateAccount' :: PublicKey -> Account -> (Contact -> STM ()) -> STM ()
104policyUpdate :: Policy -> Maybe Contact -> Maybe Contact 73updateAccount' remoteUserKey acc updater = do
105policyUpdate policy = mergeContact nullContact { contactPolicy = Just policy } 74 let rkey = key2id remoteUserKey
106 75 cmap <- readTVar (contacts acc)
107addrUpdate :: SockAddr -> Maybe Contact -> Maybe Contact 76 contact <- case HashMap.lookup rkey cmap of
108addrUpdate addr = mergeContact nullContact { contactLastSeenAddr = Just addr } 77 Just contact -> return contact
78 Nothing -> do contact <- initContact
79 writeTVar (contacts acc) $ HashMap.insert rkey contact cmap
80 return contact
81 updater contact
109 82
110updateAccount :: PublicKey -> Onion.OnionData -> Account -> STM () 83updateAccount :: PublicKey -> Onion.OnionData -> Account -> STM ()
111updateAccount remoteUserKey omsg acc = do 84updateAccount remoteUserKey omsg acc = do
112 modifyTVar' (contacts acc) $ HashMap.alter (onionUpdate omsg) (key2id remoteUserKey) 85 updateAccount' remoteUserKey acc $ onionUpdate omsg
113 writeTChan (eventChan acc) $ OnionRouted remoteUserKey omsg 86 writeTChan (eventChan acc) $ OnionRouted remoteUserKey omsg
114 87
88onionUpdate :: OnionData -> Contact -> STM ()
89onionUpdate (Onion.OnionDHTPublicKey dhtpk) contact
90 = writeTVar (contactKeyPacket contact) $ Just dhtpk
91onionUpdate (Onion.OnionFriendRequest fr) contact
92 = writeTVar (contactFriendRequest contact) $ Just fr
93
94policyUpdate :: Policy -> Contact -> STM ()
95policyUpdate policy contact = writeTVar (contactPolicy contact) $ Just policy
96
97addrUpdate :: SockAddr -> Contact -> STM ()
98addrUpdate addr contact = writeTVar (contactLastSeenAddr contact) $ Just addr
99
115setContactPolicy :: PublicKey -> Policy -> Account -> STM () 100setContactPolicy :: PublicKey -> Policy -> Account -> STM ()
116setContactPolicy remoteUserKey policy acc = do 101setContactPolicy remoteUserKey policy acc = do
117 modifyTVar' (contacts acc) $ HashMap.alter (policyUpdate policy) (key2id remoteUserKey) 102 updateAccount' remoteUserKey acc $ policyUpdate policy
118 writeTChan (eventChan acc) $ PolicyChange remoteUserKey policy 103 writeTChan (eventChan acc) $ PolicyChange remoteUserKey policy
119 104
120setContactAddr :: PublicKey -> SockAddr -> Account -> STM () 105setContactAddr :: PublicKey -> SockAddr -> Account -> STM ()
121setContactAddr remoteUserKey addr acc = do 106setContactAddr remoteUserKey addr acc = do
122 modifyTVar' (contacts acc) $ HashMap.alter (addrUpdate addr) (key2id remoteUserKey) 107 updateAccount' remoteUserKey acc $ addrUpdate addr
123 writeTChan (eventChan acc) $ AddrChange remoteUserKey addr 108 writeTChan (eventChan acc) $ AddrChange remoteUserKey addr
124 109
110
111
112addContactInfo :: ContactInfo -> SecretKey -> STM ()
113addContactInfo (ContactInfo as) sk = do
114 a <- newAccount sk
115 modifyTVar' as $ HashMap.insert (key2id $ toPublic sk) a
116
117delContactInfo :: ContactInfo -> PublicKey -> STM ()
118delContactInfo (ContactInfo as) pk = modifyTVar' as $ HashMap.delete (key2id pk)
119
120newAccount :: SecretKey -> STM Account
121newAccount sk = Account sk <$> newTVar HashMap.empty
122 <*> newTVar Set.empty
123 <*> newBroadcastTChan
124
125dnsPresentation :: ContactInfo -> STM String 125dnsPresentation :: ContactInfo -> STM String
126dnsPresentation (ContactInfo accsvar) = do 126dnsPresentation (ContactInfo accsvar) = do
127 accs <- readTVar accsvar 127 accs <- readTVar accsvar
128 ms <- forM accs $ \Account { userSecret = sec, contacts = cvar } -> do 128 ms <- forM accs $ \Account { userSecret = sec, contacts = cvar } -> do
129 cs <- readTVar cvar 129 cs <- readTVar cvar
130 rs <- forM (HashMap.toList cs) $ \(nid,c) -> do
131 mkpkt <- readTVar (contactKeyPacket c)
132 return $ fmap ((,) nid) mkpkt
130 return $ 133 return $
131 "; local key = " ++ show (key2id $ toPublic sec) ++ "\n" 134 "; local key = " ++ show (key2id $ toPublic sec) ++ "\n"
132 ++ concatMap dnsPresentation1 135 ++ concatMap dnsPresentation1 (catMaybes rs)
133 (mapMaybe (\(nid,m) -> ((,) nid) <$> contactKeyPacket m)
134 $ HashMap.toList cs)
135 return $ concat ms 136 return $ concat ms
136 137
137dnsPresentation1 :: (NodeId,DHTPublicKey) -> String 138dnsPresentation1 :: (NodeId,DHTPublicKey) -> String
@@ -147,13 +148,8 @@ friendRequests (ContactInfo roster) = do
147 accs <- readTVar roster 148 accs <- readTVar roster
148 forM accs $ \Account { userSecret = sec, contacts = cvar } -> do 149 forM accs $ \Account { userSecret = sec, contacts = cvar } -> do
149 cs <- readTVar cvar 150 cs <- readTVar cvar
150 let remotes = mapMaybe (\(nid,m) -> ((,) nid) <$> contactFriendRequest m) 151 rs <- forM (HashMap.toList cs) $ \(nid,c) -> do
151 $ HashMap.toList cs 152 mfr <- readTVar (contactFriendRequest c)
152 return remotes 153 return $ fmap ((,) nid) mfr
153 154 return $ catMaybes rs
154myKeyPairs :: ContactInfo -> STM [(SecretKey,PublicKey)]
155myKeyPairs (ContactInfo accounts) = do
156 acnts <- readTVar accounts
157 forM (HashMap.toList acnts) $ \(nid, Account{userSecret}) -> do
158 return (userSecret,id2key nid)
159 155