#!/usr/bin/perl # Flow of the Program: # *Send message to the server - send_msg_all # *Connect to the server - sub connect_server # -unblock the server - nonblock # -Login to the server - send_login # -Timer started to wait for messages - wait_for_msg # >Handler - handle # $Process the incoming meswsages - process_incoming # @Recieve messages and display in textview - rcv_msg use warnings; use strict; use Gtk2 -init; use Glib qw/TRUE FALSE/; use IO::Socket::INET; use Tie::RefHash; use IO::Select; #global variables my $buffer; my $host = "Deadpickle-hobo"; my $port = 6666; my $conn_stat = 'idle'; my %inbuffer = (); my %outbuffer = (); my %ready = (); my $select; my $conn; my $user; #the main chat widget my $main_window = Gtk2::Window->new("toplevel"); $main_window->signal_connect(delete_event => sub {Gtk2->main_quit;}); $main_window->set_default_size(250, 200); my $table = Gtk2::Table->new(4, 2, FALSE); $buffer = Gtk2::TextBuffer->new; my $button = Gtk2::Button->new("Send"); my $entry = Gtk2::Entry->new(); my $label = Gtk2::Label->new("Chat Client Test"); my $textview = Gtk2::TextView->new_with_buffer($buffer); $textview->set_cursor_visible (FALSE); my $swindow = Gtk2::ScrolledWindow->new( undef, undef); $swindow->set_policy( 'automatic', 'automatic'); $swindow->set_shadow_type( 'etched-out'); $swindow->add( $textview); $table->attach_defaults($label, 0, 1, 0, 1); $table->attach_defaults($swindow, 0, 2, 1, 3); $table->attach_defaults($entry, 0, 1, 3, 4); $table->attach_defaults($button, 1, 2, 3, 4); $main_window->add($table); $main_window->show_all(); $button->signal_connect("clicked" => sub { send_msg_all($entry->get_text); $entry->set_text('');} ); #run the login dialog dialog($buffer); Gtk2->main; #-------------------Login Dialog------------------- sub dialog{ my $buffer = shift; my $dialog_window = Gtk2::Window->new('toplevel'); $dialog_window->signal_connect(delete_event => sub {Gtk2->main_quit}); my $dialog_table = Gtk2::Table->new(2, 2, FALSE); my $dialog_label1 = Gtk2::Label->new('Chat Login:'); my $dialog_label2 = Gtk2::Label->new('User:'); my $dialog_label3 = Gtk2::Label->new('Host:'); my $chat_user = Gtk2::Entry->new(); $chat_user->set_text(''); my $dialog_button1 = Gtk2::Button->new('Connect'); $dialog_table->attach_defaults($dialog_label1, 0, 1, 0, 1); $dialog_table->attach_defaults($chat_user, 1, 2, 0, 1); $dialog_table->attach_defaults($dialog_button1, 1, 2, 1, 2); $dialog_button1->signal_connect("clicked" => sub {$user = $chat_user->get_text; $dialog_window->destroy; $buffer->insert(($buffer->get_end_iter), "Username: $user...\n"); connect_server()}); $dialog_window->add($dialog_table); $dialog_window->show_all; return 1; } #------------------Connect to server--------------------- #establishes connection to the server sub connect_server{ if ($conn_stat ne 'connected') { $buffer->insert(($buffer->get_end_iter), "Connecting to Server $host:$port...\n"); $conn = IO::Socket::INET->new(PeerAddr => $host, PeerPort => $port, Proto => 'tcp') or popup_err(1); if ($conn) { %inbuffer = (); %outbuffer = (); %ready = (); tie %ready, 'Tie::RefHash'; nonblock($conn); $select = IO::Select->new($conn); $conn_stat = 'connected'; $buffer->insert(($buffer->get_end_iter), "Connected!\n"); #send login to server send_login(); #start the timer that monitors incoming messages my $timer_waiting = Glib::Timeout->add(100, \&wait_for_msg); print "$conn\n"; } } } #-------------------Error popup------------------- # pops up an error message sub popup_err{ my ($error_code) = @_; my $error; if ($error_code == 1) {$error = "Cannot create Socket!"} elsif ($error_code == 2) {$error = "Username to Short!"} elsif ($error_code == 3) {$error = "No connection Established!"} elsif ($error_code == 4) {$error = "Already Logged on with This User Name!"} elsif ($error_code == 5) {$error = "Not Connected!"} elsif ($error_code == 6) {$error = "User Successfully Added!"} elsif ($error_code == 7) {$error = "Error Registering User!"} elsif ($error_code == 8) {$error = "Already Logged Out!"} else {$error = "Unkown Error!"} $buffer->insert(($buffer->get_end_iter), "$error\n"); my $error_dialog = Gtk2::MessageDialog->new($main_window, 'destroy-with-parent', 'error', 'ok', "$error"); $error_dialog->run; $error_dialog->destroy; } #-------------------blocking------------------- # nonblock($socket) puts socket into nonblocking mode sub nonblock { my $socket = shift; $socket->blocking(0); } #-------------------Message Waiting------------------- # Wait for incoming messages from the server relayed from clients sub wait_for_msg { if ($conn_stat eq 'connected') { my ($list_size, $msg); my $server; my $rv; my $data; # check for new information on the connections we have # anything to read or accept? foreach $server ($select->can_read(1)) { # read data $data = ''; $rv = $server->recv($data, 'POSIX::BUFSIZ', 0); unless (defined($rv) && length $data) { # This would be the end of file, so close the client delete $inbuffer{$server}; delete $outbuffer{$server}; delete $ready{$server}; $select->remove($server); close $server; next; } $inbuffer{$server} .= $data; # test whether the data in the buffer or the data we # just read means there is a complete request waiting # to be fulfilled. If there is, set $ready{$client} # to the requests waiting to be fulfilled. while ($inbuffer{$server} =~ s/(.*\n)//) { push( @{$ready{$server}}, $1 ); } } # Any complete requests to process? foreach $server (keys %ready) { handle($server); } } } #-------------------Handler------------------- # handle($socket) deals with all pending requests for $client sub handle { # requests are in $ready{$server} # send output to $outbuffer{$server} my $server = shift; my $request; foreach $request (@{$ready{$server}}) { # $request is the text of the request # put text of reply into $outbuffer{$client} chomp $request; process_incoming($server, $request); } delete $ready{$server}; } #-------------------Process Incoming------------------- sub process_incoming { my ($server, $msg) = @_; my @logged_users; my @rcvd_msg = split(/::/, $msg); if ($rcvd_msg[1] eq "1") { # Login responses # 12 = already logged on # 03 = logged in if($rcvd_msg[2] eq "03") { print "Successfully Logged in!\n"; } elsif ($rcvd_msg[2] eq "12") { popup_err(4); } else { # Create pop-up for error! print "Error Logging in ", $msg, "\n"; popup_err(5); } } elsif ($rcvd_msg[1] eq "2") { # register response if ($rcvd_msg[2] eq "06") { print "New user successfully registered!\n"; popup_err(6); } elsif ($rcvd_msg[2] eq "02") { print "$msg\n"; popup_err(4); } else { print "$msg\n"; popup_err(7); } } elsif ($rcvd_msg[1] eq "3") { # quit response print "$msg\n"; # $exit_cond = 0; } elsif ($rcvd_msg[1] eq "4") { # log out response # 14 = user logged off # 13 = user not logged in to begin with print "$msg\n"; if($rcvd_msg[2] == 13) { popup_err(8); # not logged in } } elsif ($rcvd_msg[1] eq "6") { # receive user message # 13 - user not logged in # 23 - buddy (target) not logged in print "$msg\n"; rcv_msg($rcvd_msg[3], $rcvd_msg[4]); } else { print "Unrecognized response: $msg\n"; exit(0); } } #-------------------Send message to all------------------- sub send_msg_all { my ($msg) = @_; print "$conn\n"; if(defined $conn) { # Send a the Message to server print "Sending\n"; print $conn "7\:\:$user\:\:$msg\n"; } else { popup_err(3); } } #-------------------Send login------------------- #logs the user name on the server sub send_login { if(defined $conn) { if(length($user) > 0) { #send login to server print $conn "1\:\:$user\n"; } else { popup_err(2); } } else { popup_err(3); } } #-------------------Display Message------------------- sub rcv_msg { my ($from, $msg) = @_; print "Received message from $from\n"; if(defined $conn) { print "Already Connected: Proceeding with message!\n"; } else { print "No connection established!\n"; popup_err(3); } }