I decided that I've finally reached the point in my C# knowledge where I could attempt a very simplistic IRC console client. I'm not trying to reach a level to compete with mIRC or anything like that, this is just me trying to learn how sockets and network streams work and interrelate. And so far.. well, I can get it to connect to the IRC network and I can get it to join a channel but it won't display anything on the incoming side of things. I haven't really written the code for that yet, mainly because I'm not entirely sure how.
Er, well, let me say this instead. I know how to get a line from the stream and send it to the console:
Console.WriteLine(StreamReader.ReadLine());
But what I don't understand is how to make it display ALL of the incoming information from the server. IRC constantly sends information (whether it be people talking, ctcp, server messages, whatever) and I don't understand how to collect and display all of that information continiouslly.
Here's what I have so far. It's split into two files: Program.cs and IRC.cs.
Program.cs
Code:
using System;
using System.Collections.Generic;
using System.Text;
namespace IRCtesting
{
class Program
{
static void Main(string[] args)
{
System.Console.WriteLine("Starting the client..\n");
IRC irc;
if (args.Length == 0)
{
// Create a new IRC connection using the default constructor
irc = new IRC();
}
else
{
// Code to seperate and get the arguments later
irc = new IRC();
}
while (irc.canQuit == false)
{
irc.getCommand();
}
System.Console.WriteLine("Press any key to close the client...\n");
System.Console.ReadLine();
}
}
}
IRC.cs
Code:
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Net;
using System.Net.Sockets;
using System.IO;
namespace IRCtesting
{
class IRC
{
#region variables
// Public variables
public bool canQuit = false;
public bool connected = false;
public static StreamWriter writer;
public static StreamReader reader;
// Private variables
private int ircPort = 6667;
private string ircServer = "irc.esper.net";
private string nickNameMain = "CSharpIRC";
private string nickNameBckup = "CSharpIRCbck";
private string user = "USER CSharp 1 * :Dont look at me !!!";
private string channel = "";
private TcpClient ircClient;
private NetworkStream stream;
private Thread pingSender;
// Private constants
private const string CRLF = "\r\n";
private const string PING = "PING :";
#endregion
#region constructors
////////////////////////////////////////////////
//////////////CONSTRUCTORS//////////////////////
// There are six constructors which allow you //
// to specify some or all the information //
// necessary to connecting. //
////////////////////////////////////////////////
public IRC()
{
// Connect to IRC
connect();
}
public IRC(string server)
{
ircServer = server;
// Connect to IRC
connect();
}
public IRC(int port)
{
ircPort = port;
}
public IRC(string server, int port)
{
ircServer = server;
ircPort = port;
// Connect
connect();
}
public IRC(string server, int port, string mainNick)
{
ircServer = server;
ircPort = port;
nickNameMain = mainNick;
}
public IRC(string server, int port, string mainNick, string backupNick)
{
ircServer = server;
ircPort = port;
nickNameMain = mainNick;
nickNameBckup = backupNick;
// Connect to IRC using the settings
connect();
}
#endregion
private void connect()
{
// Tell people we're going to connect
System.Console.WriteLine("Connecting to " + ircServer + ":" + ircPort + " ...\n");
try
{
// Try to make a connection to the server
ircClient = new TcpClient(ircServer, ircPort);
stream = ircClient.GetStream();
reader = new StreamReader(stream);
writer = new StreamWriter(stream);
// Start up our ping handler
PingControl();
// Send the ident information to the server (i.e. our user and who we are)
writer.WriteLine(user);
writer.Flush();
writer.WriteLine("NICK " + nickNameMain);
writer.Flush();
// We're connected, so let's set our bool to true.
connected = true;
}
catch (Exception e)
{
// Show the exception
Console.WriteLine(e.ToString() + CRLF);
// Sleep, before we try again
Thread.Sleep(5000);
connect();
}
}
private void quit()
{
// Message that we're quitting
writer.WriteLine("QUIT ");
writer.Flush();
// Exit out of the program.
quit_program();
}
private void quit(string message)
{
// Message that we're quitting
writer.WriteLine("QUIT " + ":" + message);
writer.Flush();
// Exit out of the program.
quit_program();
}
private void quit_program()
{
// Close everything down
stream.Close();
writer.Close();
reader.Close();
ircClient.Close();
// Tell the console that we can quit and release control
connected = false;
canQuit = true;
}
// Join a channel, no key
private void join(string chan)
{
if (channel == "")
{
channel = chan;
writer.WriteLine("JOIN " + channel);
writer.Flush();
}
else
{
Console.WriteLine("This client only supports one channel right now.\n");
}
}
// Join a channel with a key
private void join(string channel, string key)
{
}
// Send something to the channel
private void sendToChannel(string message)
{
writer.WriteLine("PRIVMSG " + channel + " :" + message);
writer.Flush();
}
////////////////////////////////////////////////
///////////////COMMAND PARSER///////////////////
// The command parser takes the incoming text //
// from the console and splits it up into //
// tokens as well as determines what command //
// has been used and what function should be //
// called. //
////////////////////////////////////////////////
public void getCommand()
{
// Get the command string from the console
string rawCommandString = Console.ReadLine();
// Break the command into their tokenized parts so we can determine what to do
string[] commandString;
commandString = rawCommandString.Split(new char[] { ' ' });
// Get the first element of the command string and convert it to upper case
string command = commandString[0].ToString();
command = command.ToUpper();
///////////////////////////////////////////////////
// The QUIT command. Used to disconnect from the//
// server. It'll also cause our console to stop.//
///////////////////////////////////////////////////
if ((command == "QUIT") || (command == "/QUIT"))
{
// We need to check to see if the person has typed a quit message
int commandLength = commandString.Length;
if (commandLength >= 2)
{
// Determine what the message is.
commandLength = commandString.Length - 1;
string message = "";
for (int i = 1; i <= commandLength; i++)
{
message = message + commandString[i] + " ";
}
// Let's quit with our message
quit(message);
}
else
quit(); // Quit with a default message of your nick.
}
///////////////////////////////////////////////////
// The JOIN command. Used to join an IRC channel//
// and may have a key (if the channel is locked) //
///////////////////////////////////////////////////
if (((command == "JOIN") || (command == "/JOIN") || (command == "/J")))
{
// Set our channel
string chan = commandString[1].ToString();
// Does the channel have the necessary #?
if (!chan.StartsWith("#"))
{
// We'll add it here.
chan = "#" + commandString[1].ToString();
}
// Does this join command have a key for the channel?
// Check for the max number of words in the array first.
int commandLength = commandString.Length;
if (commandLength >= 3)
{
// Is the next word a space or null?
if (commandString[2].ToString() != "")
{
// We have a key! Let's get the key and join the channel.
string key = commandString[2].ToString();
join(chan, key);
}
}
// No, it doesn't, so just join a regular channel
else
join(chan);
}
///////////////////////////////////////////////////
// The "Say" command to send a message to the //
// active channel. //
///////////////////////////////////////////////////
if ((command == "SAY") || (command == "/SAY"))
{
if (channel != "")
{
// Determine what the message is.
int commandLength = commandString.Length -1;
string message = "";
for (int i = 1; i <= commandLength; i++)
{
message = message + commandString[i] + " ";
}
// Send the message to the command
sendToChannel(message);
}
else
{
Console.WriteLine("You must first join a channel.\n");
}
}
}
////////////////////////////////////////////////
////////////////PING CONROL/////////////////////
////////////////////////////////////////////////
// PING control is a set of two functions that//
// will ping the server every 15 seconds on a //
// seperate thread until we are no longer //
// connected to the server. //
////////////////////////////////////////////////
private void PingControl()
{
// Start a new thread for the Ping Control
pingSender = new Thread (new ThreadStart(PingRun));
pingSender.Start();
// Begin running the control
PingRun();
}
// Send PING to irc server every 15 seconds
private void PingRun()
{
// Is the client still running? If so, we need to ping the server
while ((canQuit == false) && (connected == true))
{
writer.WriteLine(PING + ircServer);
writer.Flush();
Thread.Sleep(15000);
}
}
}
}
I should add that once I get the incoming information to display I plan to scrap the console version and start on a GUI version. But I really need some help on learning how to make it display everything. Even some basic ideas and concepts will help me out.
Thanks guys.