initial commit
|
@ -0,0 +1,41 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.openprivacy.ca/openprivacy/libricochet-go/application"
|
||||||
|
"git.openprivacy.ca/openprivacy/libricochet-go/channels"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ChatChannelListener struct {
|
||||||
|
rai *application.ApplicationInstance
|
||||||
|
ra *application.RicochetApplication
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func (this *ChatChannelListener) Init(rai *application.ApplicationInstance, ra *application.RicochetApplication) {
|
||||||
|
this.rai = rai
|
||||||
|
this.ra = ra
|
||||||
|
}
|
||||||
|
|
||||||
|
// We always want bidirectional chat channels
|
||||||
|
func (this *ChatChannelListener) OpenInbound() {
|
||||||
|
outboutChatChannel := this.rai.Connection.Channel("im.ricochet.chat", channels.Outbound)
|
||||||
|
if outboutChatChannel == nil {
|
||||||
|
this.rai.Connection.Do(func() error {
|
||||||
|
this.rai.Connection.RequestOpenChannel("im.ricochet.chat",
|
||||||
|
&channels.ChatChannel{
|
||||||
|
Handler: this,
|
||||||
|
})
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *ChatChannelListener) ChatMessage(messageID uint32, when time.Time, message string) bool {
|
||||||
|
DeliverMessageToUI(this.rai.RemoteHostname, message, uint(messageID), false, when)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *ChatChannelListener) ChatMessageAck(messageID uint32, accepted bool) {
|
||||||
|
gcd.Acknowledged(acknowledgementIDs[messageID])
|
||||||
|
}
|
80
gcd.go
|
@ -6,22 +6,27 @@ import (
|
||||||
"github.com/therecipe/qt/core"
|
"github.com/therecipe/qt/core"
|
||||||
"log"
|
"log"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var TIME_FORMAT = "Mon 3:04pm"
|
||||||
|
|
||||||
type GrandCentralDispatcher struct {
|
type GrandCentralDispatcher struct {
|
||||||
core.QObject
|
core.QObject
|
||||||
|
|
||||||
currentOpenConversation string
|
currentOpenConversation string
|
||||||
|
|
||||||
// messages pane stuff
|
// messages pane stuff
|
||||||
_ func(from, message string) `signal:"AppendMessage"`
|
_ func(from, message string, mID uint, ts string) `signal:"AppendMessage"`
|
||||||
_ func() `signal:"ClearMessages"`
|
_ func() `signal:"ClearMessages"`
|
||||||
_ func() `signal:"ResetMessagePane"`
|
_ func() `signal:"ResetMessagePane"`
|
||||||
|
_ func(uint) `signal:"Acknowledged"`
|
||||||
|
|
||||||
// contact list stuff
|
// contact list stuff
|
||||||
_ func(onion string, num int) `signal:"SetUnread"`
|
_ func(onion string, num int) `signal:"SetUnread"`
|
||||||
_ func(onion string, status int) `signal:"SetConnectionStatus"`
|
_ func(onion string, status int) `signal:"SetConnectionStatus"`
|
||||||
_ func(name, onion, image, badge string, trusted bool) `signal:"AddContact"`
|
_ func(name, onion, server, image, badge string, trusted bool) `signal:"AddContact"`
|
||||||
_ func(onion string) `signal:"MarkTrusted"`
|
_ func(onion string) `signal:"MarkTrusted"`
|
||||||
|
|
||||||
// profile-area stuff
|
// profile-area stuff
|
||||||
|
@ -32,15 +37,15 @@ type GrandCentralDispatcher struct {
|
||||||
_ func(str string) `signal:"InvokePopup"`
|
_ func(str string) `signal:"InvokePopup"`
|
||||||
|
|
||||||
// exfiltrated signals (written in go, below)
|
// exfiltrated signals (written in go, below)
|
||||||
_ func(message string) `signal:"sendMessage,auto"`
|
_ func(message string, mid uint) `signal:"sendMessage,auto"`
|
||||||
_ func(onion string) `signal:"loadMessagesPane,auto"`
|
_ func(onion string) `signal:"loadMessagesPane,auto"`
|
||||||
_ func(signal string) `signal:"broadcast,auto"` // convenience relay signal
|
_ func(signal string) `signal:"broadcast,auto"` // convenience relay signal
|
||||||
_ func(str string) `signal:"importString,auto"`
|
_ func(str string) `signal:"importString,auto"`
|
||||||
_ func(str string) `signal:"popup,auto"`
|
_ func(str string) `signal:"popup,auto"`
|
||||||
_ func(nick string) `signal:"updateNick,auto"`
|
_ func(nick string) `signal:"updateNick,auto"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *GrandCentralDispatcher) sendMessage(message string) {
|
func (this *GrandCentralDispatcher) sendMessage(message string, mID uint) {
|
||||||
if len(message) > 65530 {
|
if len(message) > 65530 {
|
||||||
gcd.InvokePopup("message is too long")
|
gcd.InvokePopup("message is too long")
|
||||||
return
|
return
|
||||||
|
@ -50,6 +55,16 @@ func (this *GrandCentralDispatcher) sendMessage(message string) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(gcd.currentOpenConversation) == 32 { // SEND TO GROUP
|
||||||
|
if !peer.GetGroup(gcd.currentOpenConversation).Accepted {
|
||||||
|
peer.GetGroup(gcd.currentOpenConversation).Accepted = true
|
||||||
|
peer.Save()
|
||||||
|
}
|
||||||
|
|
||||||
|
peer.SendMessageToGroup(gcd.currentOpenConversation, message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: require explicit invite accept/reject instead of implicitly trusting on send
|
// TODO: require explicit invite accept/reject instead of implicitly trusting on send
|
||||||
if !peer.GetContact(gcd.currentOpenConversation).Trusted {
|
if !peer.GetContact(gcd.currentOpenConversation).Trusted {
|
||||||
peer.GetContact(gcd.currentOpenConversation).Trusted = true
|
peer.GetContact(gcd.currentOpenConversation).Trusted = true
|
||||||
|
@ -57,13 +72,13 @@ func (this *GrandCentralDispatcher) sendMessage(message string) {
|
||||||
gcd.MarkTrusted(gcd.currentOpenConversation)
|
gcd.MarkTrusted(gcd.currentOpenConversation)
|
||||||
}
|
}
|
||||||
|
|
||||||
select { // fancy trick to do a non-blocking send. this means the user can only send a limited number of messages
|
select { // 1 weird trick to do a non-blocking send. this means the user can only send a limited number of messages
|
||||||
// before the channel buffer fills. TODO: stop the user from sending if the buffer is full
|
// before the channel buffer fills. TODO: stop the user from sending if the buffer is full
|
||||||
case outgoingMessages <- Message{gcd.currentOpenConversation, message, true}:
|
case outgoingMessages <- Message{gcd.currentOpenConversation, message, true, mID, time.Now()}:
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
DeliverMessageToUI(gcd.currentOpenConversation, message, true)
|
DeliverMessageToUI(gcd.currentOpenConversation, message, mID, true, time.Now())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *GrandCentralDispatcher) loadMessagesPane(onion string) {
|
func (this *GrandCentralDispatcher) loadMessagesPane(onion string) {
|
||||||
|
@ -71,6 +86,16 @@ func (this *GrandCentralDispatcher) loadMessagesPane(onion string) {
|
||||||
gcd.currentOpenConversation = onion
|
gcd.currentOpenConversation = onion
|
||||||
gcd.SetUnread(onion, 0)
|
gcd.SetUnread(onion, 0)
|
||||||
|
|
||||||
|
if len(onion) == 32 { // eg 48e7dcfc353e6d77da2c31d63654fd19
|
||||||
|
log.Printf("LOADING GROUP %s", onion)
|
||||||
|
tl := peer.GetGroup(onion).GetTimeline()
|
||||||
|
log.Printf("messages: %d", len(tl))
|
||||||
|
for i := range tl {
|
||||||
|
gcd.AppendMessage(tl[i].PeerID, tl[i].Message, 0, tl[i].Timestamp.Format(TIME_FORMAT))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
_, exists := contactMgr[onion]
|
_, exists := contactMgr[onion]
|
||||||
if exists { // (if not, they haven't been accepted as a contact yet)
|
if exists { // (if not, they haven't been accepted as a contact yet)
|
||||||
contactMgr[onion].Unread = 0
|
contactMgr[onion].Unread = 0
|
||||||
|
@ -81,7 +106,7 @@ func (this *GrandCentralDispatcher) loadMessagesPane(onion string) {
|
||||||
if messages[i].FromMe {
|
if messages[i].FromMe {
|
||||||
from = "me"
|
from = "me"
|
||||||
}
|
}
|
||||||
gcd.AppendMessage(from, messages[i].Message)
|
gcd.AppendMessage(from, messages[i].Message, messages[i].MessageID, messages[i].Timestamp.Format(TIME_FORMAT))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -89,7 +114,7 @@ func (this *GrandCentralDispatcher) loadMessagesPane(onion string) {
|
||||||
func (this *GrandCentralDispatcher) broadcast(signal string) {
|
func (this *GrandCentralDispatcher) broadcast(signal string) {
|
||||||
switch signal {
|
switch signal {
|
||||||
default:
|
default:
|
||||||
log.Fatalf("unhandled broadcast signal: %v", signal)
|
log.Printf("unhandled broadcast signal: %v", signal)
|
||||||
case "ResetMessagePane":
|
case "ResetMessagePane":
|
||||||
gcd.ResetMessagePane()
|
gcd.ResetMessagePane()
|
||||||
}
|
}
|
||||||
|
@ -99,10 +124,27 @@ func (this *GrandCentralDispatcher) importString(str string) {
|
||||||
log.Printf("importing: %s\n", str)
|
log.Printf("importing: %s\n", str)
|
||||||
onion := str
|
onion := str
|
||||||
name := onion
|
name := onion
|
||||||
|
str = strings.TrimSpace(str)
|
||||||
|
|
||||||
if strings.Contains(str, " ") {// usually people prepend spaces and we don't want it going into the name (use ~ for that)
|
//eg: torv3JFDWkXExBsZLkjvfkkuAxHsiLGZBk0bvoeJID9ItYnU=EsEBCiBhOWJhZDU1OTQ0NWI3YmM2N2YxYTM5YjkzMTNmNTczNRIgpHeNaG+6jy750eDhwLO39UX4f2xs0irK/M3P6mDSYQIaOTJjM2ttb29ibnlnaGoyenc2cHd2N2Q1N3l6bGQ3NTNhdW8zdWdhdWV6enB2ZmFrM2FoYzRiZHlkCiJAdVSSVgsksceIfHe41OJu9ZFHO8Kwv3G6F5OK3Hw4qZ6hn6SiZjtmJlJezoBH0voZlCahOU7jCOg+dsENndZxAA==
|
||||||
|
if str[0:5] == "torv3" { // GROUP INVITE
|
||||||
|
groupID, err := peer.ImportGroup(str)
|
||||||
|
if err != nil {
|
||||||
|
gcd.InvokePopup("not a valid group invite")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
group := peer.GetGroup(groupID)
|
||||||
|
peer.JoinServer(group.GroupServer)
|
||||||
|
peer.Save()
|
||||||
|
fmt.Printf("imported groupid=%s server=%s", groupID, group.GroupServer)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.Contains(str, " ") { // usually people prepend spaces and we don't want it going into the name (use ~ for that)
|
||||||
parts := strings.Split(strings.TrimSpace(str), " ")
|
parts := strings.Split(strings.TrimSpace(str), " ")
|
||||||
str = parts[len(parts) - 1]
|
str = parts[len(parts)-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.Contains(str, "~") {
|
if strings.Contains(str, "~") {
|
||||||
|
|
120
main.go
|
@ -17,7 +17,12 @@ import (
|
||||||
"time"
|
"time"
|
||||||
"strconv"
|
"strconv"
|
||||||
"git.openprivacy.ca/openprivacy/asaur"
|
"git.openprivacy.ca/openprivacy/asaur"
|
||||||
)
|
"git.openprivacy.ca/openprivacy/libricochet-go/application"
|
||||||
|
"git.openprivacy.ca/openprivacy/libricochet-go/channels"
|
||||||
|
"log"
|
||||||
|
"cwtch.im/cwtch/model"
|
||||||
|
"encoding/hex"
|
||||||
|
)
|
||||||
|
|
||||||
var gcd *GrandCentralDispatcher
|
var gcd *GrandCentralDispatcher
|
||||||
|
|
||||||
|
@ -27,6 +32,9 @@ var contactMgr ContactManager
|
||||||
var peer libpeer.CwtchPeer
|
var peer libpeer.CwtchPeer
|
||||||
var outgoingMessages chan Message
|
var outgoingMessages chan Message
|
||||||
|
|
||||||
|
// need this to translate from the message IDs the UI uses to the ones the acknowledgement system uses on the wire
|
||||||
|
var acknowledgementIDs map[uint32]uint
|
||||||
|
|
||||||
type Contact struct {
|
type Contact struct {
|
||||||
Messages []Message
|
Messages []Message
|
||||||
Unread int
|
Unread int
|
||||||
|
@ -40,20 +48,22 @@ func (this *Contact) AddMessage(m Message) {
|
||||||
type Message struct {
|
type Message struct {
|
||||||
With, Message string
|
With, Message string
|
||||||
FromMe bool
|
FromMe bool
|
||||||
|
MessageID uint
|
||||||
|
Timestamp time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeliverMessageToUI(from, message string, fromMe bool) {
|
func DeliverMessageToUI(from, message string, mID uint, fromMe bool, ts time.Time) {
|
||||||
_, found := contactMgr[from]
|
_, found := contactMgr[from]
|
||||||
if !found {
|
if !found {
|
||||||
contactMgr[from] = &Contact{[]Message{}, 0, 0}
|
contactMgr[from] = &Contact{[]Message{}, 0, 0}
|
||||||
}
|
}
|
||||||
|
|
||||||
contactMgr[from].AddMessage(Message{from, message, fromMe})
|
contactMgr[from].AddMessage(Message{from, message, fromMe, mID, ts})
|
||||||
if gcd.currentOpenConversation == from {
|
if gcd.currentOpenConversation == from {
|
||||||
if fromMe {
|
if fromMe {
|
||||||
from = "me"
|
from = "me"
|
||||||
}
|
}
|
||||||
gcd.AppendMessage(from, message)
|
gcd.AppendMessage(from, message, mID, ts.Format(TIME_FORMAT))
|
||||||
} else {
|
} else {
|
||||||
contactMgr[from].Unread++
|
contactMgr[from].Unread++
|
||||||
gcd.SetUnread(from, contactMgr[from].Unread)
|
gcd.SetUnread(from, contactMgr[from].Unread)
|
||||||
|
@ -66,6 +76,7 @@ func init() {
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
contactMgr = make(ContactManager)
|
contactMgr = make(ContactManager)
|
||||||
|
acknowledgementIDs = make(map[uint32]uint)
|
||||||
|
|
||||||
core.QCoreApplication_SetAttribute(core.Qt__AA_EnableHighDpiScaling, true)
|
core.QCoreApplication_SetAttribute(core.Qt__AA_EnableHighDpiScaling, true)
|
||||||
widgets.NewQApplication(len(os.Args), os.Args)
|
widgets.NewQApplication(len(os.Args), os.Args)
|
||||||
|
@ -89,22 +100,24 @@ func main() {
|
||||||
view.Show()
|
view.Show()
|
||||||
go torStatusPoller()
|
go torStatusPoller()
|
||||||
go presencePoller()
|
go presencePoller()
|
||||||
|
go groupPoller()
|
||||||
go ricochetListener()
|
go ricochetListener()
|
||||||
go alice()
|
|
||||||
widgets.QApplication_Exec()
|
widgets.QApplication_Exec()
|
||||||
}
|
}
|
||||||
|
|
||||||
func alice() {
|
func groupPoller() {
|
||||||
i := 0
|
|
||||||
|
|
||||||
for {
|
for {
|
||||||
time.Sleep(time.Second * 3)
|
time.Sleep(time.Second * 4)
|
||||||
//words, _ := diceware.Generate(3)
|
|
||||||
//DeliverMessageToUI("f76b5vtleqx2puhwgkords34gs6crgbjqud6sebfzwtlrq4ngbqgcsyd", strings.Join(words, " "), i % 3 == 0)
|
servers := peer.GetServers()
|
||||||
i++
|
groups := peer.GetGroups()
|
||||||
|
for i := range groups {
|
||||||
|
group := peer.GetGroup(groups[i])
|
||||||
|
log.Printf("setting group %s to status %d", groups[i], int(servers[group.GroupServer]))
|
||||||
|
gcd.SetConnectionStatus(groups[i], int(servers[group.GroupServer]))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func presencePoller() { // TODO: make this subscribe-able in ricochet
|
func presencePoller() { // TODO: make this subscribe-able in ricochet
|
||||||
time.Sleep(time.Second * 4)
|
time.Sleep(time.Second * 4)
|
||||||
for {
|
for {
|
||||||
|
@ -117,7 +130,7 @@ func presencePoller() { // TODO: make this subscribe-able in ricochet
|
||||||
peer.GetProfile().SetCustomAttribute(contacts[i]+"_name", c.Name)
|
peer.GetProfile().SetCustomAttribute(contacts[i]+"_name", c.Name)
|
||||||
peer.GetProfile().SetCustomAttribute(c.Name+"_onion", contacts[i])
|
peer.GetProfile().SetCustomAttribute(c.Name+"_onion", contacts[i])
|
||||||
peer.Save()
|
peer.Save()
|
||||||
gcd.AddContact(c.Name, contacts[i], randomProfileImage(contacts[i]), "0", c.Trusted)
|
gcd.AddContact(c.Name, contacts[i], "", randomProfileImage(contacts[i]), "0", c.Trusted)
|
||||||
}
|
}
|
||||||
|
|
||||||
c, found := peer.GetPeers()[contacts[i]]
|
c, found := peer.GetPeers()[contacts[i]]
|
||||||
|
@ -162,36 +175,18 @@ func torStatusPoller() {
|
||||||
}
|
}
|
||||||
|
|
||||||
gcd.TorStatus(2, status["SUMMARY"])
|
gcd.TorStatus(2, status["SUMMARY"])
|
||||||
//qCwtchApp.SetTorStatusProgress(progress)
|
}
|
||||||
//qCwtchApp.SetTorStatusSummary(status["SUMMARY"])
|
}
|
||||||
//if status["TAG"] == "done" {
|
|
||||||
|
func cwtchListener(groupID string, channel chan model.Message) {
|
||||||
|
for {
|
||||||
|
m := <-channel
|
||||||
|
log.Printf("GROUPMSG %s", m.Message)
|
||||||
|
DeliverMessageToUI(groupID, m.Message, 0, m.PeerID == peer.GetProfile().Onion, m.Timestamp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ricochetListener() {
|
func ricochetListener() {
|
||||||
processData := func(onion string, data []byte) []byte {
|
|
||||||
/* _, exists := peer.GetProfile().GetCustomAttribute(onion + "_name")
|
|
||||||
if !exists {
|
|
||||||
for peer.GetContact(onion) == nil {
|
|
||||||
time.Sleep(time.Millisecond * 30)
|
|
||||||
}
|
|
||||||
|
|
||||||
name := peer.GetContact(onion).Name
|
|
||||||
|
|
||||||
fmt.Printf("adding new untrusted contact %v <%v>\n", name, onion)
|
|
||||||
peer.GetProfile().SetCustomAttribute(onion+"_name", name)
|
|
||||||
peer.GetProfile().SetCustomAttribute(name+"_onion", onion)
|
|
||||||
peer.Save()
|
|
||||||
|
|
||||||
gcd.AddContact(name, onion, randomProfileImage(onion), "0", false)
|
|
||||||
} */
|
|
||||||
|
|
||||||
DeliverMessageToUI(onion, string(data), false)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
peer.SetPeerDataHandler(processData)
|
|
||||||
fmt.Fprintf(os.Stderr, "waiting for messages...\n")
|
|
||||||
err := peer.Listen()
|
err := peer.Listen()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("error listening for connections: %v\n", err)
|
fmt.Printf("error listening for connections: %v\n", err)
|
||||||
|
@ -219,7 +214,13 @@ func andHisBlackAndWhiteCat(incomingMessages chan Message) {
|
||||||
for {
|
for {
|
||||||
m := <-incomingMessages
|
m := <-incomingMessages
|
||||||
connection := peer.PeerWithOnion(m.With)
|
connection := peer.PeerWithOnion(m.With)
|
||||||
connection.SendPacket([]byte(m.Message))
|
connection.DoOnChannel("im.ricochet.chat", channels.Outbound, func(channel *channels.Channel) {
|
||||||
|
chatchannel, ok := channel.Handler.(*channels.ChatChannel)
|
||||||
|
if ok {
|
||||||
|
log.Printf("Sending packet")
|
||||||
|
acknowledgementIDs[chatchannel.SendMessage(m.Message)] = m.MessageID
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -257,11 +258,36 @@ func initialize(view *quick.QQuickView) {
|
||||||
|
|
||||||
gcd.UpdateMyProfile(peer.GetProfile().Name, peer.GetProfile().Onion, randomProfileImage(peer.GetProfile().Onion))
|
gcd.UpdateMyProfile(peer.GetProfile().Name, peer.GetProfile().Onion, randomProfileImage(peer.GetProfile().Onion))
|
||||||
|
|
||||||
|
aif := application.ApplicationInstanceFactory{}
|
||||||
|
aif.Init()
|
||||||
|
app := new(application.RicochetApplication)
|
||||||
|
aif.AddHandler("im.ricochet.chat", func(rai *application.ApplicationInstance) func() channels.Handler {
|
||||||
|
ccl := new(ChatChannelListener)
|
||||||
|
ccl.Init(rai, app)
|
||||||
|
return func() channels.Handler {
|
||||||
|
chat := new(channels.ChatChannel)
|
||||||
|
chat.Handler = ccl
|
||||||
|
return chat
|
||||||
|
}
|
||||||
|
})
|
||||||
|
peer.SetApplicationInstanceFactory(aif)
|
||||||
|
|
||||||
contacts := peer.GetContacts()
|
contacts := peer.GetContacts()
|
||||||
for i := range contacts {
|
for i := range contacts {
|
||||||
attr, _ := peer.GetProfile().GetCustomAttribute(contacts[i] + "_name")
|
attr, _ := peer.GetProfile().GetCustomAttribute(contacts[i] + "_name")
|
||||||
contactMgr[contacts[i]] = &Contact{[]Message{}, 0, 0}
|
contactMgr[contacts[i]] = &Contact{[]Message{}, 0, 0}
|
||||||
gcd.AddContact(attr, contacts[i], randomProfileImage(contacts[i]), "0", peer.GetContact(contacts[i]).Trusted)
|
gcd.AddContact(attr, contacts[i], "", randomProfileImage(contacts[i]), "0", peer.GetContact(contacts[i]).Trusted)
|
||||||
|
}
|
||||||
|
|
||||||
|
groups := peer.GetGroups()
|
||||||
|
for i := range groups {
|
||||||
|
group := peer.GetGroup(groups[i])
|
||||||
|
group.NewMessage = make(chan model.Message)
|
||||||
|
go cwtchListener(groups[i], group.NewMessage)
|
||||||
|
peer.JoinServer(group.GroupServer)
|
||||||
|
//TODO: base the profileImage off the groupid, not the server. probably by decoding it and then re-encoding it b32
|
||||||
|
gcd.AddContact(group.GroupID[:12], group.GroupID, group.GroupServer, randomGroupImage(groups[i]), "0", group.Accepted)
|
||||||
|
log.Printf("GROUP %s@%s", group.GroupID, group.GroupServer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -275,3 +301,13 @@ func randomProfileImage(onion string) string {
|
||||||
}
|
}
|
||||||
return "qrc:/qml/images/profiles/" + choices[int(barr[33])%len(choices)] + ".png"
|
return "qrc:/qml/images/profiles/" + choices[int(barr[33])%len(choices)] + ".png"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func randomGroupImage(onion string) string {
|
||||||
|
choices := []string{"001-borobudur","002-opera-house","003-burj-al-arab","004-chrysler","005-acropolis","006-empire-state-building","007-temple","008-indonesia-1","009-new-zealand","010-notre-dame","011-space-needle","012-seoul","013-mosque","014-milan","015-statue","016-pyramid","017-cologne","018-brandenburg-gate","019-berlin-cathedral","020-hungarian-parliament","021-buckingham","022-thailand","023-independence","024-angkor-wat","025-vaticano","026-christ-the-redeemer","027-colosseum","028-golden-gate-bridge","029-sphinx","030-statue-of-liberty","031-cradle-of-humankind","032-istanbul","033-london-eye","034-sagrada-familia","035-tower-bridge","036-burj-khalifa","037-washington","038-big-ben","039-stonehenge","040-white-house","041-ahu-tongariki","042-capitol","043-eiffel-tower","044-church-of-the-savior-on-spilled-blood","045-arc-de-triomphe","046-windmill","047-louvre","048-torii-gate","049-petronas","050-matsumoto-castle","051-fuji","052-temple-of-heaven","053-pagoda","054-chichen-itza","055-forbidden-city","056-merlion","057-great-wall-of-china","058-taj-mahal","059-pisa","060-indonesia"}
|
||||||
|
barr, err := hex.DecodeString(onion)
|
||||||
|
if err != nil || len(barr) == 0 {
|
||||||
|
fmt.Printf("error: %v %v %v\n", onion, err, barr)
|
||||||
|
return "qrc:/qml/images/extra/openprivacy.png"
|
||||||
|
}
|
||||||
|
return "qrc:/qml/images/servers/" + choices[int(barr[0])%len(choices)] + ".png"
|
||||||
|
}
|
After Width: | Height: | Size: 551 B |
After Width: | Height: | Size: 923 B |
After Width: | Height: | Size: 557 B |
After Width: | Height: | Size: 458 B |
After Width: | Height: | Size: 562 B |
After Width: | Height: | Size: 403 B |
After Width: | Height: | Size: 682 B |
After Width: | Height: | Size: 561 B |
After Width: | Height: | Size: 603 B |
After Width: | Height: | Size: 517 B |
After Width: | Height: | Size: 495 B |
After Width: | Height: | Size: 668 B |
After Width: | Height: | Size: 670 B |
After Width: | Height: | Size: 640 B |
After Width: | Height: | Size: 722 B |
After Width: | Height: | Size: 553 B |
After Width: | Height: | Size: 747 B |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 697 B |
After Width: | Height: | Size: 287 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 849 B |
After Width: | Height: | Size: 989 B |
After Width: | Height: | Size: 662 B |
After Width: | Height: | Size: 245 B |
After Width: | Height: | Size: 723 B |
After Width: | Height: | Size: 481 B |
After Width: | Height: | Size: 453 B |
After Width: | Height: | Size: 847 B |
After Width: | Height: | Size: 205 B |
After Width: | Height: | Size: 835 B |
After Width: | Height: | Size: 387 B |
After Width: | Height: | Size: 230 B |
After Width: | Height: | Size: 402 B |
After Width: | Height: | Size: 559 B |
After Width: | Height: | Size: 652 B |
After Width: | Height: | Size: 406 B |
After Width: | Height: | Size: 336 B |
After Width: | Height: | Size: 233 B |
After Width: | Height: | Size: 390 B |
After Width: | Height: | Size: 244 B |
After Width: | Height: | Size: 411 B |
After Width: | Height: | Size: 940 B |
After Width: | Height: | Size: 279 B |
After Width: | Height: | Size: 978 B |
After Width: | Height: | Size: 919 B |
After Width: | Height: | Size: 884 B |
After Width: | Height: | Size: 666 B |
After Width: | Height: | Size: 871 B |
After Width: | Height: | Size: 805 B |
After Width: | Height: | Size: 419 B |
After Width: | Height: | Size: 1000 B |
After Width: | Height: | Size: 270 B |
After Width: | Height: | Size: 214 B |
After Width: | Height: | Size: 669 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 459 B |
After Width: | Height: | Size: 445 B |
After Width: | Height: | Size: 706 B |
After Width: | Height: | Size: 602 B |
After Width: | Height: | Size: 389 B |
After Width: | Height: | Size: 356 B |
After Width: | Height: | Size: 220 B |
After Width: | Height: | Size: 233 B |
After Width: | Height: | Size: 961 B |
After Width: | Height: | Size: 394 B |
After Width: | Height: | Size: 341 B |
After Width: | Height: | Size: 410 B |
After Width: | Height: | Size: 245 B |
After Width: | Height: | Size: 233 B |
After Width: | Height: | Size: 453 B |
After Width: | Height: | Size: 569 B |
After Width: | Height: | Size: 574 B |
After Width: | Height: | Size: 357 B |
After Width: | Height: | Size: 913 B |
After Width: | Height: | Size: 539 B |
After Width: | Height: | Size: 549 B |
After Width: | Height: | Size: 503 B |
After Width: | Height: | Size: 246 B |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 643 B |
After Width: | Height: | Size: 251 B |
After Width: | Height: | Size: 696 B |
After Width: | Height: | Size: 584 B |
After Width: | Height: | Size: 524 B |
After Width: | Height: | Size: 454 B |
After Width: | Height: | Size: 362 B |
After Width: | Height: | Size: 688 B |
After Width: | Height: | Size: 247 B |
After Width: | Height: | Size: 461 B |
After Width: | Height: | Size: 586 B |
After Width: | Height: | Size: 809 B |
After Width: | Height: | Size: 362 B |
After Width: | Height: | Size: 833 B |