Exemple #1
0
func (u *gtkUI) buildStaticAccountsMenu(submenu *gtk.Menu) {
	connectAutomaticallyItem, _ := gtk.CheckMenuItemNewWithMnemonic(i18n.Local("Connect On _Startup"))
	u.config.WhenLoaded(func(a *config.ApplicationConfig) {
		connectAutomaticallyItem.SetActive(a.ConnectAutomatically)
	})

	connectAutomaticallyItem.Connect("activate", func() {
		u.setConnectAllAutomatically(connectAutomaticallyItem.GetActive())
	})
	submenu.Append(connectAutomaticallyItem)

	connectAllMenu, _ := gtk.MenuItemNewWithMnemonic(i18n.Local("_Connect All"))
	connectAllMenu.Connect("activate", func() { u.connectAllAutomatics(true) })
	submenu.Append(connectAllMenu)

	sep2, _ := gtk.SeparatorMenuItemNew()
	submenu.Append(sep2)

	addAccMenu, _ := gtk.MenuItemNewWithMnemonic(i18n.Local("_Add..."))
	addAccMenu.Connect("activate", u.showAddAccountWindow)
	submenu.Append(addAccMenu)

	importMenu, _ := gtk.MenuItemNewWithMnemonic(i18n.Local("_Import..."))
	importMenu.Connect("activate", u.runImporter)
	submenu.Append(importMenu)

	registerAccMenu, _ := gtk.MenuItemNewWithMnemonic(i18n.Local("_Register..."))
	registerAccMenu.Connect("activate", u.showServerSelectionWindow)
	submenu.Append(registerAccMenu)
}
Exemple #2
0
func (u *gtkUI) handlePeerEvent(ev events.Peer) {
	identityWarning := func(cv conversationView) {
		cv.updateSecurityWarning()
		cv.showIdentityVerificationWarning(u)
	}

	switch ev.Type {
	case events.IQReceived:
		//TODO
		log.Printf("received iq: %v\n", ev.From)
	case events.OTREnded:
		peer := ev.From
		account := u.findAccountForSession(ev.Session)
		convWindowNowOrLater(account, peer, func(cv conversationView) {
			cv.displayNotification(i18n.Local("Private conversation lost."))
			cv.updateSecurityWarning()
		})

	case events.OTRNewKeys:
		peer := ev.From
		account := u.findAccountForSession(ev.Session)
		convWindowNowOrLater(account, peer, func(cv conversationView) {
			cv.displayNotificationVerifiedOrNot(i18n.Local("Private conversation started."), i18n.Local("Unverified conversation started."))
			identityWarning(cv)
		})

	case events.OTRRenewedKeys:
		peer := ev.From
		account := u.findAccountForSession(ev.Session)
		convWindowNowOrLater(account, peer, func(cv conversationView) {
			cv.displayNotificationVerifiedOrNot(i18n.Local("Successfully refreshed the private conversation."), i18n.Local("Successfully refreshed the unverified private conversation."))
			identityWarning(cv)
		})

	case events.SubscriptionRequest:
		confirmDialog := authorizePresenceSubscriptionDialog(&u.window.Window, ev.From)

		doInUIThread(func() {
			responseType := gtk.ResponseType(confirmDialog.Run())
			switch responseType {
			case gtk.RESPONSE_YES:
				ev.Session.HandleConfirmOrDeny(ev.From, true)
			case gtk.RESPONSE_NO:
				ev.Session.HandleConfirmOrDeny(ev.From, false)
			default:
				// We got a different response, such as a close of the window. In this case we want
				// to keep the subscription request open
			}
			confirmDialog.Destroy()
		})
	case events.Subscribed:
		jid := ev.Session.GetConfig().Account
		log.Printf("[%s] Subscribed to %s\n", jid, ev.From)
		u.rosterUpdated()
	case events.Unsubscribe:
		jid := ev.Session.GetConfig().Account
		log.Printf("[%s] Unsubscribed from %s\n", jid, ev.From)
		u.rosterUpdated()
	}
}
Exemple #3
0
func (u *gtkUI) addContactWindow() {
	accounts := make([]*account, 0, len(u.accounts))

	for i := range u.accounts {
		acc := u.accounts[i]
		if acc.connected() {
			accounts = append(accounts, acc)
		}
	}

	dialog := presenceSubscriptionDialog(accounts, func(accountID, peer string) error {
		//TODO errors
		account, ok := u.roster.getAccount(accountID)
		if !ok {
			return fmt.Errorf(i18n.Local("There is no account with the id %q"), accountID)
		}

		if !account.connected() {
			return errors.New(i18n.Local("Can't send a contact request from an offline account"))
		}

		return account.session.RequestPresenceSubscription(peer)
	})

	dialog.SetTransientFor(u.window)
	dialog.ShowAll()
}
Exemple #4
0
func (u *gtkUI) showAddAccountWindow() {
	c, _ := config.NewAccount()

	u.accountDialog(nil, c, func() {
		u.addAndSaveAccountConfig(c)
		u.notify(i18n.Local("Account added"), fmt.Sprintf(i18n.Local("The account %s was added successfully."), c.Account))
	})
}
Exemple #5
0
func (conv *conversationPane) onStartOtrSignal() {
	//TODO: enable/disable depending on the conversation's encryption state
	session := conv.account.session
	c, _ := session.ConversationManager().EnsureConversationWith(conv.to, conv.currentResource())
	err := c.StartEncryptedChat(session, conv.currentResource())
	if err != nil {
		log.Printf(i18n.Local("Failed to start encrypted chat: %s\n"), err.Error())
	} else {
		conv.displayNotification(i18n.Local("Attempting to start a private conversation..."))
	}
}
Exemple #6
0
func (u *gtkUI) getMasterPassword(params config.EncryptionParameters, lastAttemptFailed bool) ([]byte, []byte, bool) {
	dialogID := "MasterPassword"
	pwdResultChan := make(chan string)
	var cleanup func()

	doInUIThread(func() {
		builder := newBuilder(dialogID)
		dialogOb := builder.getObj(dialogID)
		dialog := dialogOb.(gtki.Dialog)

		cleanup = dialog.Destroy

		passObj := builder.getObj("password")
		password := passObj.(gtki.Entry)

		msgObj := builder.getObj("passMessage")
		messageObj := msgObj.(gtki.Label)
		messageObj.SetSelectable(true)

		if lastAttemptFailed {
			messageObj.SetLabel(i18n.Local("Incorrect password entered, please try again."))
		}

		builder.ConnectSignals(map[string]interface{}{
			"on_save_signal": func() {
				passText, _ := password.GetText()
				if len(passText) > 0 {
					messageObj.SetLabel(i18n.Local("Checking password..."))
					pwdResultChan <- passText
					close(pwdResultChan)
				}
			},
			"on_cancel_signal": func() {
				close(pwdResultChan)
				u.quit()
			},
		})

		dialog.SetTransientFor(u.window)
		dialog.ShowAll()
	})

	pwd, ok := <-pwdResultChan

	if !ok {
		doInUIThread(cleanup)
		return nil, nil, false
	}

	l, r := config.GenerateKeys(pwd, params)
	doInUIThread(cleanup)
	return l, r, true
}
Exemple #7
0
func (conv *conversationPane) onEndOtrSignal() {
	//TODO: enable/disable depending on the conversation's encryption state
	session := conv.account.session
	err := session.ManuallyEndEncryptedChat(conv.to, conv.currentResource())

	if err != nil {
		log.Printf(i18n.Local("Failed to terminate the encrypted chat: %s\n"), err.Error())
	} else {
		conv.displayNotification(i18n.Local("Private conversation has ended."))
		conv.updateSecurityWarning()
	}
}
Exemple #8
0
func createStatusMessage(from string, show, showStatus string, gone bool) string {
	tail := ""
	if gone {
		tail = i18n.Local("Offline") + extraOfflineStatus(show, showStatus)
	} else {
		tail = onlineStatus(show, showStatus)
	}

	if tail != "" {
		return from + i18n.Local(" is now ") + tail
	}
	return ""
}
Exemple #9
0
func (u *gtkUI) showAddAccountWindow() error {
	c, err := config.NewAccount()
	if err != nil {
		return err
	}

	u.accountDialog(nil, c, func() {
		u.addAndSaveAccountConfig(c)
		u.notify(i18n.Local("Account added"), fmt.Sprintf(i18n.Local("The account %s was added successfully."), c.Account))
	})

	return nil
}
Exemple #10
0
// HandleErrorMessage is called when asked to handle a specific error message
func (e *OtrEventHandler) HandleErrorMessage(error otr3.ErrorCode) []byte {
	log.Printf("HandleErrorMessage(%s)", error.String())

	switch error {
	case otr3.ErrorCodeEncryptionError:
		return []byte(i18n.Local("Error occurred encrypting message."))
	case otr3.ErrorCodeMessageUnreadable:
		return []byte(i18n.Local("You transmitted an unreadable encrypted message."))
	case otr3.ErrorCodeMessageMalformed:
		return []byte(i18n.Local("You transmitted a malformed data message."))
	case otr3.ErrorCodeMessageNotInPrivate:
		return []byte(i18n.Local("You sent encrypted data to a peer, who wasn't expecting it."))
	}

	return nil
}
Exemple #11
0
func (account *account) createXMLConsoleItem(r *roster) gtki.MenuItem {
	consoleItem, _ := g.gtk.MenuItemNewWithMnemonic(i18n.Local("XML Console"))
	consoleItem.Connect("activate", func() {
		builder := newBuilder("XMLConsole")
		console := builder.getObj("XMLConsole").(gtki.Dialog)
		buf := builder.getObj("consoleContent").(gtki.TextBuffer)
		console.SetTransientFor(r.ui.window)
		console.SetTitle(strings.Replace(console.GetTitle(), "ACCOUNT_NAME", account.session.GetConfig().Account, -1))
		log := account.session.GetInMemoryLog()

		buf.Delete(buf.GetStartIter(), buf.GetEndIter())
		if log != nil {
			buf.Insert(buf.GetEndIter(), log.String())
		}

		builder.ConnectSignals(map[string]interface{}{
			"on_refresh_signal": func() {
				buf.Delete(buf.GetStartIter(), buf.GetEndIter())
				if log != nil {
					buf.Insert(buf.GetEndIter(), log.String())
				}
			},
			"on_close_signal": func() {
				console.Destroy()
			},
		})

		console.ShowAll()
	})
	return consoleItem
}
Exemple #12
0
func (account *account) createDumpInfoItem(r *roster) gtki.MenuItem {
	dumpInfoItem, _ := g.gtk.MenuItemNewWithMnemonic(i18n.Local("Dump info"))
	dumpInfoItem.Connect("activate", func() {
		r.debugPrintRosterFor(account.session.GetConfig().Account)
	})
	return dumpInfoItem
}
Exemple #13
0
func (account *account) buildNotification(template, msg string) *gtk.InfoBar {
	builder := builderForDefinition(template)

	builder.ConnectSignals(map[string]interface{}{
		"handleResponse": func(info *gtk.InfoBar, response gtk.ResponseType) {
			if response != gtk.RESPONSE_CLOSE {
				return
			}

			info.Hide()
			info.Destroy()
		},
	})

	obj, _ := builder.GetObject("infobar")
	infoBar := obj.(*gtk.InfoBar)

	obj, _ = builder.GetObject("message")
	msgLabel := obj.(*gtk.Label)
	msgLabel.SetSelectable(true)

	text := fmt.Sprintf(i18n.Local(msg), account.session.GetConfig().Account)
	msgLabel.SetText(text)

	return infoBar
}
Exemple #14
0
func (u *gtkUI) watchCommands() {
	for command := range u.commands {
		switch c := command.(type) {
		case executable:
			c.execute(u)
		case client.AuthorizeFingerprintCmd:
			account := c.Account
			uid := c.Peer
			fpr := c.Fingerprint

			//TODO: it could be a different pointer,
			//find the account by ID()
			account.AuthorizeFingerprint(uid, fpr)
			u.ExecuteCmd(client.SaveApplicationConfigCmd{})

			ac := u.findAccountForSession(c.Session.(access.Session))
			if ac != nil {
				peer := c.Peer
				convWindowNowOrLater(ac, peer, u, func(cv conversationView) {
					cv.displayNotification(fmt.Sprintf(i18n.Local("You have verified the identity of %s."), peer))
				})
			}
		case client.SaveInstanceTagCmd:
			account := c.Account
			account.InstanceTag = c.InstanceTag
			u.ExecuteCmd(client.SaveApplicationConfigCmd{})
		case client.SaveApplicationConfigCmd:
			u.SaveConfig()
		}
	}
}
Exemple #15
0
func buildVerifyIdentityNotification(acc *account, peer, resource string, win gtki.Window) gtki.InfoBar {
	builder := newBuilder("VerifyIdentityNotification")

	obj := builder.getObj("infobar")
	infoBar := obj.(gtki.InfoBar)

	obj = builder.getObj("message")
	message := obj.(gtki.Label)
	message.SetSelectable(true)

	text := fmt.Sprintf(i18n.Local("You have not verified the identity of %s"), peer)
	message.SetText(text)

	obj = builder.getObj("button_verify")
	button := obj.(gtki.Button)
	button.Connect("clicked", func() {
		doInUIThread(func() {
			resp := verifyFingerprintDialog(acc, peer, resource, win)
			if resp == gtki.RESPONSE_YES {
				infoBar.Hide()
				infoBar.Destroy()
			}
		})
	})

	infoBar.ShowAll()

	return infoBar
}
Exemple #16
0
// NewConversation will create a new OTR conversation with the given peer
//TODO: why creating a conversation is coupled to the account config and the session
//TODO: does the creation of the OTR event handler need to be guarded with a lock?
func (s *session) NewConversation(peer string) *otr3.Conversation {
	conversation := &otr3.Conversation{}
	conversation.SetOurKeys(s.privateKeys)
	conversation.SetFriendlyQueryMessage(i18n.Local("Your peer has requested a private conversation with you, but your client doesn't seem to support the OTR protocol."))

	instanceTag := conversation.InitializeInstanceTag(s.GetConfig().InstanceTag)

	if s.GetConfig().InstanceTag != instanceTag {
		s.cmdManager.ExecuteCmd(client.SaveInstanceTagCmd{
			Account:     s.GetConfig(),
			InstanceTag: instanceTag,
		})
	}

	s.GetConfig().SetOTRPoliciesFor(peer, conversation)

	eh, ok := s.otrEventHandler[peer]
	if !ok {
		eh = new(event.OtrEventHandler)
		eh.Account = s.GetConfig().Account
		eh.Peer = peer
		notificationsChan := make(chan string)
		eh.Notifications = notificationsChan
		go s.listenToNotifications(notificationsChan, peer)
		conversation.SetSMPEventHandler(eh)
		conversation.SetErrorMessageHandler(eh)
		conversation.SetMessageEventHandler(eh)
		conversation.SetSecurityEventHandler(eh)
		s.otrEventHandler[peer] = eh
	}

	return conversation
}
Exemple #17
0
// getProxyTypeFor will return the proxy type for the given i18n proxy name
func getProxyTypeFor(act string) string {
	for _, px := range proxyTypes {
		if act == i18n.Local(px[1]) {
			return px[0]
		}
	}
	return ""
}
Exemple #18
0
// Send will send the given message to the receiver given
func (s *session) Send(to, resource string, msg string) error {
	conn, ok := s.connection()
	if ok {
		log.Printf("<- to=%v {%v}\n", utils.ComposeFullJid(to, resource), msg)
		return conn.Send(utils.ComposeFullJid(to, resource), msg)
	}
	return &access.OfflineError{Msg: i18n.Local("Couldn't send message since we are not connected")}
}
Exemple #19
0
// EncryptAndSendTo encrypts and sends the message to the given peer
func (s *session) EncryptAndSendTo(peer, resource string, message string) error {
	//TODO: review whether it should create a conversation
	if s.IsConnected() {
		conversation, _ := s.convManager.EnsureConversationWith(peer, resource)
		return conversation.Send(s, resource, []byte(message))
	}
	return &access.OfflineError{Msg: i18n.Local("Couldn't send message since we are not connected")}
}
Exemple #20
0
func (u *gtkUI) captureInitialMasterPassword(k func(), onCancel func()) {
	dialogID := "CaptureInitialMasterPassword"
	builder := newBuilder(dialogID)
	dialogOb := builder.getObj(dialogID)
	pwdDialog := dialogOb.(gtki.Dialog)

	passObj := builder.getObj("password")
	password := passObj.(gtki.Entry)

	pass2Obj := builder.getObj("password2")
	password2 := pass2Obj.(gtki.Entry)

	msgObj := builder.getObj("passMessage")
	messageObj := msgObj.(gtki.Label)
	messageObj.SetSelectable(true)

	builder.ConnectSignals(map[string]interface{}{
		"on_save_signal": func() {
			passText1, _ := password.GetText()
			passText2, _ := password2.GetText()
			if len(passText1) == 0 {
				messageObj.SetLabel(i18n.Local("Password can not be empty - please try again"))
				password.GrabFocus()
			} else if passText1 != passText2 {
				messageObj.SetLabel(i18n.Local("Passwords have to be the same - please try again"))
				password.GrabFocus()
			} else {
				u.keySupplier = &onetimeSavedPassword{
					savedPassword: passText1,
					realF:         u.keySupplier,
				}
				pwdDialog.Destroy()
				k()
			}
		},
		"on_cancel_signal": func() {
			pwdDialog.Destroy()
			onCancel()
		},
	})

	doInUIThread(func() {
		pwdDialog.SetTransientFor(u.window)
		pwdDialog.ShowAll()
	})
}
func buildVerifyFingerprintDialog(accountName string, ourFp []byte, uid string, theirFp []byte) *gtk.Dialog {
	var message string
	var builderName string

	if theirFp == nil {
		builderName = "VerifyFingerprintUnknown"
		message = fmt.Sprintf(i18n.Local(
			"You can't verify the fingerprint for %s yet.\n"+
				"You first have to start an encrypted conversation with them.",
		), uid)

	} else {
		m := i18n.Local(`
Is this the correct fingerprint for %[1]s?

Fingerprint for you (%[3]s):
  %[4]s

Purported fingerprint for %[1]s:
  %[2]s
	`)

		message = fmt.Sprintf(m,
			uid,
			config.FormatFingerprint(theirFp),
			accountName,
			config.FormatFingerprint(ourFp),
		)

		builderName = "VerifyFingerprint"
	}

	builder := builderForDefinition(builderName)

	obj, _ := builder.GetObject("dialog")
	dialog := obj.(*gtk.Dialog)

	obj, _ = builder.GetObject("message")
	l := obj.(*gtk.Label)
	l.SetText(message)
	l.SetSelectable(true)

	dialog.SetTitle(fmt.Sprintf(i18n.Local("Verify fingerprint for %s"), uid))
	return dialog
}
Exemple #22
0
func (account *account) createConnectionItem() gtki.MenuItem {
	connInfoItem, _ := g.gtk.MenuItemNewWithMnemonic(i18n.Local("Connection _information..."))
	connInfoItem.Connect("activate", account.connectionInfo)
	connInfoItem.SetSensitive(!account.session.IsDisconnected())
	account.observeConnectionEvents(func() {
		connInfoItem.SetSensitive(!account.session.IsDisconnected())
	})
	return connInfoItem
}
Exemple #23
0
func (u *gtkUI) handleNotificationEvent(ev events.Notification) {
	peer := ev.Peer
	account := u.findAccountForSession(ev.Session)
	convWin, err := u.roster.openConversationView(account, peer, false)
	if err != nil {
		return
	}
	convWin.displayNotification(i18n.Local(ev.Notification))
}
Exemple #24
0
func (u *gtkUI) showFingerprintsForPeer(jid string, account *account) {
	builder := builderForDefinition("PeerFingerprints")
	dialog := getObjIgnoringErrors(builder, "dialog").(*gtk.Dialog)
	info := getObjIgnoringErrors(builder, "information").(*gtk.Label)
	grid := getObjIgnoringErrors(builder, "grid").(*gtk.Grid)

	info.SetSelectable(true)

	fprs := []*config.Fingerprint{}
	p, ok := account.session.GetConfig().GetPeer(jid)
	if ok {
		fprs = p.Fingerprints
	}

	if len(fprs) == 0 {
		info.SetText(fmt.Sprintf(i18n.Local("There are no known fingerprints for %s"), jid))
	} else {
		info.SetText(fmt.Sprintf(i18n.Local("These are the fingerprints known for %s:"), jid))
	}

	for ix, fpr := range fprs {
		flabel, _ := gtk.LabelNew(config.FormatFingerprint(fpr.Fingerprint))
		flabel.SetSelectable(true)
		trusted := i18n.Local("not trusted")
		if fpr.Trusted {
			trusted = i18n.Local("trusted")
		}

		ftrusted, _ := gtk.LabelNew(trusted)
		ftrusted.SetSelectable(true)

		grid.Attach(flabel, 0, ix, 1, 1)
		grid.Attach(ftrusted, 1, ix, 1, 1)
	}

	builder.ConnectSignals(map[string]interface{}{
		"on_close_signal": func() {
			dialog.Destroy()
		},
	})

	dialog.SetTransientFor(u.window)
	dialog.ShowAll()
}
Exemple #25
0
func authorizePresenceSubscriptionDialog(parent gtki.Window, from string) gtki.MessageDialog {
	builder := newBuilder("AuthorizeSubscription")

	confirmDialog := builder.getObj("dialog").(gtki.MessageDialog)
	text := fmt.Sprintf(i18n.Local("%s wants to talk to you. Is that ok?"), from)
	confirmDialog.SetProperty("text", text)
	confirmDialog.SetTransientFor(parent)

	return confirmDialog
}
Exemple #26
0
func (conv *conversationPane) appendDelayed(from string, timestamp time.Time, message []byte) {
	conv.appendToHistory(timestamp, false,
		taggableText{"outgoingUser", i18n.Local("(Not sent yet) ")},
		taggableText{"outgoingDelayedUser", from},
		taggableText{
			text: ":  ",
		},
		taggableText{"outgoingDelayedText", string(message)},
	)
}
Exemple #27
0
// EncryptAndSendTo encrypts and sends the message to the given peer
func (s *session) EncryptAndSendTo(peer, resource string, message string) (trace int, delayed bool, err error) {
	//TODO: review whether it should create a conversation
	if s.IsConnected() {
		conversation, _ := s.convManager.EnsureConversationWith(peer, resource)
		trace, err = conversation.Send(s, resource, []byte(message))
		eh := s.otrEventHandler[peer]
		delayed = eh.ConsumeDelayedState(trace)
		return
	}
	return 0, false, &access.OfflineError{Msg: i18n.Local("Couldn't send message since we are not connected")}
}
Exemple #28
0
func buildBadUsernameNotification(msg string) *gtk.InfoBar {
	b := builderForDefinition("BadUsernameNotification")

	infoBar := getObjIgnoringErrors(b, "infobar").(*gtk.InfoBar)
	message := getObjIgnoringErrors(b, "message").(*gtk.Label)

	message.SetSelectable(true)
	message.SetText(fmt.Sprintf(i18n.Local(msg)))

	return infoBar
}
Exemple #29
0
func (account *account) createDisconnectItem() gtki.MenuItem {
	disconnectItem, _ := g.gtk.MenuItemNewWithMnemonic(i18n.Local("_Disconnect"))
	disconnectItem.Connect("activate", func() {
		account.session.SetWantToBeOnline(false)
		account.disconnect()
	})
	disconnectItem.SetSensitive(!account.session.IsDisconnected())
	account.observeConnectionEvents(func() {
		disconnectItem.SetSensitive(!account.session.IsDisconnected())
	})
	return disconnectItem
}
Exemple #30
0
func buildBadUsernameNotification(msg string) gtki.InfoBar {
	assertInUIThread()
	b := newBuilder("BadUsernameNotification")

	infoBar := b.getObj("infobar").(gtki.InfoBar)
	message := b.getObj("message").(gtki.Label)

	message.SetSelectable(true)
	message.SetText(fmt.Sprintf(i18n.Local(msg)))

	return infoBar
}