mirror of
https://github.com/reactos/reactos.git
synced 2024-11-20 06:15:26 +00:00
197cc3f634
svn path=/trunk/; revision=35264
794 lines
21 KiB
C#
794 lines
21 KiB
C#
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);
|
||
|
||
public delegate void OnConnectHandler ();
|
||
public delegate void OnDisconnectHandler();
|
||
public delegate void OnConnectionLostHandler();
|
||
|
||
/// <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 bool awaitingGhostDeath = 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();
|
||
private string reqNickname;
|
||
private string curNickname;
|
||
private string password;
|
||
#endregion
|
||
|
||
#region Public events
|
||
|
||
public event MessageReceivedHandler MessageReceived;
|
||
|
||
public event ChannelUserDatabaseChangedHandler ChannelUserDatabaseChanged;
|
||
|
||
public event OnConnectHandler OnConnect;
|
||
public event OnConnectionLostHandler OnConnectionLost;
|
||
public event OnDisconnectHandler OnDisconnect;
|
||
|
||
#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;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Nickname for the bot.
|
||
/// </summary>
|
||
public string Nickname
|
||
{
|
||
get
|
||
{
|
||
return curNickname;
|
||
}
|
||
}
|
||
#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)
|
||
{
|
||
try
|
||
{
|
||
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();
|
||
}
|
||
catch (SocketException)
|
||
{
|
||
if (OnConnectionLost != null)
|
||
OnConnectionLost();
|
||
}
|
||
catch (IOException)
|
||
{
|
||
if (OnConnectionLost != null)
|
||
OnConnectionLost();
|
||
}
|
||
catch (Exception)
|
||
{
|
||
if (OnConnectionLost != null)
|
||
OnConnectionLost();
|
||
}
|
||
}
|
||
|
||
/// <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>
|
||
/// Send a PONG message when a PING message is received.
|
||
/// </summary>
|
||
/// <param name="message">Received IRC message.</param>
|
||
private void NoticeMessageReceived(IrcMessage message)
|
||
{
|
||
if (awaitingGhostDeath)
|
||
{
|
||
string str = string.Format("{0} has been ghosted", reqNickname);
|
||
if (message.Parameters.Contains(str))
|
||
{
|
||
ChangeNick(reqNickname);
|
||
SubmitPassword(password);
|
||
awaitingGhostDeath = false;
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <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(this,
|
||
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(this,
|
||
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));
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Process ERR_NICKNAMEINUSE message.
|
||
/// </summary>
|
||
/// <param name="message">Received IRC message.</param>
|
||
private void ERR_NICKNAMEINUSEMessageReceived(IrcMessage message)
|
||
{
|
||
try
|
||
{
|
||
if (message.Parameters == null)
|
||
{
|
||
System.Diagnostics.Debug.WriteLine(String.Format("Message has no parameters."));
|
||
return;
|
||
}
|
||
|
||
/* Connect with a different name */
|
||
string[] parameters = message.Parameters.Split(new char[] { ' ' });
|
||
string nickname = parameters[1];
|
||
ChangeNick(nickname + "__");
|
||
}
|
||
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 NOTICE message handler */
|
||
MonitorCommand(IRC.NOTICE, new MessageReceivedHandler(NoticeMessageReceived));
|
||
/* 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));
|
||
/* Install ERR_NICKNAMEINUSE message handler */
|
||
MonitorCommand(IRC.ERR_NICKNAMEINUSE, new MessageReceivedHandler(ERR_NICKNAMEINUSEMessageReceived));
|
||
/* 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;
|
||
|
||
if (OnDisconnect != null)
|
||
OnDisconnect();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Send an IRC message.
|
||
/// </summary>
|
||
/// <param name="message">The message to be sent.</param>
|
||
public void SendMessage(IrcMessage message)
|
||
{
|
||
try
|
||
{
|
||
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();
|
||
}
|
||
}
|
||
catch (SocketException)
|
||
{
|
||
if (OnConnectionLost != null)
|
||
OnConnectionLost();
|
||
}
|
||
catch (IOException)
|
||
{
|
||
if (OnConnectionLost != null)
|
||
OnConnectionLost();
|
||
}
|
||
catch (Exception)
|
||
{
|
||
if (OnConnectionLost != null)
|
||
OnConnectionLost();
|
||
}
|
||
}
|
||
|
||
/// <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)
|
||
{
|
||
}
|
||
|
||
/// <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.");
|
||
|
||
Console.WriteLine("Changing nick to {0}\n", nickname);
|
||
curNickname = nickname;
|
||
|
||
/* NICK <nickname> [ <hopcount> ] */
|
||
SendMessage(new IrcMessage(IRC.NICK, nickname));
|
||
}
|
||
|
||
/// <summary>
|
||
/// Ghost nickname.
|
||
/// </summary>
|
||
/// <param name="nickname">Nickname.</param>
|
||
public void GhostNick(string nickname,
|
||
string password)
|
||
{
|
||
if (nickname == null)
|
||
throw new ArgumentNullException("nickname", "Nickname cannot be null.");
|
||
|
||
if (password == null)
|
||
throw new ArgumentNullException("password", "Password cannot be null.");
|
||
|
||
awaitingGhostDeath = true;
|
||
|
||
/* GHOST <nickname> <password> */
|
||
SendMessage(new IrcMessage(IRC.GHOST, nickname + " " + password));
|
||
}
|
||
|
||
/// <summary>
|
||
/// Submit password to identify user.
|
||
/// </summary>
|
||
/// <param name="password">Password of registered nick.</param>
|
||
private void SubmitPassword(string password)
|
||
{
|
||
if (password == null)
|
||
throw new ArgumentNullException("password", "Password cannot be null.");
|
||
|
||
this.password = password;
|
||
|
||
/* PASS <password> */
|
||
SendMessage(new IrcMessage(IRC.PASS, password));
|
||
}
|
||
|
||
/// <summary>
|
||
/// Register.
|
||
/// </summary>
|
||
/// <param name="nickname">New nickname.</param>
|
||
/// <param name="password">Password. Can be null.</param>
|
||
/// <param name="realname">Real name. Can be null.</param>
|
||
public void Register(string nickname,
|
||
string password,
|
||
string realname)
|
||
{
|
||
if (nickname == null)
|
||
throw new ArgumentNullException("nickname", "Nickname cannot be null.");
|
||
reqNickname = nickname;
|
||
firstPingReceived = false;
|
||
if (password != null)
|
||
{
|
||
SubmitPassword(password);
|
||
}
|
||
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();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|