hushhush has asked for the wisdom of the Perl Monks concerning the following question:

hi

I'd like a chatterbox type app, as used here to run on my site.

Basically allowing one public chat area for all, and then the ability to privately chat with the admin. I want to make sure no one can impersonate the admin, and I want users to be able to choose a new nickname at will.

Any suggestions for this sort of thing, right now all I can think of is building something off a jabber server with a javascript client which seems like a lot of work for this minimal functionality.

I guess the server app. as run here isn't available, only clients. So I can't go the route of modifying it to my needs.

thanks for any help in advance

Replies are listed 'Best First'.
Re: chatterbox like server app (a highly insecure example)
by Corion (Patriarch) on Sep 17, 2008 at 14:34 UTC

    This reminds me of my highly insecure CGI chat that I have lying around. It has horrible security problems because users can easily impersonate each other and it doesn't escape links or Javascript properly. On the other hand, it's 5 years old already and the security holes were known back then even. Nowadays, I'd clean up the user input using clinton's HTML::StripScripts or something else that limits what kinds of tags you can submit as HTML to the chat. The user authentication would be done as cookies using a secret salt so impersonation couldn't be done by simply by setting a parameter in your request.

    I haven't included the templates - if there is large enough interest, I can package up the tree and release it onto CPAN.

    package CGI::Chat::Simple; use strict; use URI::Escape; use HTML::Entities; use Tie::File; use POSIX qw(strftime); use base qw[ CGI::Application ]; use vars qw( $VERSION ); $VERSION = '0.01'; =head1 NAME CGI::Chat::Simple - A very simple and insecure webchat =head1 DESCRIPTION This is an instant webchat. =head1 SYNOPSIS =for example begin use strict; use CGI::Chat::Simple; my $chat = CGI::Chat::Simple->new( TMPL_PATH => "templates", )->run; =for example end =head1 METHODS =over 4 =item B<new> =cut sub new { my ($class) = shift; my $self = $class->SUPER::new(@_); $self; }; =item B<setup> The C<setup> method is called by the CGI::Application framework when the application should initialize itself and load all necessary parameters. The wiki decides here what to do and loads all needed valu +es from the configuration or database respectively. These parameters are passed to the wiki via the C<PARAMS> parameter of CGI::Application, as C<setup> is not called directly. So the general use is like this : =for example begin my $wiki = CGI::Wiki::Simple ->new( PARAMS => { # to be done })->run; =for example end C<setup> takes a list of pairs as parameters, one mandatory and some o +ptional : =cut sub setup { my ($self) = @_; $self->run_modes( login => 'render_login', frame => 'render_frame', messages => 'render_messages', users => 'render_users', input => 'render_input', ); $self->mode_param( \&decode_runmode ); $self->start_mode("login"); my $q = $self->query; my %default_config = ( script_name => $q->script_name, ); my %args; $args{$_} = defined $self->param($_) ? $self->param($_) : $default_c +onfig{$_} for (keys %default_config); $self->param( $_ => $args{$_}) for qw( script_name action ); my (@messages); tie @messages,'Tie::File','messages.log' or die "Couldn't tie message database"; $self->param( messages => \@messages ); # Maybe later add the connection to the database here... }; =item B<decode_runmode> C<decode_runmode> decides upon the url what to do. It also initializes the following CGI::Application params : user action message messagecount id =cut sub decode_runmode { my ($self) = @_; my $q = $self->query; my $action = $q->param("action"); # Magic runmode decoding : my %rms = $self->run_modes; my $runmodes = join "|", map { quotemeta } keys %rms; if ($q->path_info =~ m!^/($runmodes)\b!) { $action = $1; $q->param("action",""); }; $action ||= 'login'; $self->param( $_ => $self->query->param($_)) for qw( user action message id messagecount ); my (@seen); tie @seen,'Tie::File','seen.log' or die "Couldn't tie seen database"; my %seen_uniq = map { split "\0" } @seen; if ($self->param('user')) { $seen_uniq{$self->param('user')} = time(); }; @seen = map { $_ . "\0" . $seen_uniq{$_} } grep { time - $seen_uniq{ +$_} < 120 } sort keys %seen_uniq; $self->param( seen => [ sort keys %seen_uniq ]); $action; }; =item B<teardown> The C<teardown> sub is called by CGI::Application when the program ends. Currently, it does nothing in CGI::Wiki::Simple. =cut sub teardown { my ($self) = @_; # Maybe later add the database disconnect here ... }; sub load_tmpl { my ($self,$name) = @_; my $template = $self->SUPER::load_tmpl( $name, die_on_bad_params => +0 ); $template->param($_,$self->param($_)) for qw(script_name user id ); $template; }; sub render { my ($self,$templatename,$actions,@params) = @_; my $template = $self->load_tmpl($templatename); $self->load_actions($template, map { $_ => 1 } @$actions ); $template->param( $_ => $self->param( $_ )) for @params; $template->output; }; sub render_login { my $self = shift; my $template = $self->load_tmpl('login.tmpl'); $template->output; }; sub render_frame { my $self = shift; my $template = $self->load_tmpl('frame.tmpl'); $template->output; }; sub render_input { my $self = shift; if ($self->param('message')) { my $line = join "\0",$self->param('user'),$self->param('message'), +time(); push @{$self->param('messages')}, $line; }; my $template = $self->load_tmpl('input.tmpl'); $template->param(id => time() . rand ); $template->output; }; sub render_messages { my $self = shift; my $template = $self->load_tmpl('messages.tmpl'); my $messagecount = $self->param('messagecount') || 15; my @messages = map { my @arr = split /\0/; { name => $arr[0], message => $arr[1], timestamp => strftime('%Y%m%d-%H:%M:%S',local +time($arr[2])) } } @{$self->param('messages')}; shift @messages while @messages > $messagecount; $template->param( messages => \@messages ); $template->output; }; sub render_users { my $self = shift; my $template = $self->load_tmpl('users.tmpl'); $template->param( users => [ map { { name => $_ } } @{$self->param(' +seen')} ] ); $template->output; }; 1; =head1 AUTHOR Max Maischein (corion@cpan.org) =head1 COPYRIGHT Copyright (C) 2003 Max Maischein. All Rights Reserved. This code is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO perl

      I am interested.

Re: chatterbox like server app
by mr_mischief (Monsignor) on Sep 17, 2008 at 14:25 UTC
    That sounds much like an IRC channel with nickname registration services, a talker program similar to EWE-too/NUTS/GAEN, or a simple BBS. Are you wanting a web interface, a specifically client-server interface, a telnet-accessible interface, or something else entirely? You don't mention posts or customizable user rooms, so many BBS, mush, and moo programs sound like overkill.

    Something like these BBSes could be stripped down, but I believe all of them are written in C. Citadel and YAWC are open source, and I think you might be able to get DOC code as well. All of the DOC, Citadel, and YAWC BBSes support direct messages to another user while some also allow public chat. Not all BBSes have chat rooms because it was primarily a posting medium. TheBBS I know uses its own code base which is a couple of major rewrites away from YAWC, and it has a nice chat functionality. Telnet to thebbs.nicorinc.com and start an account to see it in action, and you can tell them Mr Mischief recommended the board. I used to have an all-Perl code base similar to it, but that code was lost years ago. It'd be simple to write again if I had the time.

    IRC is all about chat, and that's what the 'C' stands for. The 'R' stands for 'relay', because you can have a network of more than one server. There are at least Net::IRC, POE::Component::IRC, POE::Component::Server::IRC, Parse::IRC, and all of their related modules to help with that protocol and command set in Perl. There are also Bot::BasicBot, IRC::Bot, and Infobot among others to handle writing automated IRC bots.

    Talkers are often similar to MUDs with no game programmed into them. There are pure chat systems all the way through MUSHes and MOOs that have elaborate room editing, navigation between rooms, and even object editing. http://www.talker.com is a hosting provider that specializes in hosting talkers and MUDs. They have a page that links to the code for many talker and MUD server systems on their site, although some of the links are busted. There used to be good support for talkers on IRC under the alt.talkers groups, such as alt.talkers itself, alt.talkers.programming, and alt.talkers.nuts for example. I doubt there's much traffic there these days, but Google Groups likely has lots of the old info.

Re: chatterbox like server app
by skiphoppy (Acolyte) on Sep 17, 2008 at 14:02 UTC
    ralfchat is a pretty nice chat program written in Perl that you might be able to adapt to your needs, or use as an example to write your own. You could also get the source code to the everything engine and find out how it's done there (here).
Re: chatterbox like server app
by bduggan (Pilgrim) on Sep 17, 2008 at 19:02 UTC
    Here's a little ajax one I just put together. Enjoy!
    #!/usr/bin/perl -w use strict; use CGI; use CGI::Ajax; use Storable qw/lock_store lock_retrieve/; our $file = '/tmp/messages'; our $MAX_MESSAGES = 10; our $table = eval { lock_retrieve($file) } || {}; my $cgi = new CGI; my $pjx = new CGI::Ajax( 'do_chat' => \&do_chat ); print $pjx->build_html( $cgi, \&show_page); sub do_chat { my ( $name, $msg ) = @_; if ( $name && $msg ) { push @{ $table->{messages} }, [ $name, $msg ]; shift @{ $table->{messages} } while @{ $table->{messages} } > $MAX_MESSAGES; lock_store $table, $file; } return join "\n", map "[" . $cgi->escapeHTML($_->[0]) . "] : " . $cgi->escapeHTML( $_->[1] ), @{ $table->{messages} }; } sub show_page { return $cgi->start_html( -onload => q{setInterval( 'do_chat( [],[\\'result\\'] ) +',1000 );} ) . $cgi->pre( { id => 'result' }, " " ) . $cgi->textfield( -name => 'name', -size => 10, -value => 'name', -id => 'name' ) . $cgi->textfield( -name => 'msg', -size => 50, -value => 'message', -id => 'msg' ) . $cgi->submit( -name => 'speak', -value => 'speak', -onclick => q{do_chat( ['name','msg'],['result'] );} ) . $cgi->end_html; }
Re: chatterbox like server app
by Anonymous Monk on Sep 17, 2008 at 13:57 UTC
Re: chatterbox like server app
by kubrat (Scribe) on Sep 17, 2008 at 14:42 UTC

    I don't think that there's javascript involved in the chatterbox app on this site. It's an html form which you have to keep submitting if you want the follow the conversation. If you want your chatterbox to behave more like a typical chat app then you will need javascript to keep the chatwindow updated or at least use html refresh which isn't pretty.

    Jabber? If you want your chatterbox app to be accessible to everyone then it will have to work over port 80. And if you already have a webserver running on the machine where you are going to host the app then your only option is to make it a webserver app, like CGI or whatever.

    Anyway, as you have already guessed a chat app is not as straightforward to build as it may seem on first sight. But there are plenty of free chat apps available on the net and even chat services you can use.

    Good luck.

Re: chatterbox like server app
by hushhush (Novice) on Sep 18, 2008 at 13:03 UTC
    wow thanks very much for the great replies

    I think I might try something like a basic cgi client to a local running irc server, exposing only what I need.

    cheers