Index: /trunk/bridge.go
===================================================================
--- /trunk/bridge.go	(revision 68)
+++ /trunk/bridge.go	(revision 69)
@@ -10,8 +10,10 @@
 	}
 
+	downstreamName := dc.marshalChannel(ch.conn, ch.Name)
+
 	dc.SendMessage(&irc.Message{
 		Prefix:  dc.prefix(),
 		Command: "JOIN",
-		Params:  []string{ch.Name},
+		Params:  []string{downstreamName},
 	})
 
@@ -20,5 +22,5 @@
 			Prefix:  dc.srv.prefix(),
 			Command: irc.RPL_TOPIC,
-			Params:  []string{dc.nick, ch.Name, ch.Topic},
+			Params:  []string{dc.nick, downstreamName, ch.Topic},
 		})
 	} else {
@@ -26,5 +28,5 @@
 			Prefix:  dc.srv.prefix(),
 			Command: irc.RPL_NOTOPIC,
-			Params:  []string{dc.nick, ch.Name, "No topic is set"},
+			Params:  []string{dc.nick, downstreamName, "No topic is set"},
 		})
 	}
@@ -34,7 +36,7 @@
 	// TODO: send multiple members in each message
 	for nick, membership := range ch.Members {
-		s := nick
+		s := dc.marshalNick(ch.conn, nick)
 		if membership != 0 {
-			s = string(membership) + nick
+			s = string(membership) + s
 		}
 
@@ -42,5 +44,5 @@
 			Prefix:  dc.srv.prefix(),
 			Command: irc.RPL_NAMREPLY,
-			Params:  []string{dc.nick, string(ch.Status), ch.Name, s},
+			Params:  []string{dc.nick, string(ch.Status), downstreamName, s},
 		})
 	}
@@ -49,5 +51,5 @@
 		Prefix:  dc.srv.prefix(),
 		Command: irc.RPL_ENDOFNAMES,
-		Params:  []string{dc.nick, ch.Name, "End of /NAMES list"},
+		Params:  []string{dc.nick, downstreamName, "End of /NAMES list"},
 	})
 }
Index: /trunk/downstream.go
===================================================================
--- /trunk/downstream.go	(revision 68)
+++ /trunk/downstream.go	(revision 69)
@@ -40,12 +40,17 @@
 }
 
+type consumption struct {
+	consumer     *RingConsumer
+	upstreamConn *upstreamConn
+}
+
 type downstreamConn struct {
-	net       net.Conn
-	irc       *irc.Conn
-	srv       *Server
-	logger    Logger
-	messages  chan *irc.Message
-	consumers chan *RingConsumer
-	closed    chan struct{}
+	net          net.Conn
+	irc          *irc.Conn
+	srv          *Server
+	logger       Logger
+	messages     chan *irc.Message
+	consumptions chan consumption
+	closed       chan struct{}
 
 	registered bool
@@ -58,11 +63,11 @@
 func newDownstreamConn(srv *Server, netConn net.Conn) *downstreamConn {
 	dc := &downstreamConn{
-		net:       netConn,
-		irc:       irc.NewConn(netConn),
-		srv:       srv,
-		logger:    &prefixLogger{srv.Logger, fmt.Sprintf("downstream %q: ", netConn.RemoteAddr())},
-		messages:  make(chan *irc.Message, 64),
-		consumers: make(chan *RingConsumer),
-		closed:    make(chan struct{}),
+		net:          netConn,
+		irc:          irc.NewConn(netConn),
+		srv:          srv,
+		logger:       &prefixLogger{srv.Logger, fmt.Sprintf("downstream %q: ", netConn.RemoteAddr())},
+		messages:     make(chan *irc.Message, 64),
+		consumptions: make(chan consumption),
+		closed:       make(chan struct{}),
 	}
 
@@ -87,4 +92,31 @@
 		// TODO: fill the host?
 	}
+}
+
+func (dc *downstreamConn) marshalChannel(uc *upstreamConn, name string) string {
+	return name
+}
+
+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
+}
+
+func (dc *downstreamConn) marshalNick(uc *upstreamConn, nick string) string {
+	if nick == uc.nick {
+		return dc.nick
+	}
+	return nick
+}
+
+func (dc *downstreamConn) marshalUserPrefix(uc *upstreamConn, prefix *irc.Prefix) *irc.Prefix {
+	if prefix.Name == uc.nick {
+		return dc.prefix()
+	}
+	return prefix
 }
 
@@ -139,9 +171,18 @@
 			}
 			err = dc.irc.WriteMessage(msg)
-		case consumer := <-dc.consumers:
+		case consumption := <-dc.consumptions:
+			consumer, uc := consumption.consumer, consumption.upstreamConn
 			for {
 				msg := consumer.Peek()
 				if msg == nil {
 					break
+				}
+				msg = msg.Copy()
+				switch msg.Command {
+				case "PRIVMSG":
+					// TODO: detect whether it's a user or a channel
+					msg.Params[0] = dc.marshalChannel(uc, msg.Params[0])
+				default:
+					panic("expected to consume a PRIVMSG message")
 				}
 				if dc.srv.Debug {
@@ -304,5 +345,5 @@
 				select {
 				case <-ch:
-					dc.consumers <- consumer
+					dc.consumptions <- consumption{consumer, uc}
 				case <-dc.closed:
 					closed = true
@@ -339,5 +380,5 @@
 			uc.SendMessage(msg)
 		})
-	case "JOIN":
+	case "JOIN", "PART":
 		var name string
 		if err := parseMessageParams(msg, &name); err != nil {
@@ -345,27 +386,22 @@
 		}
 
-		if ch, _ := dc.user.getChannel(name); ch != nil {
-			break // already joined
-		}
-
-		// TODO: extract network name from channel name
-		return ircError{&irc.Message{
-			Command: irc.ERR_NOSUCHCHANNEL,
-			Params:  []string{name, "Channel name ambiguous"},
-		}}
-	case "PART":
-		var name string
-		if err := parseMessageParams(msg, &name); err != nil {
-			return err
-		}
-
-		ch, err := dc.user.getChannel(name)
+		uc, upstreamName, err := dc.unmarshalChannel(name)
 		if err != nil {
-			return err
-		}
-
-		ch.conn.SendMessage(msg)
-		// TODO: remove channel from upstream config
+			return ircError{&irc.Message{
+				Command: irc.ERR_NOSUCHCHANNEL,
+				Params:  []string{name, err.Error()},
+			}}
+		}
+
+		uc.SendMessage(&irc.Message{
+			Command: msg.Command,
+			Params:  []string{upstreamName},
+		})
+		// TODO: add/remove channel from upstream config
 	case "MODE":
+		if msg.Prefix == nil {
+			return fmt.Errorf("missing prefix")
+		}
+
 		var name string
 		if err := parseMessageParams(msg, &name); err != nil {
@@ -379,5 +415,5 @@
 
 		if msg.Prefix.Name != name {
-			ch, err := dc.user.getChannel(name)
+			uc, upstreamName, err := dc.unmarshalChannel(name)
 			if err != nil {
 				return err
@@ -385,10 +421,22 @@
 
 			if modeStr != "" {
-				ch.conn.SendMessage(msg)
+				uc.SendMessage(&irc.Message{
+					Prefix:  uc.prefix(),
+					Command: "MODE",
+					Params:  []string{upstreamName, modeStr},
+				})
 			} else {
+				ch, ok := uc.channels[upstreamName]
+				if !ok {
+					return ircError{&irc.Message{
+						Command: irc.ERR_NOSUCHCHANNEL,
+						Params:  []string{name, "No such channel"},
+					}}
+				}
+
 				dc.SendMessage(&irc.Message{
 					Prefix:  dc.srv.prefix(),
 					Command: irc.RPL_CHANNELMODEIS,
-					Params:  []string{ch.Name, string(ch.modes)},
+					Params:  []string{name, string(ch.modes)},
 				})
 			}
@@ -403,5 +451,9 @@
 			if modeStr != "" {
 				dc.user.forEachUpstream(func(uc *upstreamConn) {
-					uc.SendMessage(msg)
+					uc.SendMessage(&irc.Message{
+						Prefix:  uc.prefix(),
+						Command: "MODE",
+						Params:  []string{uc.nick, modeStr},
+					})
 				})
 			} else {
@@ -420,13 +472,13 @@
 
 		for _, name := range strings.Split(targetsStr, ",") {
-			ch, err := dc.user.getChannel(name)
+			uc, upstreamName, err := dc.unmarshalChannel(name)
 			if err != nil {
 				return err
 			}
 
-			ch.conn.SendMessage(&irc.Message{
-				Prefix:  msg.Prefix,
+			uc.SendMessage(&irc.Message{
+				Prefix:  uc.prefix(),
 				Command: "PRIVMSG",
-				Params:  []string{name, text},
+				Params:  []string{upstreamName, text},
 			})
 		}
Index: /trunk/upstream.go
===================================================================
--- /trunk/upstream.go	(revision 68)
+++ /trunk/upstream.go	(revision 69)
@@ -92,4 +92,12 @@
 }
 
+func (uc *upstreamConn) prefix() *irc.Prefix {
+	return &irc.Prefix{
+		Name: uc.nick,
+		User: uc.upstream.Username,
+		// TODO: fill the host?
+	}
+}
+
 func (uc *upstreamConn) Close() error {
 	if uc.closed {
@@ -118,4 +126,8 @@
 		return nil
 	case "MODE":
+		if msg.Prefix == nil {
+			return fmt.Errorf("missing prefix")
+		}
+
 		var name, modeStr string
 		if err := parseMessageParams(msg, &name, &modeStr); err != nil {
@@ -136,9 +148,13 @@
 				return err
 			}
-		}
-
-		uc.user.forEachDownstream(func(dc *downstreamConn) {
-			dc.SendMessage(msg)
-		})
+
+			uc.user.forEachDownstream(func(dc *downstreamConn) {
+				dc.SendMessage(&irc.Message{
+					Prefix:  dc.marshalUserPrefix(uc, msg.Prefix),
+					Command: "MODE",
+					Params:  []string{dc.marshalChannel(uc, name), modeStr},
+				})
+			})
+		}
 	case "NOTICE":
 		uc.logger.Print(msg)
@@ -177,9 +193,9 @@
 			}
 		}
-
-		uc.user.forEachDownstream(func(dc *downstreamConn) {
-			dc.SendMessage(msg)
-		})
 	case "JOIN":
+		if msg.Prefix == nil {
+			return fmt.Errorf("expected a prefix")
+		}
+
 		var channels string
 		if err := parseMessageParams(msg, &channels); err != nil {
@@ -202,10 +218,18 @@
 				ch.Members[msg.Prefix.Name] = 0
 			}
-		}
-
-		uc.user.forEachDownstream(func(dc *downstreamConn) {
-			dc.SendMessage(msg)
-		})
+
+			uc.user.forEachDownstream(func(dc *downstreamConn) {
+				dc.SendMessage(&irc.Message{
+					Prefix:  dc.marshalUserPrefix(uc, msg.Prefix),
+					Command: "JOIN",
+					Params:  []string{dc.marshalChannel(uc, ch)},
+				})
+			})
+		}
 	case "PART":
+		if msg.Prefix == nil {
+			return fmt.Errorf("expected a prefix")
+		}
+
 		var channels string
 		if err := parseMessageParams(msg, &channels); err != nil {
@@ -224,9 +248,13 @@
 				delete(ch.Members, msg.Prefix.Name)
 			}
-		}
-
-		uc.user.forEachDownstream(func(dc *downstreamConn) {
-			dc.SendMessage(msg)
-		})
+
+			uc.user.forEachDownstream(func(dc *downstreamConn) {
+				dc.SendMessage(&irc.Message{
+					Prefix:  dc.marshalUserPrefix(uc, msg.Prefix),
+					Command: "PART",
+					Params:  []string{dc.marshalChannel(uc, ch)},
+				})
+			})
+		}
 	case irc.RPL_TOPIC, irc.RPL_NOTOPIC:
 		var name, topic string
@@ -311,4 +339,7 @@
 		})
 	case "PRIVMSG":
+		if err := parseMessageParams(msg, nil, nil); err != nil {
+			return err
+		}
 		uc.ring.Produce(msg)
 	case irc.RPL_YOURHOST, irc.RPL_CREATED:
@@ -332,5 +363,5 @@
 	uc.SendMessage(&irc.Message{
 		Command: "NICK",
-		Params:  []string{uc.upstream.Nick},
+		Params:  []string{uc.nick},
 	})
 	uc.SendMessage(&irc.Message{
