diff --git a/game/engines/default/engine/PlayerProfile.lua b/game/engines/default/engine/PlayerProfile.lua
index 76f91b3e29e608461b8e5217208e847f30325db0..05b2d057e70f93ad88ded25a36d73fbba0021f6a 100644
--- a/game/engines/default/engine/PlayerProfile.lua
+++ b/game/engines/default/engine/PlayerProfile.lua
@@ -551,6 +551,7 @@ function _M:currentCharacter(module, title, uuid)
 	if not self.auth then return end
 	core.profile.pushOrder(table.serialize{o="CurrentCharacter",
 		module=module,
+		mod_short=(game and type(game)=="table") and game.__mod_info.short_name or "unknown",
 		title=title,
 		valid=self.hash_valid,
 		uuid=uuid,
diff --git a/game/engines/default/engine/UserChat.lua b/game/engines/default/engine/UserChat.lua
index 05f62c4b278ae65c34cc42a1ea35cf4ab927c498..c903371426edbfa778cfb89104752051df2e1bb4 100644
--- a/game/engines/default/engine/UserChat.lua
+++ b/game/engines/default/engine/UserChat.lua
@@ -21,6 +21,7 @@ require "engine.class"
 require "engine.ui.Base"
 local KeyBind = require "engine.KeyBind"
 local Mouse = require "engine.Mouse"
+local Dialog = require "engine.ui.Dialog"
 local Slider = require "engine.ui.Slider"
 
 --- Module that handles multiplayer chats
@@ -79,6 +80,7 @@ function _M:event(e)
 		if type(game) == "table" and game.logNoNotify and e.channel == self.cur_channel then
 			game.logNoNotify("#{italic}##FIREBRICK#%s has joined channel %s (press space to talk).#{normal}#", e.login, e.channel)
 		end
+		self:updateChanList()
 	elseif e.se == "Part" then
 		self.channels[e.channel] = self.channels[e.channel] or {users={}, log={}}
 		self.channels[e.channel].users[e.login] = nil
@@ -87,6 +89,7 @@ function _M:event(e)
 		if type(game) == "table" and game.logNoNotify and e.channel == self.cur_channel then
 			game.logNoNotify("#{italic}##FIREBRICK#%s has left channel %s.#{normal}#", e.login, e.channel)
 		end
+		self:updateChanList()
 	elseif e.se == "UserInfo" then
 		local info = e.data:unserialize()
 		if not info then return end
@@ -101,6 +104,8 @@ function _M:event(e)
 				cur_char=user.cur_char and user.cur_char.title or "unknown",
 				module=user.cur_char and user.cur_char.module or "unknown",
 				valid=user.cur_char and user.cur_char.valid and "validate" or "not validated",
+				char_link=user.cur_char and user.char_link,
+				profile=user.cur_char and user.profile,
 			}
 		end
 		self.channels_changed = true
@@ -132,17 +137,12 @@ function _M:talk(msg)
 	core.profile.pushOrder(string.format("o='ChatTalk' channel=%q msg=%q", self.cur_channel, msg))
 end
 
-function _M:getUserInfo(user)
-	if not profile.auth then return end
-	if not user then return end
-	core.profile.pushOrder(string.format("o='ChatUserInfo' user=%q", user))
-end
-
 --- Request a line to send
 -- TODO: make it better than a simple dialog
 function _M:talkBox()
 	if not profile.auth then return end
-	local d = require("engine.dialogs.GetText").new("Talk", self.cur_channel, 0, 250, function(text)
+	local GetText = require "engine.dialogs.GetText"
+	local d = GetText.new("Talk", self.cur_channel, 0, 250, function(text)
 		self:talk(text)
 	end)
 	d.key:addBind("EXIT", function() game:unregisterDialog(d) end)
@@ -153,13 +153,36 @@ function _M:talkBox()
 end
 
 function _M:updateChanList(force)
-	local time = core.game.getTime()
-	if force or not self.last_chan_update or self.last_chan_update + 60000 < time then
+	local time = os.time()
+	if force or not self.last_chan_update or self.last_chan_update + 60 < time then
 		self.last_chan_update = time
 		core.profile.pushOrder(string.format("o='ChatChannelList' channel=%q", self.cur_channel))
 	end
 end
 
+--- Display user infos
+function _M:showUserInfo(login)
+	if not profile.auth then return end
+
+	local popup = Dialog:simplePopup("Requesting...", "Requesting user info...", nil, true)
+	popup.__showup = nil
+	core.display.forceRedraw()
+
+	core.profile.pushOrder(string.format("o='ChatUserInfo' login=%q", login))
+	local data = nil
+	profile:waitEvent("UserInfo", function(e) data=e.data end)
+	game:unregisterDialog(popup)
+
+	if not data then
+		Dialog:simplePopup("Error", "The server does not know about this player.")
+		return
+	end
+	data = zlib.decompress(data):unserialize()
+
+	local UserInfo = require "engine.dialogs.UserInfo"
+	game:registerDialog(UserInfo.new(data))
+end
+
 ----------------------------------------------------------------
 -- UI Section
 ----------------------------------------------------------------
@@ -212,7 +235,7 @@ function _M:resize(x, y, w, h, fontname, fontsize, color, bgcolor)
 			end
 			if last_ok then self:selectChannel(last_ok.name) end
 		else
-			if not self.on_mouse then return end
+			if not self.on_mouse or not self.dlist then return end
 			local citem = nil
 			for i = 1, #self.dlist do
 				local item = self.dlist[i]
diff --git a/game/engines/default/engine/dialogs/UserInfo.lua b/game/engines/default/engine/dialogs/UserInfo.lua
new file mode 100644
index 0000000000000000000000000000000000000000..43610f3fd07882838145850678d2b12716099574
--- /dev/null
+++ b/game/engines/default/engine/dialogs/UserInfo.lua
@@ -0,0 +1,61 @@
+-- TE4 - T-Engine 4
+-- Copyright (C) 2009, 2010 Nicolas Casalini
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program.  If not, see <http://www.gnu.org/licenses/>.
+--
+-- Nicolas Casalini "DarkGod"
+-- darkgod@te4.org
+
+require "engine.class"
+local Dialog = require "engine.ui.Dialog"
+local Button = require "engine.ui.Button"
+local Textzone = require "engine.ui.Textzone"
+
+module(..., package.seeall, class.inherit(Dialog))
+
+function _M:init(data)
+	Dialog.init(self, "User: "..data.name, 1,1)
+
+	data.current_char = data.current_char or {}
+
+	local str = tstring{{"color","GOLD"}, {"font","bold"}, data.name, {"color","LAST"}, {"font","normal"}, true, true}
+	str:add({"color","ANTIQUE_WHITE"}, "Currently playing: ", {"color", "LAST"})
+	if data.char_link then
+		str:add({"font","italic"},{"color","LIGHT_BLUE"},data.current_char.title or "unknown",{"font","normal"},{"color","LAST"},true)
+	else
+		str:add(data.current_char or "unknown",true)
+	end
+	str:add({"color","ANTIQUE_WHITE"}, "Game: ", {"color", "LAST"}, data.current_char.module or "unknown", true)
+	str:add({"color","ANTIQUE_WHITE"}, "Validation: ", {"color", "LAST"}, data.current_char.valid and "Game has been validated by the server" or "Game is not validated by the server", true)
+
+	self.c_desc = Textzone.new{width=400, height=1, auto_height=true, text=str}
+	local b_profile = require("engine.ui.Button").new{text="Go to online profile", fct=function() util.browserOpenUrl(data.profile) end}
+	local b_char = require("engine.ui.Button").new{text="Go to online charsheet", fct=function() util.browserOpenUrl(data.char_link) end}
+
+	local ui = {
+		{left=0, top=0, ui=self.c_desc},
+		{left=0, bottom=0, ui=b_profile},
+	}
+	if data.char_link then ui[#ui+1] = {right=0, bottom=0, ui=b_char} end
+	self:loadUI(ui)
+	self:setupUI(not rw, not rh)
+
+	self.key:addBinds{
+		ACCEPT = accept_key and "EXIT",
+		EXIT = function()
+			game:unregisterDialog(self)
+			if on_exit then on_exit() end
+		end,
+	}
+end
diff --git a/game/modules/tome/class/Game.lua b/game/modules/tome/class/Game.lua
index d1d086b429f955a80039470b7d11430ceac3158c..79ee7658030ae70990fa89ce25eb2efd438ca7b8 100644
--- a/game/modules/tome/class/Game.lua
+++ b/game/modules/tome/class/Game.lua
@@ -1155,11 +1155,17 @@ function _M:setupMouse(reset)
 	end)
 	-- Chat tooltips
 	profile.chat:onMouse(function(user, button, event)
-		self.tooltip:displayAtMap(nil, nil, self.w, self.h, tstring{
-			{"color","GOLD"}, {"font","bold"}, user.name, {"color","LAST"}, {"font","normal"}, true,
-			{"color","ANTIQUE_WHITE"}, "Playing: ", {"color", "LAST"}, user.cur_char,true,
-			{"color","ANTIQUE_WHITE"}, "Game: ", {"color", "LAST"}, user.module, "(", user.valid, ")",true,
-		})
+		local str = tstring{{"color","GOLD"}, {"font","bold"}, user.name, {"color","LAST"}, {"font","normal"}, true}
+		str:add({"color","ANTIQUE_WHITE"}, "Playing: ", {"color", "LAST"}, user.current_char,true)
+		if user.char_link then
+			str:add({"font","italic"},{"color","LIGHT_BLUE"},user.char_link,{"font","normal"},{"color","LAST"},true)
+		end
+		str:add({"color","ANTIQUE_WHITE"}, "Game: ", {"color", "LAST"}, user.module, "(", user.valid, ")",true)
+		self.tooltip:displayAtMap(nil, nil, self.w, self.h, str)
+
+		if button == "left" and event == "button" then
+			profile.chat:showUserInfo(user.login)
+		end
 	end)
 	if not reset then self.mouse:setCurrent() end
 end
diff --git a/game/profile-thread/Client.lua b/game/profile-thread/Client.lua
index 96ced480faf6e8a3c6e409ebab163a9591df0c09..1669de5bf007554280662d8fe350a20c0ab86969 100644
--- a/game/profile-thread/Client.lua
+++ b/game/profile-thread/Client.lua
@@ -336,13 +336,15 @@ function _M:orderChatPart(o)
 end
 
 function _M:orderChatUserInfo(o)
-	self:command("UINF", o.user)
+	self:command("UINF", o.login)
 	if self:read("200") then
 		local _, _, size = self.last_line:find("^([0-9]+)")
 		size = tonumber(size)
 		if not size or size < 1 then return end
 		local body = self:receive(size)
-		cprofile.pushEvent(string.format("e='Chat' se='UserInfo' user=%q data=%q", o.user, body))
+		cprofile.pushEvent(string.format("e='UserInfo' login=%q data=%q", o.login, body))
+	else
+		cprofile.pushEvent(string.format("e='UserInfo' unknown=true login=%q", o.login))
 	end
 end