Example #1
0
func (s *session) receivedClientPresence(stanza *data.ClientPresence) bool {
	switch stanza.Type {
	case "subscribe":
		jj := utils.RemoveResourceFromJid(stanza.From)
		if s.autoApproves[jj] {
			delete(s.autoApproves, jj)
			s.ApprovePresenceSubscription(jj, stanza.ID)
		} else {
			s.r.SubscribeRequest(jj, either(stanza.ID, "0000"), s.GetConfig().ID())
			s.publishPeerEvent(
				events.SubscriptionRequest,
				jj,
			)
		}
	case "unavailable":
		if !s.r.PeerBecameUnavailable(stanza.From) {
			return true
		}

		s.publishEvent(events.Presence{
			Session:        s,
			ClientPresence: stanza,
			Gone:           true,
		})
	case "":
		if !s.r.PeerPresenceUpdate(stanza.From, stanza.Show, stanza.Status, s.GetConfig().ID()) {
			return true
		}

		s.publishEvent(events.Presence{
			Session:        s,
			ClientPresence: stanza,
			Gone:           false,
		})
	case "subscribed":
		s.r.Subscribed(stanza.From)
		s.publishPeerEvent(
			events.Subscribed,
			utils.RemoveResourceFromJid(stanza.From),
		)
	case "unsubscribe":
		s.r.Unsubscribed(stanza.From)
		s.publishPeerEvent(
			events.Unsubscribe,
			utils.RemoveResourceFromJid(stanza.From),
		)
	case "unsubscribed":
		// Ignore
	case "error":
		s.warn(fmt.Sprintf("Got a presence error from %s: %#v\n", stanza.From, stanza.Error))
		s.r.LatestError(stanza.From, stanza.Error.Code, stanza.Error.Type, stanza.Error.Any.Space+" "+stanza.Error.Any.Local)
	default:
		s.info(fmt.Sprintf("unrecognized presence: %#v", stanza))
	}
	return true
}
Example #2
0
func (s *session) processClientMessage(stanza *data.ClientMessage) {
	log.Printf("-> Stanza %#v\n", stanza)

	from := utils.RemoveResourceFromJid(stanza.From)

	//TODO: investigate which errors are recoverable
	//https://xmpp.org/rfcs/rfc3920.html#stanzas-error
	if stanza.Type == "error" && stanza.Error != nil {
		s.alert(fmt.Sprintf("Error reported from %s: %#v", from, stanza.Error))
		return
	}

	//TODO: Add a more general solution to XEP's
	if len(stanza.Body) == 0 && len(stanza.Extensions) > 0 {
		//Extension only stanza
		return
	}

	var err error
	var messageTime time.Time
	if stanza.Delay != nil && len(stanza.Delay.Stamp) > 0 {
		// An XEP-0203 Delayed Delivery <delay/> element exists for
		// this message, meaning that someone sent it while we were
		// offline. Let's show the timestamp for when the message was
		// sent, rather than time.Now().
		messageTime, err = time.Parse(time.RFC3339, stanza.Delay.Stamp)
		if err != nil {
			s.alert("Can not parse Delayed Delivery timestamp, using quoted string instead.")
		}
	} else {
		messageTime = time.Now()
	}

	s.receiveClientMessage(from, messageTime, stanza.Body)
}
Example #3
0
// Get returns the peer if it's known and false otherwise
func (l *List) Get(jid string) (*Peer, bool) {
	l.peersLock.RLock()
	defer l.peersLock.RUnlock()

	v, ok := l.peers[utils.RemoveResourceFromJid(jid)]
	return v, ok
}
Example #4
0
func (c *cliUI) handlePresenceEvent(ev events.Presence) {
	if ev.Session.GetConfig().HideStatusUpdates {
		return
	}

	from := utils.RemoveResourceFromJid(ev.From)

	var line []byte
	line = append(line, []byte(fmt.Sprintf("   (%s) ", time.Now().Format(time.Kitchen)))...)
	line = append(line, c.termControl.Escape(c.term).Magenta...)
	line = append(line, []byte(from)...)
	line = append(line, ':')
	line = append(line, c.termControl.Escape(c.term).Reset...)
	line = append(line, ' ')

	if ev.Gone {
		line = append(line, []byte("offline")...)
	} else if len(ev.Show) > 0 {
		line = append(line, []byte(ev.Show)...)
	} else {
		line = append(line, []byte("online")...)
	}
	line = append(line, ' ')
	line = append(line, []byte(ev.Status)...)
	line = append(line, '\n')
	c.term.Write(line)
}
Example #5
0
func peerWithPendingSubscribe(jid, id, belongsTo string) *Peer {
	return &Peer{
		Jid:                xutils.RemoveResourceFromJid(jid),
		PendingSubscribeID: id,
		BelongsTo:          belongsTo,
	}
}
Example #6
0
// PeerWithState returns a new Peer that contains the given state information
func PeerWithState(jid, status, statusMsg, belongsTo string) *Peer {
	return &Peer{
		Jid:       xutils.RemoveResourceFromJid(jid),
		Status:    status,
		StatusMsg: statusMsg,
		Online:    true,
		BelongsTo: belongsTo,
	}
}
Example #7
0
func peerWithPendingSubscribe(jid, id, belongsTo string) *Peer {
	return &Peer{
		Jid:                xutils.RemoveResourceFromJid(jid),
		PendingSubscribeID: id,
		Asked:              true,
		BelongsTo:          belongsTo,
		resources:          toSet(),
	}
}
Example #8
0
// Remove returns the Peer with the jid from the List - it will first turn the jid into a bare jid.
// It returns true if it could remove the entry and false otherwise. It also returns the removed entry.
func (l *List) Remove(jid string) (*Peer, bool) {
	j := utils.RemoveResourceFromJid(jid)

	if v, ok := l.peers[j]; ok {
		delete(l.peers, j)
		return v, true
	}

	return nil, false
}
Example #9
0
func importPeerPrefsPidginStyle(f string) (map[string]map[string]*pidginOTRSettings, bool) {
	content, err := ioutil.ReadFile(f)
	if err != nil {
		return nil, false
	}

	var a pidginBlistXML
	err = xml.Unmarshal(content, &a)
	if err != nil {
		return nil, false
	}

	res := make(map[string]map[string]*pidginOTRSettings)

	for _, p := range a.Peers {
		if p.Protocol == "prpl-jabber" {
			haveOTR := false
			settings := &pidginOTRSettings{}
			for _, s := range p.Settings {
				switch s.Name {
				case "OTR/enabled":
					haveOTR = true
					settings.enabled = s.Value == "1"
				case "OTR/automatic":
					haveOTR = true
					settings.automatic = s.Value == "1"
				case "OTR/avoidloggingotr":
					haveOTR = true
					settings.avoidLoggingOTR = s.Value == "1"
				case "OTR/onlyprivate":
					haveOTR = true
					settings.onlyPrivate = s.Value == "1"
				}
			}
			if haveOTR {
				getOrMake(res, utils.RemoveResourceFromJid(p.Account))[utils.RemoveResourceFromJid(p.Name)] = settings

			}
		}
	}

	return res, true
}
Example #10
0
// PeerFrom returns a new Peer that contains the same information as the RosterEntry given
func PeerFrom(e data.RosterEntry, belongsTo, nickname string) *Peer {
	return &Peer{
		Jid:          xutils.RemoveResourceFromJid(e.Jid),
		Subscription: e.Subscription,
		Name:         e.Name,
		Nickname:     nickname,
		Groups:       toSet(e.Group...),
		BelongsTo:    belongsTo,
	}
}
Example #11
0
// Next reads stanzas from the server. If the stanza is a reply, it dispatches
// it to the correct channel and reads the next message. Otherwise it returns
// the stanza for processing.
func (c *conn) Next() (stanza data.Stanza, err error) {
	for {
		if stanza.Name, stanza.Value, err = next(c); err != nil {
			return
		}

		if _, ok := stanza.Value.(*data.StreamClose); ok {
			log.Println("xmpp: received closing stream tag")
			go c.closeImmediately()
			return
		}

		if iq, ok := stanza.Value.(*data.ClientIQ); ok && (iq.Type == "result" || iq.Type == "error") {
			var cookieValue uint64
			if cookieValue, err = strconv.ParseUint(iq.ID, 16, 64); err != nil {
				err = errors.New("xmpp: failed to parse id from iq: " + err.Error())
				return
			}
			cookie := data.Cookie(cookieValue)

			c.lock.Lock()
			inflight, ok := c.inflights[cookie]
			c.lock.Unlock()

			if !ok {
				continue
			}
			if len(inflight.to) > 0 {
				// The reply must come from the address to
				// which we sent the request.
				if inflight.to != iq.From {
					continue
				}
			} else {
				// If there was no destination on the request
				// then the matching is more complex because
				// servers differ in how they construct the
				// reply.
				if len(iq.From) > 0 && iq.From != c.jid && iq.From != utils.RemoveResourceFromJid(c.jid) && iq.From != utils.DomainFromJid(c.jid) {
					continue
				}
			}

			c.lock.Lock()
			delete(c.inflights, cookie)
			c.lock.Unlock()

			inflight.replyChan <- stanza
			continue
		}

		return
	}
}
Example #12
0
// PeerWithState returns a new Peer that contains the given state information
func PeerWithState(jid, status, statusMsg, belongsTo, resource string) *Peer {
	res := &Peer{
		Jid:       xutils.RemoveResourceFromJid(jid),
		Status:    status,
		StatusMsg: statusMsg,
		Online:    true,
		BelongsTo: belongsTo,
		resources: toSet(),
	}
	res.AddResource(resource)
	return res
}
Example #13
0
// ShouldEncryptTo returns true if the connection with this peer should be encrypted
func (a *Account) ShouldEncryptTo(jid string) bool {
	if a.AlwaysEncrypt {
		return true
	}

	bareJid := utils.RemoveResourceFromJid(jid)
	for _, contact := range a.AlwaysEncryptWith {
		if contact == bareJid {
			return true
		}
	}

	return false
}
Example #14
0
func (u *gtkUI) handleMessageEvent(ev events.Message) {
	account := u.findAccountForSession(ev.Session)
	if account == nil {
		//TODO error
		return
	}

	u.roster.messageReceived(
		account,
		utils.RemoveResourceFromJid(ev.From),
		ev.When,
		ev.Encrypted,
		ev.Body,
	)
}
Example #15
0
func importAccountsPidginStyle(f string) (map[string]*config.Account, bool) {
	content, err := ioutil.ReadFile(f)
	if err != nil {
		return nil, false
	}

	var a pidginAccountsXML
	err = xml.Unmarshal(content, &a)
	if err != nil {
		return nil, false
	}

	res := make(map[string]*config.Account)
	for _, ac := range a.Accounts {
		if ac.Protocol == "prpl-jabber" {
			nm := utils.RemoveResourceFromJid(ac.Name)
			a := &config.Account{}
			a.Account = nm
			a.Password = ac.Password
			settings := ac.settingsAsMap()
			a.Port = parseIntOr(settings["port"], 5222)

			a.Proxies = make([]string, 0)
			for _, px := range ac.Proxy {
				if px.Type == "tor" {
					a.RequireTor = true
				}
				a.Proxies = append(a.Proxies,
					composeProxyString(px.Type, px.Username, px.Password, px.Host, strconv.Itoa(px.Port)),
				)
			}

			if settings["connect_server"] != "" {
				a.Server = settings["connect_server"]
			}

			if strings.HasSuffix(a.Server, ".onion") {
				a.RequireTor = true
			}

			res[nm] = a
		}
	}

	return res, true
}
Example #16
0
// PeerFrom returns a new Peer that contains the same information as the RosterEntry given
func PeerFrom(e data.RosterEntry, belongsTo, nickname string, groups []string) *Peer {
	// merge remote and local groups
	g := groups
	if g == nil || len(g) == 0 {
		g = e.Group
	}
	allGroups := toSet(g...)

	return &Peer{
		Jid:           xutils.RemoveResourceFromJid(e.Jid),
		Subscription:  e.Subscription,
		Name:          e.Name,
		Nickname:      nickname,
		Groups:        allGroups,
		HasConfigData: groups != nil && len(groups) > 0,
		BelongsTo:     belongsTo,
		resources:     toSet(),
	}
}
Example #17
0
// ShouldEncryptTo returns true if the connection with this peer should be encrypted
func (a *Account) ShouldEncryptTo(jid string) bool {
	p, ok := a.GetPeer(jid)

	if ok && p.EncryptionSettings != Default && p.EncryptionSettings != "" {
		return p.EncryptionSettings == AlwaysEncrypt
	}

	if a.AlwaysEncrypt {
		return true
	}

	bareJid := utils.RemoveResourceFromJid(jid)
	for _, contact := range a.AlwaysEncryptWith {
		if contact == bareJid {
			return true
		}
	}

	return false
}
Example #18
0
func (u *gtkUI) handlePresenceEvent(ev events.Presence) {
	if ev.Session.GetConfig().HideStatusUpdates {
		return
	}

	log.Printf("[%s] Presence from %v: show: %v status: %v gone: %v\n", ev.To, ev.From, ev.Show, ev.Status, ev.Gone)
	u.rosterUpdated()

	account := u.findAccountForSession(ev.Session)
	if account == nil {
		return
	}

	u.roster.presenceUpdated(
		account,
		utils.RemoveResourceFromJid(ev.From),
		ev.Show,
		ev.Status,
		ev.Gone,
	)
}
Example #19
0
// Is returns true if this account represents the same identity as the given JID
func (a *Account) Is(jid string) bool {
	return a.Account == utils.RemoveResourceFromJid(jid)
}
Example #20
0
// Get returns the peer if it's known and false otherwise
func (l *List) Get(jid string) (*Peer, bool) {
	v, ok := l.peers[utils.RemoveResourceFromJid(jid)]
	return v, ok
}