ui/main.go

221 lines
6.8 KiB
Go
Raw Permalink Normal View History

2018-10-23 18:52:13 +00:00
package main
import (
2018-11-22 00:01:17 +00:00
libapp "cwtch.im/cwtch/app"
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"
"git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
"git.openprivacy.ca/openprivacy/libricochet-go/log"
2019-02-13 00:06:52 +00:00
"github.com/therecipe/qt/gui"
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/quickcontrols2"
"os"
"path"
2019-02-14 02:53:36 +00:00
"runtime"
"path/filepath"
"os/user"
"fmt"
2018-10-28 02:49:14 +00:00
)
2018-10-23 18:52:13 +00:00
2019-02-19 21:32:52 +00:00
const androidBaseDir = "/data/data/org.qtproject.example.go/"
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() {
if len(os.Args) >= 3 && os.Args[2] == "-debug" {
log.SetLevel(log.LevelDebug)
} else {
log.SetLevel(log.LevelInfo)
}
2018-11-22 00:01:17 +00:00
// our globals
gcd := gothings.NewGrandCentralDispatcher(nil)
gcd.UIState = gothings.NewUIState(gcd)
2019-02-11 21:05:01 +00:00
the.AcknowledgementIDs = make(map[string][]*the.AckId)
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" {
2018-11-22 00:01:17 +00:00
qmlSource = core.QUrl_FromLocalFile("./qml/main.qml")
} else {
qmlSource = core.NewQUrl3("qrc:/qml/main.qml", 0)
}
2018-10-23 18:52:13 +00:00
2019-02-13 00:06:52 +00:00
app := gui.NewQGuiApplication(len(os.Args), os.Args)
app.SetWindowIcon(gui.NewQIcon5(":/qml/images/cwtch-icon.png"))
2019-03-06 18:32:21 +00:00
var translator = core.NewQTranslator(nil)
translator.Load("translation_"+core.QLocale_System().Name(), ":/i18n/", "", "")
core.QCoreApplication_InstallTranslator(translator)
2019-02-13 04:10:46 +00:00
core.QCoreApplication_SetAttribute(core.Qt__AA_EnableHighDpiScaling, true)
quickcontrols2.QQuickStyle_SetStyle("Universe")
engine := qml.NewQQmlApplicationEngine(nil)
2018-10-23 18:52:13 +00:00
2018-11-22 00:01:17 +00:00
// variables we want to access from inside qml
2019-02-14 02:53:36 +00:00
if runtime.GOOS == "android" {
gcd.SetThemeScale(2.9)
} else {
gcd.SetThemeScale(1.0)
}
2019-02-13 04:10:46 +00:00
engine.RootContext().SetContextProperty("gcd", gcd)
engine.Load(qmlSource)
2018-10-23 18:52:13 +00:00
if os.Getenv("CWTCH_FOLDER") != "" {
the.CwtchDir = os.Getenv("CWTCH_FOLDER")
2019-02-19 21:32:52 +00:00
} else if runtime.GOOS == "android" {
the.CwtchDir = path.Join(androidBaseDir, "files")
} else {
usr, err := user.Current()
if err != nil {
fmt.Printf("\nerror: could not load current user: %v\n", err)
os.Exit(1)
}
the.CwtchDir = path.Join(usr.HomeDir, ".cwtch")
}
2019-02-14 02:53:36 +00:00
torpath := "tor"
if runtime.GOOS == "android" {
2019-02-19 21:32:52 +00:00
torpath = path.Join(androidBaseDir, "lib/libtor.so")
} else {
dir, _ := filepath.Abs(filepath.Dir(os.Args[0]))
if _, err := os.Stat(path.Join(dir, "tor")); os.IsNotExist(err) {
if _, err := os.Stat(path.Join(dir, "deploy", "linux", "tor")); os.IsNotExist(err) {
if _, err := os.Stat(path.Join(dir, "deploy", "windows", "tor")); os.IsNotExist(err) {
log.Warnln("Cannot find bundled Tor")
} else {
torpath = path.Join(dir, "deploy", "windows", "tor")
}
} else {
torpath = path.Join(dir, "deploy", "linux", "tor")
}
} else {
torpath = path.Join(dir, "tor")
}
2019-02-14 02:53:36 +00:00
}
acn, err := connectivity.StartTor(the.CwtchDir, torpath)
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
loadCwtchData(gcd, acn)
go characters.IncomingListener(gcd.UIState.AddMessage, gcd.UIState.AddSendMessageError)
go characters.TorStatusPoller(gcd.TorStatus, acn)
2018-11-22 00:01:17 +00:00
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
})
2019-02-13 04:10:46 +00:00
engine.SetNetworkAccessManagerFactory(factory)
2019-02-13 00:06:52 +00:00
app.Exec()
acn.Close()
2018-11-22 00:01:17 +00:00
}
2018-10-23 18:52:13 +00:00
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
func loadCwtchData(gcd *gothings.GrandCentralDispatcher, acn connectivity.ACN) {
2018-10-30 19:48:37 +00:00
var err error
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 {
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)
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
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 {
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 {
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])
displayName, _ := contact.GetAttribute("nick")
deleted, _ := contact.GetAttribute("deleted")
if deleted != "deleted" {
gcd.UIState.AddContact(&gobjects.Contact{
Handle: contacts[i],
DisplayName: displayName,
Image: cwutil.RandomProfileImage(contacts[i]),
Trusted: contact.Trusted,
})
}
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-11-28 21:29:32 +00:00
nick, exists := group.GetAttribute("nick")
if !exists {
nick = group.GroupID[:12]
}
deleted,_ := group.GetAttribute("deleted")
// Only join servers for active and explicitly accepted groups.
if deleted != "deleted"{
gcd.UIState.AddContact(&gobjects.Contact{
Handle: group.GroupID,
DisplayName: nick,
Image: cwutil.RandomGroupImage(group.GroupID),
Server: group.GroupServer,
Trusted: group.Accepted,
})
}
2019-03-04 22:02:11 +00:00
// Only send a join server packet if we haven't joined this server yet...
_,connecting := the.Peer.GetServers()[group.GroupServer]
if group.Accepted && !connecting {
the.Peer.JoinServer(group.GroupServer)
}
2018-10-28 02:49:14 +00:00
}
2018-11-28 22:14:02 +00:00
}