diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..69a7a03 --- /dev/null +++ b/.gitignore @@ -0,0 +1,25 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.swp +bin/ diff --git a/GNUmakefile b/GNUmakefile new file mode 100644 index 0000000..00b2b5c --- /dev/null +++ b/GNUmakefile @@ -0,0 +1,31 @@ +# +# Makefile for hookAPI +# +# switches: +# define the ones you want in the CFLAGS definition... +# +# TRACE - turn on tracing/debugging code +# +# +# +# + +# Version for distribution +VER=1_0r1 + +MAKEFILE=GNUmakefile + +# We Use Compact Memory Model + +all: bin/example + @[ -d bin ] || exit + +bin/example: _example/example.go xmpp.go + @[ -d bin ] || mkdir bin + go build -o $@ _example/example.go + @strip $@ || echo "example OK" + +clean: + +distclean: clean + @rm -rf bin diff --git a/_example/example.go b/_example/example.go index fbd0b12..d0da4a3 100644 --- a/_example/example.go +++ b/_example/example.go @@ -5,10 +5,11 @@ import ( "crypto/tls" "flag" "fmt" - "github.com/mattn/go-xmpp" + "github.com/kjx98/go-xmpp" "log" "os" "strings" + "time" ) var server = flag.String("server", "", "server") @@ -16,7 +17,7 @@ var username = flag.String("username", "", "username") var password = flag.String("password", "", "password") var status = flag.String("status", "xa", "status") var statusMessage = flag.String("status-msg", "I for one welcome our new codebot overlords.", "status message") -var notls = flag.Bool("notls", false, "No TLS") +var notls = flag.Bool("notls", true, "No TLS") var debug = flag.Bool("debug", false, "debug output") var session = flag.Bool("session", false, "use server session") @@ -55,6 +56,7 @@ func main() { Debug: *debug, Session: *session, Status: *status, + Resource: "bot", StatusMessage: *statusMessage, } @@ -72,18 +74,52 @@ func main() { } switch v := chat.(type) { case xmpp.Chat: - fmt.Println(v.Remote, v.Text) + if v.Type == "roster" { + fmt.Println("roster", v.Roster) + } else { + for _, element := range v.OtherElem { + if element.XMLName.Space == "jabber:x:conference" { + // if not join + talk.JoinMUCNoHistory(v.Remote, "bot") + } + // composing, paused, active + if element.XMLName.Space == + "http://jabber.org/protocol/chatstates" && + element.XMLName.Local == "composing" { + fmt.Println(v.Remote, "is composing") + } + } + if strings.TrimSpace(v.Text) != "" { + fmt.Println(v.Remote, v.Text) + } + } case xmpp.Presence: - fmt.Println(v.From, v.Show) + fmt.Println("Presence:", v.From, v.Show, v.Type) + case xmpp.Roster, xmpp.Contact: + // TODO: update local roster + fmt.Println("Roster/Contact:", v) + case xmpp.IQ: + // ping ignore + if v.Type == "result" && v.ID == "c2s1" { + fmt.Printf("Got pong from %s to %s\n", v.From, v.To) + } + default: + fmt.Printf("def: %v\n", v) } } }() + // get roster first + talk.Roster() + talk.SendOrg("") for { in := bufio.NewReader(os.Stdin) line, err := in.ReadString('\n') if err != nil { continue } + if len(line) >= 4 && line[:4] == "quit" { + break + } line = strings.TrimRight(line, "\n") tokens := strings.SplitN(line, " ", 2) @@ -91,4 +127,6 @@ func main() { talk.Send(xmpp.Chat{Remote: tokens[0], Type: "chat", Text: tokens[1]}) } } + talk.SendOrg("`)) || bytes.Equal(bytes.TrimSpace(v.Query), []byte(``)) { + if v.Query.XMLName.Space == "urn:xmpp:ping" { + fmt.Println("clientIQ ping") err := c.SendResultPing(v.ID, v.From) if err != nil { return Chat{}, err } } - return IQ{ID: v.ID, From: v.From, To: v.To, Type: v.Type, Query: v.Query}, nil + // + // TODO: shall we check XMLName.Local is "query"? + if (v.Type == "result" || v.Type == "set") && + v.Query.XMLName.Space == "jabber:iq:roster" { + var item rosterItem + var r Roster + vv := strings.Split(v.Query.InnerXML, "/>") + for _, ss := range vv { + if strings.TrimSpace(ss) == "" { + continue + } + ss += "/>" + if err := xml.Unmarshal([]byte(ss), &item); err != nil { + return nil, errors.New("unmarshal roster : " + err.Error()) + } else { + if item.Subscription == "remove" { + continue + } + r = append(r, Contact{item.Jid, item.Name, item.Group}) + } + } + return Chat{Type: "roster", Roster: r}, nil + } + return IQ{ID: v.ID, From: v.From, To: v.To, Type: v.Type, + Query: []byte(v.Query.InnerXML)}, nil } } } @@ -857,14 +882,15 @@ type clientPresence struct { type clientIQ struct { // info/query - XMLName xml.Name `xml:"jabber:client iq"` - From string `xml:"from,attr"` - ID string `xml:"id,attr"` - To string `xml:"to,attr"` - Type string `xml:"type,attr"` // error, get, result, set - Query []byte `xml:",innerxml"` - Error clientError - Bind bindBind + XMLName xml.Name `xml:"jabber:client iq"` + From string `xml:"from,attr"` + ID string `xml:"id,attr"` + To string `xml:"to,attr"` + Type string `xml:"type,attr"` // error, get, result, set + Query XMLElement `xml:",any"` + + Error clientError + Bind bindBind } type clientError struct { @@ -880,11 +906,11 @@ type clientQuery struct { } type rosterItem struct { - XMLName xml.Name `xml:"jabber:iq:roster item"` - Jid string `xml:",attr"` - Name string `xml:",attr"` - Subscription string `xml:",attr"` - Group []string + XMLName xml.Name `xml:"item"` + Jid string `xml:"jid,attr"` + Name string `xml:"name,attr"` + Subscription string `xml:"subscription,attr"` + Group []string `"xml:"group"` } // Scan XML token stream to find next StartElement.