2018-10-23 18:52:13 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2018-11-22 00:01:17 +00:00
|
|
|
libapp "cwtch.im/cwtch/app"
|
|
|
|
"cwtch.im/cwtch/model"
|
2018-11-28 22:14:02 +00:00
|
|
|
"cwtch.im/ui/go/characters"
|
|
|
|
"cwtch.im/ui/go/cwutil"
|
|
|
|
"cwtch.im/ui/go/gobjects"
|
|
|
|
"cwtch.im/ui/go/gothings"
|
|
|
|
"cwtch.im/ui/go/the"
|
|
|
|
"fmt"
|
|
|
|
"git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
|
2018-12-05 16:05:39 +00:00
|
|
|
"git.openprivacy.ca/openprivacy/libricochet-go/log"
|
2018-11-28 22:14:02 +00:00
|
|
|
"github.com/therecipe/qt/core"
|
2019-01-28 22:00:46 +00:00
|
|
|
"github.com/therecipe/qt/network"
|
|
|
|
"github.com/therecipe/qt/qml"
|
2018-10-25 00:13:03 +00:00
|
|
|
"github.com/therecipe/qt/quick"
|
|
|
|
"github.com/therecipe/qt/quickcontrols2"
|
|
|
|
"github.com/therecipe/qt/widgets"
|
|
|
|
"os"
|
|
|
|
"os/user"
|
|
|
|
"path"
|
2018-10-28 02:49:14 +00:00
|
|
|
)
|
2018-10-23 18:52:13 +00:00
|
|
|
|
2018-11-22 00:01:17 +00:00
|
|
|
func init() {
|
|
|
|
// make go-defined types available in qml
|
|
|
|
gothings.GrandCentralDispatcher_QmlRegisterType2("CustomQmlTypes", 1, 0, "GrandCentralDispatcher")
|
2018-10-23 18:52:13 +00:00
|
|
|
}
|
|
|
|
|
2018-11-22 00:01:17 +00:00
|
|
|
func main() {
|
2019-01-21 21:17:51 +00:00
|
|
|
log.SetLevel(log.LevelDebug)
|
|
|
|
|
2018-11-22 00:01:17 +00:00
|
|
|
// our globals
|
|
|
|
gcd := gothings.NewGrandCentralDispatcher(nil)
|
|
|
|
gcd.UIState = gothings.NewUIState(gcd)
|
2019-02-04 22:22:58 +00:00
|
|
|
the.AcknowledgementIDs = make(map[string][]uint)
|
2018-11-22 00:01:17 +00:00
|
|
|
gcd.OutgoingMessages = make(chan gobjects.Letter, 1000)
|
|
|
|
|
|
|
|
//TODO: put theme stuff somewhere better
|
|
|
|
gcd.SetThemeScale(1.0)
|
|
|
|
|
|
|
|
// this is to load local qml files quickly when developing
|
|
|
|
var qmlSource *core.QUrl
|
|
|
|
if len(os.Args) == 2 && os.Args[1] == "-local" {
|
|
|
|
qmlSource = core.QUrl_FromLocalFile("./qml/main.qml")
|
|
|
|
} else {
|
|
|
|
qmlSource = core.NewQUrl3("qrc:/qml/main.qml", 0)
|
|
|
|
}
|
2018-10-23 18:52:13 +00:00
|
|
|
|
2018-11-22 00:01:17 +00:00
|
|
|
// window construction boilerplate
|
|
|
|
view := initializeQtView()
|
2018-10-23 18:52:13 +00:00
|
|
|
|
2018-11-22 00:01:17 +00:00
|
|
|
// variables we want to access from inside qml
|
|
|
|
view.RootContext().SetContextProperty("gcd", gcd)
|
2018-10-23 18:52:13 +00:00
|
|
|
|
2018-11-22 00:01:17 +00:00
|
|
|
// this actually loads the qml
|
|
|
|
view.SetSource(qmlSource)
|
2018-10-23 18:52:13 +00:00
|
|
|
|
2019-02-04 22:34:16 +00:00
|
|
|
acn, err := connectivity.StartTor(the.CwtchDir, "")
|
|
|
|
if err != nil {
|
|
|
|
log.Errorf("Could not start Tor: %v", err)
|
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
|
2018-11-22 00:01:17 +00:00
|
|
|
// these are long-lived pollers/listeners for incoming messages and status changes
|
2019-02-04 22:34:16 +00:00
|
|
|
loadCwtchData(gcd, acn)
|
2019-01-21 21:17:51 +00:00
|
|
|
go characters.IncomingListener(gcd.UIState.AddMessage)
|
2018-11-22 00:01:17 +00:00
|
|
|
go characters.PostmanPat(gcd.OutgoingMessages)
|
|
|
|
go characters.TorStatusPoller(gcd.TorStatus)
|
|
|
|
go characters.PresencePoller(gcd.UIState.GetContact, gcd.UIState.AddContact, gcd.UIState.UpdateContact)
|
|
|
|
go characters.GroupPoller(gcd.UIState.GetContact, gcd.UIState.UpdateContact)
|
2018-10-23 18:52:13 +00:00
|
|
|
|
2019-01-28 22:02:36 +00:00
|
|
|
// prevent qt from initiating network connections (possible deanon attempts!)
|
2019-01-28 22:00:46 +00:00
|
|
|
factory := qml.NewQQmlNetworkAccessManagerFactory()
|
|
|
|
factory.ConnectCreate(func(parent *core.QObject) *network.QNetworkAccessManager {
|
|
|
|
nam := network.NewQNetworkAccessManager(parent)
|
|
|
|
nam.SetNetworkAccessible(network.QNetworkAccessManager__NotAccessible)
|
|
|
|
proxy := network.NewQNetworkProxy()
|
|
|
|
proxy.SetHostName("0.0.0.0")
|
|
|
|
nam.SetProxy(proxy)
|
|
|
|
//nam.ConnectCreateRequest(func(op network.QNetworkAccessManager__Operation, originalReq *network.QNetworkRequest, outgoingData *core.QIODevice) *network.QNetworkReply {
|
|
|
|
// log.Errorf("network access request detected - possible remote content insertion bug!!!")
|
|
|
|
// return nil
|
|
|
|
//})
|
|
|
|
return nam
|
|
|
|
})
|
|
|
|
view.Engine().SetNetworkAccessManagerFactory(factory)
|
2019-01-28 22:02:36 +00:00
|
|
|
|
|
|
|
// here we go!
|
2018-11-22 00:01:17 +00:00
|
|
|
view.Show()
|
|
|
|
widgets.QApplication_Exec()
|
2019-02-04 22:34:16 +00:00
|
|
|
acn.Close()
|
2018-11-22 00:01:17 +00:00
|
|
|
}
|
2018-10-23 18:52:13 +00:00
|
|
|
|
2018-11-22 00:01:17 +00:00
|
|
|
// window construction boilerplate
|
|
|
|
func initializeQtView() *quick.QQuickView {
|
2018-10-23 18:52:13 +00:00
|
|
|
core.QCoreApplication_SetAttribute(core.Qt__AA_EnableHighDpiScaling, true)
|
|
|
|
widgets.NewQApplication(len(os.Args), os.Args)
|
|
|
|
quickcontrols2.QQuickStyle_SetStyle("Universe")
|
|
|
|
view := quick.NewQQuickView(nil)
|
|
|
|
view.SetResizeMode(quick.QQuickView__SizeRootObjectToView)
|
2019-02-04 18:46:59 +00:00
|
|
|
//view.SetMinimumHeight(800) // these end up getting overridden by main.qml
|
|
|
|
//view.SetMinimumWidth(1200)
|
2018-10-29 18:00:21 +00:00
|
|
|
view.SetTitle("cwtch")
|
2018-10-25 00:13:03 +00:00
|
|
|
|
2018-11-22 00:01:17 +00:00
|
|
|
return view
|
2018-10-25 00:13:03 +00:00
|
|
|
}
|
|
|
|
|
2018-11-22 00:01:17 +00:00
|
|
|
// this is mostly going to get factored out when we add profile support
|
|
|
|
// for now, it loads a single peer and fills the ui with its data
|
2019-02-04 22:34:16 +00:00
|
|
|
func loadCwtchData(gcd *gothings.GrandCentralDispatcher, acn connectivity.ACN) {
|
2018-10-30 19:48:37 +00:00
|
|
|
var err error
|
2018-10-29 18:00:21 +00:00
|
|
|
if os.Getenv("CWTCH_FOLDER") != "" {
|
2018-11-22 00:01:17 +00:00
|
|
|
the.CwtchDir = os.Getenv("CWTCH_FOLDER")
|
2018-10-23 18:52:13 +00:00
|
|
|
} else {
|
|
|
|
usr, err := user.Current()
|
|
|
|
if err != nil {
|
|
|
|
fmt.Printf("\nerror: could not load current user: %v\n", err)
|
|
|
|
os.Exit(1)
|
|
|
|
}
|
2018-11-22 00:01:17 +00:00
|
|
|
the.CwtchDir = path.Join(usr.HomeDir, ".cwtch")
|
2018-10-23 18:52:13 +00:00
|
|
|
}
|
|
|
|
|
2018-10-30 19:48:37 +00:00
|
|
|
/*_, err := app2.NewApp(dirname, "/data/data/org.qtproject.example.go/lib/libtor.so")
|
|
|
|
if err != nil {
|
2018-12-05 16:05:39 +00:00
|
|
|
log.Errorf("ERROR CREATING CWTCH APP: %v", err)
|
2018-10-30 19:48:37 +00:00
|
|
|
}
|
|
|
|
time.Sleep(time.Second * 10)
|
|
|
|
*/
|
2018-11-22 00:01:17 +00:00
|
|
|
os.MkdirAll(the.CwtchDir, 0700)
|
2018-10-30 18:43:51 +00:00
|
|
|
|
2019-02-04 22:34:16 +00:00
|
|
|
the.CwtchApp = libapp.NewApp(acn, the.CwtchDir)
|
2018-11-26 21:57:28 +00:00
|
|
|
|
2018-11-22 00:01:17 +00:00
|
|
|
err = the.CwtchApp.LoadProfiles("be gay do crime")
|
2018-10-23 18:52:13 +00:00
|
|
|
if err != nil {
|
2018-11-22 00:01:17 +00:00
|
|
|
//TODO no more fatalfs
|
2018-12-05 16:05:39 +00:00
|
|
|
log.Errorf("couldn't load profiles: %v", err)
|
|
|
|
os.Exit(1)
|
2018-11-22 00:01:17 +00:00
|
|
|
}
|
2018-10-23 18:52:13 +00:00
|
|
|
|
2018-11-22 00:01:17 +00:00
|
|
|
if len(the.CwtchApp.ListPeers()) == 0 {
|
2018-12-05 16:05:39 +00:00
|
|
|
log.Infoln("couldn't load your config file. attempting to create one now")
|
2018-11-22 00:01:17 +00:00
|
|
|
the.Peer, err = the.CwtchApp.CreatePeer("alice", "be gay do crime")
|
2018-10-23 18:52:13 +00:00
|
|
|
if err != nil {
|
2018-12-05 16:05:39 +00:00
|
|
|
log.Errorf("couldn't create one. is your cwtch folder writable?")
|
|
|
|
os.Exit(1)
|
2018-10-23 18:52:13 +00:00
|
|
|
}
|
2018-11-22 00:01:17 +00:00
|
|
|
} else {
|
|
|
|
the.Peer = the.CwtchApp.PrimaryIdentity()
|
2018-10-23 18:52:13 +00:00
|
|
|
}
|
|
|
|
|
2018-11-22 00:01:17 +00:00
|
|
|
gcd.UpdateMyProfile(the.Peer.GetProfile().Name, the.Peer.GetProfile().Onion, cwutil.RandomProfileImage(the.Peer.GetProfile().Onion))
|
|
|
|
the.CwtchApp.LaunchPeers()
|
2018-10-28 02:49:14 +00:00
|
|
|
|
2018-11-22 00:01:17 +00:00
|
|
|
contacts := the.Peer.GetContacts()
|
2018-10-23 18:52:13 +00:00
|
|
|
for i := range contacts {
|
2018-11-22 00:01:17 +00:00
|
|
|
contact, _ := the.Peer.GetProfile().GetContact(contacts[i])
|
2019-02-05 00:41:18 +00:00
|
|
|
displayName, _ := contact.GetAttribute("nick")
|
2018-11-22 00:01:17 +00:00
|
|
|
gcd.UIState.AddContact(&gobjects.Contact{
|
2019-01-21 21:17:51 +00:00
|
|
|
Handle: contacts[i],
|
|
|
|
DisplayName: displayName,
|
|
|
|
Image: cwutil.RandomProfileImage(contacts[i]),
|
|
|
|
Trusted: contact.Trusted,
|
2018-11-22 00:01:17 +00:00
|
|
|
})
|
2018-10-28 02:49:14 +00:00
|
|
|
}
|
|
|
|
|
2018-11-22 00:01:17 +00:00
|
|
|
groups := the.Peer.GetGroups()
|
2018-10-28 02:49:14 +00:00
|
|
|
for i := range groups {
|
2018-11-22 00:01:17 +00:00
|
|
|
group := the.Peer.GetGroup(groups[i])
|
2018-10-28 02:49:14 +00:00
|
|
|
group.NewMessage = make(chan model.Message)
|
2018-11-22 00:01:17 +00:00
|
|
|
the.Peer.JoinServer(group.GroupServer)
|
2018-11-28 21:29:32 +00:00
|
|
|
nick, exists := group.GetAttribute("nick")
|
|
|
|
if !exists {
|
|
|
|
nick = group.GroupID[:12]
|
|
|
|
}
|
2018-11-22 00:01:17 +00:00
|
|
|
gcd.UIState.AddContact(&gobjects.Contact{
|
2019-01-21 21:17:51 +00:00
|
|
|
Handle: group.GroupID,
|
|
|
|
DisplayName: nick,
|
|
|
|
Image: cwutil.RandomGroupImage(group.GroupID),
|
|
|
|
Server: group.GroupServer,
|
|
|
|
Trusted: group.Accepted,
|
2018-11-22 00:01:17 +00:00
|
|
|
})
|
2018-10-28 02:49:14 +00:00
|
|
|
}
|
2018-11-28 22:14:02 +00:00
|
|
|
}
|