Index: /trunk/db.go
===================================================================
--- /trunk/db.go	(revision 145)
+++ /trunk/db.go	(revision 146)
@@ -36,4 +36,5 @@
 	ID   int64
 	Name string
+	Key  string
 }
 
@@ -194,5 +195,5 @@
 	defer db.lock.RUnlock()
 
-	rows, err := db.db.Query("SELECT id, name FROM Channel WHERE network = ?", networkID)
+	rows, err := db.db.Query("SELECT id, name, key FROM Channel WHERE network = ?", networkID)
 	if err != nil {
 		return nil, err
@@ -203,7 +204,9 @@
 	for rows.Next() {
 		var ch Channel
-		if err := rows.Scan(&ch.ID, &ch.Name); err != nil {
+		var key *string
+		if err := rows.Scan(&ch.ID, &ch.Name, &key); err != nil {
 			return nil, err
 		}
+		ch.Key = fromStringPtr(key)
 		channels = append(channels, ch)
 	}
@@ -219,5 +222,7 @@
 	defer db.lock.Unlock()
 
-	_, err := db.db.Exec("INSERT OR REPLACE INTO Channel(network, name) VALUES (?, ?)", networkID, ch.Name)
+	key := toStringPtr(ch.Key)
+	_, err := db.db.Exec(`INSERT OR REPLACE INTO Channel(network, name, key)
+		VALUES (?, ?, ?)`, networkID, ch.Name, key)
 	return err
 }
Index: /trunk/downstream.go
===================================================================
--- /trunk/downstream.go	(revision 145)
+++ /trunk/downstream.go	(revision 146)
@@ -833,11 +833,16 @@
 			uc.SendMessage(msg)
 		})
-	case "JOIN", "PART":
-		var names string
-		if err := parseMessageParams(msg, &names); err != nil {
-			return err
-		}
-
-		for _, name := range strings.Split(names, ",") {
+	case "JOIN":
+		var namesStr string
+		if err := parseMessageParams(msg, &namesStr); err != nil {
+			return err
+		}
+
+		var keys []string
+		if len(msg.Params) > 1 {
+			keys = strings.Split(msg.Params[1], ",")
+		}
+
+		for i, name := range strings.Split(namesStr, ",") {
 			uc, upstreamName, err := dc.unmarshalEntity(name)
 			if err != nil {
@@ -848,21 +853,57 @@
 			}
 
+			var key string
+			if len(keys) > i {
+				key = keys[i]
+			}
+
+			params := []string{upstreamName}
+			if key != "" {
+				params = append(params, key)
+			}
 			uc.SendMessage(&irc.Message{
-				Command: msg.Command,
-				Params:  []string{upstreamName},
-			})
-
-			switch msg.Command {
-			case "JOIN":
-				err := dc.srv.db.StoreChannel(uc.network.ID, &Channel{
-					Name: upstreamName,
-				})
-				if err != nil {
-					dc.logger.Printf("failed to create channel %q in DB: %v", upstreamName, err)
-				}
-			case "PART":
-				if err := dc.srv.db.DeleteChannel(uc.network.ID, upstreamName); err != nil {
-					dc.logger.Printf("failed to delete channel %q in DB: %v", upstreamName, err)
-				}
+				Command: "JOIN",
+				Params:  params,
+			})
+
+			err = dc.srv.db.StoreChannel(uc.network.ID, &Channel{
+				Name: upstreamName,
+				Key:  key,
+			})
+			if err != nil {
+				dc.logger.Printf("failed to create channel %q in DB: %v", upstreamName, err)
+			}
+		}
+	case "PART":
+		var namesStr string
+		if err := parseMessageParams(msg, &namesStr); err != nil {
+			return err
+		}
+
+		var reason string
+		if len(msg.Params) > 1 {
+			reason = msg.Params[1]
+		}
+
+		for _, name := range strings.Split(namesStr, ",") {
+			uc, upstreamName, err := dc.unmarshalEntity(name)
+			if err != nil {
+				return ircError{&irc.Message{
+					Command: irc.ERR_NOSUCHCHANNEL,
+					Params:  []string{name, err.Error()},
+				}}
+			}
+
+			params := []string{upstreamName}
+			if reason != "" {
+				params = append(params, reason)
+			}
+			uc.SendMessage(&irc.Message{
+				Command: "PART",
+				Params:  params,
+			})
+
+			if err := dc.srv.db.DeleteChannel(uc.network.ID, upstreamName); err != nil {
+				dc.logger.Printf("failed to delete channel %q in DB: %v", upstreamName, err)
 			}
 		}
Index: /trunk/upstream.go
===================================================================
--- /trunk/upstream.go	(revision 145)
+++ /trunk/upstream.go	(revision 146)
@@ -318,7 +318,11 @@
 
 		for _, ch := range channels {
+			params := []string{ch.Name}
+			if ch.Key != "" {
+				params = append(params, ch.Key)
+			}
 			uc.SendMessage(&irc.Message{
 				Command: "JOIN",
-				Params:  []string{ch.Name},
+				Params:  params,
 			})
 		}
