Index: /trunk/downstream.go
===================================================================
--- /trunk/downstream.go	(revision 72)
+++ /trunk/downstream.go	(revision 73)
@@ -59,4 +59,5 @@
 	username   string
 	realname   string
+	upstream   *Upstream
 }
 
@@ -98,11 +99,36 @@
 }
 
+func (dc *downstreamConn) forEachUpstream(f func(*upstreamConn)) {
+	dc.user.forEachUpstream(func(uc *upstreamConn) {
+		if dc.upstream != nil && uc.upstream != dc.upstream {
+			return
+		}
+		f(uc)
+	})
+}
+
 func (dc *downstreamConn) unmarshalChannel(name string) (*upstreamConn, string, error) {
-	// TODO: extract network name from channel name
-	ch, err := dc.user.getChannel(name)
-	if err != nil {
-		return nil, "", err
-	}
-	return ch.conn, ch.Name, nil
+	// TODO: extract network name from channel name if dc.upstream == nil
+	var channel *upstreamChannel
+	var err error
+	dc.forEachUpstream(func(uc *upstreamConn) {
+		if err != nil {
+			return
+		}
+		if ch, ok := uc.channels[name]; ok {
+			if channel != nil {
+				err = fmt.Errorf("ambiguous channel name %q", name)
+			} else {
+				channel = ch
+			}
+		}
+	})
+	if channel == nil {
+		return nil, "", ircError{&irc.Message{
+			Command: irc.ERR_NOSUCHCHANNEL,
+			Params:  []string{name, "No such channel"},
+		}}
+	}
+	return channel.conn, channel.Name, nil
 }
 
@@ -275,7 +301,16 @@
 
 func (dc *downstreamConn) register() error {
-	u := dc.srv.getUser(strings.TrimPrefix(dc.username, "~"))
+	username := strings.TrimPrefix(dc.username, "~")
+	var network string
+	if i := strings.LastIndexAny(username, "/@"); i >= 0 {
+		network = username[i+1:]
+	}
+	if i := strings.IndexAny(username, "/@"); i >= 0 {
+		username = username[:i]
+	}
+
+	u := dc.srv.getUser(username)
 	if u == nil {
-		dc.logger.Printf("failed authentication: unknown username %q", dc.username)
+		dc.logger.Printf("failed authentication: unknown username %q", username)
 		dc.SendMessage(&irc.Message{
 			Prefix:  dc.srv.prefix(),
@@ -286,4 +321,17 @@
 	}
 
+	if network != "" {
+		dc.upstream = dc.srv.getUpstream(network)
+		if dc.upstream == nil {
+			dc.logger.Printf("failed registration: unknown upstream %q", network)
+			dc.SendMessage(&irc.Message{
+				Prefix:  dc.srv.prefix(),
+				Command: irc.ERR_PASSWDMISMATCH,
+				Params:  []string{"*", fmt.Sprintf("Unknown upstream server %q", network)},
+			})
+			return nil
+		}
+	}
+
 	dc.registered = true
 	dc.user = u
@@ -320,5 +368,5 @@
 	})
 
-	u.forEachUpstream(func(uc *upstreamConn) {
+	dc.forEachUpstream(func(uc *upstreamConn) {
 		// TODO: fix races accessing upstream connection data
 		for _, ch := range uc.channels {
@@ -328,6 +376,5 @@
 		}
 
-		// TODO: let clients specify the ring buffer name in their username
-		historyName := ""
+		historyName := dc.username
 
 		var seqPtr *uint64
@@ -377,5 +424,5 @@
 		}}
 	case "NICK":
-		dc.user.forEachUpstream(func(uc *upstreamConn) {
+		dc.forEachUpstream(func(uc *upstreamConn) {
 			uc.SendMessage(msg)
 		})
@@ -449,5 +496,5 @@
 
 			if modeStr != "" {
-				dc.user.forEachUpstream(func(uc *upstreamConn) {
+				dc.forEachUpstream(func(uc *upstreamConn) {
 					uc.SendMessage(&irc.Message{
 						Command: "MODE",
Index: /trunk/server.go
===================================================================
--- /trunk/server.go	(revision 72)
+++ /trunk/server.go	(revision 73)
@@ -83,9 +83,12 @@
 }
 
-func (u *user) getChannel(name string) (*upstreamChannel, error) {
+func (u *user) getChannel(name string, upstream *Upstream) (*upstreamChannel, error) {
 	var channel *upstreamChannel
 	var err error
 	u.forEachUpstream(func(uc *upstreamConn) {
 		if err != nil {
+			return
+		}
+		if upstream != nil && uc.upstream != upstream {
 			return
 		}
@@ -197,4 +200,13 @@
 }
 
+func (s *Server) getUpstream(name string) *Upstream {
+	for i, upstream := range s.Upstreams {
+		if upstream.Addr == name {
+			return &s.Upstreams[i]
+		}
+	}
+	return nil
+}
+
 func (s *Server) Serve(ln net.Listener) error {
 	for {
Index: /trunk/upstream.go
===================================================================
--- /trunk/upstream.go	(revision 72)
+++ /trunk/upstream.go	(revision 73)
@@ -101,4 +101,13 @@
 }
 
+func (uc *upstreamConn) forEachDownstream(f func(*downstreamConn)) {
+	uc.user.forEachDownstream(func(dc *downstreamConn) {
+		if dc.upstream != nil && dc.upstream != uc.upstream {
+			return
+		}
+		f(dc)
+	})
+}
+
 func (uc *upstreamConn) getChannel(name string) (*upstreamChannel, error) {
 	ch, ok := uc.channels[name]
@@ -141,5 +150,5 @@
 			}
 
-			uc.user.forEachDownstream(func(dc *downstreamConn) {
+			uc.forEachDownstream(func(dc *downstreamConn) {
 				dc.SendMessage(&irc.Message{
 					Prefix:  dc.marshalUserPrefix(uc, msg.Prefix),
@@ -211,5 +220,5 @@
 			}
 
-			uc.user.forEachDownstream(func(dc *downstreamConn) {
+			uc.forEachDownstream(func(dc *downstreamConn) {
 				dc.SendMessage(&irc.Message{
 					Prefix:  dc.marshalUserPrefix(uc, msg.Prefix),
@@ -241,5 +250,5 @@
 			}
 
-			uc.user.forEachDownstream(func(dc *downstreamConn) {
+			uc.forEachDownstream(func(dc *downstreamConn) {
 				dc.SendMessage(&irc.Message{
 					Prefix:  dc.marshalUserPrefix(uc, msg.Prefix),
@@ -327,5 +336,5 @@
 		ch.complete = true
 
-		uc.user.forEachDownstream(func(dc *downstreamConn) {
+		uc.forEachDownstream(func(dc *downstreamConn) {
 			forwardChannel(dc, ch)
 		})
