We have been recently struggling with trying to find a good group discussion forum for real-time collaboration. With members of new team spread over multiple time zones and network availability, it is good to have real-time interactivity without going through email or mailing lists. IRC with some logging and searchability would be nice as long as it is reasonably secure. We are still looking into it, so let me know if you have any good answers.
While trying to figure out, I happened onto the cool Google Chat Room hack. Google group talk by default only lets you create invitations to group chat and add more people to it. The is no subscribe mechanism to join an existing group chat unless someone in the chat invites you in. if you drop off the connection, you have to be re-invited again. What we want is a persistent chat room in Google Chat.
If you happen to be using external chat software (ala Pidgin, Adium, etc.), then there is a hack to create a pseudo room.
It turns out that there is a way to keep a persistent channel open using group chat. All google chats are named as private-chat-UUID. From pidgin etc. You can join a chat with whatever UUID you pick and it creates the room if it does not exist. Once the room is created and you invite people, all the people can log off and on but can still
join the same room without needing to be invited again. Voila! Channel. The nice thing is that all these chats show up on the gmail folder and are searchable. So you just join a chat with a randomly generated UUID (using uuidgen or other web tools for random UUID generation). Note that just knowing the random UUID is not enough for outsiders to join the room. All participants have to be invited at least once by the initiator. So it does remain secure as a normal group chat.
This blog post has more details.
Now that there is an IRC/ChatRoom, what about people who are interested in seeing what the discussions were when they were offline and search for any technical information in the future? It is relatively easy to use a script running on an always on machine to capture all the google chat and email it as an archive to all users. Here is the shell of such a script. Making it send emails or create other archives is left as an exercise to the reader…
#
# Basic script adapted from Net:XMPP client.pl to join a chatroom and print out the log...
#
use Net::XMPP;
use strict;
if ($#ARGV < 6)
{
print "\nUsage: perl chatter.pl
exit(0);
}
my $server = $ARGV[0];
my $port = $ARGV[1];
my $username = $ARGV[2];
my $domain = $ARGV[3];
my $password = $ARGV[4];
my $chatroom = $ARGV[5];
my $resource = $ARGV[6];
my $connectiontype = 'tcpip';
my $tls = 1;
$SIG{HUP} = \&Stop;
$SIG{KILL} = \&Stop;
$SIG{TERM} = \&Stop;
$SIG{INT} = \&Stop;
my $Connection = new Net::XMPP::Client();
$Connection->SetCallBacks(message=>\&InMessage,
presence=>\&InPresence,
iq=>\&InIQ);
my $status = $Connection->Connect(
hostname => $server, port => $port,
componentname => $domain,
connectiontype => $connectiontype, tls => $tls);
if (!(defined($status)))
{
print "ERROR: Server is down or connection was not allowed.\n";
print " ($!)\n";
exit(0);
}
# Change hostname
my $sid = $Connection->{SESSION}->{id};
$Connection->{STREAM}->{SIDS}->{$sid}->{hostname} = $domain;
# Authenticate
my @result = $Connection->AuthSend(
username => $username, password => $password,
resource => $resource);
if ($result[0] ne "ok")
{
print "ERROR: Authorization failed: $result[0] - $result[1]\n";
exit(0);
}
print "*** Logged in to $server:$port...\n";
$Connection->RosterGet();
print "*** Getting Roster to tell server to send presence info...\n";
$Connection->PresenceSend();
print "*** Sending presence to tell world that we are logged in...\n";
$Connection->PresenceSend(to=>$chatroom."\@groupchat.google.com/".$username."\@".$domain,show=>"available");
while(defined($Connection->Process())) { }
print "ERROR: The connection was killed...\n";
exit(0);
sub Stop
{
print "Exiting...\n";
$Connection->Disconnect();
exit(0);
}
sub InMessage
{
my $sid = shift;
my $message = shift;
my $type = $message->GetType();
my $fromJID = $message->GetFrom("jid");
my $from = $fromJID->GetUserID();
my $resource = $fromJID->GetResource();
my $subject = $message->GetSubject();
my $body = $message->GetBody();
print "$resource: $body\n";
}
sub InIQ
{
my $sid = shift;
my $iq = shift;
my $from = $iq->GetFrom();
my $type = $iq->GetType();
my $query = $iq->GetQuery();
my $xmlns = $query->GetXMLNS();
print "===\n";
print "IQ\n";
print " From $from\n";
print " Type: $type\n";
print " XMLNS: $xmlns";
print "===\n";
#print $iq->GetXML(),"\n";
#print "===\n";
}
sub InPresence
{
my $sid = shift;
my $presence = shift;
my $from = $presence->GetFrom();
my $type = $presence->GetType();
my $status = $presence->GetStatus();
print "$from: $status\n";
}