mirror of
https://github.com/reactos/reactos.git
synced 2025-07-29 03:51:41 +00:00
Import TechBot
svn path=/trunk/; revision=13064
This commit is contained in:
parent
568b27baeb
commit
9dab4509fa
94 changed files with 24386 additions and 0 deletions
32
irc/TechBot/TechBot.IRCLibrary/AssemblyInfo.cs
Normal file
32
irc/TechBot/TechBot.IRCLibrary/AssemblyInfo.cs
Normal file
|
@ -0,0 +1,32 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
// Information about this assembly is defined by the following
|
||||
// attributes.
|
||||
//
|
||||
// change them to the information which is associated with the assembly
|
||||
// you compile.
|
||||
|
||||
[assembly: AssemblyTitle("")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("")]
|
||||
[assembly: AssemblyCopyright("")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// The assembly version has following format :
|
||||
//
|
||||
// Major.Minor.Build.Revision
|
||||
//
|
||||
// You can specify all values by your own or you can build default build and revision
|
||||
// numbers with the '*' character (the default):
|
||||
|
||||
[assembly: AssemblyVersion("1.0.*")]
|
||||
|
||||
// The following attributes specify the key for the sign of your assembly. See the
|
||||
// .NET Framework documentation for more information about signing.
|
||||
// This is not required, if you don't want signing let these attributes like they're.
|
||||
[assembly: AssemblyDelaySign(false)]
|
||||
[assembly: AssemblyKeyFile("")]
|
20
irc/TechBot/TechBot.IRCLibrary/Default.build
Normal file
20
irc/TechBot/TechBot.IRCLibrary/Default.build
Normal file
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0"?>
|
||||
<project name="TechBot.IRCLibrary" default="build">
|
||||
|
||||
<property name="output.dir" value="..\bin" />
|
||||
|
||||
<target name="build" description="Build component">
|
||||
<mkdir dir="${output.dir}" />
|
||||
<csc target="library"
|
||||
output="${output.dir}\TechBot.IRCLibrary.dll"
|
||||
optimize="true"
|
||||
debug="true"
|
||||
doc="${output.dir}\TechBot.IRCLibrary.xml"
|
||||
warninglevel="0">
|
||||
<sources>
|
||||
<include name="*.cs" />
|
||||
</sources>
|
||||
</csc>
|
||||
</target>
|
||||
|
||||
</project>
|
26
irc/TechBot/TechBot.IRCLibrary/IRC.cs
Normal file
26
irc/TechBot/TechBot.IRCLibrary/IRC.cs
Normal file
|
@ -0,0 +1,26 @@
|
|||
using System;
|
||||
|
||||
namespace TechBot.IRCLibrary
|
||||
{
|
||||
/// <summary>
|
||||
/// IRC constants and helper methods.
|
||||
/// </summary>
|
||||
public class IRC
|
||||
{
|
||||
#region IRC commands
|
||||
|
||||
public const string JOIN = "JOIN";
|
||||
public const string NICK = "NICK";
|
||||
public const string PART = "PART";
|
||||
public const string PING = "PING";
|
||||
public const string PONG = "PONG";
|
||||
public const string PRIVMSG = "PRIVMSG";
|
||||
public const string USER = "USER";
|
||||
|
||||
public const string RPL_NAMREPLY = "353";
|
||||
public const string RPL_ENDOFNAMES = "366";
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
134
irc/TechBot/TechBot.IRCLibrary/IrcChannel.cs
Normal file
134
irc/TechBot/TechBot.IRCLibrary/IrcChannel.cs
Normal file
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
Channels names are strings (beginning with a '&' or '#' character) of
|
||||
length up to 200 characters. Apart from the the requirement that the
|
||||
first character being either '&' or '#'; the only restriction on a
|
||||
channel name is that it may not contain any spaces (' '), a control G
|
||||
(^G or ASCII 7), or a comma (',' which is used as a list item
|
||||
separator by the protocol).
|
||||
*/
|
||||
using System;
|
||||
using System.Collections;
|
||||
|
||||
namespace TechBot.IRCLibrary
|
||||
{
|
||||
/// <summary>
|
||||
/// IRC channel type.
|
||||
/// </summary>
|
||||
public enum IrcChannelType
|
||||
{
|
||||
Public,
|
||||
Private,
|
||||
Secret
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// IRC channel.
|
||||
/// </summary>
|
||||
public class IrcChannel
|
||||
{
|
||||
#region Private fields
|
||||
|
||||
private IrcClient owner;
|
||||
private string name;
|
||||
private IrcChannelType type = IrcChannelType.Public;
|
||||
private ArrayList users = new ArrayList();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public properties
|
||||
|
||||
/// <summary>
|
||||
/// Owner of this channel.
|
||||
/// </summary>
|
||||
public IrcClient Owner
|
||||
{
|
||||
get
|
||||
{
|
||||
return owner;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Name of channel (no leading #).
|
||||
/// </summary>
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Type of channel.
|
||||
/// </summary>
|
||||
public IrcChannelType Type
|
||||
{
|
||||
get
|
||||
{
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Users in this channel.
|
||||
/// </summary>
|
||||
public ArrayList Users
|
||||
{
|
||||
get
|
||||
{
|
||||
return users;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="owner">Owner of this channel.</param>
|
||||
/// <param name="name">Name of channel.</param>
|
||||
public IrcChannel(IrcClient owner, string name)
|
||||
{
|
||||
if (owner == null)
|
||||
{
|
||||
throw new ArgumentNullException("owner", "Owner cannot be null.");
|
||||
}
|
||||
if (name == null)
|
||||
{
|
||||
throw new ArgumentNullException("name", "Name cannot be null.");
|
||||
}
|
||||
this.owner = owner;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Locate a user.
|
||||
/// </summary>
|
||||
/// <param name="nickname">Nickname of user (no decorations).</param>
|
||||
/// <returns>User or null if not found.</returns>
|
||||
public IrcUser LocateUser(string nickname)
|
||||
{
|
||||
foreach (IrcUser user in Users)
|
||||
{
|
||||
/* FIXME: There are special cases for nickname comparison */
|
||||
if (nickname.ToLower().Equals(user.Nickname.ToLower()))
|
||||
{
|
||||
return user;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Talk to the channel.
|
||||
/// </summary>
|
||||
/// <param name="text">Text to send to the channel.</param>
|
||||
public void Talk(string text)
|
||||
{
|
||||
owner.SendMessage(new IrcMessage(IRC.PRIVMSG, String.Format("#{0} :{1}", name, text)));
|
||||
}
|
||||
}
|
||||
}
|
654
irc/TechBot/TechBot.IRCLibrary/IrcClient.cs
Normal file
654
irc/TechBot/TechBot.IRCLibrary/IrcClient.cs
Normal file
|
@ -0,0 +1,654 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Collections;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace TechBot.IRCLibrary
|
||||
{
|
||||
/// <summary>
|
||||
/// Delegate that delivers an IRC message.
|
||||
/// </summary>
|
||||
public delegate void MessageReceivedHandler(IrcMessage message);
|
||||
|
||||
/// <summary>
|
||||
/// Delegate that notifies if the user database for a channel has changed.
|
||||
/// </summary>
|
||||
public delegate void ChannelUserDatabaseChangedHandler(IrcChannel channel);
|
||||
|
||||
/// <summary>
|
||||
/// An IRC client.
|
||||
/// </summary>
|
||||
public class IrcClient
|
||||
{
|
||||
/// <summary>
|
||||
/// Monitor when an IRC command is received.
|
||||
/// </summary>
|
||||
private class IrcCommandEventRegistration
|
||||
{
|
||||
/// <summary>
|
||||
/// IRC command to monitor.
|
||||
/// </summary>
|
||||
private string command;
|
||||
public string Command
|
||||
{
|
||||
get
|
||||
{
|
||||
return command;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handler to call when command is received.
|
||||
/// </summary>
|
||||
private MessageReceivedHandler handler;
|
||||
public MessageReceivedHandler Handler
|
||||
{
|
||||
get
|
||||
{
|
||||
return handler;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="command">IRC command to monitor.</param>
|
||||
/// <param name="handler">Handler to call when command is received.</param>
|
||||
public IrcCommandEventRegistration(string command,
|
||||
MessageReceivedHandler handler)
|
||||
{
|
||||
this.command = command;
|
||||
this.handler = handler;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A buffer to store lines of text.
|
||||
/// </summary>
|
||||
private class LineBuffer
|
||||
{
|
||||
/// <summary>
|
||||
/// Full lines of text in buffer.
|
||||
/// </summary>
|
||||
private ArrayList strings;
|
||||
|
||||
/// <summary>
|
||||
/// Part of the last line of text in buffer.
|
||||
/// </summary>
|
||||
private string left = "";
|
||||
|
||||
/// <summary>
|
||||
/// Standard constructor.
|
||||
/// </summary>
|
||||
public LineBuffer()
|
||||
{
|
||||
strings = new ArrayList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return true if there is a complete line in the buffer or false if there is not.
|
||||
/// </summary>
|
||||
public bool DataAvailable
|
||||
{
|
||||
get
|
||||
{
|
||||
return (strings.Count > 0);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return next complete line in buffer or null if none exists.
|
||||
/// </summary>
|
||||
/// <returns>Next complete line in buffer or null if none exists.</returns>
|
||||
public string Read()
|
||||
{
|
||||
if (DataAvailable)
|
||||
{
|
||||
string line = strings[0] as string;
|
||||
strings.RemoveAt(0);
|
||||
return line;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a string to buffer splitting it into lines.
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
public void Write(string data)
|
||||
{
|
||||
data = left + data;
|
||||
left = "";
|
||||
string[] sa = data.Split(new char[] { '\n' });
|
||||
if (sa.Length <= 0)
|
||||
{
|
||||
left = data;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
left = "";
|
||||
}
|
||||
for (int i = 0; i < sa.Length; i++)
|
||||
{
|
||||
if (i < sa.Length - 1)
|
||||
{
|
||||
/* This is a complete line. Remove any \r characters at the end of the line. */
|
||||
string line = sa[i].TrimEnd(new char[] { '\r', '\n'});
|
||||
/* Silently ignore empty lines */
|
||||
if (!line.Equals(String.Empty))
|
||||
{
|
||||
strings.Add(line);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This may be a partial line. */
|
||||
left = sa[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// State for asynchronous reads.
|
||||
/// </summary>
|
||||
private class StateObject
|
||||
{
|
||||
/// <summary>
|
||||
/// Network stream where data is read from.
|
||||
/// </summary>
|
||||
public NetworkStream Stream;
|
||||
|
||||
/// <summary>
|
||||
/// Buffer where data is put.
|
||||
/// </summary>
|
||||
public byte[] Buffer;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="stream">Network stream where data is read from.</param>
|
||||
/// <param name="buffer">Buffer where data is put.</param>
|
||||
public StateObject(NetworkStream stream, byte[] buffer)
|
||||
{
|
||||
this.Stream = stream;
|
||||
this.Buffer = buffer;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#region Private fields
|
||||
private bool firstPingReceived = false;
|
||||
private System.Text.Encoding encoding = System.Text.Encoding.UTF8;
|
||||
private TcpClient tcpClient;
|
||||
private NetworkStream networkStream;
|
||||
private bool connected = false;
|
||||
private LineBuffer messageStream;
|
||||
private ArrayList ircCommandEventRegistrations = new ArrayList();
|
||||
private ArrayList channels = new ArrayList();
|
||||
#endregion
|
||||
|
||||
#region Public events
|
||||
|
||||
public event MessageReceivedHandler MessageReceived;
|
||||
|
||||
public event ChannelUserDatabaseChangedHandler ChannelUserDatabaseChanged;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public properties
|
||||
|
||||
/// <summary>
|
||||
/// Encoding used.
|
||||
/// </summary>
|
||||
public System.Text.Encoding Encoding
|
||||
{
|
||||
get
|
||||
{
|
||||
return encoding;
|
||||
}
|
||||
set
|
||||
{
|
||||
encoding = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// List of joined channels.
|
||||
/// </summary>
|
||||
public ArrayList Channels
|
||||
{
|
||||
get
|
||||
{
|
||||
return channels;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private methods
|
||||
|
||||
/// <summary>
|
||||
/// Signal MessageReceived event.
|
||||
/// </summary>
|
||||
/// <param name="message">Message that was received.</param>
|
||||
private void OnMessageReceived(IrcMessage message)
|
||||
{
|
||||
foreach (IrcCommandEventRegistration icre in ircCommandEventRegistrations)
|
||||
{
|
||||
if (message.Command.ToLower().Equals(icre.Command.ToLower()))
|
||||
{
|
||||
icre.Handler(message);
|
||||
}
|
||||
}
|
||||
if (MessageReceived != null)
|
||||
{
|
||||
MessageReceived(message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Signal ChannelUserDatabaseChanged event.
|
||||
/// </summary>
|
||||
/// <param name="channel">Message that was received.</param>
|
||||
private void OnChannelUserDatabaseChanged(IrcChannel channel)
|
||||
{
|
||||
if (ChannelUserDatabaseChanged != null)
|
||||
{
|
||||
ChannelUserDatabaseChanged(channel);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start an asynchronous read.
|
||||
/// </summary>
|
||||
private void Receive()
|
||||
{
|
||||
if ((networkStream != null) && (networkStream.CanRead))
|
||||
{
|
||||
byte[] buffer = new byte[1024];
|
||||
networkStream.BeginRead(buffer, 0, buffer.Length,
|
||||
new AsyncCallback(ReadComplete),
|
||||
new StateObject(networkStream, buffer));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Socket is closed.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asynchronous read has completed.
|
||||
/// </summary>
|
||||
/// <param name="ar">IAsyncResult object.</param>
|
||||
private void ReadComplete(IAsyncResult ar)
|
||||
{
|
||||
StateObject stateObject = (StateObject) ar.AsyncState;
|
||||
if (stateObject.Stream.CanRead)
|
||||
{
|
||||
int bytesReceived = stateObject.Stream.EndRead(ar);
|
||||
if (bytesReceived > 0)
|
||||
{
|
||||
messageStream.Write(Encoding.GetString(stateObject.Buffer, 0, bytesReceived));
|
||||
while (messageStream.DataAvailable)
|
||||
{
|
||||
OnMessageReceived(new IrcMessage(messageStream.Read()));
|
||||
}
|
||||
}
|
||||
}
|
||||
Receive();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Locate channel.
|
||||
/// </summary>
|
||||
/// <param name="name">Channel name.</param>
|
||||
/// <returns>Channel or null if none was found.</returns>
|
||||
private IrcChannel LocateChannel(string name)
|
||||
{
|
||||
foreach (IrcChannel channel in Channels)
|
||||
{
|
||||
if (name.ToLower().Equals(channel.Name.ToLower()))
|
||||
{
|
||||
return channel;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send a PONG message when a PING message is received.
|
||||
/// </summary>
|
||||
/// <param name="message">Received IRC message.</param>
|
||||
private void PingMessageReceived(IrcMessage message)
|
||||
{
|
||||
SendMessage(new IrcMessage(IRC.PONG, message.Parameters));
|
||||
firstPingReceived = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process RPL_NAMREPLY message.
|
||||
/// </summary>
|
||||
/// <param name="message">Received IRC message.</param>
|
||||
private void RPL_NAMREPLYMessageReceived(IrcMessage message)
|
||||
{
|
||||
try
|
||||
{
|
||||
// :Oslo2.NO.EU.undernet.org 353 E101 = #E101 :E101 KongFu_uK @Exception
|
||||
/* "( "=" / "*" / "@" ) <channel>
|
||||
:[ "@" / "+" ] <nick> *( " " [ "@" / "+" ] <nick> )
|
||||
- "@" is used for secret channels, "*" for private
|
||||
channels, and "=" for others (public channels). */
|
||||
if (message.Parameters == null)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine(String.Format("Message has no parameters."));
|
||||
return;
|
||||
}
|
||||
string[] parameters = message.Parameters.Split(new char[] { ' '});
|
||||
if (parameters.Length < 5)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine(String.Format("{0} is two few parameters.", parameters.Length));
|
||||
return;
|
||||
}
|
||||
IrcChannelType type;
|
||||
switch (parameters[1])
|
||||
{
|
||||
case "=":
|
||||
type = IrcChannelType.Public;
|
||||
break;
|
||||
case "*":
|
||||
type = IrcChannelType.Private;
|
||||
break;
|
||||
case "@":
|
||||
type = IrcChannelType.Secret;
|
||||
break;
|
||||
default:
|
||||
type = IrcChannelType.Public;
|
||||
break;
|
||||
}
|
||||
IrcChannel channel = LocateChannel(parameters[2].Substring(1));
|
||||
if (channel == null)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine(String.Format("Channel not found '{0}'.",
|
||||
parameters[2].Substring(1)));
|
||||
return;
|
||||
}
|
||||
string nickname = parameters[3];
|
||||
if (nickname[0] != ':')
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine(String.Format("String should start with : and not {0}.", nickname[0]));
|
||||
return;
|
||||
}
|
||||
/* Skip : */
|
||||
IrcUser user = channel.LocateUser(nickname.Substring(1));
|
||||
if (user == null)
|
||||
{
|
||||
user = new IrcUser(nickname.Substring(1));
|
||||
channel.Users.Add(user);
|
||||
}
|
||||
for (int i = 4; i < parameters.Length; i++)
|
||||
{
|
||||
nickname = parameters[i];
|
||||
user = channel.LocateUser(nickname);
|
||||
if (user == null)
|
||||
{
|
||||
user = new IrcUser(nickname);
|
||||
channel.Users.Add(user);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine(String.Format("Ex. {0}", ex));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process RPL_ENDOFNAMES message.
|
||||
/// </summary>
|
||||
/// <param name="message">Received IRC message.</param>
|
||||
private void RPL_ENDOFNAMESMessageReceived(IrcMessage message)
|
||||
{
|
||||
try
|
||||
{
|
||||
/* <channel> :End of NAMES list */
|
||||
if (message.Parameters == null)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine(String.Format("Message has no parameters."));
|
||||
return;
|
||||
}
|
||||
|
||||
string[] parameters = message.Parameters.Split(new char[] { ' ' });
|
||||
IrcChannel channel = LocateChannel(parameters[1].Substring(1));
|
||||
if (channel == null)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine(String.Format("Channel not found '{0}'.",
|
||||
parameters[0].Substring(1)));
|
||||
return;
|
||||
}
|
||||
|
||||
OnChannelUserDatabaseChanged(channel);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine(String.Format("Ex. {0}", ex));
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Connect to the specified IRC server on the specified port.
|
||||
/// </summary>
|
||||
/// <param name="server">Address of IRC server.</param>
|
||||
/// <param name="port">Port of IRC server.</param>
|
||||
public void Connect(string server, int port)
|
||||
{
|
||||
if (connected)
|
||||
{
|
||||
throw new AlreadyConnectedException();
|
||||
}
|
||||
else
|
||||
{
|
||||
messageStream = new LineBuffer();
|
||||
tcpClient = new TcpClient();
|
||||
tcpClient.Connect(server, port);
|
||||
tcpClient.NoDelay = true;
|
||||
tcpClient.LingerState = new LingerOption(false, 0);
|
||||
networkStream = tcpClient.GetStream();
|
||||
connected = networkStream.CanRead && networkStream.CanWrite;
|
||||
if (!connected)
|
||||
{
|
||||
throw new Exception("Cannot read and write from socket.");
|
||||
}
|
||||
/* Install PING message handler */
|
||||
MonitorCommand(IRC.PING, new MessageReceivedHandler(PingMessageReceived));
|
||||
/* Install RPL_NAMREPLY message handler */
|
||||
MonitorCommand(IRC.RPL_NAMREPLY, new MessageReceivedHandler(RPL_NAMREPLYMessageReceived));
|
||||
/* Install RPL_ENDOFNAMES message handler */
|
||||
MonitorCommand(IRC.RPL_ENDOFNAMES, new MessageReceivedHandler(RPL_ENDOFNAMESMessageReceived));
|
||||
/* Start receiving data */
|
||||
Receive();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disconnect from IRC server.
|
||||
/// </summary>
|
||||
public void Diconnect()
|
||||
{
|
||||
if (!connected)
|
||||
{
|
||||
throw new NotConnectedException();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
|
||||
connected = false;
|
||||
tcpClient.Close();
|
||||
tcpClient = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send an IRC message.
|
||||
/// </summary>
|
||||
/// <param name="message">The message to be sent.</param>
|
||||
public void SendMessage(IrcMessage message)
|
||||
{
|
||||
if (!connected)
|
||||
{
|
||||
throw new NotConnectedException();
|
||||
}
|
||||
|
||||
/* Serialize sending messages */
|
||||
lock (typeof(IrcClient))
|
||||
{
|
||||
NetworkStream networkStream = tcpClient.GetStream();
|
||||
byte[] bytes = Encoding.GetBytes(message.Line);
|
||||
networkStream.Write(bytes, 0, bytes.Length);
|
||||
networkStream.Flush();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Monitor when a message with an IRC command is received.
|
||||
/// </summary>
|
||||
/// <param name="command">IRC command to monitor.</param>
|
||||
/// <param name="handler">Handler to call when command is received.</param>
|
||||
public void MonitorCommand(string command, MessageReceivedHandler handler)
|
||||
{
|
||||
if (command == null)
|
||||
{
|
||||
throw new ArgumentNullException("command", "Command cannot be null.");
|
||||
}
|
||||
if (handler == null)
|
||||
{
|
||||
throw new ArgumentNullException("handler", "Handler cannot be null.");
|
||||
}
|
||||
ircCommandEventRegistrations.Add(new IrcCommandEventRegistration(command, handler));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Talk to the channel.
|
||||
/// </summary>
|
||||
/// <param name="nickname">Nickname of user to talk to.</param>
|
||||
/// <param name="text">Text to send to the channel.</param>
|
||||
public void TalkTo(string nickname, string text)
|
||||
{
|
||||
if (nickname == null)
|
||||
{
|
||||
throw new ArgumentNullException("nickname", "Nickname cannot be null.");
|
||||
}
|
||||
if (text == null)
|
||||
{
|
||||
throw new ArgumentNullException("text", "Text cannot be null.");
|
||||
}
|
||||
|
||||
SendMessage(new IrcMessage(IRC.PRIVMSG, String.Format("{0} :{1}", nickname, text)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Change nickname.
|
||||
/// </summary>
|
||||
/// <param name="nickname">New nickname.</param>
|
||||
public void ChangeNick(string nickname)
|
||||
{
|
||||
if (nickname == null)
|
||||
{
|
||||
throw new ArgumentNullException("nickname", "Nickname cannot be null.");
|
||||
}
|
||||
|
||||
/* NICK <nickname> [ <hopcount> ] */
|
||||
SendMessage(new IrcMessage(IRC.NICK, nickname));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register.
|
||||
/// </summary>
|
||||
/// <param name="nickname">New nickname.</param>
|
||||
/// <param name="realname">Real name. Can be null.</param>
|
||||
public void Register(string nickname, string realname)
|
||||
{
|
||||
if (nickname == null)
|
||||
{
|
||||
throw new ArgumentNullException("nickname", "Nickname cannot be null.");
|
||||
}
|
||||
firstPingReceived = false;
|
||||
ChangeNick(nickname);
|
||||
/* OLD: USER <username> <hostname> <servername> <realname> */
|
||||
/* NEW: USER <user> <mode> <unused> <realname> */
|
||||
SendMessage(new IrcMessage(IRC.USER, String.Format("{0} 0 * :{1}",
|
||||
nickname, realname != null ? realname : "Anonymous")));
|
||||
|
||||
/* Wait for PING for up til 10 seconds */
|
||||
int timer = 0;
|
||||
while (!firstPingReceived && timer < 200)
|
||||
{
|
||||
System.Threading.Thread.Sleep(50);
|
||||
timer++;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Join an IRC channel.
|
||||
/// </summary>
|
||||
/// <param name="name">Name of channel (without leading #).</param>
|
||||
/// <returns>New channel.</returns>
|
||||
public IrcChannel JoinChannel(string name)
|
||||
{
|
||||
IrcChannel channel = new IrcChannel(this, name);
|
||||
channels.Add(channel);
|
||||
/* JOIN ( <channel> *( "," <channel> ) [ <key> *( "," <key> ) ] ) / "0" */
|
||||
SendMessage(new IrcMessage(IRC.JOIN, String.Format("#{0}", name)));
|
||||
return channel;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Part an IRC channel.
|
||||
/// </summary>
|
||||
/// <param name="channel">IRC channel. If null, the user parts from all channels.</param>
|
||||
/// <param name="message">Part message. Can be null.</param>
|
||||
public void PartChannel(IrcChannel channel, string message)
|
||||
{
|
||||
/* PART <channel> *( "," <channel> ) [ <Part Message> ] */
|
||||
if (channel != null)
|
||||
{
|
||||
SendMessage(new IrcMessage(IRC.PART, String.Format("#{0}{1}",
|
||||
channel.Name, message != null ? String.Format(" :{0}", message) : "")));
|
||||
channels.Remove(channel);
|
||||
}
|
||||
else
|
||||
{
|
||||
string channelList = null;
|
||||
foreach (IrcChannel myChannel in Channels)
|
||||
{
|
||||
if (channelList == null)
|
||||
{
|
||||
channelList = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
channelList += ",";
|
||||
}
|
||||
channelList += myChannel.Name;
|
||||
}
|
||||
if (channelList != null)
|
||||
{
|
||||
SendMessage(new IrcMessage(IRC.PART, String.Format("#{0}{1}",
|
||||
channelList, message != null ? String.Format(" :{0}", message) : "")));
|
||||
Channels.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
50
irc/TechBot/TechBot.IRCLibrary/IrcException.cs
Normal file
50
irc/TechBot/TechBot.IRCLibrary/IrcException.cs
Normal file
|
@ -0,0 +1,50 @@
|
|||
using System;
|
||||
|
||||
namespace TechBot.IRCLibrary
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for all IRC exceptions.
|
||||
/// </summary>
|
||||
public class IrcException : Exception
|
||||
{
|
||||
public IrcException() : base()
|
||||
{
|
||||
}
|
||||
|
||||
public IrcException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public IrcException(string message, Exception innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Thrown when there is no connection to an IRC server.
|
||||
/// </summary>
|
||||
public class NotConnectedException : IrcException
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Thrown when there is an attempt to connect to an IRC server and there is already a connection.
|
||||
/// </summary>
|
||||
public class AlreadyConnectedException : IrcException
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Thrown when there is attempted to parse a malformed or invalid IRC message.
|
||||
/// </summary>
|
||||
public class MalformedMessageException : IrcException
|
||||
{
|
||||
public MalformedMessageException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public MalformedMessageException(string message, Exception innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
503
irc/TechBot/TechBot.IRCLibrary/IrcMessage.cs
Normal file
503
irc/TechBot/TechBot.IRCLibrary/IrcMessage.cs
Normal file
|
@ -0,0 +1,503 @@
|
|||
using System;
|
||||
|
||||
namespace TechBot.IRCLibrary
|
||||
{
|
||||
/*
|
||||
<message> ::= [':' <prefix> <SPACE> ] <command> <params> <crlf>
|
||||
<prefix> ::= <servername> | <nick> [ '!' <user> ] [ '@' <host> ]
|
||||
<command> ::= <letter> { <letter> } | <number> <number> <number>
|
||||
<SPACE> ::= ' ' { ' ' }
|
||||
<params> ::= <SPACE> [ ':' <trailing> | <middle> <params> ]
|
||||
|
||||
<middle> ::= <Any *non-empty* sequence of octets not including SPACE
|
||||
or NUL or CR or LF, the first of which may not be ':'>
|
||||
<trailing> ::= <Any, possibly *empty*, sequence of octets not including
|
||||
NUL or CR or LF>
|
||||
|
||||
<crlf> ::= CR LF
|
||||
|
||||
NOTES:
|
||||
|
||||
1) <SPACE> is consists only of SPACE character(s) (0x20).
|
||||
Specially notice that TABULATION, and all other control
|
||||
characters are considered NON-WHITE-SPACE.
|
||||
|
||||
2) After extracting the parameter list, all parameters are equal,
|
||||
whether matched by <middle> or <trailing>. <Trailing> is just
|
||||
a syntactic trick to allow SPACE within parameter.
|
||||
|
||||
3) The fact that CR and LF cannot appear in parameter strings is
|
||||
just artifact of the message framing. This might change later.
|
||||
|
||||
4) The NUL character is not special in message framing, and
|
||||
basically could end up inside a parameter, but as it would
|
||||
cause extra complexities in normal C string handling. Therefore
|
||||
NUL is not allowed within messages.
|
||||
|
||||
5) The last parameter may be an empty string.
|
||||
|
||||
6) Use of the extended prefix (['!' <user> ] ['@' <host> ]) must
|
||||
not be used in server to server communications and is only
|
||||
intended for server to client messages in order to provide
|
||||
clients with more useful information about who a message is
|
||||
from without the need for additional queries.
|
||||
*/
|
||||
/*
|
||||
NOTICE AUTH :*** Looking up your hostname
|
||||
NOTICE AUTH :*** Checking Ident
|
||||
NOTICE AUTH :*** Found your hostname
|
||||
NOTICE AUTH :*** No ident response
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// IRC message.
|
||||
/// </summary>
|
||||
public class IrcMessage
|
||||
{
|
||||
#region Private fields
|
||||
private string line;
|
||||
private string prefix;
|
||||
private string prefixServername;
|
||||
private string prefixNickname;
|
||||
private string prefixUser;
|
||||
private string prefixHost;
|
||||
private string command;
|
||||
private string parameters;
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Line of text that is to be parsed as an IRC message.
|
||||
/// </summary>
|
||||
public string Line
|
||||
{
|
||||
get
|
||||
{
|
||||
return line;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Does the message have a prefix?
|
||||
/// </summary>
|
||||
public bool HasPrefix
|
||||
{
|
||||
get
|
||||
{
|
||||
return prefix != null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prefix or null if none exists.
|
||||
/// </summary>
|
||||
public string Prefix
|
||||
{
|
||||
get
|
||||
{
|
||||
return prefix;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Servername part of prefix or null if no prefix or servername exists.
|
||||
/// </summary>
|
||||
public string PrefixServername
|
||||
{
|
||||
get
|
||||
{
|
||||
return prefixServername;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Nickname part of prefix or null if no prefix or nick exists.
|
||||
/// </summary>
|
||||
public string PrefixNickname
|
||||
{
|
||||
get
|
||||
{
|
||||
return prefixNickname;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// User part of (extended) prefix or null if no (extended) prefix exists.
|
||||
/// </summary>
|
||||
public string PrefixUser
|
||||
{
|
||||
get
|
||||
{
|
||||
return prefixUser;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Host part of (extended) prefix or null if no (extended) prefix exists.
|
||||
/// </summary>
|
||||
public string PrefixHost
|
||||
{
|
||||
get
|
||||
{
|
||||
return prefixHost;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Command part of message.
|
||||
/// </summary>
|
||||
public string Command
|
||||
{
|
||||
get
|
||||
{
|
||||
return command;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Is command numeric?
|
||||
/// </summary>
|
||||
public bool IsCommandNumeric
|
||||
{
|
||||
get
|
||||
{
|
||||
if (command == null || command.Length != 3)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
try
|
||||
{
|
||||
Int32.Parse(command);
|
||||
return true;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Command part of message as text.
|
||||
/// </summary>
|
||||
public string CommandText
|
||||
{
|
||||
get
|
||||
{
|
||||
return command;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Command part of message as a number.
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException">Thrown if IsCommandNumeric returns false.</exception>
|
||||
public int CommandNumber
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsCommandNumeric)
|
||||
{
|
||||
return Int32.Parse(command);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parameters part of message.
|
||||
/// </summary>
|
||||
public string Parameters
|
||||
{
|
||||
get
|
||||
{
|
||||
return parameters;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="line">Line of text that is to be parsed as an IRC message.</param>
|
||||
public IrcMessage(string line)
|
||||
{
|
||||
/*
|
||||
* <message> ::= [':' <prefix> <SPACE> ] <command> <params> <crlf>
|
||||
* <prefix> ::= <servername> | <nick> [ '!' <user> ] [ '@' <host> ]
|
||||
* :Oslo1.NO.EU.undernet.org 461 MYNICK USER :Not enough parameters
|
||||
*/
|
||||
try
|
||||
{
|
||||
this.line = line;
|
||||
int i = 0;
|
||||
|
||||
#region Prefix
|
||||
if (line[i].Equals(':'))
|
||||
{
|
||||
i++;
|
||||
prefix = "";
|
||||
/* This message has a prefix */
|
||||
string s = "";
|
||||
while (i < line.Length && line[i] != ' ' && line[i] != '!' && line[i] != '@')
|
||||
{
|
||||
s += line[i++];
|
||||
}
|
||||
if (IsValidIrcNickname(s))
|
||||
{
|
||||
prefixNickname = s;
|
||||
prefix += prefixNickname;
|
||||
if (line[i] == '!')
|
||||
{
|
||||
/* This message has an extended prefix */
|
||||
i++;
|
||||
s = "";
|
||||
while (i < line.Length && line[i] != ' ' && line[i] != '@')
|
||||
{
|
||||
s += line[i];
|
||||
i++;
|
||||
}
|
||||
prefixUser = s;
|
||||
prefix += "!" + prefixUser;
|
||||
}
|
||||
if (line[i] == '@')
|
||||
{
|
||||
/* This message has a host prefix */
|
||||
s = "";
|
||||
do
|
||||
{
|
||||
s += line[++i];
|
||||
}
|
||||
while (i < line.Length && line[i] != ' ');
|
||||
prefixHost = s;
|
||||
prefix += "@" + prefixHost;
|
||||
}
|
||||
}
|
||||
else /* Assume it is a servername */
|
||||
{
|
||||
prefixServername = s;
|
||||
prefix += prefixServername;
|
||||
}
|
||||
|
||||
/* Skip spaces */
|
||||
while (i < line.Length && line[i] == ' ')
|
||||
{
|
||||
i++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
prefix = null;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Command
|
||||
if (Char.IsDigit(line[i]))
|
||||
{
|
||||
if (!Char.IsDigit(line, i + 1) || !Char.IsDigit(line, i + 2))
|
||||
{
|
||||
throw new Exception();
|
||||
}
|
||||
command = String.Format("{0}{1}{2}", line[i++], line[i++], line[i++]);
|
||||
}
|
||||
else
|
||||
{
|
||||
command = "";
|
||||
while (i < line.Length && Char.IsLetter(line[i]))
|
||||
{
|
||||
command += line[i];
|
||||
i++;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Parameters
|
||||
while (true)
|
||||
{
|
||||
/* Skip spaces */
|
||||
while (i < line.Length && line[i] == ' ')
|
||||
{
|
||||
i++;
|
||||
}
|
||||
if (i < line.Length && line[i].Equals(':'))
|
||||
{
|
||||
i++;
|
||||
|
||||
/* Trailing */
|
||||
while (i < line.Length && line[i] != ' ' && line[i] != '\r' && line[i] != '\n' && line[i] != 0)
|
||||
{
|
||||
if (parameters == null)
|
||||
{
|
||||
parameters = "";
|
||||
}
|
||||
parameters += line[i];
|
||||
i++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Middle */
|
||||
while (i < line.Length && line[i] != '\r' && line[i] != '\n' && line[i] != 0)
|
||||
{
|
||||
if (parameters == null)
|
||||
{
|
||||
parameters = "";
|
||||
}
|
||||
parameters += line[i];
|
||||
i++;
|
||||
}
|
||||
}
|
||||
if (i >= line.Length)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new MalformedMessageException("The message is malformed.", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="prefixServername"></param>
|
||||
/// <param name="prefixNickname"></param>
|
||||
/// <param name="prefixUser"></param>
|
||||
/// <param name="prefixHost"></param>
|
||||
/// <param name="command"></param>
|
||||
/// <param name="parameters"></param>
|
||||
public IrcMessage(string prefixServername,
|
||||
string prefixNickname,
|
||||
string prefixUser,
|
||||
string prefixHost,
|
||||
string command,
|
||||
string parameters)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="command">IRC command.</param>
|
||||
/// <param name="parameters">IRC command parameters. May be null if there are no parameters.</param>
|
||||
public IrcMessage(string command,
|
||||
string parameters)
|
||||
{
|
||||
if (command == null || !IsValidIrcCommand(command))
|
||||
{
|
||||
throw new ArgumentException("Command is not a valid IRC command.", "command");
|
||||
}
|
||||
/* An IRC message must not be longer than 512 characters (including terminating CRLF) */
|
||||
int parametersLength = (parameters != null) ? 1 + parameters.Length : 0;
|
||||
if (command.Length + parametersLength > 510)
|
||||
{
|
||||
throw new MalformedMessageException("IRC message cannot be longer than 512 characters.");
|
||||
}
|
||||
this.command = command;
|
||||
this.parameters = parameters;
|
||||
if (parameters != null)
|
||||
{
|
||||
this.line = String.Format("{0} {1}\r\n", command, parameters);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.line = String.Format("{0}\r\n", command);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns wether a string of text is a valid IRC command.
|
||||
/// </summary>
|
||||
/// <param name="command">The IRC command.</param>
|
||||
/// <returns>True, if <c ref="command">command</c> is a valid IRC command, false if not.</returns>
|
||||
private static bool IsValidIrcCommand(string command)
|
||||
{
|
||||
foreach (char c in command)
|
||||
{
|
||||
if (!Char.IsLetter(c))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private const string IrcSpecial = @"-[]\`^{}";
|
||||
private const string IrcSpecialNonSpecs = @"_";
|
||||
|
||||
/// <summary>
|
||||
/// Returns wether a character is an IRC special character.
|
||||
/// </summary>
|
||||
/// <param name="c">Character to test.</param>
|
||||
/// <returns>True if the character is an IRC special character, false if not.</returns>
|
||||
private static bool IsSpecial(char c)
|
||||
{
|
||||
foreach (char validCharacter in IrcSpecial)
|
||||
{
|
||||
if (c.Equals(validCharacter))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
foreach (char validCharacter in IrcSpecialNonSpecs)
|
||||
{
|
||||
if (c.Equals(validCharacter))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns wether a string of text is a valid IRC nickname.
|
||||
/// </summary>
|
||||
/// <param name="nickname">The IRC nickname.</param>
|
||||
/// <returns>True, if <c ref="nickname">nickname</c> is a valid IRC nickname, false if not.</returns>
|
||||
private static bool IsValidIrcNickname(string nickname)
|
||||
{
|
||||
/*
|
||||
* <nick> ::= <letter> { <letter> | <number> | <special> }
|
||||
* <letter> ::= 'a' ... 'z' | 'A' ... 'Z'
|
||||
* <number> ::= '0' ... '9'
|
||||
* <special> ::= '-' | '[' | ']' | '\' | '`' | '^' | '{' | '}'
|
||||
*/
|
||||
/* An IRC nicknmame must be 1 - 9 characters in length. We don't care so much if it is larger */
|
||||
if ((nickname.Length < 1) || (nickname.Length > 30))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
/* First character must be a letter. */
|
||||
if (!Char.IsLetter(nickname[0]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
/* Check the other valid characters for validity. */
|
||||
foreach (char c in nickname)
|
||||
{
|
||||
if (!Char.IsLetter(c) && !Char.IsDigit(c) && !IsSpecial(c))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write contents to a string.
|
||||
/// </summary>
|
||||
/// <returns>Contents as a string.</returns>
|
||||
public override string ToString()
|
||||
{
|
||||
return String.Format("Line({0})Prefix({1})Command({2})Parameters({3})",
|
||||
line, prefix != null ? prefix : "(null)",
|
||||
command != null ? command : "(null)",
|
||||
parameters != null ? parameters : "(null)");
|
||||
}
|
||||
}
|
||||
}
|
96
irc/TechBot/TechBot.IRCLibrary/IrcUser.cs
Normal file
96
irc/TechBot/TechBot.IRCLibrary/IrcUser.cs
Normal file
|
@ -0,0 +1,96 @@
|
|||
using System;
|
||||
|
||||
namespace TechBot.IRCLibrary
|
||||
{
|
||||
/// <summary>
|
||||
/// IRC user.
|
||||
/// </summary>
|
||||
public class IrcUser
|
||||
{
|
||||
#region Private fields
|
||||
|
||||
private string nickname;
|
||||
private string decoratedNickname;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public properties
|
||||
|
||||
/// <summary>
|
||||
/// Nickname of user.
|
||||
/// </summary>
|
||||
public string Nickname
|
||||
{
|
||||
get
|
||||
{
|
||||
return nickname;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decorated nickname of user.
|
||||
/// </summary>
|
||||
public string DecoratedNickname
|
||||
{
|
||||
get
|
||||
{
|
||||
return decoratedNickname;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wether user is channel operator.
|
||||
/// </summary>
|
||||
public bool Operator
|
||||
{
|
||||
get
|
||||
{
|
||||
return decoratedNickname.StartsWith("@");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wether user has voice.
|
||||
/// </summary>
|
||||
public bool Voice
|
||||
{
|
||||
get
|
||||
{
|
||||
return decoratedNickname.StartsWith("+");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="nickname">Nickname (possibly decorated) of user.</param>
|
||||
public IrcUser(string nickname)
|
||||
{
|
||||
this.decoratedNickname = nickname.Trim();
|
||||
this.nickname = StripDecoration(decoratedNickname);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Strip docoration of nickname.
|
||||
/// </summary>
|
||||
/// <param name="nickname">Possible decorated nickname.</param>
|
||||
/// <returns>Undecorated nickname.</returns>
|
||||
public static string StripDecoration(string decoratedNickname)
|
||||
{
|
||||
if (decoratedNickname.StartsWith("@"))
|
||||
{
|
||||
return decoratedNickname.Substring(1);
|
||||
}
|
||||
else if (decoratedNickname.StartsWith("+"))
|
||||
{
|
||||
return decoratedNickname.Substring(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
return decoratedNickname;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
16
irc/TechBot/TechBot.IRCLibrary/TechBot.IRCLibrary.cmbx
Normal file
16
irc/TechBot/TechBot.IRCLibrary/TechBot.IRCLibrary.cmbx
Normal file
|
@ -0,0 +1,16 @@
|
|||
<Combine fileversion="1.0" name="TechBot.IRCLibrary" description="">
|
||||
<StartMode startupentry="TechBot.IRCLibrary" single="True">
|
||||
<Execute entry="TechBot.IRCLibrary" type="None" />
|
||||
</StartMode>
|
||||
<Entries>
|
||||
<Entry filename=".\.\TechBot.IRCLibrary.prjx" />
|
||||
</Entries>
|
||||
<Configurations active="Debug">
|
||||
<Configuration name="Release">
|
||||
<Entry name="TechBot.IRCLibrary" configurationname="Debug" build="False" />
|
||||
</Configuration>
|
||||
<Configuration name="Debug">
|
||||
<Entry name="TechBot.IRCLibrary" configurationname="Debug" build="False" />
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
</Combine>
|
31
irc/TechBot/TechBot.IRCLibrary/TechBot.IRCLibrary.prjx
Normal file
31
irc/TechBot/TechBot.IRCLibrary/TechBot.IRCLibrary.prjx
Normal file
|
@ -0,0 +1,31 @@
|
|||
<Project name="TechBot.IRCLibrary" standardNamespace="TechBot.IRCLibrary" description="" newfilesearch="None" enableviewstate="True" version="1.1" projecttype="C#">
|
||||
<Contents>
|
||||
<File name=".\AssemblyInfo.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
|
||||
<File name=".\IrcException.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
|
||||
<File name=".\IRC.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
|
||||
<File name=".\IrcChannel.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
|
||||
<File name=".\IrcMessage.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
|
||||
<File name=".\IrcUser.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
|
||||
<File name=".\IrcClient.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
|
||||
<File name=".\Default.build" subtype="Code" buildaction="Nothing" dependson="" data="" />
|
||||
</Contents>
|
||||
<References />
|
||||
<DeploymentInformation target="" script="" strategy="File" />
|
||||
<Configuration runwithwarnings="True" name="Debug">
|
||||
<CodeGeneration runtime="MsNet" compiler="Csc" compilerversion="" warninglevel="4" nowarn="" includedebuginformation="True" optimize="False" unsafecodeallowed="False" generateoverflowchecks="True" mainclass="" target="Library" definesymbols="" generatexmldocumentation="False" win32Icon="" noconfig="False" nostdlib="False" />
|
||||
<Execution commandlineparameters="" consolepause="False" />
|
||||
<Output directory="..\bin\Debug" assembly="TechBot.IRCLibrary" executeScript="" executeBeforeBuild="" executeAfterBuild="" executeBeforeBuildArguments="" executeAfterBuildArguments="" />
|
||||
</Configuration>
|
||||
<Configurations active="Debug">
|
||||
<Configuration runwithwarnings="True" name="Debug">
|
||||
<CodeGeneration runtime="MsNet" compiler="Csc" compilerversion="" warninglevel="4" nowarn="" includedebuginformation="True" optimize="False" unsafecodeallowed="False" generateoverflowchecks="True" mainclass="" target="Library" definesymbols="" generatexmldocumentation="False" win32Icon="" noconfig="False" nostdlib="False" />
|
||||
<Execution commandlineparameters="" consolepause="False" />
|
||||
<Output directory="..\bin\Debug" assembly="TechBot.IRCLibrary" executeScript="" executeBeforeBuild="" executeAfterBuild="" executeBeforeBuildArguments="" executeAfterBuildArguments="" />
|
||||
</Configuration>
|
||||
<Configuration runwithwarnings="True" name="Release">
|
||||
<CodeGeneration runtime="MsNet" compiler="Csc" compilerversion="" warninglevel="4" nowarn="" includedebuginformation="False" optimize="True" unsafecodeallowed="False" generateoverflowchecks="False" mainclass="" target="Library" definesymbols="" generatexmldocumentation="False" win32Icon="" noconfig="False" nostdlib="False" />
|
||||
<Execution commandlineparameters="" consolepause="False" />
|
||||
<Output directory="..\bin\Release" assembly="TechBot.IRCLibrary" executeScript="" executeBeforeBuild="" executeAfterBuild="" executeBeforeBuildArguments="" executeAfterBuildArguments="" />
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
</Project>
|
Loading…
Add table
Add a link
Reference in a new issue