diff --git a/client/commands.go b/client/commands.go
index 0f58109..594cb5b 100644
--- a/client/commands.go
+++ b/client/commands.go
@@ -6,6 +6,28 @@ const (
 	INIT         = "init"
 	CONNECTED    = "connected"
 	DISCONNECTED = "disconnected"
+	ACTION       = "ACTION"
+	AWAY         = "AWAY"
+	CTCP         = "CTCP"
+	CTCPREPLY    = "CTCPREPLY"
+	INVITE       = "INVITE"
+	JOIN         = "JOIN"
+	KICK         = "KICK"
+	MODE         = "MODE"
+	NICK         = "NICK"
+	NOTICE       = "NOTICE"
+	OPER         = "OPER"
+	PART         = "PART"
+	PASS         = "PASS"
+	PING         = "PING"
+	PONG         = "PONG"
+	PRIVMSG      = "PRIVMSG"
+	QUIT         = "QUIT"
+	TOPIC        = "TOPIC"
+	USER         = "USER"
+	VERSION      = "VERSION"
+	WHO          = "WHO"
+	WHOIS        = "WHOIS"
 )
 
 // this file contains the various commands you can
@@ -20,18 +42,18 @@ const (
 func (conn *Conn) Raw(rawline string) { conn.out <- rawline }
 
 // Pass() sends a PASS command to the server
-func (conn *Conn) Pass(password string) { conn.out <- "PASS " + password }
+func (conn *Conn) Pass(password string) { conn.out <- PASS + " " + password }
 
 // Nick() sends a NICK command to the server
-func (conn *Conn) Nick(nick string) { conn.out <- "NICK " + nick }
+func (conn *Conn) Nick(nick string) { conn.out <- NICK + " " + nick }
 
 // User() sends a USER command to the server
 func (conn *Conn) User(ident, name string) {
-	conn.out <- "USER " + ident + " 12 * :" + name
+	conn.out <- USER + " " + ident + " 12 * :" + name
 }
 
 // Join() sends a JOIN command to the server
-func (conn *Conn) Join(channel string) { conn.out <- "JOIN " + channel }
+func (conn *Conn) Join(channel string) { conn.out <- JOIN + " " + channel }
 
 // Part() sends a PART command to the server with an optional part message
 func (conn *Conn) Part(channel string, message ...string) {
@@ -39,7 +61,7 @@ func (conn *Conn) Part(channel string, message ...string) {
 	if msg != "" {
 		msg = " :" + msg
 	}
-	conn.out <- "PART " + channel + msg
+	conn.out <- PART + " " + channel + msg
 }
 
 // Kick() sends a KICK command to remove a nick from a channel
@@ -48,7 +70,7 @@ func (conn *Conn) Kick(channel, nick string, message ...string) {
 	if msg != "" {
 		msg = " :" + msg
 	}
-	conn.out <- "KICK " + channel + " " + nick + msg
+	conn.out <- KICK + " " + channel + " " + nick + msg
 }
 
 // Quit() sends a QUIT command to the server with an optional quit message
@@ -57,20 +79,20 @@ func (conn *Conn) Quit(message ...string) {
 	if msg == "" {
 		msg = "GoBye!"
 	}
-	conn.out <- "QUIT :" + msg
+	conn.out <- QUIT + " :" + msg
 }
 
 // Whois() sends a WHOIS command to the server
-func (conn *Conn) Whois(nick string) { conn.out <- "WHOIS " + nick }
+func (conn *Conn) Whois(nick string) { conn.out <- WHOIS + " " + nick }
 
 //Who() sends a WHO command to the server
-func (conn *Conn) Who(nick string) { conn.out <- "WHO " + nick }
+func (conn *Conn) Who(nick string) { conn.out <- WHO + " " + nick }
 
 // Privmsg() sends a PRIVMSG to the target t
-func (conn *Conn) Privmsg(t, msg string) { conn.out <- "PRIVMSG " + t + " :" + msg }
+func (conn *Conn) Privmsg(t, msg string) { conn.out <- PRIVMSG + " " + t + " :" + msg }
 
 // Notice() sends a NOTICE to the target t
-func (conn *Conn) Notice(t, msg string) { conn.out <- "NOTICE " + t + " :" + msg }
+func (conn *Conn) Notice(t, msg string) { conn.out <- NOTICE + " " + t + " :" + msg }
 
 // Ctcp() sends a (generic) CTCP message to the target t
 // with an optional argument
@@ -93,10 +115,10 @@ func (conn *Conn) CtcpReply(t, ctcp string, arg ...string) {
 }
 
 // Version() sends a CTCP "VERSION" to the target t
-func (conn *Conn) Version(t string) { conn.Ctcp(t, "VERSION") }
+func (conn *Conn) Version(t string) { conn.Ctcp(t, VERSION) }
 
 // Action() sends a CTCP "ACTION" to the target t
-func (conn *Conn) Action(t, msg string) { conn.Ctcp(t, "ACTION", msg) }
+func (conn *Conn) Action(t, msg string) { conn.Ctcp(t, ACTION, msg) }
 
 // Topic() sends a TOPIC command to the channel
 //   Topic(channel) retrieves the current channel topic (see "332" handler)
@@ -106,7 +128,7 @@ func (conn *Conn) Topic(channel string, topic ...string) {
 	if t != "" {
 		t = " :" + t
 	}
-	conn.out <- "TOPIC " + channel + t
+	conn.out <- TOPIC + " " + channel + t
 }
 
 // Mode() sends a MODE command to the server. This one can get complicated if
@@ -121,7 +143,7 @@ func (conn *Conn) Mode(t string, modestring ...string) {
 	if mode != "" {
 		mode = " " + mode
 	}
-	conn.out <- "MODE " + t + mode
+	conn.out <- MODE + " " + t + mode
 }
 
 // Away() sends an AWAY command to the server
@@ -132,15 +154,18 @@ func (conn *Conn) Away(message ...string) {
 	if msg != "" {
 		msg = " :" + msg
 	}
-	conn.out <- "AWAY" + msg
+	conn.out <- AWAY + msg
 }
 
 // Invite() sends an INVITE command to the server
-func (conn *Conn) Invite(nick, channel string) {
-	conn.out <- "INVITE " + nick + " " + channel
-}
+func (conn *Conn) Invite(nick, channel string) { conn.out <- INVITE + " " + nick + " " + channel }
 
 // Oper() sends an OPER command to the server
-func (conn *Conn) Oper(user, pass string) {
-	conn.out <- "OPER " + user + " " + pass
-}
+func (conn *Conn) Oper(user, pass string) { conn.out <- OPER + " " + user + " " + pass }
+
+// Ping() sends a PING command to the server
+// A PONG response is to be expected afterwards
+func (conn *Conn) Ping(message string) { conn.out <- PING + " :" + message }
+
+// Ping() sends a PONG command to the server
+func (conn *Conn) Pong(message string) { conn.out <- PONG + " :" + message }
diff --git a/client/commands_test.go b/client/commands_test.go
index c3bb6ee..05650e3 100644
--- a/client/commands_test.go
+++ b/client/commands_test.go
@@ -75,4 +75,10 @@ func TestClientCommands(t *testing.T) {
 
 	c.Oper("user", "pass")
 	s.nc.Expect("OPER user pass")
+
+	c.Ping("woot")
+	s.nc.Expect("PING :woot")
+
+	c.Pong("pwoot")
+	s.nc.Expect("PONG :pwoot")
 }
diff --git a/client/connection.go b/client/connection.go
index f66f3c5..e1128a2 100644
--- a/client/connection.go
+++ b/client/connection.go
@@ -236,7 +236,7 @@ func (conn *Conn) ping() {
 	for {
 		select {
 		case <-tick.C:
-			conn.Raw(fmt.Sprintf("PING :%d", time.Now().UnixNano()))
+			conn.Ping(fmt.Sprintf("%d", time.Now().UnixNano()))
 		case <-conn.cPing:
 			tick.Stop()
 			return
diff --git a/client/handlers.go b/client/handlers.go
index 9e1c41b..5d017be 100644
--- a/client/handlers.go
+++ b/client/handlers.go
@@ -9,12 +9,12 @@ import (
 
 // sets up the internal event handlers to do essential IRC protocol things
 var intHandlers = map[string]HandlerFunc{
-	INIT:   (*Conn).h_init,
-	"001":  (*Conn).h_001,
-	"433":  (*Conn).h_433,
-	"CTCP": (*Conn).h_CTCP,
-	"NICK": (*Conn).h_NICK,
-	"PING": (*Conn).h_PING,
+	INIT:  (*Conn).h_init,
+	"001": (*Conn).h_001,
+	"433": (*Conn).h_433,
+	CTCP:  (*Conn).h_CTCP,
+	NICK:  (*Conn).h_NICK,
+	PING:  (*Conn).h_PING,
 }
 
 func (conn *Conn) addIntHandlers() {
@@ -36,7 +36,7 @@ func (conn *Conn) h_init(line *Line) {
 
 // Basic ping/pong handler
 func (conn *Conn) h_PING(line *Line) {
-	conn.Raw("PONG :" + line.Args[0])
+	conn.Pong(line.Args[0])
 }
 
 // Handler to trigger a "CONNECTED" event on receipt of numeric 001
@@ -80,10 +80,10 @@ func (conn *Conn) h_433(line *Line) {
 
 // Handle VERSION requests and CTCP PING
 func (conn *Conn) h_CTCP(line *Line) {
-	if line.Args[0] == "VERSION" {
-		conn.CtcpReply(line.Nick, "VERSION", "powered by goirc...")
-	} else if line.Args[0] == "PING" {
-		conn.CtcpReply(line.Nick, "PING", line.Args[2])
+	if line.Args[0] == VERSION {
+		conn.CtcpReply(line.Nick, VERSION, "powered by goirc...")
+	} else if line.Args[0] == PING {
+		conn.CtcpReply(line.Nick, PING, line.Args[2])
 	}
 }
 
diff --git a/client/line.go b/client/line.go
index 706d373..b29a8fe 100644
--- a/client/line.go
+++ b/client/line.go
@@ -62,7 +62,7 @@ func parseLine(s string) *Line {
 	// So, I think CTCP and (in particular) CTCP ACTION are better handled as
 	// separate events as opposed to forcing people to have gargantuan
 	// handlers to cope with the possibilities.
-	if (line.Cmd == "PRIVMSG" || line.Cmd == "NOTICE") &&
+	if (line.Cmd == PRIVMSG || line.Cmd == NOTICE) &&
 		len(line.Args[1]) > 2 &&
 		strings.HasPrefix(line.Args[1], "\001") &&
 		strings.HasSuffix(line.Args[1], "\001") {
@@ -72,16 +72,16 @@ func parseLine(s string) *Line {
 			// Replace the line with the unwrapped CTCP
 			line.Args[1] = t[1]
 		}
-		if c := strings.ToUpper(t[0]); c == "ACTION" && line.Cmd == "PRIVMSG" {
+		if c := strings.ToUpper(t[0]); c == ACTION && line.Cmd == PRIVMSG {
 			// make a CTCP ACTION it's own event a-la PRIVMSG
 			line.Cmd = c
 		} else {
 			// otherwise, dispatch a generic CTCP/CTCPREPLY event that
 			// contains the type of CTCP in line.Args[0]
-			if line.Cmd == "PRIVMSG" {
-				line.Cmd = "CTCP"
+			if line.Cmd == PRIVMSG {
+				line.Cmd = CTCP
 			} else {
-				line.Cmd = "CTCPREPLY"
+				line.Cmd = CTCPREPLY
 			}
 			line.Args = append([]string{c}, line.Args...)
 		}
diff --git a/client/state_handlers.go b/client/state_handlers.go
index ffc9211..380f760 100644
--- a/client/state_handlers.go
+++ b/client/state_handlers.go
@@ -9,19 +9,19 @@ import (
 )
 
 var stHandlers = map[string]HandlerFunc{
-	"JOIN":  (*Conn).h_JOIN,
-	"KICK":  (*Conn).h_KICK,
-	"MODE":  (*Conn).h_MODE,
-	"NICK":  (*Conn).h_STNICK,
-	"PART":  (*Conn).h_PART,
-	"QUIT":  (*Conn).h_QUIT,
-	"TOPIC": (*Conn).h_TOPIC,
-	"311":   (*Conn).h_311,
-	"324":   (*Conn).h_324,
-	"332":   (*Conn).h_332,
-	"352":   (*Conn).h_352,
-	"353":   (*Conn).h_353,
-	"671":   (*Conn).h_671,
+	JOIN:  (*Conn).h_JOIN,
+	KICK:  (*Conn).h_KICK,
+	MODE:  (*Conn).h_MODE,
+	NICK:  (*Conn).h_STNICK,
+	PART:  (*Conn).h_PART,
+	QUIT:  (*Conn).h_QUIT,
+	TOPIC: (*Conn).h_TOPIC,
+	"311": (*Conn).h_311,
+	"324": (*Conn).h_324,
+	"332": (*Conn).h_332,
+	"352": (*Conn).h_352,
+	"353": (*Conn).h_353,
+	"671": (*Conn).h_671,
 }
 
 func (conn *Conn) addSTHandlers() {