"path"
)
-//~ type StdLogger struct {
-//~ }
-
-//~ func (s *StdLogger) Log(v ...interface{}) {
- //~ log.Println(v...)
-//~ }
-
-//~ func (s *StdLogger) Logf(fmt string, v ...interface{}) {
- //~ log.Printf(fmt, v...)
-//~ }
-
-
func (botdata *XmppBot) makeXMPPMessage(to string, message interface{}, subject interface{}) *xmpp.Message {
xmppmsgheader := xmpp.Header{To: to,
From: botdata.my_jid_,
}
}
-
-func init() {
- //~ logger := &StdLogger{}
- //~ xmpp.Debug = logger
- //~ xmpp.Info = logger
- //~ xmpp.Warn = logger
-}
-
func (botdata *XmppBot) handleEventsforXMPP(xmppout chan <- xmpp.Stanza, presence_events <- chan interface{}, jabber_events <- chan JabberEvent) {
var last_status_msg *string
defer func() {
if x := recover(); x != nil {
Syslog_.Printf("handleEventsforXMPP: run time panic: %v", x)
+ //FIXME: signal that xmpp bot has crashed
}
+ for _ = range(jabber_events) {} //cleanout jabber_events queue
}()
for {
select {
- case pe := <-presence_events:
+ case pe, pe_still_open := <-presence_events:
+ if ! pe_still_open { return }
+ Debug_.Printf("handleEventsforXMPP<-presence_events: %T %+v", pe, pe)
switch pec := pe.(type) {
case xmpp.Stanza:
xmppout <- pec
}
}
default:
- break
+ Debug_.Println("handleEventsforXMPP<-presence_events: unknown type received: quitting")
+ return
}
- case je := <-jabber_events:
+ case je, je_still_open := <-jabber_events:
+ if ! je_still_open { return }
+ Debug_.Printf("handleEventsforXMPP<-jabber_events: %T %+v", je, je)
simple_jid := removeJIDResource(je.JID)
jid_data, jid_in_map := botdata.realraum_jids_[simple_jid]
+
+ //send status if requested, even if user never changed any settings and thus is not in map
+ if last_status_msg != nil && je.StatusNow {
+ xmppout <- botdata.makeXMPPMessage(je.JID, last_status_msg, nil)
+ }
+
if jid_in_map {
- if last_status_msg != nil && (je.StatusNow || (! jid_data.Online && je.Online && jid_data.Wants == R3OnlineOnlyWithRecapInfo) ) {
+ //if R3OnlineOnlyWithRecapInfo, we want a status update when coming online
+ if last_status_msg != nil && ! jid_data.Online && je.Online && jid_data.Wants == R3OnlineOnlyWithRecapInfo {
xmppout <- botdata.makeXMPPMessage(je.JID, last_status_msg, nil)
}
jid_data.Online = je.Online
defer func() {
if x := recover(); x != nil {
Syslog_.Printf("handleIncomingXMPPStanzas: run time panic: %v", x)
- close(jabber_events)
}
+ close(jabber_events)
}()
+ var error_count int = 0
var incoming_stanza interface{}
+
+ handleStanzaError := func() bool {
+ error_count++
+ if error_count > 15 {
+ Syslog_.Println("handleIncomingXMPPStanzas: too many errors in series.. bailing out")
+ botdata.StopBot()
+ return true
+ }
+ return false
+ }
+
for incoming_stanza = range xmppin {
switch stanza := incoming_stanza.(type) {
case *xmpp.Message:
+ if stanza.GetHeader() == nil { continue }
+ if stanza.Type == "error" || stanza.Error != nil {
+ Syslog_.Printf("XMPP %T Error: %s", stanza, stanza)
+ if stanza.Error.Type == "cancel" {
+ // asume receipient not reachable -> disable
+ Syslog_.Printf("Error reaching %s. Disabling user, please reenable manually", stanza.From)
+ jabber_events <- JabberEvent{stanza.From, false, R3NeverInfo, false}
+ continue
+ }
+ if handleStanzaError() { return }
+ continue
+ } else { error_count = 0 }
botdata.handleIncomingMessageDialog(*stanza, xmppout, jabber_events)
case *xmpp.Presence:
- if stanza.GetHeader() == nil {
+ if stanza.GetHeader() == nil { continue }
+ if stanza.Type == "error" || stanza.Error != nil {
+ Syslog_.Printf("XMPP %T Error: %s", stanza, stanza)
+ if handleStanzaError() { return }
continue
- }
+ } else { error_count = 0 }
switch stanza.GetHeader().Type {
case "subscribe":
xmppout <- botdata.makeXMPPPresence(stanza.GetHeader().From, "subscribed", "", "")
default:
jabber_events <- JabberEvent{stanza.GetHeader().From, true, R3NoChange, false}
}
+
case *xmpp.Iq:
- if stanza.GetHeader() == nil {
+ if stanza.GetHeader() == nil { continue }
+ if stanza.Type == "error" || stanza.Error != nil {
+ Syslog_.Printf("XMPP %T Error: %s", stanza, stanza)
+ if handleStanzaError() { return }
continue
- }
+ } else { error_count = 0 }
+
+ if HandleServerToClientPing(stanza, xmppout) {continue} //if true then routine handled it and we can continue
+ Debug_.Printf("Unhandled Iq: %s", stanza)
}
}
}
+func init() {
+ //~ xmpp.Debug = &XMPPDebugLogger{}
+ xmpp.Info = &XMPPDebugLogger{}
+ xmpp.Warn = &XMPPLogger{}
+}
+
func NewStartedBot(loginjid, loginpwd, password, state_save_dir string, insecuretls bool) (*XmppBot, chan interface{}, error) {
var err error
botdata := new(XmppBot)
botdata.config_file_ = path.Join(state_save_dir, "r3xmpp."+removeJIDResource(loginjid)+".json")
- //~ logger := &StdLogger{}
- //~ xmpp.Debug = logger
- //~ xmpp.Info = logger
- //~ xmpp.Warn = logger
-
xmpp.TlsConfig = tls.Config{InsecureSkipVerify: insecuretls}
botdata.realraum_jids_.loadFrom(botdata.config_file_)
roster := xmpp.Roster(botdata.xmppclient_)
for _, entry := range roster {
+ Debug_.Print(entry)
if entry.Subscription == "from" {
botdata.xmppclient_.Out <- botdata.makeXMPPPresence(entry.Jid, "subscribe", "","")
}
}
func (botdata *XmppBot) StopBot() {
+ Syslog_.Println("Stopping XMPP Bot")
if botdata.xmppclient_ != nil {
close(botdata.xmppclient_.Out)
}
*botdata.presence_events_ <- false
close(*botdata.presence_events_)
}
+ botdata.config_file_ = ""
+ botdata.realraum_jids_ = nil
+ botdata.xmppclient_ = nil
}