|
Posted by deadpickle on February 11, 2008, 3:13 pm
Please log in for more thread options
I am trying to build a chat client that uses IRC and is built in the
framework of Gtk2. So far it works well but not great. Right now the
client connects to a server and joins a channel. Also, the client can
send messages to the channel and amazingly they are received on the
channel. The problem I am encountering is that the chat client is not
receiving all the raw lines sent by the IRC server (for an example of
what I mean try this script: http://www.oreilly.com/pub/h/1964). If it
is not receiving all the lines then it can only send messages not
receive them. So I am looking for help on how I can get the program to
receive messages so that they can be displayed in the window.
#!/usr/local/bin/perl -w
use strict;
use Gtk2 '-init';
use Glib qw/TRUE FALSE/;
use IO::Socket;
#-------------------Shared Variables-------------------
my $server = "irc.freenode.net";
my $nick = "simple";
my $login = "simple";
my $channel = "#GRRUVI";
my $sock;
#-------------------Main Loop-------------------
my $window = Gtk2::Window->new('toplevel');
$window->signal_connect( delete_event => sub {
close($sock);
Gtk2->main_quit;
});
$window->set_default_size( 300, 200 );
my $table = Gtk2::Table->new(2, 1, FALSE);
my $scroller = Gtk2::ScrolledWindow->new;
my $textview = Gtk2::TextView->new;
my $entry = Gtk2::Entry->new;
$scroller->add($textview);
$table->attach_defaults($scroller, 0, 1, 0, 1);
$table->attach_defaults($entry, 0, 1, 1, 2);
$window->add($table);
# allows for sending each line with an enter keypress
my $send_sig = $entry->signal_connect ('key-press-event' => sub {
my ($widget,$event)= @_;
if( $event->keyval() == 65293){ # a return key press
my $text = $entry->get_text;
if(defined $sock){ print $sock "PRIVMSG $channel :$text
\r\n";}
$entry->set_text('');
$entry->set_position(0);
}
});
$entry->signal_handler_block($send_sig); #not connected yet
$entry->set_editable(0);
$window->show_all;
connecting();
Glib::IO->add_watch( fileno $sock, [qw/in hup err/], \&incoming_data,
$sock );
Gtk2->main;
#-------------------Connect to Server-------------------
sub connecting {
# Connect to the IRC server.
$sock = new IO::Socket::INET(
PeerAddr => $server,
PeerPort => 6667,
Proto => 'tcp'
) or die "Can't connect\n";
# Log on to the server.
print $sock "NICK $nick\r\n";
print $sock "USER $login 8 * :Perl IRC Hacks Robot\r\n";
# Read lines from the server until it tells us we have connected.
while (my $input = <$sock>) {
# Check the numerical responses from the server.
if ($input =~ /004/) {
# We are now logged in.
last;
}
elsif ($input =~ /433/) {
die "Nickname is already in use.";
}
}
# Join the channel.
print $sock "JOIN $channel\r\n";
$entry->set_editable(1);
$entry->grab_focus;
$entry->signal_handler_unblock ($send_sig);
Gtk2->main_iteration while Gtk2->events_pending;
}
#-------------------Incoming data-------------------
sub incoming_data {
my ( $fd, $condition, $fh ) = @_;
if ( $condition eq 'in' ) {
my $input = scalar <$fh>;
chop $input;
# if ( defined $data ) {
# # do something useful with the text.
# my $buffer = $textview->get_buffer;
# $buffer->insert( $buffer->get_end_iter, $data );
# }
if ($input =~ /^PING(.*)$/i) {
# We must respond to PINGs to avoid being disconnected.
print $sock "PONG $1\r\n";
}
else {
# Print the raw line received by the bot.
print "$input\n";
}
}
return TRUE;
}
|
|
Posted by deadpickle on February 12, 2008, 12:25 am
Please log in for more thread options
I noticed a few things:
I tested the program using mIRC. I logged into the channel with the
client and under another name with mIRC. Logging in works fine, I can
see the clients nickname in the channel. What the problem seems to be
is when the MOTD is displayed. It seems that only a few lines of the
MOTD are displayed before the 'in' condition is stopped and the
message stops displaying in the terminal window. When I type in mIRC,
a line of the MOTD is displayed in terminal window. The $input
variable seems to be behind the real-time sending of the messages. I'm
not sure how to remove this lag and I'm looking for ideas.
#!/usr/local/bin/perl -w
use strict;
use Gtk2 '-init';
use Glib qw/TRUE FALSE/;
use IO::Socket;
#-------------------Shared Variables-------------------
my $server = "irc.freenode.net";
my $nick = "simple";
my $login = "simple";
my $channel = "#GRRUVI";
my $sock;
#-------------------Main Loop-------------------
my $window = Gtk2::Window->new('toplevel');
$window->signal_connect( delete_event => sub {
close($sock);
Gtk2->main_quit;
});
$window->set_default_size( 300, 200 );
my $table = Gtk2::Table->new(2, 1, FALSE);
my $scroller = Gtk2::ScrolledWindow->new;
my $textview = Gtk2::TextView->new;
my $entry = Gtk2::Entry->new;
$scroller->add($textview);
$table->attach_defaults($scroller, 0, 1, 0, 1);
$table->attach_defaults($entry, 0, 1, 1, 2);
$window->add($table);
# allows for sending each line with an enter keypress
my $send_sig = $entry->signal_connect ('key-press-event' => sub {
my ($widget,$event)= @_;
if( $event->keyval() == 65293){ # a return key press
my $text = $entry->get_text;
if(defined $sock){ print $sock "PRIVMSG $channel :$text
\r\n";}
$entry->set_text('');
$entry->set_position(0);
}
});
$entry->signal_handler_block($send_sig); #not connected yet
$entry->set_editable(0);
$window->show_all;
connecting();
Glib::IO->add_watch( fileno $sock, [qw/in hup err/], \&incoming_data,
$sock );
Gtk2->main;
#-------------------Connect to Server-------------------
sub connecting {
# Connect to the IRC server.
$sock = new IO::Socket::INET(
PeerAddr => $server,
PeerPort => 6667,
Proto => 'tcp'
) or die "Can't connect\n";
# Log on to the server.
print $sock "NICK $nick\r\n";
print $sock "USER $login 8 * :Perl IRC Hacks Robot\r\n";
# Read lines from the server until it tells us we have connected.
while (my $input = <$sock>) {
# Check the numerical responses from the server.
if ($input =~ /004/) {
# We are now logged in.
last;
}
elsif ($input =~ /433/) {
die "Nickname is already in use.";
}
}
# Join the channel.
print $sock "JOIN $channel\r\n";
$entry->set_editable(1);
$entry->grab_focus;
$entry->signal_handler_unblock ($send_sig);
Gtk2->main_iteration while Gtk2->events_pending;
}
#-------------------Incoming data-------------------
sub incoming_data {
my ( $fd, $condition, $fh ) = @_;
if ( $condition eq 'in' ) {
my $input = scalar <$fh>;
chop $input;
# if ( defined $data ) {
# # do something useful with the text.
# my $buffer = $textview->get_buffer;
# $buffer->insert( $buffer->get_end_iter, $data );
# }
if ($input =~ /^PING(.*)$/i) {
# We must respond to PINGs to avoid being disconnected.
print $sock "PONG $1\r\n";
}
else {
# Print the raw line received by the bot.
print "$input\n";
}
}
return TRUE;
}
|
|
Posted by Ben Morrow on February 12, 2008, 11:06 am
Please log in for more thread options
> I noticed a few things:
> I tested the program using mIRC. I logged into the channel with the
> client and under another name with mIRC. Logging in works fine, I can
> see the clients nickname in the channel. What the problem seems to be
> is when the MOTD is displayed. It seems that only a few lines of the
> MOTD are displayed before the 'in' condition is stopped and the
> message stops displaying in the terminal window. When I type in mIRC,
> a line of the MOTD is displayed in terminal window. The $input
> variable seems to be behind the real-time sending of the messages. I'm
> not sure how to remove this lag and I'm looking for ideas.
You are reading the filehandle in buffered mode, which is not compatible
with select (which is used by Glib::IO->add_watch). Either switch to
sysread, or push a :unix layer to switch to unbuffered mode.
Ben
|
|
Posted by deadpickle on February 13, 2008, 11:43 pm
Please log in for more thread options >
> > I noticed a few things:
> > I tested the program using mIRC. I logged into the channel with the
> > client and under another name with mIRC. Logging in works fine, I can
> > see the clients nickname in the channel. What the problem seems to be
> > is when the MOTD is displayed. It seems that only a few lines of the
> > MOTD are displayed before the 'in' condition is stopped and the
> > message stops displaying in the terminal window. When I type in mIRC,
> > a line of the MOTD is displayed in terminal window. The $input
> > variable seems to be behind the real-time sending of the messages. I'm
> > not sure how to remove this lag and I'm looking for ideas.
>
> You are reading the filehandle in buffered mode, which is not compatible
> with select (which is used by Glib::IO->add_watch). Either switch to
> sysread, or push a :unix layer to switch to unbuffered mode.
>
> Ben
Yep your both right. Adding sysread corrected the problem and now I
have another question. I am trying to complete the IRC Client with
giving the user the ability to disconnect and reconnect to the IRC
server. The problem I am encountering is that when the user
disconnects the Glib::IO tries to read from the closed socket. I tried
to undefine the Glib::IO but that hasent work.
#!/usr/local/bin/perl -w
use strict;
use Gtk2 '-init';
use Glib qw/TRUE FALSE/;
use IO::Socket;
#-------------------Global Variables-------------------
my $chat_state = 'Connect';
my $sock;
my $channel;
my $nick;
my $irc;
my $chat_entry;
my $chat_send_sig;
my $chat_textview;
my $chat_button;
my $watch;
#############################################
#specials that will be input by the efault file
$channel = '#GRRUVI';
$nick = 'Lahowetz';
$irc = 'irc.freenode.net';
my $login = $nick;
#############################################
#-------------------Main Loop-------------------
&chat_build;
Gtk2->main;
#-------------------chat Build-------------------
sub chat_build {
my $chat_window = Gtk2::Window->new('toplevel');
$chat_window->set_title('Chat Client');
$chat_window->set_position('center');
$chat_window->set_default_size( 300, 200 );
$chat_window->signal_connect(delete_event=> sub);
my $chat_scroll = Gtk2::ScrolledWindow->new;
$chat_textview = Gtk2::TextView->new;
$chat_entry = Gtk2::Entry->new;
my $chat_vbox = Gtk2::VBox->new;
my $chat_buffer = $chat_textview->get_buffer;
$chat_buffer->create_mark( 'end', $chat_buffer->get_end_iter,
FALSE );
$chat_buffer->signal_connect(insert_text => sub {
$chat_textview->scroll_to_mark( $chat_buffer->get_mark('end'),
0.0, TRUE, 0, 0.5 );
});
$chat_button = Gtk2::Button->new;
$chat_button->set_label($chat_state);
$chat_scroll->add($chat_textview);
$chat_vbox->add($chat_scroll);
$chat_vbox->pack_start( $chat_entry, FALSE, FALSE, 0 );
$chat_vbox->pack_start( $chat_button, FALSE, FALSE, 0 );
$chat_window->add($chat_vbox);
# allows for sending each line with an enter keypress
$chat_send_sig = $chat_entry->signal_connect ('key-press-event' =>
sub {
my ($widget,$event)= @_;
if( $event->keyval() == 65293){ # a return key press
my $text = $chat_entry->get_text;
if(defined $sock){ print $sock "PRIVMSG $channel :$text
\r\n";}
$chat_entry->set_text('');
$chat_entry->set_position(0);
post($nick, $text);
}
});
$chat_entry->signal_handler_block($chat_send_sig); #not connected
yet
$chat_entry->set_editable(0);
$chat_textview->set_editable(0);
$chat_textview->set_cursor_visible(0);
$chat_window->show_all;
$chat_button->signal_connect("clicked" => sub {
if ($chat_state eq 'Connect') {
$chat_button->set_label('Disconnect');
$chat_state='Disconnect';
connecting();
}
else {
$chat_button->set_label('Connect');
$chat_state='Connect';
close $sock;
undef $watch;
}
});
return;
}
#-------------------Connect to IRC Server-------------------
sub connecting {
# Connect to the IRC server.
$sock = new IO::Socket::INET(
PeerAddr => $irc,
PeerPort => 6667,
Proto => 'tcp',
) or die "Can't connect\n";
if (defined $sock){
my $sys_msg = "Connected to $irc ...";
post($nick, $sys_msg);
}
# Log on to the server.
print $sock "NICK $nick\r\n";
print $sock "USER $login 8 * :Just a Tester\r\n";
# Read lines from the server until it tells us we have connected.
while (my $input = <$sock>) {
# Check the numerical responses from the server.
if ($input =~ /004/) {
# We are now logged in.
my $sys_msg = "Logged in to $irc ...";
post($nick, $sys_msg);
print $sock "JOIN $channel\r\n";
$watch = Glib::IO->add_watch( fileno $sock, [qw/in hup
err/], \&incoming_data, $sock );
$chat_entry->set_editable(1);
$chat_entry->grab_focus;
$chat_entry->signal_handler_unblock ($chat_send_sig);
last;
}
elsif ($input =~ /433/) {
my $sys_msg = "Nickname is already in use";
post($nick, $sys_msg);
$chat_state = 'Connect';
$chat_button->set_label($chat_state);
$chat_entry->signal_handler_block($chat_send_sig);
close $sock;
last;
}
}
Gtk2->main_iteration while Gtk2->events_pending;
}
#-------------------Watch for IRC Inputs-------------------
sub incoming_data {
my ( $fd, $condition, $fh ) = @_;
if ( $condition eq 'in' ) {
my $input;
sysread $fh, $input, 1000000;
chop $input;
if ($input =~ /^PING(.*)$/i) {
# We must respond to PINGs to avoid being disconnected.
print $sock "PONG $1\r\n";
}
if ($input =~ m/PRIVMSG\s($channel)/) {
print "$input\n";
my @sender = split(/!/, $input);
my @message = split(/:/, $input);
my $length = length($sender[0]);
my $who = substr($sender[0], 1, $length);
post($who, $message[2]);
}
if ($input =~ m/QUIT/) {
print "$input\n";
my @sender = split(/!/, $input);
my $length = length($sender[0]);
my $who = substr($sender[0], 1, $length);
my $sys_msg = "$who has QUIT!";
post($who, $sys_msg);
}
if ($input =~ m/JOIN/) {
print "$input\n";
my @sender = split(/!/, $input);
my $length = length($sender[0]);
my $who = substr($sender[0], 1, $length);
my $sys_msg = "$who has JOINED $channel!";
post($who, $sys_msg);
}
else {
# Print the raw line received by the bot.
print "$input\n";
}
}
return TRUE;
}
#-------------------Post messages in the Window-------------------
sub post{
my ($name, $msg) = @_;
my $chat_buffer = $chat_textview->get_buffer;
$chat_buffer->insert( $chat_buffer->get_end_iter, "$name: $msg
\n" );
}
|
|
Posted by zentara on February 14, 2008, 1:39 pm
Please log in for more thread options On Wed, 13 Feb 2008 20:43:10 -0800 (PST), deadpickle
>Yep your both right. Adding sysread corrected the problem and now I
>have another question. I am trying to complete the IRC Client with
>giving the user the ability to disconnect and reconnect to the IRC
>server. The problem I am encountering is that when the user
>disconnects the Glib::IO tries to read from the closed socket. I tried
>to undefine the Glib::IO but that hasent work.
Without messing with your code, I can tell you what you need to do.
You need to stop the current connection, then reconnect. There are
a couple of ways to do it. It is probably best to have a disconnect and
connect subs.
But basically you need to return false from your io callback and close
the socket.
Usually, you would do it something like
sub disconnect{
Gtk2::Helper->remove_watch( $sock );
close $sock;
#here you would reenable the Connect button,
#and do miscelaneous clean-up
#the reconnect again with a fresh socket
#and GLIB::IO watch on the new $sock.
# would be done in the "connect sub".
return 0;
}
zentara
--
I'm not really a human, but I play one on earth.
http://zentara.net/japh.html
|
| Similar Threads | Posted | | Chat client/server print failed | January 15, 2008, 7:32 pm |
| Gtk2-Perl!How to change color of the selection bar in widget Gtk2::SimpleList? | December 3, 2007, 1:16 pm |
| DCC Chat in irssi. | May 23, 2007, 3:35 am |
| Chat and earn friends like Orkut through this link | November 2, 2007, 4:43 am |
| new forum -- homework help/chit chat/easy communication | October 8, 2005, 12:08 pm |
| gtk2 + png | March 10, 2005, 9:34 am |
| Gtk2::TreeView | October 22, 2004, 11:24 pm |
| Problem with Gtk2 | August 9, 2005, 12:56 pm |
| how to use gtk2 threads | March 20, 2006, 5:21 am |
| how to use gtk2 threads | March 20, 2006, 5:21 am |
|