summaryrefslogtreecommitdiff
path: root/src/Network/Tox
diff options
context:
space:
mode:
Diffstat (limited to 'src/Network/Tox')
-rw-r--r--src/Network/Tox/ContactInfo.hs100
1 files changed, 100 insertions, 0 deletions
diff --git a/src/Network/Tox/ContactInfo.hs b/src/Network/Tox/ContactInfo.hs
new file mode 100644
index 00000000..f4c4bf12
--- /dev/null
+++ b/src/Network/Tox/ContactInfo.hs
@@ -0,0 +1,100 @@
1{-# LANGUAGE NamedFieldPuns #-}
2module Network.Tox.ContactInfo where
3
4import Control.Concurrent.STM
5import Control.Monad
6import Crypto.PubKey.Curve25519
7import qualified Data.HashMap.Strict as HashMap
8 ;import Data.HashMap.Strict (HashMap)
9import Data.Maybe
10import Network.Tox.DHT.Transport as DHT
11import Network.Tox.NodeId
12import Network.Tox.Onion.Transport as Onion
13import System.IO
14
15newtype ContactInfo = ContactInfo { accounts :: TVar (HashMap NodeId Account) }
16
17data Account = Account
18 { userSecret :: SecretKey -- local secret key
19 , contacts :: TVar (HashMap NodeId Contact) -- received contact info
20 }
21
22data Contact = Contact
23 { contactKeyPacket :: Maybe (DHT.DHTPublicKey)
24 , contactFriendRequest :: Maybe (DHT.FriendRequest)
25 }
26
27mergeContact :: Contact -> Maybe Contact -> Maybe Contact
28mergeContact (Contact newk newf) (Just (Contact oldk oldf)) =
29 Just (Contact mergek mergef)
30 where
31 mergek = mplus oldk $ do
32 n <- newk
33 stamp <- fmap DHT.dhtpkNonce oldk `mplus` return minBound
34 guard (stamp <= DHT.dhtpkNonce n)
35 return n
36 mergef = mplus oldf newf
37mergeContact new Nothing = Just new
38
39newContactInfo :: IO ContactInfo
40newContactInfo = atomically $ ContactInfo <$> newTVar HashMap.empty
41
42newAccount :: SecretKey -> STM Account
43newAccount sk = Account sk <$> newTVar HashMap.empty
44
45addContactInfo :: ContactInfo -> SecretKey -> STM ()
46addContactInfo (ContactInfo as) sk = do
47 a <- newAccount sk
48 modifyTVar' as $ HashMap.insert (key2id $ toPublic sk) a
49
50delContactInfo :: ContactInfo -> PublicKey -> STM ()
51delContactInfo (ContactInfo as) pk = modifyTVar' as $ HashMap.delete (key2id pk)
52
53updateContactInfo :: ContactInfo -> Onion.AnnouncedRendezvous -> (PublicKey,Onion.OnionData) -> IO ()
54updateContactInfo roster Onion.AnnouncedRendezvous{remoteUserKey} (localUserKey,omsg) = do
55 hPutStrLn stderr "updateContactInfo!!!"
56 atomically $ do
57 as <- readTVar (accounts roster)
58 maybe (return ())
59 (updateAccount remoteUserKey omsg)
60 $ HashMap.lookup (key2id localUserKey) as
61
62
63updateAccount :: PublicKey -> Onion.OnionData -> Account -> STM ()
64updateAccount remoteUserKey (Onion.OnionDHTPublicKey dhtpk) acc = do
65 modifyTVar' (contacts acc) $ HashMap.alter (mergeContact $ Contact (Just dhtpk) Nothing)
66 (key2id remoteUserKey)
67
68updateAccount remoteUserKey (Onion.OnionFriendRequest fr) acc = do
69 modifyTVar' (contacts acc) $ HashMap.alter (mergeContact $ Contact Nothing (Just fr))
70 (key2id remoteUserKey)
71
72dnsPresentation :: ContactInfo -> STM String
73dnsPresentation (ContactInfo accsvar) = do
74 accs <- readTVar accsvar
75 ms <- forM accs $ \Account { userSecret = sec, contacts = cvar } -> do
76 cs <- readTVar cvar
77 return $
78 "; local key = " ++ show (key2id $ toPublic sec) ++ "\n"
79 ++ concatMap dnsPresentation1
80 (mapMaybe (\(nid,m) -> ((,) nid) <$> contactKeyPacket m)
81 $ HashMap.toList cs)
82 return $ concat ms
83
84dnsPresentation1 :: (NodeId,DHTPublicKey) -> String
85dnsPresentation1 (nid,dk) = unlines
86 [ concat [ show nid, ".tox. IN CNAME ", show (key2id $ dhtpk dk), ".dht." ]
87 ]
88
89type LocalKey = NodeId
90type RemoteKey = NodeId
91
92friendRequests :: ContactInfo -> STM (HashMap LocalKey [(RemoteKey,DHT.FriendRequest)])
93friendRequests (ContactInfo roster) = do
94 accs <- readTVar roster
95 forM accs $ \Account { userSecret = sec, contacts = cvar } -> do
96 cs <- readTVar cvar
97 let remotes = mapMaybe (\(nid,m) -> ((,) nid) <$> contactFriendRequest m)
98 $ HashMap.toList cs
99 return remotes
100