diff --git a/cmd/goatak_server/main.go b/cmd/goatak_server/main.go
index a5c1d2a..be33d21 100644
--- a/cmd/goatak_server/main.go
+++ b/cmd/goatak_server/main.go
@@ -323,12 +323,12 @@ func (app *App) MessageProcessor() {
}
func (app *App) route(msg *cot.CotMessage) {
- if len(msg.Detail.GetDest()) > 0 {
- for _, s := range msg.Detail.GetDest() {
+ if dest := msg.Detail.GetDest(); len(dest) > 0 {
+ for _, s := range dest {
app.SendToCallsign(s, msg.TakMessage)
}
} else {
- app.SendToAllOther(msg)
+ app.SendBroadcast(msg)
}
}
@@ -366,7 +366,7 @@ func (app *App) cleanOldUnits() {
}
}
-func (app *App) SendToAllOther(msg *cot.CotMessage) {
+func (app *App) SendBroadcast(msg *cot.CotMessage) {
app.ForAllClients(func(ch client.ClientHandler) bool {
if ch.GetName() != msg.From && ch.CanSeeScope(msg.Scope) {
if err := ch.SendMsg(msg.TakMessage); err != nil {
@@ -384,6 +384,19 @@ func (app *App) SendToCallsign(callsign string, msg *cotproto.TakMessage) {
if err := ch.SendMsg(msg); err != nil {
app.Logger.Errorf("error: %v", err)
}
+ }
+ }
+ return true
+ })
+}
+
+func (app *App) SendToUid(uid string, msg *cotproto.TakMessage) {
+ app.ForAllClients(func(ch client.ClientHandler) bool {
+ for c := range ch.GetUids() {
+ if c == uid {
+ if err := ch.SendMsg(msg); err != nil {
+ app.Logger.Errorf("error: %v", err)
+ }
return false
}
}
diff --git a/cmd/goatak_server/processors.go b/cmd/goatak_server/processors.go
index 7627fb8..7ab281b 100644
--- a/cmd/goatak_server/processors.go
+++ b/cmd/goatak_server/processors.go
@@ -44,9 +44,9 @@ func (app *App) loggerProcessor(msg *cot.CotMessage) {
func (app *App) removeItemProcessor(msg *cot.CotMessage) {
// t-x-d-d
- if msg.Detail != nil && msg.Detail.Has("link") {
- uid := msg.Detail.GetFirst("link").GetAttr("uid")
- typ := msg.Detail.GetFirst("link").GetAttr("type")
+ if link := msg.GetFirstLink("p-p"); link != nil {
+ uid := link.GetAttr("uid")
+ typ := link.GetAttr("type")
if uid == "" {
app.Logger.Warnf("invalid remove message: %s", msg.Detail)
return
diff --git a/cmd/webclient/http_server.go b/cmd/webclient/http_server.go
index 7155fe9..236a0a0 100644
--- a/cmd/webclient/http_server.go
+++ b/cmd/webclient/http_server.go
@@ -180,7 +180,7 @@ func addMessageHandler(app *App) func(req *air.Request, res *air.Response) error
}
if msg.Id == "" {
- msg.Id = uuid.New().String()
+ msg.Id = uuid.NewString()
}
app.SendMsg(model.MakeChatMessage(msg))
app.messages.Add(msg)
diff --git a/cmd/webclient/processors.go b/cmd/webclient/processors.go
index 83983a0..661885a 100644
--- a/cmd/webclient/processors.go
+++ b/cmd/webclient/processors.go
@@ -48,9 +48,9 @@ func (app *App) loggerProcessor(msg *cot.CotMessage) {
func (app *App) removeItemProcessor(msg *cot.CotMessage) {
// t-x-d-d
- if msg.Detail != nil && msg.Detail.Has("link") {
- uid := msg.Detail.GetFirst("link").GetAttr("uid")
- typ := msg.Detail.GetFirst("link").GetAttr("type")
+ if link := msg.GetFirstLink("p-p"); link != nil {
+ uid := link.GetAttr("uid")
+ typ := link.GetAttr("type")
if uid == "" {
app.Logger.Warnf("invalid remove message: %s", msg.Detail)
return
@@ -60,7 +60,6 @@ func (app *App) removeItemProcessor(msg *cot.CotMessage) {
case model.CONTACT:
app.Logger.Debugf("remove %s by message", uid)
v.SetOffline()
- app.processChange(v)
return
case model.UNIT, model.POINT:
app.Logger.Debugf("remove unit/point %s type %s by message", uid, typ)
diff --git a/pkg/cot/cotmessage.go b/pkg/cot/cotmessage.go
index 8baa875..71a8245 100644
--- a/pkg/cot/cotmessage.go
+++ b/pkg/cot/cotmessage.go
@@ -113,14 +113,14 @@ func (m *CotMessage) IsChat() bool {
if m == nil || m.TakMessage == nil {
return false
}
- return m.GetType() == "b-t-f" && m.Detail != nil && m.Detail.Has("__chat")
+ return m.GetType() == "b-t-f"
}
func (m *CotMessage) IsChatReceipt() bool {
if m == nil || m.TakMessage == nil {
return false
}
- return (m.GetType() == "b-t-f-r" || m.GetType() == "b-t-f-d") && m.Detail != nil && m.Detail.Has("__chatreceipt")
+ return m.GetType() == "b-t-f-r" || m.GetType() == "b-t-f-d"
}
func (m *CotMessage) PrintChat() string {
@@ -161,6 +161,9 @@ func (m *CotMessage) GetLon() float64 {
}
func (m *CotMessage) GetParent() (string, string) {
+ if m.Detail == nil {
+ return "", ""
+ }
for _, link := range m.Detail.GetAll("link") {
if link.GetAttr("relation") == "p-p" {
return link.GetAttr("uid"), link.GetAttr("parent_callsign")
@@ -169,6 +172,18 @@ func (m *CotMessage) GetParent() (string, string) {
return "", ""
}
+func (m *CotMessage) GetFirstLink(relation string) *Node {
+ if m.Detail == nil {
+ return nil
+ }
+ for _, link := range m.Detail.GetAll("link") {
+ if link.GetAttr("relation") == relation {
+ return link
+ }
+ }
+ return nil
+}
+
func TimeFromMillis(ms uint64) time.Time {
return time.Unix(0, 1000000*int64(ms))
}
diff --git a/pkg/cot/node.go b/pkg/cot/node.go
index 9385b2b..4bc66d1 100644
--- a/pkg/cot/node.go
+++ b/pkg/cot/node.go
@@ -45,7 +45,7 @@ func DetailsFromString(s string) (*Node, error) {
return x, err
}
-func (n *Node) AddLink(uid, typ, parent string) {
+func (n *Node) AddPpLink(uid, typ, callsign string) {
params := make(map[string]string)
if uid != "" {
params["uid"] = uid
@@ -53,8 +53,8 @@ func (n *Node) AddLink(uid, typ, parent string) {
if typ != "" {
params["type"] = typ
}
- if parent != "" {
- params["parent_callsign"] = parent
+ if callsign != "" {
+ params["parent_callsign"] = callsign
}
//params["production_time"] = prodTime.UTC().Format(time.RFC3339)
params["relation"] = "p-p"
diff --git a/pkg/cot/util.go b/pkg/cot/util.go
index 04cf973..ded83c8 100644
--- a/pkg/cot/util.go
+++ b/pkg/cot/util.go
@@ -43,7 +43,7 @@ func MakeOfflineMsg(uid string, typ string) *cotproto.TakMessage {
msg := BasicMsg("t-x-d-d", uuid.New().String(), time.Minute*3)
msg.CotEvent.How = "h-g-i-g-o"
xd := NewXmlDetails()
- xd.AddLink(uid, typ, "")
+ xd.AddPpLink(uid, typ, "")
msg.CotEvent.Detail = &cotproto.Detail{XmlDetail: xd.AsXMLString()}
return msg
}
@@ -54,7 +54,7 @@ func MakeDpMsg(uid string, typ string, name string, lat float64, lon float64) *c
msg.CotEvent.Lat = lat
msg.CotEvent.Lon = lon
xd := NewXmlDetails()
- xd.AddLink(uid, typ, "")
+ xd.AddPpLink(uid, typ, "")
msg.CotEvent.Detail = &cotproto.Detail{
XmlDetail: xd.AsXMLString(),
Contact: &cotproto.Contact{Callsign: name},
diff --git a/pkg/model/chat.go b/pkg/model/chat.go
index 7e4b393..7324578 100644
--- a/pkg/model/chat.go
+++ b/pkg/model/chat.go
@@ -78,41 +78,6 @@ func (m *ChatMessage) String() string {
return fmt.Sprintf("Chat %s (%s) -> %s (%s) \"%s\"", m.From, m.FromUid, m.Chatroom, m.ToUid, m.Text)
}
-// direct
-// <__chat parent="RootContactGroup" groupOwner="false" chatroom="Cl1" id="{{uid_to}}" senderCallsign="Kott">
-//
-//
-// Roger
-// <__serverdestination destinations="192.168.0.15:4242:tcp:{{uid_from}}"/>
-//
-
-// chatroom
-// <__chat parent="RootContactGroup" groupOwner="false" chatroom="All Chat Rooms" id="All Chat Rooms" senderCallsign="Kott">
-//
-//
-// Roger
-// <__serverdestination destinations="192.168.0.15:4242:tcp:{{uid_from}}"/>
-
-// red
-// <__chat parent="TeamGroups" groupOwner="false" chatroom="Red" id="Red" senderCallsign="Kott">
-//
-//
-// at VDO
-// <__serverdestination destinations="192.168.0.15:4242:tcp:ANDROID-dc4a1fb7ad4180be"/>
-//
-
-// add contact to group
-// <__chat parent="UserGroups" groupOwner="true" messageId="82741635-04dc-413b-9b66-289fde3e22f0" chatroom="j" id="c06c2986-f122-4e85-b213-88498a6fe8bb" senderCallsign="Kott">
-//
-//
-//
-//
-//
-//
-//
-// <__serverdestination destinations="192.168.1.72:4242:tcp:ANDROID-765a942cbe30d010"/>
-// [UPDATED CONTACTS]
-
func MsgToChat(m *cot.CotMessage) *ChatMessage {
chat := m.Detail.GetFirst("__chat")
if chat == nil {
@@ -125,19 +90,23 @@ func MsgToChat(m *cot.CotMessage) *ChatMessage {
Parent: chat.GetAttr("parent"),
Chatroom: chat.GetAttr("chatroom"),
From: chat.GetAttr("senderCallsign"),
+ ToUid: chat.GetAttr("id"),
}
if cg := chat.GetFirst("chatgrp"); cg != nil {
c.FromUid = cg.GetAttr("uid0")
- c.ToUid = cg.GetAttr("uid1")
}
- for _, dest := range m.Detail.GetFirst("marti").GetAll("dest") {
- if dest.GetAttr("callsign") != "" {
- c.Direct = true
+ if link := m.GetFirstLink("p-p"); link != nil {
+ if uid := link.GetAttr("uid"); uid != "" {
+ c.FromUid = uid
}
}
+ if c.Chatroom != c.ToUid {
+ c.Direct = true
+ }
+
if rem := m.Detail.GetFirst("remarks"); rem != nil {
c.Text = html.UnescapeString(rem.GetText())
} else {
@@ -152,14 +121,14 @@ func MakeChatMessage(c *ChatMessage) *cotproto.TakMessage {
msgUid := fmt.Sprintf("GeoChat.%s.%s.%s", c.FromUid, c.ToUid, c.Id)
msg := cot.BasicMsg("b-t-f", msgUid, time.Second*10)
xd := cot.NewXmlDetails()
- xd.AddLink(c.FromUid, "", "")
+ xd.AddPpLink(c.FromUid, "", "")
- chat := xd.AddChild("__chat", map[string]string{"parent": "RootContactGroup", "groupOwner": "false", "chatroom": c.Chatroom, "senderCallsign": c.From, "id": c.ToUid, "messageId": c.Id}, "")
+ chat := xd.AddChild("__chat", map[string]string{"parent": c.Parent, "groupOwner": "false", "chatroom": c.Chatroom, "senderCallsign": c.From, "id": c.ToUid, "messageId": c.Id}, "")
chat.AddChild("chatgrp", map[string]string{"uid0": c.FromUid, "uid1": c.ToUid, "id": c.ToUid}, "")
xd.AddChild("remarks", map[string]string{"source": "BAO.F.ATAK." + c.FromUid, "to": c.ToUid, "time": t}, html.EscapeString(c.Text))
- if c.Chatroom != c.ToUid {
+ if c.Direct {
marti := xd.AddChild("marti", nil, "")
marti.AddChild("dest", map[string]string{"callsign": c.Chatroom}, "")
}
diff --git a/pkg/model/chat_test.go b/pkg/model/chat_test.go
new file mode 100644
index 0000000..233ae0c
--- /dev/null
+++ b/pkg/model/chat_test.go
@@ -0,0 +1,99 @@
+package model
+
+import (
+ "github.com/kdudkov/goatak/pkg/cot"
+ "github.com/kdudkov/goatak/pkg/cotproto"
+ "github.com/magiconair/properties/assert"
+ "testing"
+ "time"
+)
+
+func TestChat(t *testing.T) {
+ // user1 (uid1) -> user2 (uid2)
+
+ d := "<__chat parent=\"RootContactGroup\" groupOwner=\"false\" messageId=\"4de0262c-633f-46eb-b8e5-5ef1eb1e5e22\" chatroom=\"user2\" id=\"uid2\" senderCallsign=\"user1\">" +
+ "" +
+ "" +
+ "<__serverdestination destinations=\"1.1.1.1:4242:tcp:uid1\"/>" +
+ "at breach" +
+ ""
+
+ m := cot.BasicMsg("b-t-f", "GeoChat.uid1.uid2.4de0262c-633f-46eb-b8e5-5ef1eb1e5e22", time.Minute)
+ xd, _ := cot.DetailsFromString(d)
+ m.CotEvent.Detail = &cotproto.Detail{XmlDetail: xd.AsXMLString()}
+ msg := cot.CotMessage{TakMessage: m, Detail: xd}
+
+ assert.Equal(t, msg.IsChat(), true)
+
+ cm := MsgToChat(&msg)
+
+ assert.Equal(t, cm.From, "user1")
+ assert.Equal(t, cm.FromUid, "uid1")
+ assert.Equal(t, cm.ToUid, "uid2")
+ assert.Equal(t, cm.Chatroom, "user2")
+ assert.Equal(t, cm.Direct, true)
+}
+
+func TestBtfd(t *testing.T) {
+ d := "<__chatreceipt parent=\"RootContactGroup\" groupOwner=\"false\" messageId=\"4de0262c-633f-46eb-b8e5-5ef1eb1e5e22\" chatroom=\"user1\" id=\"uid1\" senderCallsign=\"user2\">" +
+ "" +
+ "" +
+ "<__serverdestination destinations=\"2.2.2.2:4242:tcp:uid2\"/>" +
+ ""
+
+ m := cot.BasicMsg("b-t-f-d", "4de0262c-633f-46eb-b8e5-5ef1eb1e5e22", time.Minute)
+ xd, _ := cot.DetailsFromString(d)
+ m.CotEvent.Detail = &cotproto.Detail{XmlDetail: xd.AsXMLString()}
+ msg := cot.CotMessage{TakMessage: m, Detail: xd}
+
+ assert.Equal(t, msg.IsChatReceipt(), true)
+
+ //cm := MsgToChat(&msg)
+ //
+ //assert.Equal(t, cm.From, "user1")
+ //assert.Equal(t, cm.FromUid, "uid1")
+ //assert.Equal(t, cm.ToUid, "uid2")
+ //assert.Equal(t, cm.Chatroom, "user2")
+ //assert.Equal(t, cm.Direct, true)
+}
+
+func TestBtfr(t *testing.T) {
+ d := "<__chatreceipt parent=\"RootContactGroup\" groupOwner=\"false\" messageId=\"4de0262c-633f-46eb-b8e5-5ef1eb1e5e22\" chatroom=\"user1\" id=\"uid1\" senderCallsign=\"user2\">" +
+ "" +
+ "" +
+ "<__serverdestination destinations=\"2.2.2.2:4242:tcp:uid2\"/>" +
+ ""
+
+ m := cot.BasicMsg("b-t-f-r", "4de0262c-633f-46eb-b8e5-5ef1eb1e5e22", time.Minute)
+ xd, _ := cot.DetailsFromString(d)
+ m.CotEvent.Detail = &cotproto.Detail{XmlDetail: xd.AsXMLString()}
+ msg := cot.CotMessage{TakMessage: m, Detail: xd}
+
+ assert.Equal(t, msg.IsChatReceipt(), true)
+}
+
+func TestMsgRed(t *testing.T) {
+ // user1 - Red
+ d := "<__chat parent=\"TeamGroups\" groupOwner=\"false\" messageId=\"9f46716f-c875-43b0-8162-3da74196353f\" chatroom=\"Red\" id=\"Red\" senderCallsign=\"user1\">" +
+ "" +
+ "" +
+ "<__serverdestination destinations=\"1.1.1.1:4242:tcp:uid1\"/>" +
+ "Roger" +
+ ""
+
+ m := cot.BasicMsg("b-t-f", "GeoChat.uid1.Red.9f46716f-c875-43b0-8162-3da74196353f", time.Minute)
+ xd, _ := cot.DetailsFromString(d)
+ m.CotEvent.Detail = &cotproto.Detail{XmlDetail: xd.AsXMLString()}
+ msg := cot.CotMessage{TakMessage: m, Detail: xd}
+
+ assert.Equal(t, msg.IsChat(), true)
+
+ cm := MsgToChat(&msg)
+
+ assert.Equal(t, cm.From, "user1")
+ assert.Equal(t, cm.FromUid, "uid1")
+ assert.Equal(t, cm.ToUid, "Red")
+ assert.Equal(t, cm.Chatroom, "Red")
+ assert.Equal(t, cm.Direct, false)
+ assert.Equal(t, cm.Text, "Roger")
+}