diff --git a/plugins/Gameknot.py b/plugins/Gameknot.py
index c023369b7..0f1d1323d 100644
--- a/plugins/Gameknot.py
+++ b/plugins/Gameknot.py
@@ -55,21 +55,14 @@ def configure(onStart, afterConnect, advanced):
 
 class Gameknot(callbacks.PrivmsgCommandAndRegexp):
     threaded = True
-    regexps = sets.Set(['gameknotSnarfer'])
+    regexps = sets.Set(['gameknotSnarfer', 'gameknotStatsSnarfer'])
     _gkrating = re.compile(r'(\d+)')
     _gkgames = re.compile(r's:  
(\d+)')
     _gkrecord = re.compile(r'"#FFFF00">(\d+)[^"]+"#FFFF00">(\d+)[^"]+'\
         '"#FFFF00">(\d+)')
     _gkteam = re.compile(r'Team:(<.*?>)+(?P.*?)')
     _gkseen = re.compile(r'(seen on GK:\s+([^[]+)\s+|.*?is hiding.*?)')
-    def gkstats(self, irc, msg, args):
-        """
-
-        Returns the stats Gameknot keeps on .  Gameknot is an online
-        website for playing chess (rather similar to correspondence chess, just
-        somewhat faster) against players from all over the world.
-        """
-        name = privmsgs.getArgs(args)
+    def getStats(self, name):
         gkprofile = 'http://www.gameknot.com/stats.pl?%s' % name
         try:
             fd = urllib2.urlopen(gkprofile)
@@ -92,20 +85,32 @@ class Gameknot(callbacks.PrivmsgCommandAndRegexp):
                 games = '%s active games' % games
             if 'Team:' in profile:
                 team = self._gkteam.search(profile).group('name')
-                irc.reply(msg, '%s (team: %s) is rated %s and has %s ' \
-                          'and a record of W-%s, L-%s, D-%s.  %s' % \
-                          (name, team, rating, games, w, l, d, seen))
+                s = '%s (team: %s) is rated %s and has %s ' \
+                    'and a record of W-%s, L-%s, D-%s.  %s' % \
+                    (name, team, rating, games, w, l, d, seen)
             else:
-                irc.reply(msg, '%s is rated %s and has %s ' \
-                          'and a record of W-%s, L-%s, D-%s.  %s' % \
-                          (name, rating, games, w, l, d, seen))
+                s = '%s is rated %s and has %s ' \
+                    'and a record of W-%s, L-%s, D-%s.  %s' % \
+                    (name, rating, games, w, l, d, seen)
+            return s
         except AttributeError:
             if ('User %s not found!' % name) in profile:
-                irc.error(msg, 'No user %s exists.' % name)
+                raise callbacks.Error, 'No user %s exists.' % name
             else:
-                irc.error(msg, 'The format of the page was odd.')
+                raise callbacks.Error, 'The format of the page was odd.'
         except urllib2.URLError:
-            irc.error(msg, 'Couldn\'t connect to gameknot.com.')
+            raise callbacks.Error, 'Couldn\'t connect to gameknot.com'
+        
+        
+    def gkstats(self, irc, msg, args):
+        """
+
+        Returns the stats Gameknot keeps on .  Gameknot is an online
+        website for playing chess (rather similar to correspondence chess, just
+        somewhat faster) against players from all over the world.
+        """
+        name = privmsgs.getArgs(args)
+        irc.reply(msg, self.getStats(name))
 
     _gkPlayer = re.compile(r"popd\('(Rating[^']+)'\).*?>([^<]+)<")
     _gkRating = re.compile(r": (\d+)[^:]+: | 
(\d+)[^,]+, (\d+)[^,]+, (\d+)")
@@ -140,6 +145,12 @@ class Gameknot(callbacks.PrivmsgCommandAndRegexp):
         except Exception, e:
             irc.error(msg, debug.exnToString(e))
 
+    def gameknotStatsSnarfer(self, irc, msg, match):
+        r"http://gameknot\.com/stats\.pl\?([^&]+)"
+        name = match.group(1)
+        s = self.getStats(name)
+        irc.queueMsg(ircmsgs.privmsg(msg.args[0], s))
+
 Class = Gameknot
 
 # vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
diff --git a/test/test_Gameknot.py b/test/test_Gameknot.py
new file mode 100644
index 000000000..5a31ab4ee
--- /dev/null
+++ b/test/test_Gameknot.py
@@ -0,0 +1,51 @@
+#!/usr/bin/env python
+
+###
+# Copyright (c) 2002, Jeremiah Fincher
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+#   * Redistributions of source code must retain the above copyright notice,
+#     this list of conditions, and the following disclaimer.
+#   * Redistributions in binary form must reproduce the above copyright notice,
+#     this list of conditions, and the following disclaimer in the
+#     documentation and/or other materials provided with the distribution.
+#   * Neither the name of the author of this software nor the name of
+#     contributors to this software may be used to endorse or promote products
+#     derived from this software without specific prior written consent.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+###
+
+from test import *
+
+class GameknotTestCase(PluginTestCase):
+    plugins = ('Gameknot',)
+    def testGkstats(self):
+        self.assertNotError('gkstats jemfinch')
+        self.assertError('gkstats %s' % mktemp())
+
+    def testUrlSnarfer(self):
+        self.assertNotError('http://gameknot.com/chess.pl?bd=1019508')
+
+    def testStatsUrlSnarfer(self):
+        self.assertNotError('http://gameknot.com/stats.pl?ironchefchess')
+        self.assertRegexp('http://gameknot.com/stats.pl?ddipaolo&1',
+                          r'^[^&]+$')
+
+
+
+# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
+