Example #1
0
// ParseModeLine parses a line of mode changes into core.DataChange structs.
// Redundant changes are compressed down into one.
// An error is returned if unknown modes are encountered, or modes are dropped
// due to missing parameters. The remainder of the modes are still parsed.
// e is the user or channel being changed.
func (p *ModeParser) ParseModeLine(source *core.User, e core.Extensible, modeline []byte, params []string) ([]core.DataChange, os.Error) {
	var adding bool = true
	var unknown string
	var missing string
	var param int
	modes := string(modeline)
	changes := make(map[string]core.DataChange)

	for _, char := range modes {

		if char == '+' {
			adding = true
			continue
		} else if char == '-' {
			adding = false
			continue
		}

		if v, ok := p.simple[char]; ok {
			if v, ok := p.extended[char]; ok {
				newchanges := v(adding, e, "")
				for _, it := range newchanges {
					changes[it.Name] = it
				}
				continue
			}

			var change core.DataChange
			change.Name = v
			if adding {
				change.Data = "on"
			}

			changes[change.Name] = change
			continue
		}

		if v, ok := p.parametered[char]; ok {
			var change core.DataChange
			if adding {
				if param >= len(params) {
					missing += string(char)
					continue
				}

				if v, ok := p.extended[char]; ok {
					newch := v(adding, e, params[param])
					param++
					for _, it := range newch {
						changes[it.Name] = it
					}
					continue
				}

				change.Name = v
				change.Data = params[param]
				param++
			} else {
				if v, ok := p.extended[char]; ok {
					newchanges := v(adding, e, "")
					for _, it := range newchanges {
						changes[it.Name] = it
					}
					continue
				}

				change.Name = v
			}

			changes[change.Name] = change
			continue
		}

		if v, ok := p.list[char]; ok {
			if param >= len(params) {
				missing += string(char)
				continue
			}
			var change core.DataChange
			cparam := params[param]
			param++

			if v, ok := p.extended[char]; ok {
				newchanges := v(adding, e, cparam)
				for _, it := range newchanges {
					if it.Data != "" {
						it.Data += fmt.Sprintf(" setby-%s setat-%d", source.GetSetBy(), time.Seconds())
					}
					changes[it.Name] = it
				}
				continue
			}

			if adding {
				change.Name = v + " " + cparam
				change.Data = fmt.Sprintf("on setby-%s setat-%d", source.GetSetBy(), time.Seconds())
			} else {
				change.Name = v + " " + cparam
			}

			changes[change.Name] = change
			continue
		}

		if v, ok := p.membership[char]; ok {
			var ch *core.Channel
			var ok bool
			if ch, ok = e.(*core.Channel); !ok {
				continue
			}
			if param >= len(params) {
				missing += string(char)
				continue
			}
			par := params[param]
			param++

			if v, ok := p.extended[char]; ok {
				newchanges := v(adding, e, par)
				for _, it := range newchanges {
					if it.Member != nil {
						changes["m"+it.Member.User().ID()+" "+it.Name] = it
					} else {
						changes[it.Name] = it
					}
				}
				continue
			}

			var u *core.User
			var m *core.Membership
			if u = core.GetUser(par); u == nil {
				if u = core.GetUserByNick(par); u == nil {
					continue
				}
			}
			if m = ch.GetMember(u); m == nil {
				continue
			}

			var change core.DataChange
			change.Name = v
			change.Member = m

			if adding {
				change.Data = "on"
			}

			changes["m"+change.Member.User().ID()+" "+change.Name] = change
			continue
		}

		unknown += string(char)
	}

	// Turn the modes into a slice.
	c := make([]core.DataChange, 0, len(changes))
	for _, change := range changes {
		c = append(c, change)
	}

	// Get the error, if we had one.
	var errstring string
	if unknown != "" {
		errstring += "Unknown mode letters: " + unknown
		if missing != "" {
			errstring += "  "
		}
	}
	if missing != "" {
		errstring += "Missing parameters for: " + missing
	}
	var err os.Error
	if errstring != "" {
		err = os.NewError(errstring)
	}

	return c, err
}
Example #2
0
// Handle a single (potential) server link.
// outgoing indicates whether it is outgoing or incoming.
func link(c *net.TCPConn, outgoing bool) {
	errMsg := "Input Error"

	serverMutex.Lock()

	// Create a new server, and add it to the server list.
	l := new(local)
	l.local = l
	l.next = servers
	if servers != nil {
		servers.prev = &(l.server)
	}
	servers = &(l.server)
	l.c = c

	serverMutex.Unlock()

	// Defer deletion of the server. If it's already deleted, no harm done.
	defer func() {
		l.Delete(errMsg)
	}()

	if outgoing {
		link_auth(l)
	}

	errMsg = irc.ReadLine(l.c, make([]byte, 20960), func(line []byte) {

		// Parse the line.
		prefix, command, params, perr := irc.Parse(commands, line, l.authed)

		// Look up the server or user this command is from.
		var source interface{}
		if len(prefix) == 9 {
			u := core.GetUser(string(prefix))
			if u == nil {
				source = nil
			} else if u.Owner() != me {
				source = nil
			} else {
				userver := u.Owndata().(*server)
				if userver.local == l {
					source = u
				}
			}
		} else if len(prefix) == 3 {
			v := core.GetSID(string(prefix))
			if v == nil {
				source = nil
			} else if s, ok := v.(*server); ok {
				if s.local == l {
					source = s
				}
			}
		} else if len(prefix) == 0 {
			// No prefix; it's from this server.
			source = &(l.server)
		} else {
			// Prefix is gibberish.
			source = nil
		}

		// If we successfully got a command and source, run it.
		if source != nil && command != nil {
			command.Handler(source, params)
		} else if perr != nil {

			// The IRC protocol is stupid.
			switch perr.Num {
			case irc.CmdNotFound:
				irc.SendLine(l, from(nil), l.sid, "421", "%s :%s",
					perr.CmdName, perr)
			case irc.CmdForRegistered:
				irc.SendFrom(l, from(nil), "451 %s :%s", perr.CmdName,
					perr)
			case irc.CmdForUnregistered:
				irc.SendFrom(l, from(nil), "462 %s :%s", l.sid, perr)
			default:
				irc.SendFrom(l, from(nil), "461 %s %s :%s", l.sid,
					perr.CmdName, perr)
			}
		}
	})
}