Support private messages
Modified: trunk/irc/TechBot/TechBot.IRCLibrary/IrcChannel.cs
Modified: trunk/irc/TechBot/TechBot.IRCLibrary/IrcClient.cs
Modified: trunk/irc/TechBot/TechBot.IRCLibrary/IrcMessage.cs
Modified: trunk/irc/TechBot/TechBot.IRCLibrary/IrcUser.cs
Modified: trunk/irc/TechBot/TechBot.Library/IrcService.cs
Modified: trunk/irc/TechBot/TechBot.Library/MessageContext.cs

Modified: trunk/irc/TechBot/TechBot.IRCLibrary/IrcChannel.cs
--- trunk/irc/TechBot/TechBot.IRCLibrary/IrcChannel.cs	2005-02-16 22:30:50 UTC (rev 13609)
+++ trunk/irc/TechBot/TechBot.IRCLibrary/IrcChannel.cs	2005-02-16 22:38:49 UTC (rev 13610)
@@ -128,7 +128,10 @@
 		/// <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)));
+			owner.SendMessage(new IrcMessage(IRC.PRIVMSG,
+			                                 String.Format("#{0} :{1}",
+			                                               name,
+			                                               text)));
 		}
 	}
 }

Modified: trunk/irc/TechBot/TechBot.IRCLibrary/IrcClient.cs
--- trunk/irc/TechBot/TechBot.IRCLibrary/IrcClient.cs	2005-02-16 22:30:50 UTC (rev 13609)
+++ trunk/irc/TechBot/TechBot.IRCLibrary/IrcClient.cs	2005-02-16 22:38:49 UTC (rev 13610)
@@ -391,7 +391,8 @@
 				IrcUser user = channel.LocateUser(nickname.Substring(1));
 				if (user == null)
 				{
-					user = new IrcUser(nickname.Substring(1));
+					user = new IrcUser(this,
+					                   nickname.Substring(1));
 					channel.Users.Add(user);
 				}
 				for (int i = 4; i < parameters.Length; i++)
@@ -400,7 +401,8 @@
 					user = channel.LocateUser(nickname);
 					if (user == null)
 					{
-						user = new IrcUser(nickname);
+						user = new IrcUser(this,
+						                   nickname);
 						channel.Users.Add(user);
 					}
 				}
@@ -509,7 +511,7 @@
 			{
 				throw new NotConnectedException();
 			}
-
+			
 			/* Serialize sending messages */
 			lock (typeof(IrcClient))
 			{
@@ -545,16 +547,6 @@
 		/// <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>

Modified: trunk/irc/TechBot/TechBot.IRCLibrary/IrcMessage.cs
--- trunk/irc/TechBot/TechBot.IRCLibrary/IrcMessage.cs	2005-02-16 22:30:50 UTC (rev 13609)
+++ trunk/irc/TechBot/TechBot.IRCLibrary/IrcMessage.cs	2005-02-16 22:38:49 UTC (rev 13610)
@@ -428,7 +428,7 @@
 		}
 
 		private const string IrcSpecial = @"-[]\`^{}";
-		private const string IrcSpecialNonSpecs = @"_";
+		private const string IrcSpecialNonSpecs = @"_|";
 
 		/// <summary>
 		/// Returns wether a character is an IRC special character.

Modified: trunk/irc/TechBot/TechBot.IRCLibrary/IrcUser.cs
--- trunk/irc/TechBot/TechBot.IRCLibrary/IrcUser.cs	2005-02-16 22:30:50 UTC (rev 13609)
+++ trunk/irc/TechBot/TechBot.IRCLibrary/IrcUser.cs	2005-02-16 22:38:49 UTC (rev 13610)
@@ -9,6 +9,7 @@
 	{
 		#region Private fields
 
+		private IrcClient owner;
 		private string nickname;
 		private string decoratedNickname;
 
@@ -17,6 +18,17 @@
 		#region Public properties
 
 		/// <summary>
+		/// Owner of this channel.
+		/// </summary>
+		public IrcClient Owner
+		{
+			get
+			{
+				return owner;
+			}
+		}
+
+		/// <summary>
 		/// Nickname of user.
 		/// </summary>
 		public string Nickname
@@ -65,14 +77,38 @@
 		/// <summary>
 		/// Constructor.
 		/// </summary>
+		/// <param name="owner">Owner of this channel.</param>
 		/// <param name="nickname">Nickname (possibly decorated) of user.</param>
-		public IrcUser(string nickname)
+		public IrcUser(IrcClient owner,
+		               string nickname)
 		{
+			if (owner == null)
+			{
+				throw new ArgumentNullException("owner", "Owner cannot be null.");
+			}
+			this.owner = owner;
 			this.decoratedNickname = nickname.Trim();
 			this.nickname = StripDecoration(decoratedNickname);
 		}
 
 		/// <summary>
+		/// Talk to the user.
+		/// </summary>
+		/// <param name="text">Text to send to the user.</param>
+		public void Talk(string text)
+		{
+			if (text == null)
+			{
+				throw new ArgumentNullException("text", "Text cannot be null.");
+			}
+
+			owner.SendMessage(new IrcMessage(IRC.PRIVMSG,
+			                                 String.Format("{0} :{1}",
+			                                               nickname,
+			                                               text)));
+		}
+
+		/// <summary>
 		/// Strip docoration of nickname.
 		/// </summary>
 		/// <param name="nickname">Possible decorated nickname.</param>

Modified: trunk/irc/TechBot/TechBot.Library/IrcService.cs
--- trunk/irc/TechBot/TechBot.Library/IrcService.cs	2005-02-16 22:30:50 UTC (rev 13609)
+++ trunk/irc/TechBot/TechBot.Library/IrcService.cs	2005-02-16 22:38:49 UTC (rev 13610)
@@ -104,13 +104,44 @@
 			}
 		}
 
+		private string GetMessageSource(MessageContext context)
+		{
+			if (context is ChannelMessageContext)
+			{
+				ChannelMessageContext channelContext = context as ChannelMessageContext;
+				return String.Format("#{0}",
+				                     channelContext.Channel.Name);
+			}
+			else if (context is UserMessageContext)
+			{
+				UserMessageContext userContext = context as UserMessageContext;
+				return userContext.User.Nickname;
+			}
+			else
+			{
+				throw new InvalidOperationException(String.Format("Unhandled message context '{0}'",
+				                                                  context.GetType()));
+			}
+		}
+
 		public void WriteLine(MessageContext context,
 		                      string message)
 		{
-			Console.WriteLine(String.Format("Sending: {0} to #{1}",
-			                                message,
-			                                context.Channel != null ? context.Channel.Name : "(null)"));
-			context.Channel.Talk(message);
+			if (context is ChannelMessageContext)
+			{
+				ChannelMessageContext channelContext = context as ChannelMessageContext;
+				channelContext.Channel.Talk(message);
+			}
+			else if (context is UserMessageContext)
+			{
+				UserMessageContext userContext = context as UserMessageContext;
+				userContext.User.Talk(message);
+			}
+			else
+			{
+				throw new InvalidOperationException(String.Format("Unhandled message context '{0}'",
+				                                                  context.GetType()));
+			}
 		}
 
 		private void ExtractMessage(string parameters,
@@ -139,16 +170,36 @@
 			int index = message.Parameters.IndexOf(' ');
 			if (index == -1)
 				index = message.Parameters.Length;
-			channelName = message.Parameters.Substring(1, index - 1);
+			else
+				index = index - 1;
+			channelName = message.Parameters.Substring(1, index);
 			return true;
 		}
 
+		private bool GetTargetNickname(IrcMessage message,
+		                               out string nickname)
+		{
+			if (message.Parameters == null)
+			{
+				nickname = null;
+				return false;
+			}
+
+			int index = message.Parameters.IndexOf(' ');
+			if (index == -1)
+				index = message.Parameters.Length;
+			nickname = message.Parameters.Substring(0, index);
+			Console.WriteLine("nickname: " + nickname);
+			return true;
+		}
+
 		private bool ShouldAcceptMessage(IrcMessage message,
 		                                 out MessageContext context)
 		{
 			if (message.Command.ToUpper().Equals("PRIVMSG"))
 			{
 				string channelName;
+				string nickname;
 				if (GetChannelName(message,
 				                   out channelName))
 				{
@@ -156,11 +207,24 @@
 					{
 						if (String.Compare(channel.Name, channelName, true) == 0)
 						{
-							context = new MessageContext(channel);
+							context = new ChannelMessageContext(channel);
 							return true;
 						}
 					}
 				}
+				else if (GetTargetNickname(message,
+				                           out nickname))
+				{
+					IrcUser targetUser = new IrcUser(client,
+					                                 nickname);
+					if (String.Compare(targetUser.Nickname, botname, true) == 0)
+					{
+						IrcUser sourceUser = new IrcUser(client,
+						                                 message.PrefixNickname);
+						context = new UserMessageContext(sourceUser);
+						return true;
+					}
+				}
 			}
 			context = null;
 			return false;
@@ -180,9 +244,9 @@
 					if (ShouldAcceptMessage(message,
 					                        out context))
 					{
-						Console.WriteLine(String.Format("Injecting: {0} from #{1}",
+						Console.WriteLine(String.Format("Injecting: {0} from {1}",
 						                                injectMessage,
-						                                context.Channel.Name));
+						                                GetMessageSource(context)));
 						service.InjectMessage(context,
 						                      injectMessage);
 					}

Modified: trunk/irc/TechBot/TechBot.Library/MessageContext.cs
--- trunk/irc/TechBot/TechBot.Library/MessageContext.cs	2005-02-16 22:30:50 UTC (rev 13609)
+++ trunk/irc/TechBot/TechBot.Library/MessageContext.cs	2005-02-16 22:38:49 UTC (rev 13610)
@@ -3,8 +3,14 @@
 
 namespace TechBot.Library
 {
-	public class MessageContext
+	public abstract class MessageContext
 	{
+	}
+
+
+
+	public class ChannelMessageContext : MessageContext
+	{
 		private IrcChannel channel;
 
 		public IrcChannel Channel
@@ -15,9 +21,29 @@
 			}
 		}
 		
-		public MessageContext(IrcChannel channel)
+		public ChannelMessageContext(IrcChannel channel)
 		{
 			this.channel = channel;
 		}
 	}
+
+	
+	
+	public class UserMessageContext : MessageContext
+	{
+		private IrcUser user;
+
+		public IrcUser User
+		{
+			get
+			{
+				return user;
+			}
+		}
+		
+		public UserMessageContext(IrcUser user)
+		{
+			this.user = user;
+		}
+	}
 }