package main import ( libapp "cwtch.im/cwtch/app" "cwtch.im/cwtch/model" "cwtch.im/ui/go/characters" "cwtch.im/ui/go/cwtchthings" "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/application" "git.openprivacy.ca/openprivacy/libricochet-go/channels" "git.openprivacy.ca/openprivacy/libricochet-go/connectivity" "github.com/therecipe/qt/core" "github.com/therecipe/qt/quick" "github.com/therecipe/qt/quickcontrols2" "github.com/therecipe/qt/widgets" "log" "os" "os/user" "path" ) func init() { // make go-defined types available in qml gothings.GrandCentralDispatcher_QmlRegisterType2("CustomQmlTypes", 1, 0, "GrandCentralDispatcher") } func main() { // our globals gcd := gothings.NewGrandCentralDispatcher(nil) gcd.UIState = gothings.NewUIState(gcd) the.AcknowledgementIDs = make(map[uint32]uint) 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) } // window construction boilerplate view := initializeQtView() // variables we want to access from inside qml view.RootContext().SetContextProperty("gcd", gcd) // this actually loads the qml view.SetSource(qmlSource) // these are long-lived pollers/listeners for incoming messages and status changes loadCwtchData(gcd) 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) // here we go! view.Show() widgets.QApplication_Exec() } // window construction boilerplate func initializeQtView() *quick.QQuickView { 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) view.SetMinimumHeight(280) view.SetMinimumWidth(300) view.SetTitle("cwtch") return view } // 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) { var err error if os.Getenv("CWTCH_FOLDER") != "" { the.CwtchDir = os.Getenv("CWTCH_FOLDER") } 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") } /*_, err := app2.NewApp(dirname, "/data/data/org.qtproject.example.go/lib/libtor.so") if err != nil { log.Printf("ERROR CREATING CWTCH APP: %v", err) } time.Sleep(time.Second * 10) */ os.MkdirAll(the.CwtchDir, 0700) mn, err := connectivity.StartTor(the.CwtchDir, "") if err != nil { log.Printf("[!!!] Could not start Tor: %v", err) } the.CwtchApp = libapp.NewApp(mn, the.CwtchDir) err = the.CwtchApp.LoadProfiles("be gay do crime") if err != nil { //TODO no more fatalfs log.Fatalf("couldn't load profiles: %v", err) } if len(the.CwtchApp.ListPeers()) == 0 { log.Printf("couldn't load your config file. attempting to create one now") the.Peer, err = the.CwtchApp.CreatePeer("alice", "be gay do crime") if err != nil { log.Fatalf("couldn't create one. is your cwtch folder writable?") } the.CwtchApp.SaveProfile(the.Peer) } else { the.Peer = the.CwtchApp.PrimaryIdentity() } gcd.UpdateMyProfile(the.Peer.GetProfile().Name, the.Peer.GetProfile().Onion, cwutil.RandomProfileImage(the.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(cwtchthings.ChatChannelListener) ccl.Init(rai, app, gcd.UIState.AddMessage, gcd.Acknowledged) return func() channels.Handler { chat := new(channels.ChatChannel) chat.Handler = ccl return chat } }) the.Peer.SetApplicationInstanceFactory(aif) the.CwtchApp.LaunchPeers() contacts := the.Peer.GetContacts() for i := range contacts { contact, _ := the.Peer.GetProfile().GetContact(contacts[i]) displayName, _ := contact.GetAttribute("name") gcd.UIState.AddContact(&gobjects.Contact{ contacts[i], displayName, cwutil.RandomProfileImage(contacts[i]), "", 0, 0, contact.Trusted, }) } groups := the.Peer.GetGroups() for i := range groups { log.Printf("adding saved group %v", groups[i]) group := the.Peer.GetGroup(groups[i]) group.NewMessage = make(chan model.Message) go characters.CwtchListener(gcd.UIState.AddMessage, groups[i], group.NewMessage) the.Peer.JoinServer(group.GroupServer) nick, exists := group.GetAttribute("nick") if !exists { nick = group.GroupID[:12] } gcd.UIState.AddContact(&gobjects.Contact{ group.GroupID, nick, cwutil.RandomGroupImage(group.GroupID), group.GroupServer, 0, 0, group.Accepted, }) } }