diff --git a/dispatcher.go b/dispatcher.go
index fbf977e1fd8eceb97688ec30a9770d3351cb6971..efed8b78d4f9437370b7ce613e31ba0f78ec335b 100644
--- a/dispatcher.go
+++ b/dispatcher.go
@@ -3,15 +3,3 @@ package jc
 type Dispatcher interface {
 	Run()
 }
-
-type Links []Link
-
-type Link struct {
-	endpoints []Endpoint
-	filters   []string
-}
-
-type Endpoint struct {
-	Channel   string
-	Transport string
-}
diff --git a/dispatcher/dispatcher.go b/dispatcher/dispatcher.go
index 56ecdb646293b6de3bc5acb1c5693704da51e4fb..37c883c5957c72318e87bb3d369de0645501ef1d 100644
--- a/dispatcher/dispatcher.go
+++ b/dispatcher/dispatcher.go
@@ -79,6 +79,14 @@ func (d *Dispatcher) Run() {
 			d.join(name, ev)
 		case *jc.MessageEvent:
 			d.message(name, ev)
+		case *jc.NickEvent:
+			d.nick(name, ev)
+		case *jc.PrivMessageEvent:
+			d.privMessage(name, ev)
+		case *jc.PartEvent:
+			d.part(name, ev)
+		case *jc.QuitEvent:
+			d.quit(name, ev)
 		}
 	}
 }
@@ -115,6 +123,38 @@ func (d *Dispatcher) findLink(transport string, channels ...string) []Link {
 	return links
 }
 
+func (d *Dispatcher) findTransports(transport string, nick string, channels ...string) []Endpoint {
+	var endpoints []Endpoint
+	var links []Link
+	var channel string
+
+	if len(channels) == 0 {
+		channel = ""
+		links = d.findLink(transport)
+	} else {
+		channel = channels[0]
+		links = d.findLink(transport, channel)
+	}
+
+	for _, link := range links {
+		if isFiltered(link.filters, nick) {
+			continue
+		}
+
+		for _, endpoint := range link.endpoints {
+			if channel == "" && endpoint.transport == transport {
+				continue
+			} else if channel != "" && endpoint.transport == transport && endpoint.channel == channel {
+				continue
+			}
+
+			endpoints = append(endpoints, endpoint)
+		}
+	}
+
+	return endpoints
+}
+
 func isFiltered(filters []string, nick string) bool {
 	for _, v := range filters {
 		if v == nick {
diff --git a/dispatcher/events.go b/dispatcher/events.go
index 7c2908bcd4a456a42b80aaae8bf5cc6dd5c77558..6da078f12dd5c8ad6dc09868d357b8cfa4c8eecf 100644
--- a/dispatcher/events.go
+++ b/dispatcher/events.go
@@ -9,44 +9,72 @@ import (
 func (d *Dispatcher) join(transport string, ev *jc.JoinEvent) {
 	log.Printf("Receive JoinEvent from %s: %s on %s", transport, ev.Nick, ev.Channel)
 
-	links := d.findLink(transport, ev.Channel)
-	for _, link := range links {
-		if isFiltered(link.filters, ev.Nick) {
-			continue
-		}
-
-		for _, endpoint := range link.endpoints {
-			if endpoint.transport == transport && endpoint.channel == ev.Channel {
-				continue
-			}
-
-			d.transports[endpoint.transport].Join(&jc.JoinEvent{
-				Nick:    ev.Nick + "_jc",
-				Channel: endpoint.channel,
-			})
-		}
+	endpoints := d.findTransports(transport, ev.Nick, ev.Channel)
+	for _, endpoint := range endpoints {
+		d.transports[endpoint.transport].Join(&jc.JoinEvent{
+			Nick:    ev.Nick,
+			Channel: endpoint.channel,
+		})
 	}
 }
 
 func (d *Dispatcher) message(transport string, ev *jc.MessageEvent) {
 	log.Printf("Receive MessageEvent from %s: %s on %s", transport, ev.Nick, ev.Channel)
 
-	links := d.findLink(transport, ev.Channel)
-	for _, link := range links {
-		if isFiltered(link.filters, ev.Nick) {
-			continue
-		}
-
-		for _, endpoint := range link.endpoints {
-			if endpoint.transport == transport && endpoint.channel == ev.Channel {
-				continue
-			}
-
-			d.transports[endpoint.transport].Message(&jc.MessageEvent{
-				Nick:    ev.Nick + "_jc",
-				Channel: endpoint.channel,
-				Text:    ev.Text,
-			})
-		}
+	endpoints := d.findTransports(transport, ev.Nick, ev.Channel)
+	for _, endpoint := range endpoints {
+		d.transports[endpoint.transport].Message(&jc.MessageEvent{
+			Nick:    ev.Nick,
+			Channel: endpoint.channel,
+			Text:    ev.Text,
+		})
+	}
+}
+
+func (d *Dispatcher) nick(transport string, ev *jc.NickEvent) {
+	log.Printf("Receive NickEvent from %s : %s to %s", transport, ev.OldNick, ev.NewNick)
+
+	endpoints := d.findTransports(transport, ev.OldNick)
+	for _, endpoint := range endpoints {
+		d.transports[endpoint.transport].Nick(&jc.NickEvent{
+			OldNick: ev.OldNick,
+			NewNick: ev.NewNick,
+		})
+	}
+}
+
+func (d *Dispatcher) privMessage(transport string, ev *jc.PrivMessageEvent) {
+	log.Printf("Receive PrivMessageEvent from %s: %s on %s", transport, ev.Nick, ev.Channel)
+
+	endpoints := d.findTransports(transport, ev.Nick, ev.Channel)
+	for _, endpoint := range endpoints {
+		d.transports[endpoint.transport].PrivMessage(&jc.PrivMessageEvent{
+			Nick:    ev.Nick,
+			Channel: endpoint.channel,
+			Text:    ev.Text,
+		})
+	}
+}
+
+func (d *Dispatcher) part(transport string, ev *jc.PartEvent) {
+	log.Printf("Receive PartEvent from %s: %s on %s", transport, ev.Nick, ev.Channel)
+
+	endpoints := d.findTransports(transport, ev.Nick, ev.Channel)
+	for _, endpoint := range endpoints {
+		d.transports[endpoint.transport].Part(&jc.PartEvent{
+			Nick:    ev.Nick,
+			Channel: endpoint.channel,
+		})
+	}
+}
+
+func (d *Dispatcher) quit(transport string, ev *jc.QuitEvent) {
+	log.Printf("Receive QuitEvent from %s: %s", transport, ev.Nick)
+
+	endpoints := d.findTransports(transport, ev.Nick)
+	for _, endpoint := range endpoints {
+		d.transports[endpoint.transport].Quit(&jc.QuitEvent{
+			Nick: ev.Nick,
+		})
 	}
 }
diff --git a/irc/events.go b/irc/events.go
index b1f916b0575ba0da02d364c1cbd3936766b8d752..5d31aa9bd9390b786e4711f79f497aea4efb1818 100644
--- a/irc/events.go
+++ b/irc/events.go
@@ -42,7 +42,7 @@ func (t *Transport) connected(client *irc.Conn, line *irc.Line) {
 func (t *Transport) disconnected(client *irc.Conn, line *irc.Line) {
 	if t.client != client {
 		// all should already have been cleaned
-		log.Print("%s got disconnected", client.Me().Nick)
+		log.Printf("%s got disconnected", client.Me().Nick)
 		return
 	}
 
diff --git a/irc/transport.go b/irc/transport.go
index e44a8344fbc3a50e64c428f8d44b0140e130e97f..8efde314f75c9b4559a853b7abf7898cc02ea409 100644
--- a/irc/transport.go
+++ b/irc/transport.go
@@ -118,7 +118,7 @@ func (t *Transport) newNick(nick string) string {
 		delete(t.realNicks, nick)
 	}
 
-	newNick := nick + "_"
+	newNick := nick + "^"
 	t.realNicks[newNick] = realNick
 	return newNick
 }