示例#1
0
func sendJabberNotification(ctx httputil.Context, u string, test entities.TestResult) (err error) {
	//exit early if we have no url
	if u == "" {
		return
	}

	//make sure we have configuration values
	if Config.Username == "" || Config.Domain == "" || Config.Password == "" {
		ctx.Errorf("Unable to send notification (%s): configuration not specified", test.ImportPath)
		return
	}

	ctx.Infof("Send jabber notification (%s): %s", test.ImportPath, u)

	//open a tcp connection to the jabber server
	netConn, err := net.Dial("tcp", "talk.google.com:5222")
	if err != nil {
		return
	}
	defer netConn.Close()

	//use that connection in the xmpp config and dial out
	config := &xmpp.Config{Conn: netConn}
	conn, err := xmpp.Dial("", Config.Username, Config.Domain, Config.Password, config)
	if err != nil {
		return
	}

	//send off the message
	message := fmt.Sprintf("%s @ %s status is now %s", test.ImportPath, test.Revision, test.Status)
	err = conn.Send(u, message)
	return
}
示例#2
0
func main() {
	flag.Parse()

	oldState, err := terminal.MakeRaw(0)
	if err != nil {
		panic(err.Error())
	}
	defer terminal.Restore(0, oldState)
	term := terminal.NewTerminal(os.Stdin, "> ")
	if width, height, err := terminal.GetSize(0); err == nil {
		term.SetSize(width, height)
	}

	if len(*configFile) == 0 {
		homeDir := os.Getenv("HOME")
		if len(homeDir) == 0 {
			homeDir = "/"
		}
		*configFile = homeDir + "/.xmpp-client"
	}

	config, err := ParseConfig(*configFile)
	if err != nil {
		alert(term, "Failed to parse config file: "+err.Error())
		config = new(Config)
		if !enroll(config, term) {
			return
		}
		config.filename = *configFile
		config.Save()
	}

	password := config.Password
	if len(password) == 0 {
		if password, err = term.ReadPassword(fmt.Sprintf("Password for %s (will not be saved to disk): ", config.Account)); err != nil {
			alert(term, "Failed to read password: "******"@", 2)
	if len(parts) != 2 {
		alert(term, "invalid username (want user@domain): "+config.Account)
		return
	}
	user := parts[0]
	domain := parts[1]

	var addr string
	if len(config.Server) > 0 && config.Port > 0 {
		addr = fmt.Sprintf("%s:%d", config.Server, config.Port)
	} else {
		if len(config.Proxies) > 0 {
			alert(term, "Cannot connect via a proxy without Server and Port being set in the config file as an SRV lookup would leak information.")
			return
		}
		host, port, err := xmpp.Resolve(domain)
		if err != nil {
			alert(term, "Failed to resolve XMPP server: "+err.Error())
			return
		}
		addr = fmt.Sprintf("%s:%d", host, port)
	}

	var dialer proxy.Dialer
	for i := len(config.Proxies) - 1; i >= 0; i-- {
		u, err := url.Parse(config.Proxies[i])
		if err != nil {
			alert(term, "Failed to parse "+config.Proxies[i]+" as a URL: "+err.Error())
			return
		}
		if dialer == nil {
			dialer = proxy.Direct
		}
		if dialer, err = proxy.FromURL(u, dialer); err != nil {
			alert(term, "Failed to parse "+config.Proxies[i]+" as a proxy: "+err.Error())
			return
		}
	}

	xmppConfig := &xmpp.Config{
		Log:    &lineLogger{term, nil},
		Create: *createAccount,
	}

	if len(config.RawLogFile) > 0 {
		rawLog, err := os.OpenFile(config.RawLogFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
		if err != nil {
			alert(term, "Failed to open raw log file: "+err.Error())
			return
		}

		lock := new(sync.Mutex)
		in := rawLogger{
			out:    rawLog,
			prefix: []byte("<- "),
			lock:   lock,
		}
		out := rawLogger{
			out:    rawLog,
			prefix: []byte("-> "),
			lock:   lock,
		}
		in.other, out.other = &out, &in

		xmppConfig.InLog = &in
		xmppConfig.OutLog = &out

		defer in.flush()
		defer out.flush()
	}

	if dialer != nil {
		info(term, "Making connection to "+addr+" via proxy")
		if xmppConfig.Conn, err = dialer.Dial("tcp", addr); err != nil {
			alert(term, "Failed to connect via proxy: "+err.Error())
			return
		}
	}

	conn, err := xmpp.Dial(addr, user, domain, password, xmppConfig)
	if err != nil {
		alert(term, "Failed to connect to XMPP server: "+err.Error())
		return
	}

	s := Session{
		account:           config.Account,
		conn:              conn,
		term:              term,
		conversations:     make(map[string]*otr.Conversation),
		knownStates:       make(map[string]string),
		privateKey:        new(otr.PrivateKey),
		config:            config,
		pendingRosterChan: make(chan *rosterEdit),
		pendingSubscribes: make(map[string]string),
		lastActionTime:    time.Now(),
	}
	info(term, "Fetching roster")

	//var rosterReply chan xmpp.Stanza
	rosterReply, _, err := s.conn.RequestRoster()
	if err != nil {
		alert(term, "Failed to request roster: "+err.Error())
		return
	}

	conn.SignalPresence("")

	s.input = Input{
		term:        term,
		uidComplete: new(priorityList),
	}
	commandChan := make(chan interface{})
	go s.input.ProcessCommands(commandChan)

	stanzaChan := make(chan xmpp.Stanza)
	go s.readMessages(stanzaChan)

	s.privateKey.Parse(config.PrivateKey)
	s.timeouts = make(map[xmpp.Cookie]time.Time)

	ticker := time.NewTicker(1 * time.Second)

MainLoop:
	for {
		select {
		case now := <-ticker.C:
			haveExpired := false
			for _, expiry := range s.timeouts {
				if now.After(expiry) {
					haveExpired = true
					break
				}
			}
			if !haveExpired {
				continue
			}

			newTimeouts := make(map[xmpp.Cookie]time.Time)
			for cookie, expiry := range s.timeouts {
				if now.After(expiry) {
					s.conn.Cancel(cookie)
				} else {
					newTimeouts[cookie] = expiry
				}
			}
			s.timeouts = newTimeouts

		case edit := <-s.pendingRosterChan:
			if !edit.isComplete {
				info(s.term, "Please edit "+edit.fileName+" and run /rostereditdone when complete")
				s.pendingRosterEdit = edit
				continue
			}
			if s.processEditedRoster(edit) {
				s.pendingRosterEdit = nil
			} else {
				alert(s.term, "Please reedit file and run /rostereditdone again")
			}

		case rosterStanza, ok := <-rosterReply:
			if !ok {
				alert(s.term, "Failed to read roster: "+err.Error())
				return
			}
			if s.roster, err = xmpp.ParseRoster(rosterStanza); err != nil {
				alert(s.term, "Failed to parse roster: "+err.Error())
				return
			}
			for _, entry := range s.roster {
				s.input.AddUser(entry.Jid)
			}
			info(s.term, "Roster received")

		case cmd, ok := <-commandChan:
			if !ok {
				warn(term, "Exiting because command channel closed")
				break MainLoop
			}
			s.lastActionTime = time.Now()
			switch cmd := cmd.(type) {
			case quitCommand:
				break MainLoop
			case versionCommand:
				replyChan, cookie, err := s.conn.SendIQ(cmd.User, "get", xmpp.VersionQuery{})
				if err != nil {
					alert(s.term, "Error sending version request: "+err.Error())
					continue
				}
				s.timeouts[cookie] = time.Now().Add(5 * time.Second)
				go s.awaitVersionReply(replyChan, cmd.User)
			case rosterCommand:
				info(s.term, "Current roster:")
				maxLen := 0
				for _, item := range s.roster {
					if maxLen < len(item.Jid) {
						maxLen = len(item.Jid)
					}
				}

				for _, item := range s.roster {
					line := "  "
					line += item.Jid
					numSpaces := 1 + (maxLen - len(item.Jid))
					for i := 0; i < numSpaces; i++ {
						line += " "
					}
					line += item.Subscription + "\t" + item.Name
					if state, ok := s.knownStates[item.Jid]; ok {
						line += "\t" + state
					}
					info(s.term, line)
				}
			case rosterEditCommand:
				if s.pendingRosterEdit != nil {
					warn(s.term, "Aborting previous roster edit")
					s.pendingRosterEdit = nil
				}
				rosterCopy := make([]xmpp.RosterEntry, len(s.roster))
				copy(rosterCopy, s.roster)
				go s.editRoster(rosterCopy)
			case rosterEditDoneCommand:
				if s.pendingRosterEdit == nil {
					warn(s.term, "No roster edit in progress. Use /rosteredit to start one")
					continue
				}
				go s.loadEditedRoster(*s.pendingRosterEdit)
			case confirmCommand:
				s.handleConfirmOrDeny(cmd.User, true /* confirm */)
			case denyCommand:
				s.handleConfirmOrDeny(cmd.User, false /* deny */)
			case addCommand:
				s.conn.SendPresence(cmd.User, "subscribe", "" /* generate id */)
			case msgCommand:
				conversation, ok := s.conversations[cmd.to]
				var msgs [][]byte
				if ok {
					var err error
					msgs, err = conversation.Send([]byte(cmd.msg))
					if err != nil {
						alert(s.term, err.Error())
						break
					}
				} else {
					msgs = [][]byte{[]byte(cmd.msg)}
				}

				for _, msg := range msgs {
					s.conn.Send(cmd.to, string(msg))
				}
			case otrCommand:
				s.conn.Send(string(cmd.User), string(otr.QueryMessage))
			case authQACommand:
				to := string(cmd.User)
				conversation, ok := s.conversations[to]
				if !ok {
					alert(s.term, "Can't authenticate without a secure conversation established")
					break
				}
				msgs, err := conversation.Authenticate(cmd.Question, []byte(cmd.Secret))
				if err != nil {
					alert(s.term, "Error while starting authentication with "+to+": "+err.Error())
				}
				for _, msg := range msgs {
					s.conn.Send(to, string(msg))
				}
			}
		case rawStanza, ok := <-stanzaChan:
			if !ok {
				warn(term, "Exiting because channel to server closed")
				break MainLoop
			}
			switch stanza := rawStanza.Value.(type) {
			case *xmpp.ClientMessage:
				s.processClientMessage(stanza)
			case *xmpp.ClientPresence:
				s.processPresence(stanza)
			case *xmpp.ClientIQ:
				if stanza.Type != "get" && stanza.Type != "set" {
					continue
				}
				reply := s.processIQ(stanza)
				if reply == nil {
					reply = xmpp.ErrorReply{
						Type:  "cancel",
						Error: xmpp.ErrorBadRequest{},
					}
				}
				if err := s.conn.SendIQReply(stanza.From, "result", stanza.Id, reply); err != nil {
					alert(term, "Failed to send IQ message: "+err.Error())
				}
			default:
				info(term, fmt.Sprintf("%s %s", rawStanza.Name, rawStanza.Value))
			}
		}
	}

	os.Stdout.Write([]byte("\n"))
}
示例#3
0
func main() {
	flag.Parse()

	oldState, err := terminal.MakeRaw(0)
	if err != nil {
		panic(err.Error())
	}
	defer terminal.Restore(0, oldState)
	term := terminal.NewTerminal(os.Stdin, "> ")
	updateTerminalSize(term)

	resizeChan := make(chan os.Signal)
	go func() {
		for _ = range resizeChan {
			updateTerminalSize(term)
		}
	}()
	signal.Notify(resizeChan, syscall.SIGWINCH)

	if len(*configFile) == 0 {
		homeDir := os.Getenv("HOME")
		if len(homeDir) == 0 {
			alert(term, "$HOME not set. Please either export $HOME or use the -config-file option.\n")
			return
		}
		persistentDir := filepath.Join(homeDir, "Persistent")
		if stat, err := os.Lstat(persistentDir); err == nil && stat.IsDir() {
			// Looks like Tails.
			homeDir = persistentDir
		}
		*configFile = filepath.Join(homeDir, ".xmpp-client")
	}

	config, err := ParseConfig(*configFile)
	if err != nil {
		alert(term, "Failed to parse config file: "+err.Error())
		config = new(Config)
		if !enroll(config, term) {
			return
		}
		config.filename = *configFile
		config.Save()
	}

	password := config.Password
	if len(password) == 0 {
		if password, err = term.ReadPassword(fmt.Sprintf("Password for %s (will not be saved to disk): ", config.Account)); err != nil {
			alert(term, "Failed to read password: "******"@", 2)
	if len(parts) != 2 {
		alert(term, "invalid username (want user@domain): "+config.Account)
		return
	}
	user := parts[0]
	domain := parts[1]

	var addr string
	addrTrusted := false

	if len(config.Server) > 0 && config.Port > 0 {
		addr = fmt.Sprintf("%s:%d", config.Server, config.Port)
		addrTrusted = true
	} else {
		if len(config.Proxies) > 0 {
			alert(term, "Cannot connect via a proxy without Server and Port being set in the config file as an SRV lookup would leak information.")
			return
		}
		host, port, err := xmpp.Resolve(domain)
		if err != nil {
			alert(term, "Failed to resolve XMPP server: "+err.Error())
			return
		}
		addr = fmt.Sprintf("%s:%d", host, port)
	}

	var dialer proxy.Dialer
	for i := len(config.Proxies) - 1; i >= 0; i-- {
		u, err := url.Parse(config.Proxies[i])
		if err != nil {
			alert(term, "Failed to parse "+config.Proxies[i]+" as a URL: "+err.Error())
			return
		}
		if dialer == nil {
			dialer = proxy.Direct
		}
		if dialer, err = proxy.FromURL(u, dialer); err != nil {
			alert(term, "Failed to parse "+config.Proxies[i]+" as a proxy: "+err.Error())
			return
		}
	}

	var certSHA256 []byte
	if len(config.ServerCertificateSHA256) > 0 {
		certSHA256, err = hex.DecodeString(config.ServerCertificateSHA256)
		if err != nil {
			alert(term, "Failed to parse ServerCertificateSHA256 (should be hex string): "+err.Error())
			return
		}
		if len(certSHA256) != 32 {
			alert(term, "ServerCertificateSHA256 is not 32 bytes long")
			return
		}
	}
	xmppConfig := &xmpp.Config{
		Log:                     &lineLogger{term, nil},
		Create:                  *createAccount,
		TrustedAddress:          addrTrusted,
		Archive:                 false,
		ServerCertificateSHA256: certSHA256,
	}

	if len(config.RawLogFile) > 0 {
		rawLog, err := os.OpenFile(config.RawLogFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
		if err != nil {
			alert(term, "Failed to open raw log file: "+err.Error())
			return
		}

		lock := new(sync.Mutex)
		in := rawLogger{
			out:    rawLog,
			prefix: []byte("<- "),
			lock:   lock,
		}
		out := rawLogger{
			out:    rawLog,
			prefix: []byte("-> "),
			lock:   lock,
		}
		in.other, out.other = &out, &in

		xmppConfig.InLog = &in
		xmppConfig.OutLog = &out

		defer in.flush()
		defer out.flush()
	}

	if dialer != nil {
		info(term, "Making connection to "+addr+" via proxy")
		if xmppConfig.Conn, err = dialer.Dial("tcp", addr); err != nil {
			alert(term, "Failed to connect via proxy: "+err.Error())
			return
		}
	}

	conn, err := xmpp.Dial(addr, user, domain, password, xmppConfig)
	if err != nil {
		alert(term, "Failed to connect to XMPP server: "+err.Error())
		return
	}

	s := Session{
		account:           config.Account,
		conn:              conn,
		term:              term,
		conversations:     make(map[string]*otr.Conversation),
		knownStates:       make(map[string]string),
		privateKey:        new(otr.PrivateKey),
		config:            config,
		pendingRosterChan: make(chan *rosterEdit),
		pendingSubscribes: make(map[string]string),
		lastActionTime:    time.Now(),
	}
	info(term, "Fetching roster")

	//var rosterReply chan xmpp.Stanza
	rosterReply, _, err := s.conn.RequestRoster()
	if err != nil {
		alert(term, "Failed to request roster: "+err.Error())
		return
	}

	conn.SignalPresence("")

	s.input = Input{
		term:        term,
		uidComplete: new(priorityList),
	}
	commandChan := make(chan interface{})
	go s.input.ProcessCommands(commandChan)

	stanzaChan := make(chan xmpp.Stanza)
	go s.readMessages(stanzaChan)

	s.privateKey.Parse(config.PrivateKey)
	s.timeouts = make(map[xmpp.Cookie]time.Time)

	info(term, fmt.Sprintf("Your fingerprint is %x", s.privateKey.Fingerprint()))

	ticker := time.NewTicker(1 * time.Second)

MainLoop:
	for {
		select {
		case now := <-ticker.C:
			haveExpired := false
			for _, expiry := range s.timeouts {
				if now.After(expiry) {
					haveExpired = true
					break
				}
			}
			if !haveExpired {
				continue
			}

			newTimeouts := make(map[xmpp.Cookie]time.Time)
			for cookie, expiry := range s.timeouts {
				if now.After(expiry) {
					s.conn.Cancel(cookie)
				} else {
					newTimeouts[cookie] = expiry
				}
			}
			s.timeouts = newTimeouts

		case edit := <-s.pendingRosterChan:
			if !edit.isComplete {
				info(s.term, "Please edit "+edit.fileName+" and run /rostereditdone when complete")
				s.pendingRosterEdit = edit
				continue
			}
			if s.processEditedRoster(edit) {
				s.pendingRosterEdit = nil
			} else {
				alert(s.term, "Please reedit file and run /rostereditdone again")
			}

		case rosterStanza, ok := <-rosterReply:
			if !ok {
				alert(s.term, "Failed to read roster: "+err.Error())
				return
			}
			if s.roster, err = xmpp.ParseRoster(rosterStanza); err != nil {
				alert(s.term, "Failed to parse roster: "+err.Error())
				return
			}
			for _, entry := range s.roster {
				s.input.AddUser(entry.Jid)
			}
			info(s.term, "Roster received")

		case cmd, ok := <-commandChan:
			if !ok {
				warn(term, "Exiting because command channel closed")
				break MainLoop
			}
			s.lastActionTime = time.Now()
			switch cmd := cmd.(type) {
			case quitCommand:
				for to, conversation := range s.conversations {
					msgs := conversation.End()
					for _, msg := range msgs {
						s.conn.Send(to, string(msg))
					}
				}
				break MainLoop
			case versionCommand:
				replyChan, cookie, err := s.conn.SendIQ(cmd.User, "get", xmpp.VersionQuery{})
				if err != nil {
					alert(s.term, "Error sending version request: "+err.Error())
					continue
				}
				s.timeouts[cookie] = time.Now().Add(5 * time.Second)
				go s.awaitVersionReply(replyChan, cmd.User)
			case rosterCommand:
				info(s.term, "Current roster:")
				maxLen := 0
				for _, item := range s.roster {
					if maxLen < len(item.Jid) {
						maxLen = len(item.Jid)
					}
				}

				for _, item := range s.roster {
					state, ok := s.knownStates[item.Jid]

					line := ""
					if ok {
						line += "[*] "
					} else if cmd.OnlineOnly {
						continue
					} else {
						line += "[ ] "
					}

					line += item.Jid
					numSpaces := 1 + (maxLen - len(item.Jid))
					for i := 0; i < numSpaces; i++ {
						line += " "
					}
					line += item.Subscription + "\t" + item.Name
					if ok {
						line += "\t" + state
					}
					info(s.term, line)
				}
			case rosterEditCommand:
				if s.pendingRosterEdit != nil {
					warn(s.term, "Aborting previous roster edit")
					s.pendingRosterEdit = nil
				}
				rosterCopy := make([]xmpp.RosterEntry, len(s.roster))
				copy(rosterCopy, s.roster)
				go s.editRoster(rosterCopy)
			case rosterEditDoneCommand:
				if s.pendingRosterEdit == nil {
					warn(s.term, "No roster edit in progress. Use /rosteredit to start one")
					continue
				}
				go s.loadEditedRoster(*s.pendingRosterEdit)
			case toggleStatusUpdatesCommand:
				s.config.HideStatusUpdates = !s.config.HideStatusUpdates
				s.config.Save()
				// Tell the user the current state of the statuses
				if s.config.HideStatusUpdates {
					info(s.term, "Status updated disabled")
				} else {
					info(s.term, "Status updates enabled")
				}
			case confirmCommand:
				s.handleConfirmOrDeny(cmd.User, true /* confirm */)
			case denyCommand:
				s.handleConfirmOrDeny(cmd.User, false /* deny */)
			case addCommand:
				s.conn.SendPresence(cmd.User, "subscribe", "" /* generate id */)
			case msgCommand:
				conversation, ok := s.conversations[cmd.to]
				if (!ok || !conversation.IsEncrypted()) && config.ShouldEncryptTo(cmd.to) {
					warn(s.term, fmt.Sprintf("Did not send: no encryption established with %s", cmd.to))
					continue
				}
				var msgs [][]byte
				message := []byte(cmd.msg)
				// Automatically tag all outgoing plaintext
				// messages with a whitespace tag that
				// indicates that we support OTR.
				if config.OTRAutoAppendTag &&
					!bytes.Contains(message, []byte("?OTR")) &&
					(!ok || !conversation.IsEncrypted()) {
					message = append(message, OTRWhitespaceTag...)
				}
				if ok {
					var err error
					msgs, err = conversation.Send(message)
					if err != nil {
						alert(s.term, err.Error())
						break
					}
				} else {
					msgs = [][]byte{[]byte(message)}
				}
				for _, message := range msgs {
					s.conn.Send(cmd.to, string(message))
				}
			case otrCommand:
				s.conn.Send(string(cmd.User), otr.QueryMessage)
			case otrInfoCommand:
				info(term, fmt.Sprintf("Your OTR fingerprint is %x", s.privateKey.Fingerprint()))
				for to, conversation := range s.conversations {
					if conversation.IsEncrypted() {
						info(s.term, fmt.Sprintf("Secure session with %s underway:", to))
						printConversationInfo(s, to, conversation)
					}
				}
			case endOTRCommand:
				to := string(cmd.User)
				conversation, ok := s.conversations[to]
				if !ok {
					alert(s.term, "No secure session established")
					break
				}
				msgs := conversation.End()
				for _, msg := range msgs {
					s.conn.Send(to, string(msg))
				}
			case authQACommand:
				to := string(cmd.User)
				conversation, ok := s.conversations[to]
				if !ok {
					alert(s.term, "Can't authenticate without a secure conversation established")
					break
				}
				msgs, err := conversation.Authenticate(cmd.Question, []byte(cmd.Secret))
				if err != nil {
					alert(s.term, "Error while starting authentication with "+to+": "+err.Error())
				}
				for _, msg := range msgs {
					s.conn.Send(to, string(msg))
				}
			case authOobCommand:
				fpr, err := hex.DecodeString(cmd.Fingerprint)
				if err != nil {
					alert(s.term, fmt.Sprintf("Invalid fingerprint %s - not authenticated", cmd.Fingerprint))
					break
				}
				existing := s.config.UserIdForFingerprint(fpr)
				if len(existing) != 0 {
					alert(s.term, fmt.Sprintf("Fingerprint %s already belongs to %s", cmd.Fingerprint, existing))
					break
				}
				s.config.KnownFingerprints = append(s.config.KnownFingerprints, KnownFingerprint{fingerprint: fpr, UserId: cmd.User})
				s.config.Save()
				info(s.term, fmt.Sprintf("Saved manually verified fingerprint %s for %s", cmd.Fingerprint, cmd.User))
			case awayCommand:
				s.conn.SignalPresence("away")
			case chatCommand:
				s.conn.SignalPresence("chat")
			case dndCommand:
				s.conn.SignalPresence("dnd")
			case xaCommand:
				s.conn.SignalPresence("xa")
			case onlineCommand:
				s.conn.SignalPresence("")
			}
		case rawStanza, ok := <-stanzaChan:
			if !ok {
				warn(term, "Exiting because channel to server closed")
				break MainLoop
			}
			switch stanza := rawStanza.Value.(type) {
			case *xmpp.ClientMessage:
				s.processClientMessage(stanza)
			case *xmpp.ClientPresence:
				s.processPresence(stanza)
			case *xmpp.ClientIQ:
				if stanza.Type != "get" && stanza.Type != "set" {
					continue
				}
				reply := s.processIQ(stanza)
				if reply == nil {
					reply = xmpp.ErrorReply{
						Type:  "cancel",
						Error: xmpp.ErrorBadRequest{},
					}
				}
				if err := s.conn.SendIQReply(stanza.From, "result", stanza.Id, reply); err != nil {
					alert(term, "Failed to send IQ message: "+err.Error())
				}
			default:
				info(term, fmt.Sprintf("%s %s", rawStanza.Name, rawStanza.Value))
			}
		}
	}

	os.Stdout.Write([]byte("\n"))
}
示例#4
0
func Echo(ws *websocket.Conn) {
	fmt.Println("socket open")
	var recMes message

	err := websocket.JSON.Receive(ws, &recMes)
	if err != nil {
		fmt.Println("Can't receive message")
	}

	if recMes.Type != "login" {
		fmt.Println("not login message")
		return
	}

	userName := strings.Split(recMes.Data["UserName"], "@")
	if len(userName) < 2 {
		userName = []string{userName[0], ""}
	}

	xmppConfig := xmpp.Config{nil, nil, nil, nil, false, false, false, []byte("")}
	talk, err := xmpp.Dial(recMes.Data["Server"], userName[0], userName[1], recMes.Data["Password"], &xmppConfig)
	if err != nil {
		fmt.Println("login error")
		return
	}

	senMes := message{"login", nil}

	if err := websocket.JSON.Send(ws, senMes); err != nil {
		fmt.Println("Can't send")
		return
	}

	fmt.Println("Ready")

	rosterReply, _, err := talk.RequestRoster()
	if err != nil {
		fmt.Println("Can't roster")
	}

	talk.SignalPresence("")

	ses := session{
		talk: talk,
		ws:   ws,
	}

	stanzaChan := make(chan xmpp.Stanza)
	go ses.receiveMessage(stanzaChan)

	webSocketChan := make(chan string)
	go ses.receiveWebSocket(webSocketChan)

	for {
		select {
		case rosterStanza, ok := <-rosterReply:
			var roster []xmpp.RosterEntry
			if !ok {
				fmt.Println("fail to read roaster")
				return
			}
			if roster, err = xmpp.ParseRoster(rosterStanza); err != nil {
				fmt.Println("fail to parse roaster")
				return
			}
			if err := websocket.JSON.Send(ws, rosterMessage{"roster", roster}); err != nil {
				fmt.Println("Can't send")
				return
			}
			fmt.Println("Roster information sent to the client")
		case rawStanza, ok := <-stanzaChan:
			if !ok {
				fmt.Println("stanzaChan receive failed")
				return
			}
			switch stanza := rawStanza.Value.(type) {
			case *xmpp.ClientMessage:
				fmt.Println("Message comming")
				if stanza.Body == "" {
					break
				}
				chatMes := message{"chat", map[string]string{"Remote": xmpp.RemoveResourceFromJid(stanza.From), "Text": stanza.Body}}

				if err := websocket.JSON.Send(ws, chatMes); err != nil {
					fmt.Println("Can't send")
					break
				}
			case *xmpp.ClientPresence:
				fmt.Println("ClientPresence comming")
				fmt.Println(stanza.From, stanza.Type)

				var status string
				if len(stanza.Show) > 0 {
					status = stanza.Show
				} else {
					status = "available"
				}

				preMes := message{"presence", map[string]string{"Remote": xmpp.RemoveResourceFromJid(stanza.From), "Mode": status}}
				if err := websocket.JSON.Send(ws, preMes); err != nil {
					fmt.Println("Can't send")
					return
				}
			}
		case receivedMessage, ok := <-webSocketChan:
			if !ok {
				fmt.Println("webSocketChan receive failed")
				return
			}
			var sendMes message
			if err = json.Unmarshal([]byte(receivedMessage), &sendMes); err != nil {
				fmt.Println("Can't receive")
			} else {

				if err = talk.Send(sendMes.Data["Remote"], sendMes.Data["Text"]); err != nil {
					fmt.Println("failed to send")
				}
				fmt.Println("Message sent" + sendMes.Data["Remote"] + sendMes.Data["Text"])
			}
		}
	}
	fmt.Println("function ends")
}