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 }
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) }
// 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 }
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) }
func peerWithPendingSubscribe(jid, id, belongsTo string) *Peer { return &Peer{ Jid: xutils.RemoveResourceFromJid(jid), PendingSubscribeID: id, BelongsTo: belongsTo, } }
// 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, } }
func peerWithPendingSubscribe(jid, id, belongsTo string) *Peer { return &Peer{ Jid: xutils.RemoveResourceFromJid(jid), PendingSubscribeID: id, Asked: true, BelongsTo: belongsTo, resources: toSet(), } }
// 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 }
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 }
// 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, } }
// 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 } }
// 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 }
// 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 }
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, ) }
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 }
// 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(), } }
// 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 }
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, ) }
// 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) }
// 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 }