+++ /dev/null
-<?xml version="1.0"?>\r
-<project name="TechBot" default="build">\r
-\r
- <target name="build" description="Build components">\r
- <delete dir="bin" failonerror="false" />\r
- <nant buildfile="Compression/Default.build" />\r
- <nant buildfile="CHMLibrary/Default.build" />\r
- <nant buildfile="TechBot.IRCLibrary/Default.build" />\r
- <nant buildfile="TechBot.Library/Default.build" />\r
- <nant buildfile="TechBot.Console/Default.build" />\r
- <nant buildfile="TechBot/Default.build" />\r
- </target>\r
-\r
-</project>\r
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+using TechBot.Library;
+
+namespace TechBot.Console
+{
+ public class ConsoleServiceOutput : IServiceOutput
+ {
+ public void WriteLine(MessageContext context,
+ string message)
+ {
+ System.Console.WriteLine(message);
+ }
+ }
+
+ public class ConsoleTechBotService : TechBotService
+ {
+ public ConsoleTechBotService(
+ string chmPath,
+ string mainChm)
+ : base(new ConsoleServiceOutput(), chmPath, mainChm)
+ {
+ }
+
+ public override void Run()
+ {
+ //Call the base class
+ base.Run();
+
+ while (true)
+ {
+ string s = System.Console.ReadLine();
+ InjectMessage(null, s);
+ }
+ }
+ }
+}
\r
namespace TechBot.Console\r
{\r
- public class ConsoleServiceOutput : IServiceOutput\r
- {\r
- public void WriteLine(MessageContext context,\r
- string message)\r
- {\r
- System.Console.WriteLine(message);\r
- }\r
- }\r
-\r
- \r
class MainClass\r
{\r
private static void VerifyRequiredOption(string optionName,\r
}\r
\r
\r
- private static void RunIrcService()\r
- {\r
- IrcService ircService = new IrcService(IRCServerHostName,\r
- IRCServerHostPort,\r
- IRCChannelNames,\r
- IRCBotName,\r
- IRCBotPassword,\r
- ChmPath,\r
- MainChm,\r
- //NtstatusXml,\r
- //WinerrorXml,\r
- //HresultXml,\r
- //WmXml,\r
- //SvnCommand,\r
- BugUrl,\r
- WineBugUrl,\r
- SambaBugUrl);\r
- ircService.Run();\r
- }\r
- \r
- public static void Main(string[] args)\r
- {\r
- if (args.Length > 0 && args[0].ToLower().Equals("irc"))\r
- {\r
- RunIrcService();\r
- return;\r
- }\r
- \r
- System.Console.WriteLine("TechBot running console service...");\r
- TechBotService service = new TechBotService(new ConsoleServiceOutput(),\r
- ChmPath,\r
- MainChm);\r
- //NtstatusXml,\r
- //WinerrorXml,\r
- //HresultXml,\r
- //WmXml,\r
- //SvnCommand,\r
- //BugUrl,\r
- //WineBugUrl,\r
- //SambaBugUrl);\r
- service.Run();\r
- while (true)\r
- {\r
- string s = System.Console.ReadLine();\r
- service.InjectMessage(null,\r
- s);\r
- }\r
- }\r
+ //private static void RunIrcService()\r
+ //{\r
+ // IrcTechBotService ircService = new IrcTechBotService(IRCServerHostName,\r
+ // IRCServerHostPort,\r
+ // IRCChannelNames,\r
+ // IRCBotName,\r
+ // IRCBotPassword,\r
+ // ChmPath,\r
+ // MainChm);\r
+ // ircService.Run();\r
+ //}\r
+\r
+ public static void Main(string[] args)\r
+ {\r
+ TechBotService m_TechBot = null;\r
+\r
+ if (args.Length > 0 && args[0].ToLower().Equals("irc"))\r
+ {\r
+ m_TechBot = new IrcTechBotService(IRCServerHostName,\r
+ IRCServerHostPort,\r
+ IRCChannelNames,\r
+ IRCBotName,\r
+ IRCBotPassword,\r
+ ChmPath,\r
+ MainChm);\r
+ }\r
+ else\r
+ {\r
+ System.Console.WriteLine("TechBot running console service...");\r
+ m_TechBot = new ConsoleTechBotService(\r
+ ChmPath,\r
+ MainChm);\r
+\r
+\r
+ }\r
+\r
+ m_TechBot.Run();\r
+ }\r
}\r
-}\r
+}
\ No newline at end of file
-->
<ItemGroup>
<Compile Include="AssemblyInfo.cs" />
+ <Compile Include="ConsoleTechBotService.cs" />
<Compile Include="Main.cs" />
</ItemGroup>
<ItemGroup>
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace TechBot.Library
+{
+ public class CommandAttribute : Attribute
+ {
+ private string m_Name = null;
+ private string m_Help = "No help for this command is available";
+ private string m_Desc = "No description for this command is available";
+
+ public CommandAttribute(string name)
+ {
+ m_Name = name;
+ }
+
+ public string Name
+ {
+ get { return m_Name; }
+ }
+
+ public string Help
+ {
+ get { return m_Help; }
+ set { m_Help = value; }
+ }
+
+ public string Description
+ {
+ get { return m_Desc; }
+ set { m_Desc = value; }
+ }
+ }
+}
--- /dev/null
+using System;
+
+namespace TechBot.Library
+{
+ /// <summary>
+ /// This class implements an alias attribute to work in conjunction
+ /// with the <see cref="CommandLineSwitchAttribute">CommandLineSwitchAttribute</see>
+ /// attribute. If the CommandLineSwitchAttribute exists, then this attribute
+ /// defines an alias for it.
+ /// </summary>
+ [AttributeUsage( AttributeTargets.Property )]
+ public class CommandParameterAliasAttribute : Attribute
+ {
+ #region Private Variables
+ protected string m_Alias = "";
+ #endregion
+
+ #region Public Properties
+ public string Alias
+ {
+ get { return m_Alias; }
+ }
+
+ #endregion
+
+ #region Constructors
+ public CommandParameterAliasAttribute(string alias)
+ {
+ m_Alias = alias;
+ }
+ #endregion
+ }
+
+}
--- /dev/null
+using System;
+
+namespace TechBot.Library
+{
+ /// <summary>Implements a basic command-line switch by taking the
+ /// switching name and the associated description.</summary>
+ /// <remark>Only currently is implemented for properties, so all
+ /// auto-switching variables should have a get/set method supplied.</remark>
+ [AttributeUsage( AttributeTargets.Property )]
+ public class CommandParameterAttribute : Attribute
+ {
+ #region Private Variables
+ private string m_name = "";
+ private string m_description = "";
+ private bool m_Required = true;
+ #endregion
+
+ #region Public Properties
+ /// <summary>Accessor for retrieving the switch-name for an associated
+ /// property.</summary>
+ public string Name { get { return m_name; } }
+
+ /// <summary>Accessor for retrieving the description for a switch of
+ /// an associated property.</summary>
+ public string Description { get { return m_description; } }
+
+ public bool Required { get { return m_Required; } }
+
+ #endregion
+
+ #region Constructors
+
+ /// <summary>
+ /// Attribute constructor.
+ /// </summary>
+ public CommandParameterAttribute(string name, string description)
+ {
+ m_name = name;
+ m_description = description;
+ }
+ #endregion
+ }
+}
+++ /dev/null
-using System;\r
-\r
-namespace TechBot.Library\r
-{\r
- public abstract class BugCommand : Command//, ICommand\r
- {\r
- public BugCommand(TechBotService techBot) : base (techBot)\r
- {\r
- }\r
-\r
- public override void Handle(MessageContext context,\r
- string commandName,\r
- string parameters)\r
- {\r
- string bugText = parameters;\r
- if (bugText.Equals(String.Empty))\r
- {\r
- TechBot.ServiceOutput.WriteLine(context,\r
- "Please provide a valid bug number.");\r
- return;\r
- }\r
-\r
- NumberParser np = new NumberParser();\r
- long bug = np.Parse(bugText);\r
- if (np.Error)\r
- {\r
- TechBot.ServiceOutput.WriteLine(context,\r
- String.Format("{0} is not a valid bug number.",\r
- bugText));\r
- return;\r
- }\r
-\r
- /*\r
- string bugUrl = this.RosBugUrl;\r
-\r
- if (context is ChannelMessageContext)\r
- {\r
- ChannelMessageContext channelContext = context as ChannelMessageContext;\r
- if (channelContext.Channel.Name == "winehackers")\r
- bugUrl = this.WineBugUrl;\r
- else if (channelContext.Channel.Name == "samba-technical")\r
- bugUrl = this.SambaBugUrl;\r
- }*/\r
-\r
- TechBot.ServiceOutput.WriteLine(context, String.Format(BugUrl, bug));\r
- }\r
-\r
- protected abstract string BugUrl { get; }\r
- }\r
-}\r
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace TechBot.Library
+{
+ public class CommandBuilderCollection : List<CommandBuilder>
+ {
+ public CommandBuilder Find(string name)
+ {
+ foreach (CommandBuilder command in this)
+ {
+ if (command.Name == name)
+ return command;
+ }
+
+ return null;
+ }
+ }
+}
+++ /dev/null
-using System;
-
-namespace TechBot.Library
-{
- /*
- public interface ICommand
- {
- bool CanHandle(string commandName);
- void Handle(MessageContext context,
- string commandName,
- string parameters);
- //string Help();
- }*/
-
- public abstract class Command
- {
- protected TechBotService m_TechBotService = null;
-
- public Command(TechBotService techbot)
- {
- m_TechBotService = techbot;
- }
-
- public TechBotService TechBot
- {
- get { return m_TechBotService; }
- }
-
- public abstract string[] AvailableCommands { get; }
-
- public abstract void Handle(MessageContext context,
- string commandName,
- string parameters);
-
- /*
- protected bool CanHandle(string commandName,
- string[] availableCommands)
- {
- foreach (string availableCommand in availableCommands)
- {
- if (String.Compare(availableCommand, commandName, true) == 0)
- return true;
- }
- return false;
- }
- */
-
- public virtual string Help()
- {
- return "No help is available for this command";
- }
- }
-}
-using System;\r
-using System.IO;\r
-using System.Data;\r
-using System.Text.RegularExpressions;\r
-using HtmlHelp;\r
-using HtmlHelp.ChmDecoding;\r
-\r
-namespace TechBot.Library\r
-{\r
- public class ApiCommand : Command\r
- {\r
- private const bool IsVerbose = false;\r
-\r
- private HtmlHelpSystem chm;\r
- private string chmPath;\r
- private string mainChm;\r
-\r
- public ApiCommand(TechBotService techBot)\r
- : base(techBot)\r
- {\r
- Run();\r
- }\r
- \r
- private void WriteIfVerbose(MessageContext context,\r
- string message)\r
- {\r
- if (IsVerbose)\r
- TechBot.ServiceOutput.WriteLine(context,\r
- message);\r
- }\r
-\r
- private void Run()\r
- {\r
- string CHMFilename = Path.Combine(chmPath, mainChm);\r
- chm = new HtmlHelpSystem();\r
- chm.OpenFile(CHMFilename, null);\r
- \r
- Console.WriteLine(String.Format("Loaded main CHM: {0}",\r
- Path.GetFileName(CHMFilename)));\r
- foreach (string filename in Directory.GetFiles(chmPath))\r
- {\r
- if (!Path.GetExtension(filename).ToLower().Equals(".chm"))\r
- continue;\r
- if (Path.GetFileName(filename).ToLower().Equals(mainChm))\r
- continue;\r
-\r
- Console.WriteLine(String.Format("Loading CHM: {0}",\r
- Path.GetFileName(filename)));\r
- try\r
- {\r
- chm.MergeFile(filename);\r
- }\r
- catch (Exception ex)\r
- {\r
- Console.WriteLine(String.Format("Could not load CHM: {0}. Exception {1}",\r
- Path.GetFileName(filename),\r
- ex));\r
- }\r
- }\r
- Console.WriteLine(String.Format("Loaded {0} CHMs",\r
- chm.FileList.Length));\r
- }\r
-\r
- public override string[] AvailableCommands\r
- {\r
- get { return new string[] { "api" }; }\r
- }\r
-\r
- /*\r
- public bool CanHandle(string commandName)\r
- {\r
- return CanHandle(commandName,\r
- new string[] { "api" });\r
- }\r
-*/\r
- \r
- public override void Handle(MessageContext context,\r
- string commandName,\r
- string parameters)\r
- {\r
- if (parameters.Trim().Equals(String.Empty))\r
- DisplayNoKeyword(context);\r
- else\r
- Search(context,\r
- parameters);\r
- }\r
-\r
- public override string Help()\r
- {\r
- return "!api <apiname>";\r
- }\r
- \r
- private bool SearchIndex(MessageContext context,\r
- string keyword)\r
- {\r
- if (chm.HasIndex)\r
- {\r
- IndexItem item = chm.Index.SearchIndex(keyword,\r
- IndexType.KeywordLinks);\r
- if (item != null && item.Topics.Count > 0)\r
- {\r
- WriteIfVerbose(context,\r
- String.Format("Keyword {0} found in index",\r
- item.KeyWord));\r
- IndexTopic indexTopic = item.Topics[0] as IndexTopic;\r
- return DisplayResult(context,\r
- keyword,\r
- indexTopic);\r
- }\r
- else\r
- {\r
- WriteIfVerbose(context,\r
- String.Format("Keyword {0} not found in index",\r
- keyword));\r
- return false;\r
- }\r
- }\r
- else\r
- return false;\r
- }\r
-\r
- private void SearchFullText(MessageContext context,\r
- string keyword)\r
- {\r
- string sort = "Rating ASC";\r
- WriteIfVerbose(context,\r
- String.Format("Searching fulltext database for {0}",\r
- keyword));\r
-\r
- bool partialMatches = false;\r
- bool titlesOnly = true;\r
- int maxResults = 100;\r
- DataTable results = chm.PerformSearch(keyword,\r
- maxResults,\r
- partialMatches,\r
- titlesOnly);\r
- WriteIfVerbose(context,\r
- String.Format("results.Rows.Count = {0}",\r
- results != null ?\r
- results.Rows.Count.ToString() : "(none)"));\r
- if (results != null && results.Rows.Count > 0)\r
- {\r
- results.DefaultView.Sort = sort;\r
- if (!DisplayResult(context,\r
- keyword,\r
- results))\r
- {\r
- DisplayNoResult(context,\r
- keyword);\r
- }\r
- }\r
- else\r
- {\r
- DisplayNoResult(context,\r
- keyword);\r
- }\r
- }\r
-\r
- private void Search(MessageContext context,\r
- string keyword)\r
- {\r
- if (!SearchIndex(context,\r
- keyword))\r
- SearchFullText(context,\r
- keyword);\r
- }\r
- \r
- private bool DisplayResult(MessageContext context,\r
- string keyword,\r
- IndexTopic indexTopic)\r
- {\r
- keyword = keyword.Trim().ToLower();\r
- string url = indexTopic.URL;\r
- WriteIfVerbose(context,\r
- String.Format("URL from index search {0}",\r
- url));\r
- string prototype = ExtractPrototype(context,\r
- url);\r
- if (prototype == null || prototype.Trim().Equals(String.Empty))\r
- return false;\r
- string formattedPrototype = FormatPrototype(prototype);\r
- TechBot.ServiceOutput.WriteLine(context,\r
- formattedPrototype);\r
- return true;\r
- }\r
- \r
- private bool DisplayResult(MessageContext context,\r
- string keyword,\r
- DataTable results)\r
- {\r
- keyword = keyword.Trim().ToLower();\r
- for (int i = 0; i < results.DefaultView.Count; i++)\r
- {\r
- DataRowView row = results.DefaultView[i];\r
- string title = row["Title"].ToString();\r
- WriteIfVerbose(context,\r
- String.Format("Examining {0}", title));\r
- if (title.Trim().ToLower().Equals(keyword))\r
- {\r
- string location = row["Location"].ToString();\r
- string rating = row["Rating"].ToString();\r
- string url = row["Url"].ToString();\r
- string prototype = ExtractPrototype(context,\r
- url);\r
- if (prototype == null || prototype.Trim().Equals(String.Empty))\r
- continue;\r
- string formattedPrototype = FormatPrototype(prototype);\r
- TechBot.ServiceOutput.WriteLine(context,\r
- formattedPrototype);\r
- return true;\r
- }\r
- }\r
- return false;\r
- }\r
-\r
- private void DisplayNoResult(MessageContext context,\r
- string keyword)\r
- {\r
- TechBot.ServiceOutput.WriteLine(context,\r
- String.Format("I don't know about keyword {0}",\r
- keyword));\r
- }\r
-\r
- private void DisplayNoKeyword(MessageContext context)\r
- {\r
- TechBot.ServiceOutput.WriteLine(context,\r
- "Please give me a keyword.");\r
- }\r
-\r
- private string ReplaceComments(string s)\r
- {\r
- return Regex.Replace(s, "//(.+)\r\n", "");\r
- }\r
-\r
- private string ReplaceLineEndings(string s)\r
- {\r
- return Regex.Replace(s, "(\r\n)+", " ");\r
- }\r
-\r
- private string ReplaceSpaces(string s)\r
- {\r
- return Regex.Replace(s, @" +", " ");\r
- }\r
- \r
- private string ReplaceSpacesBeforeLeftParenthesis(string s)\r
- {\r
- return Regex.Replace(s, @"\( ", @"(");\r
- }\r
-\r
- private string ReplaceSpacesBeforeRightParenthesis(string s)\r
- {\r
- return Regex.Replace(s, @" \)", @")");\r
- }\r
-\r
- private string ReplaceSemicolon(string s)\r
- {\r
- return Regex.Replace(s, @";", @"");\r
- }\r
-\r
- private string FormatPrototype(string prototype)\r
- {\r
- string s = ReplaceComments(prototype);\r
- s = ReplaceLineEndings(s);\r
- s = ReplaceSpaces(s);\r
- s = ReplaceSpacesBeforeLeftParenthesis(s);\r
- s = ReplaceSpacesBeforeRightParenthesis(s);\r
- s = ReplaceSemicolon(s);\r
- return s;\r
- }\r
- \r
- private string ExtractPrototype(MessageContext context,\r
- string url)\r
- {\r
- string page = GetPage(context,\r
- url);\r
- Match match = Regex.Match(page,\r
- "<PRE class=\"?syntax\"?>(.+)</PRE>",\r
- RegexOptions.Multiline |\r
- RegexOptions.Singleline);\r
- if (match.Groups.Count > 1)\r
- {\r
- string prototype = match.Groups[1].ToString();\r
- return StripHtml(StripAfterSlashPre(prototype));\r
- }\r
- \r
- return "";\r
- }\r
- \r
- private string StripAfterSlashPre(string html)\r
- {\r
- int index = html.IndexOf("</PRE>");\r
- if (index != -1)\r
- {\r
- return html.Substring(0, index);\r
- }\r
- else\r
- return html;\r
- }\r
- \r
- private string StripHtml(string html)\r
- {\r
- return Regex.Replace(html, @"<(.|\n)*?>", String.Empty);\r
- }\r
-\r
- private string GetPage(MessageContext context,\r
- string url)\r
- {\r
- string CHMFileName = "";\r
- string topicName = "";\r
- string anchor = "";\r
- CHMStream.CHMStream baseStream;\r
- if (!chm.BaseStream.GetCHMParts(url, ref CHMFileName, ref topicName, ref anchor))\r
- {\r
- baseStream = chm.BaseStream;\r
- CHMFileName = baseStream.CHMFileName;\r
- topicName = url;\r
- anchor = "";\r
- }\r
- else\r
- {\r
- baseStream = GetBaseStreamFromCHMFileName(context,\r
- CHMFileName);\r
- }\r
-\r
- if ((topicName == "") || (CHMFileName == "") || (baseStream == null))\r
- {\r
- return "";\r
- }\r
-\r
- return baseStream.ExtractTextFile(topicName);\r
- }\r
-\r
- private CHMStream.CHMStream GetBaseStreamFromCHMFileName(MessageContext context,\r
- string CHMFileName)\r
- {\r
- foreach (CHMFile file in chm.FileList)\r
- {\r
- WriteIfVerbose(context,\r
- String.Format("Compare: {0} <> {1}",\r
- file.ChmFilePath,\r
- CHMFileName));\r
- if (file.ChmFilePath.ToLower().Equals(CHMFileName.ToLower()))\r
- {\r
- return file.BaseStream;\r
- }\r
- }\r
- WriteIfVerbose(context,\r
- String.Format("Could not find loaded CHM file in list: {0}",\r
- CHMFileName));\r
- return null;\r
- }\r
- }\r
-}\r
+using System;
+using System.IO;
+using System.Data;
+using System.Text.RegularExpressions;
+using HtmlHelp;
+using HtmlHelp.ChmDecoding;
+
+namespace TechBot.Library
+{
+ [Command("api", Help = "!api <apiname>")]
+ public class ApiCommand : Command
+ {
+ private const bool IsVerbose = false;
+
+ private HtmlHelpSystem chm;
+ private string chmPath;
+ private string mainChm;
+
+ public ApiCommand()
+ {
+ Run();
+ }
+
+ private void WriteIfVerbose(MessageContext context,
+ string message)
+ {
+ if (IsVerbose)
+ TechBot.ServiceOutput.WriteLine(context,
+ message);
+ }
+
+ private void Run()
+ {
+ string CHMFilename = Path.Combine(chmPath, mainChm);
+ chm = new HtmlHelpSystem();
+ chm.OpenFile(CHMFilename, null);
+
+ Console.WriteLine(String.Format("Loaded main CHM: {0}",
+ Path.GetFileName(CHMFilename)));
+ foreach (string filename in Directory.GetFiles(chmPath))
+ {
+ if (!Path.GetExtension(filename).ToLower().Equals(".chm"))
+ continue;
+ if (Path.GetFileName(filename).ToLower().Equals(mainChm))
+ continue;
+
+ Console.WriteLine(String.Format("Loading CHM: {0}",
+ Path.GetFileName(filename)));
+ try
+ {
+ chm.MergeFile(filename);
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine(String.Format("Could not load CHM: {0}. Exception {1}",
+ Path.GetFileName(filename),
+ ex));
+ }
+ }
+ Console.WriteLine(String.Format("Loaded {0} CHMs",
+ chm.FileList.Length));
+ }
+
+ public override void Handle(MessageContext context)
+ {
+ if (parameters.Trim().Equals(String.Empty))
+ DisplayNoKeyword(context);
+ else
+ Search(context,
+ parameters);
+ }
+
+ private bool SearchIndex(MessageContext context,
+ string keyword)
+ {
+ if (chm.HasIndex)
+ {
+ IndexItem item = chm.Index.SearchIndex(keyword,
+ IndexType.KeywordLinks);
+ if (item != null && item.Topics.Count > 0)
+ {
+ WriteIfVerbose(context,
+ String.Format("Keyword {0} found in index",
+ item.KeyWord));
+ IndexTopic indexTopic = item.Topics[0] as IndexTopic;
+ return DisplayResult(context,
+ keyword,
+ indexTopic);
+ }
+ else
+ {
+ WriteIfVerbose(context,
+ String.Format("Keyword {0} not found in index",
+ keyword));
+ return false;
+ }
+ }
+ else
+ return false;
+ }
+
+ private void SearchFullText(MessageContext context,
+ string keyword)
+ {
+ string sort = "Rating ASC";
+ WriteIfVerbose(context,
+ String.Format("Searching fulltext database for {0}",
+ keyword));
+
+ bool partialMatches = false;
+ bool titlesOnly = true;
+ int maxResults = 100;
+ DataTable results = chm.PerformSearch(keyword,
+ maxResults,
+ partialMatches,
+ titlesOnly);
+ WriteIfVerbose(context,
+ String.Format("results.Rows.Count = {0}",
+ results != null ?
+ results.Rows.Count.ToString() : "(none)"));
+ if (results != null && results.Rows.Count > 0)
+ {
+ results.DefaultView.Sort = sort;
+ if (!DisplayResult(context,
+ keyword,
+ results))
+ {
+ DisplayNoResult(context,
+ keyword);
+ }
+ }
+ else
+ {
+ DisplayNoResult(context,
+ keyword);
+ }
+ }
+
+ private void Search(MessageContext context,
+ string keyword)
+ {
+ if (!SearchIndex(context,
+ keyword))
+ SearchFullText(context,
+ keyword);
+ }
+
+ private bool DisplayResult(MessageContext context,
+ string keyword,
+ IndexTopic indexTopic)
+ {
+ keyword = keyword.Trim().ToLower();
+ string url = indexTopic.URL;
+ WriteIfVerbose(context,
+ String.Format("URL from index search {0}",
+ url));
+ string prototype = ExtractPrototype(context,
+ url);
+ if (prototype == null || prototype.Trim().Equals(String.Empty))
+ return false;
+ string formattedPrototype = FormatPrototype(prototype);
+ TechBot.ServiceOutput.WriteLine(context,
+ formattedPrototype);
+ return true;
+ }
+
+ private bool DisplayResult(MessageContext context,
+ string keyword,
+ DataTable results)
+ {
+ keyword = keyword.Trim().ToLower();
+ for (int i = 0; i < results.DefaultView.Count; i++)
+ {
+ DataRowView row = results.DefaultView[i];
+ string title = row["Title"].ToString();
+ WriteIfVerbose(context,
+ String.Format("Examining {0}", title));
+ if (title.Trim().ToLower().Equals(keyword))
+ {
+ string location = row["Location"].ToString();
+ string rating = row["Rating"].ToString();
+ string url = row["Url"].ToString();
+ string prototype = ExtractPrototype(context,
+ url);
+ if (prototype == null || prototype.Trim().Equals(String.Empty))
+ continue;
+ string formattedPrototype = FormatPrototype(prototype);
+ TechBot.ServiceOutput.WriteLine(context,
+ formattedPrototype);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void DisplayNoResult(MessageContext context,
+ string keyword)
+ {
+ TechBot.ServiceOutput.WriteLine(context,
+ String.Format("I don't know about keyword {0}",
+ keyword));
+ }
+
+ private void DisplayNoKeyword(MessageContext context)
+ {
+ TechBot.ServiceOutput.WriteLine(context,
+ "Please give me a keyword.");
+ }
+
+ private string ReplaceComments(string s)
+ {
+ return Regex.Replace(s, "//(.+)\r\n", "");
+ }
+
+ private string ReplaceLineEndings(string s)
+ {
+ return Regex.Replace(s, "(\r\n)+", " ");
+ }
+
+ private string ReplaceSpaces(string s)
+ {
+ return Regex.Replace(s, @" +", " ");
+ }
+
+ private string ReplaceSpacesBeforeLeftParenthesis(string s)
+ {
+ return Regex.Replace(s, @"\( ", @"(");
+ }
+
+ private string ReplaceSpacesBeforeRightParenthesis(string s)
+ {
+ return Regex.Replace(s, @" \)", @")");
+ }
+
+ private string ReplaceSemicolon(string s)
+ {
+ return Regex.Replace(s, @";", @"");
+ }
+
+ private string FormatPrototype(string prototype)
+ {
+ string s = ReplaceComments(prototype);
+ s = ReplaceLineEndings(s);
+ s = ReplaceSpaces(s);
+ s = ReplaceSpacesBeforeLeftParenthesis(s);
+ s = ReplaceSpacesBeforeRightParenthesis(s);
+ s = ReplaceSemicolon(s);
+ return s;
+ }
+
+ private string ExtractPrototype(MessageContext context,
+ string url)
+ {
+ string page = GetPage(context,
+ url);
+ Match match = Regex.Match(page,
+ "<PRE class=\"?syntax\"?>(.+)</PRE>",
+ RegexOptions.Multiline |
+ RegexOptions.Singleline);
+ if (match.Groups.Count > 1)
+ {
+ string prototype = match.Groups[1].ToString();
+ return StripHtml(StripAfterSlashPre(prototype));
+ }
+
+ return "";
+ }
+
+ private string StripAfterSlashPre(string html)
+ {
+ int index = html.IndexOf("</PRE>");
+ if (index != -1)
+ {
+ return html.Substring(0, index);
+ }
+ else
+ return html;
+ }
+
+ private string StripHtml(string html)
+ {
+ return Regex.Replace(html, @"<(.|\n)*?>", String.Empty);
+ }
+
+ private string GetPage(MessageContext context,
+ string url)
+ {
+ string CHMFileName = "";
+ string topicName = "";
+ string anchor = "";
+ CHMStream.CHMStream baseStream;
+ if (!chm.BaseStream.GetCHMParts(url, ref CHMFileName, ref topicName, ref anchor))
+ {
+ baseStream = chm.BaseStream;
+ CHMFileName = baseStream.CHMFileName;
+ topicName = url;
+ anchor = "";
+ }
+ else
+ {
+ baseStream = GetBaseStreamFromCHMFileName(context,
+ CHMFileName);
+ }
+
+ if ((topicName == "") || (CHMFileName == "") || (baseStream == null))
+ {
+ return "";
+ }
+
+ return baseStream.ExtractTextFile(topicName);
+ }
+
+ private CHMStream.CHMStream GetBaseStreamFromCHMFileName(MessageContext context,
+ string CHMFileName)
+ {
+ foreach (CHMFile file in chm.FileList)
+ {
+ WriteIfVerbose(context,
+ String.Format("Compare: {0} <> {1}",
+ file.ChmFilePath,
+ CHMFileName));
+ if (file.ChmFilePath.ToLower().Equals(CHMFileName.ToLower()))
+ {
+ return file.BaseStream;
+ }
+ }
+ WriteIfVerbose(context,
+ String.Format("Could not find loaded CHM file in list: {0}",
+ CHMFileName));
+ return null;
+ }
+ }
+}
--- /dev/null
+using System;
+
+namespace TechBot.Library
+{
+ public abstract class Command
+ {
+ protected TechBotService m_TechBotService = null;
+ protected MessageContext m_Context = null;
+
+ public TechBotService TechBot
+ {
+ get { return m_TechBotService; }
+ set { m_TechBotService = value; }
+ }
+
+ public MessageContext Context
+ {
+ get { return m_Context; }
+ set { m_Context = value; }
+ }
+
+ public string Name
+ {
+ get
+ {
+ CommandAttribute commandAttribute = (CommandAttribute)
+ Attribute.GetCustomAttribute(GetType(), typeof(CommandAttribute));
+
+ return commandAttribute.Name;
+ }
+ }
+
+ public void ParseParameters(string paramaters)
+ {
+ ParametersParser parser = new ParametersParser(paramaters, this);
+ parser.Parse();
+ }
+
+ protected virtual void Say(string message)
+ {
+ TechBot.ServiceOutput.WriteLine(Context, message);
+ }
+
+ protected virtual void Say(string format , params object[] args)
+ {
+ TechBot.ServiceOutput.WriteLine(Context, String.Format(format, args));
+ }
+
+ public abstract void ExecuteCommand();
+ }
+}
{
protected XmlDocument m_XmlDocument;
- public XmlCommand(TechBotService techBot)
- : base(techBot)
+ public XmlCommand()
{
m_XmlDocument = new XmlDocument();
m_XmlDocument.Load(XmlFile);
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace TechBot.Library
+{
+ public abstract class XmlLookupCommand : XmlCommand
+ {
+ private string m_Text = null;
+
+ [CommandParameter("text", "The value to check")]
+ public string Text
+ {
+ get { return m_Text; }
+ set { m_Text = value; }
+ }
+ }
+}
--- /dev/null
+using System;
+
+namespace TechBot.Library
+{
+ public abstract class BugCommand : Command
+ {
+ private string m_BugID = null;
+
+ public BugCommand()
+ {
+ }
+
+ [CommandParameter("id", "The bug ID")]
+ public string BugID
+ {
+ get { return m_BugID; }
+ set { m_BugID = value; }
+ }
+
+ public override void ExecuteCommand()
+ {
+ if (BugID == null)
+ {
+ Say("Please provide a valid bug number.");
+ }
+ else
+ {
+ try
+ {
+ Say(BugUrl, Int32.Parse(BugID));
+ }
+ catch (Exception)
+ {
+ Say("{0} is not a valid bug number.", BugID);
+ }
+ }
+ }
+
+ protected abstract string BugUrl { get; }
+ }
+}
-using System;\r
-using System.Xml;\r
-using System.Collections;\r
-\r
-namespace TechBot.Library\r
-{\r
- public class ErrorCommand : Command\r
- {\r
- private NtStatusCommand ntStatus;\r
- private WinerrorCommand winerror;\r
- private HResultCommand hresult;\r
-\r
- public ErrorCommand(TechBotService techBot)\r
- : base(techBot)\r
- {\r
- this.ntStatus = new NtStatusCommand(techBot);\r
- this.winerror = new WinerrorCommand(techBot);\r
- this.hresult = new HResultCommand(techBot);\r
- }\r
- \r
- /*\r
- public bool CanHandle(string commandName)\r
- {\r
- return CanHandle(commandName,\r
- new string[] { "error" });\r
- }\r
- */\r
-\r
- public override string[] AvailableCommands\r
- {\r
- get { return new string[] { "error" }; }\r
- }\r
-\r
- private static int GetSeverity(long error)\r
- {\r
- return (int)((error >> 30) & 0x3);\r
- }\r
-\r
- private static bool IsCustomer(long error)\r
- {\r
- return (error & 0x20000000) != 0;\r
- }\r
- \r
- private static bool IsReserved(long error)\r
- {\r
- return (error & 0x10000000) != 0;\r
- }\r
-\r
- private static int GetFacility(long error)\r
- {\r
- return (int)((error >> 16) & 0xFFF);\r
- }\r
- \r
- private static short GetCode(long error)\r
- {\r
- return (short)((error >> 0) & 0xFFFF);\r
- }\r
-\r
- private static string FormatSeverity(long error)\r
- {\r
- int severity = GetSeverity(error);\r
- switch (severity)\r
- {\r
- case 0: return "SUCCESS";\r
- case 1: return "INFORMATIONAL";\r
- case 2: return "WARNING";\r
- case 3: return "ERROR";\r
- }\r
- return null;\r
- }\r
-\r
- private static string FormatFacility(long error)\r
- {\r
- int facility = GetFacility(error);\r
- return facility.ToString();\r
- }\r
-\r
- private static string FormatCode(long error)\r
- {\r
- int code = GetCode(error);\r
- return code.ToString();\r
- }\r
-\r
- public override void Handle(MessageContext context,\r
- string commandName,\r
- string parameters)\r
- {\r
- string originalErrorText = parameters.Trim();\r
- if (originalErrorText.Equals(String.Empty))\r
- {\r
- TechBot.ServiceOutput.WriteLine(context,\r
- "Please provide an Error Code.");\r
- return;\r
- }\r
- \r
- string errorText = originalErrorText;\r
-\r
- retry:\r
- NumberParser np = new NumberParser();\r
- long error = np.Parse(errorText);\r
- if (np.Error)\r
- {\r
- TechBot.ServiceOutput.WriteLine(context,\r
- String.Format("{0} is not a valid Error Code.",\r
- originalErrorText));\r
- return;\r
- }\r
- \r
- ArrayList descriptions = new ArrayList();\r
-\r
- // Error is out of bounds\r
- if ((ulong)error > uint.MaxValue)\r
- {\r
- // Do nothing\r
- }\r
- // Error is outside of the range [0, 65535]: it cannot be a plain Win32 error code\r
- else if ((ulong)error > ushort.MaxValue)\r
- {\r
- // Customer bit is set: custom error code\r
- if (IsCustomer(error))\r
- {\r
- string description = String.Format("[custom, severity {0}, facility {1}, code {2}]",\r
- FormatSeverity(error),\r
- FormatFacility(error),\r
- FormatCode(error));\r
- descriptions.Add(description);\r
- }\r
- // Reserved bit is set: HRESULT_FROM_NT(ntstatus)\r
- else if (IsReserved(error))\r
- {\r
- int status = (int)(error & 0xCFFFFFFF);\r
- string description = ntStatus.GetNtstatusDescription(status);\r
- \r
- if (description == null)\r
- description = status.ToString("X");\r
- \r
- description = String.Format("HRESULT_FROM_NT({0})", description);\r
- descriptions.Add(description);\r
- }\r
- // Win32 facility: HRESULT_FROM_WIN32(winerror)\r
- else if (GetFacility(error) == 7)\r
- {\r
- // Must be an error code\r
- if (GetSeverity(error) == 2)\r
- {\r
- short err = GetCode(error);\r
- string description = winerror.GetWinerrorDescription(err);\r
- \r
- if (description == null)\r
- description = err.ToString("D");\r
- \r
- description = String.Format("HRESULT_FROM_WIN32({0})", description);\r
- descriptions.Add(description);\r
- }\r
- }\r
- }\r
-\r
- string winerrorDescription = winerror.GetWinerrorDescription(error);\r
- string ntstatusDescription = ntStatus.GetNtstatusDescription(error);\r
- string hresultDescription = hresult.GetHresultDescription(error);\r
- \r
- if (winerrorDescription != null)\r
- descriptions.Add(winerrorDescription);\r
- if (ntstatusDescription != null)\r
- descriptions.Add(ntstatusDescription);\r
- if (hresultDescription != null)\r
- descriptions.Add(hresultDescription);\r
-\r
- if (descriptions.Count == 0)\r
- {\r
- // Last chance heuristics: attempt to parse a 8-digit decimal as hexadecimal\r
- if (errorText.Length == 8)\r
- {\r
- errorText = "0x" + errorText;\r
- goto retry;\r
- }\r
-\r
- TechBot.ServiceOutput.WriteLine(context,\r
- String.Format("I don't know about Error Code {0}.",\r
- originalErrorText));\r
- }\r
- else if (descriptions.Count == 1)\r
- {\r
- string description = (string)descriptions[0];\r
- TechBot.ServiceOutput.WriteLine(context,\r
- String.Format("{0} is {1}.",\r
- originalErrorText,\r
- description));\r
- }\r
- else\r
- {\r
- TechBot.ServiceOutput.WriteLine(context,\r
- String.Format("{0} could be:",\r
- originalErrorText));\r
- \r
- foreach(string description in descriptions)\r
- TechBot.ServiceOutput.WriteLine(context, String.Format("\t{0}", description));\r
- }\r
- }\r
-\r
- public override string Help()\r
- {\r
- return "!error <value>";\r
- }\r
- }\r
-}\r
+using System;
+using System.Xml;
+using System.Collections;
+
+namespace TechBot.Library
+{
+ [Command("error", Help = "!error <value>")]
+ public class ErrorCommand : Command
+ {
+ private NtStatusCommand ntStatus;
+ private WinErrorCommand winerror;
+ private HResultCommand hresult;
+
+ public ErrorCommand()
+ {
+ this.ntStatus = new NtStatusCommand();
+ this.winerror = new WinErrorCommand();
+ this.hresult = new HResultCommand();
+ }
+
+ private static int GetSeverity(long error)
+ {
+ return (int)((error >> 30) & 0x3);
+ }
+
+ private static bool IsCustomer(long error)
+ {
+ return (error & 0x20000000) != 0;
+ }
+
+ private static bool IsReserved(long error)
+ {
+ return (error & 0x10000000) != 0;
+ }
+
+ private static int GetFacility(long error)
+ {
+ return (int)((error >> 16) & 0xFFF);
+ }
+
+ private static short GetCode(long error)
+ {
+ return (short)((error >> 0) & 0xFFFF);
+ }
+
+ private static string FormatSeverity(long error)
+ {
+ int severity = GetSeverity(error);
+ switch (severity)
+ {
+ case 0: return "SUCCESS";
+ case 1: return "INFORMATIONAL";
+ case 2: return "WARNING";
+ case 3: return "ERROR";
+ }
+ return null;
+ }
+
+ private static string FormatFacility(long error)
+ {
+ int facility = GetFacility(error);
+ return facility.ToString();
+ }
+
+ private static string FormatCode(long error)
+ {
+ int code = GetCode(error);
+ return code.ToString();
+ }
+
+ public override void Handle(MessageContext context)
+ {
+ if (Text.Equals(String.Empty))
+ {
+ TechBot.ServiceOutput.WriteLine(context,
+ "Please provide an Error Code.");
+ return;
+ }
+
+ string errorText = originalErrorText;
+
+ retry:
+ NumberParser np = new NumberParser();
+ long error = np.Parse(errorText);
+ if (np.Error)
+ {
+ TechBot.ServiceOutput.WriteLine(context,
+ String.Format("{0} is not a valid Error Code.",
+ originalErrorText));
+ return;
+ }
+
+ ArrayList descriptions = new ArrayList();
+
+ // Error is out of bounds
+ if ((ulong)error > uint.MaxValue)
+ {
+ // Do nothing
+ }
+ // Error is outside of the range [0, 65535]: it cannot be a plain Win32 error code
+ else if ((ulong)error > ushort.MaxValue)
+ {
+ // Customer bit is set: custom error code
+ if (IsCustomer(error))
+ {
+ string description = String.Format("[custom, severity {0}, facility {1}, code {2}]",
+ FormatSeverity(error),
+ FormatFacility(error),
+ FormatCode(error));
+ descriptions.Add(description);
+ }
+ // Reserved bit is set: HRESULT_FROM_NT(ntstatus)
+ else if (IsReserved(error))
+ {
+ int status = (int)(error & 0xCFFFFFFF);
+ string description = ntStatus.GetNtstatusDescription(status);
+
+ if (description == null)
+ description = status.ToString("X");
+
+ description = String.Format("HRESULT_FROM_NT({0})", description);
+ descriptions.Add(description);
+ }
+ // Win32 facility: HRESULT_FROM_WIN32(winerror)
+ else if (GetFacility(error) == 7)
+ {
+ // Must be an error code
+ if (GetSeverity(error) == 2)
+ {
+ short err = GetCode(error);
+ string description = winerror.GetWinerrorDescription(err);
+
+ if (description == null)
+ description = err.ToString("D");
+
+ description = String.Format("HRESULT_FROM_WIN32({0})", description);
+ descriptions.Add(description);
+ }
+ }
+ }
+
+ string winerrorDescription = winerror.GetWinerrorDescription(error);
+ string ntstatusDescription = ntStatus.GetNtstatusDescription(error);
+ string hresultDescription = hresult.GetHresultDescription(error);
+
+ if (winerrorDescription != null)
+ descriptions.Add(winerrorDescription);
+ if (ntstatusDescription != null)
+ descriptions.Add(ntstatusDescription);
+ if (hresultDescription != null)
+ descriptions.Add(hresultDescription);
+
+ if (descriptions.Count == 0)
+ {
+ // Last chance heuristics: attempt to parse a 8-digit decimal as hexadecimal
+ if (errorText.Length == 8)
+ {
+ errorText = "0x" + errorText;
+ goto retry;
+ }
+
+ TechBot.ServiceOutput.WriteLine(context,
+ String.Format("I don't know about Error Code {0}.",
+ originalErrorText));
+ }
+ else if (descriptions.Count == 1)
+ {
+ string description = (string)descriptions[0];
+ TechBot.ServiceOutput.WriteLine(context,
+ String.Format("{0} is {1}.",
+ originalErrorText,
+ description));
+ }
+ else
+ {
+ TechBot.ServiceOutput.WriteLine(context,
+ String.Format("{0} could be:",
+ originalErrorText));
+
+ foreach(string description in descriptions)
+ TechBot.ServiceOutput.WriteLine(context, String.Format("\t{0}", description));
+ }
+ }
+ }
+}
--- /dev/null
+using System;
+using System.Collections;
+
+namespace TechBot.Library
+{
+ [Command("help", Help = "!help")]
+ public class HelpCommand : Command
+ {
+ private string m_CommandName = null;
+
+ public HelpCommand()
+ {
+ }
+
+ [CommandParameter("Name", "The command name to show help")]
+ public string CommandName
+ {
+ get { return m_CommandName; }
+ set { m_CommandName = value; }
+ }
+
+ public override void ExecuteCommand()
+ {
+ if (CommandName == null)
+ {
+ Say("I support the following commands:");
+
+ foreach (CommandBuilder command in TechBot.Commands)
+ {
+ Say("!{0} - {1}",
+ command.Name,
+ command.Description);
+ }
+ }
+ else
+ {
+ CommandBuilder cmdBuilder = TechBot.Commands.Find(CommandName);
+
+ if (cmdBuilder == null)
+ {
+ Say("Command '{0}' is not recognized. Type '!help' to show all available commands", CommandName);
+ }
+ else
+ {
+ Say("Command '{0}' help:", CommandName);
+ Say("");
+ }
+ }
+ }
+ }
+}
-using System;\r
-using System.Xml;\r
-\r
-namespace TechBot.Library\r
-{\r
- public class HResultCommand : XmlCommand\r
- {\r
- public HResultCommand(TechBotService techBot)\r
- : base(techBot)\r
- {\r
- }\r
-\r
- public override string XmlFile\r
- {\r
- get { return Settings.Default.HResultXml; }\r
- }\r
-\r
- public override string[] AvailableCommands\r
- {\r
- get { return new string[] { "hresult" }; }\r
- }\r
-\r
- /*\r
- public bool CanHandle(string commandName)\r
- {\r
- return CanHandle(commandName,\r
- new string[] { "hresult" });\r
- }\r
- */\r
-\r
- public override void Handle(MessageContext context,\r
- string commandName,\r
- string parameters)\r
- {\r
- string hresultText = parameters;\r
- if (hresultText.Equals(String.Empty))\r
- {\r
- TechBot.ServiceOutput.WriteLine(context,\r
- "Please provide a valid HRESULT value.");\r
- return;\r
- }\r
-\r
- NumberParser np = new NumberParser();\r
- long hresult = np.Parse(hresultText);\r
- if (np.Error)\r
- {\r
- TechBot.ServiceOutput.WriteLine(context,\r
- String.Format("{0} is not a valid HRESULT value.",\r
- hresultText));\r
- return;\r
- }\r
- \r
- string description = GetHresultDescription(hresult);\r
- if (description != null)\r
- {\r
- TechBot.ServiceOutput.WriteLine(context,\r
- String.Format("{0} is {1}.",\r
- hresultText,\r
- description));\r
- }\r
- else\r
- {\r
- TechBot.ServiceOutput.WriteLine(context,\r
- String.Format("I don't know about HRESULT {0}.",\r
- hresultText));\r
- }\r
- }\r
- \r
- public override string Help()\r
- {\r
- return "!hresult <value>";\r
- }\r
- \r
- public string GetHresultDescription(long hresult)\r
- {\r
- XmlElement root = base.m_XmlDocument.DocumentElement;\r
- XmlNode node = root.SelectSingleNode(String.Format("Hresult[@value='{0}']",\r
- hresult.ToString("X8")));\r
- if (node != null)\r
- {\r
- XmlAttribute text = node.Attributes["text"];\r
- if (text == null)\r
- throw new Exception("Node has no text attribute.");\r
- return text.Value;\r
- }\r
- else\r
- return null;\r
- }\r
- }\r
-}\r
+using System;
+using System.Xml;
+
+namespace TechBot.Library
+{
+ [Command("hresult", Help = "!hresult <value>")]
+ public class HResultCommand : XmlLookupCommand
+ {
+ public HResultCommand()
+ {
+ }
+
+ public override string XmlFile
+ {
+ get { return Settings.Default.HResultXml; }
+ }
+
+ public override void ExecuteCommand()
+ {
+ if (Text.Equals(String.Empty))
+ {
+ TechBot.ServiceOutput.WriteLine(Context,
+ "Please provide a valid HRESULT value.");
+ return;
+ }
+
+ NumberParser np = new NumberParser();
+ long hresult = np.Parse(Text);
+ if (np.Error)
+ {
+ TechBot.ServiceOutput.WriteLine(Context,
+ String.Format("{0} is not a valid HRESULT value.",
+ Text));
+ return;
+ }
+
+ string description = GetHresultDescription(hresult);
+ if (description != null)
+ {
+ TechBot.ServiceOutput.WriteLine(Context,
+ String.Format("{0} is {1}.",
+ Text,
+ description));
+ }
+ else
+ {
+ TechBot.ServiceOutput.WriteLine(Context,
+ String.Format("I don't know about HRESULT {0}.",
+ Text));
+ }
+ }
+
+ public string GetHresultDescription(long hresult)
+ {
+ XmlElement root = base.m_XmlDocument.DocumentElement;
+ XmlNode node = root.SelectSingleNode(String.Format("Hresult[@value='{0}']",
+ hresult.ToString("X8")));
+ if (node != null)
+ {
+ XmlAttribute text = node.Attributes["text"];
+ if (text == null)
+ throw new Exception("Node has no text attribute.");
+ return text.Value;
+ }
+ else
+ return null;
+ }
+ }
+}
-using System;\r
-using System.Xml;\r
-\r
-namespace TechBot.Library\r
-{\r
- public class NtStatusCommand : XmlCommand\r
- {\r
- public NtStatusCommand(TechBotService techBot)\r
- : base(techBot)\r
- {\r
- }\r
-\r
- public override string XmlFile\r
- {\r
- get { return Settings.Default.NtStatusXml; }\r
- }\r
-\r
- public override string[] AvailableCommands\r
- {\r
- get { return new string[] { "ntstatus" }; }\r
- }\r
-/* \r
- public bool CanHandle(string commandName)\r
- {\r
- return CanHandle(commandName,\r
- new string[] { "ntstatus" });\r
- }\r
-*/\r
- public override void Handle(MessageContext context,\r
- string commandName,\r
- string parameters)\r
- {\r
- string ntstatusText = parameters;\r
- if (ntstatusText.Equals(String.Empty))\r
- {\r
- TechBot.ServiceOutput.WriteLine(context,\r
- "Please provide a valid NTSTATUS value.");\r
- return;\r
- }\r
-\r
- NumberParser np = new NumberParser();\r
- long ntstatus = np.Parse(ntstatusText);\r
- if (np.Error)\r
- {\r
- TechBot.ServiceOutput.WriteLine(context,\r
- String.Format("{0} is not a valid NTSTATUS value.",\r
- ntstatusText));\r
- return;\r
- }\r
- \r
- string description = GetNtstatusDescription(ntstatus);\r
- if (description != null)\r
- {\r
- TechBot.ServiceOutput.WriteLine(context,\r
- String.Format("{0} is {1}.",\r
- ntstatusText,\r
- description));\r
- }\r
- else\r
- {\r
- TechBot.ServiceOutput.WriteLine(context,\r
- String.Format("I don't know about NTSTATUS {0}.",\r
- ntstatusText));\r
- }\r
- }\r
-\r
- public override string Help()\r
- {\r
- return "!ntstatus <value>";\r
- }\r
- \r
- public string GetNtstatusDescription(long ntstatus)\r
- {\r
- XmlElement root = base.m_XmlDocument.DocumentElement;\r
- XmlNode node = root.SelectSingleNode(String.Format("Ntstatus[@value='{0}']",\r
- ntstatus.ToString("X8")));\r
- if (node != null)\r
- {\r
- XmlAttribute text = node.Attributes["text"];\r
- if (text == null)\r
- throw new Exception("Node has no text attribute.");\r
- return text.Value;\r
- }\r
- else\r
- return null;\r
- }\r
- }\r
-}\r
+using System;
+using System.Xml;
+
+namespace TechBot.Library
+{
+ [Command("ntstatus", Help = "!ntstatus <value>")]
+ public class NtStatusCommand : XmlLookupCommand
+ {
+ public NtStatusCommand()
+ {
+ }
+
+ public override string XmlFile
+ {
+ get { return Settings.Default.NtStatusXml; }
+ }
+
+ public override void ExecuteCommand()
+ {
+ if (Text.Equals(String.Empty))
+ {
+ TechBot.ServiceOutput.WriteLine(Context,
+ "Please provide a valid NTSTATUS value.");
+ return;
+ }
+
+ NumberParser np = new NumberParser();
+ long ntstatus = np.Parse(Text);
+ if (np.Error)
+ {
+ TechBot.ServiceOutput.WriteLine(Context,
+ String.Format("{0} is not a valid NTSTATUS value.",
+ Text));
+ return;
+ }
+
+ string description = GetNtstatusDescription(ntstatus);
+ if (description != null)
+ {
+ TechBot.ServiceOutput.WriteLine(Context,
+ String.Format("{0} is {1}.",
+ Text,
+ description));
+ }
+ else
+ {
+ TechBot.ServiceOutput.WriteLine(Context,
+ String.Format("I don't know about NTSTATUS {0}.",
+ Text));
+ }
+ }
+
+ public string GetNtstatusDescription(long ntstatus)
+ {
+ XmlElement root = base.m_XmlDocument.DocumentElement;
+ XmlNode node = root.SelectSingleNode(String.Format("Ntstatus[@value='{0}']",
+ ntstatus.ToString("X8")));
+ if (node != null)
+ {
+ XmlAttribute text = node.Attributes["text"];
+ if (text == null)
+ throw new Exception("Node has no text attribute.");
+ return text.Value;
+ }
+ else
+ return null;
+ }
+ }
+}
namespace TechBot.Library
{
+ [Command("rosbug", Help = "!rosbug <number>")]
class ReactOSBugUrl : BugCommand
{
- public ReactOSBugUrl(TechBotService techBot)
- : base(techBot)
+ public ReactOSBugUrl()
{
}
- public override string[] AvailableCommands
- {
- get { return new string[] { "rosbug" }; }
- }
-
protected override string BugUrl
{
get { return "http://www.reactos.org/bugzilla/show_bug.cgi?id={0}"; }
}
-
- public override string Help()
- {
- return "!rosbug <number>";
- }
}
}
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace TechBot.Library
+{
+ [Command("sambabug", Help = "!sambabug <number>")]
+ class SambaBugUrl : BugCommand
+ {
+ public SambaBugUrl()
+ {
+ }
+
+ protected override string BugUrl
+ {
+ get { return "https://bugzilla.samba.org/show_bug.cgi?id={0}"; }
+ }
+ }
+}
--- /dev/null
+using System;
+
+namespace TechBot.Library
+{
+ [Command("svn", Help = "!svn")]
+ public class SvnCommand : Command
+ {
+ private string m_SvnRoot;
+
+ public SvnCommand()
+ {
+ m_SvnRoot = Settings.Default.SVNRoot;
+ }
+
+ public override void ExecuteCommand()
+ {
+ Say("svn co {0}", m_SvnRoot);
+ }
+ }
+}
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace TechBot.Library
+{
+ [Command("winebug", Help = "!winebug <number>")]
+ class WineBugUrl : BugCommand
+ {
+ public WineBugUrl()
+ {
+ }
+
+ protected override string BugUrl
+ {
+ get { return "http://bugs.winehq.org/show_bug.cgi?id={0}"; }
+ }
+ }
+}
-using System;\r
-using System.Xml;\r
-\r
-namespace TechBot.Library\r
-{\r
- public class WinerrorCommand : XmlCommand\r
- {\r
- public WinerrorCommand(TechBotService techBot)\r
- : base(techBot)\r
- {\r
- }\r
-\r
- public override string XmlFile\r
- {\r
- get { return Settings.Default.WinErrorXml; }\r
- }\r
-\r
- public override string[] AvailableCommands\r
- {\r
- get { return new string[] { "winerror" }; }\r
- }\r
-\r
- public override void Handle(MessageContext context,\r
- string commandName,\r
- string parameters)\r
- {\r
- string winerrorText = parameters;\r
- if (winerrorText.Equals(String.Empty))\r
- {\r
- TechBot.ServiceOutput.WriteLine(context,\r
- "Please provide a valid System Error Code value.");\r
- return;\r
- }\r
-\r
- NumberParser np = new NumberParser();\r
- long winerror = np.Parse(winerrorText);\r
- if (np.Error)\r
- {\r
- TechBot.ServiceOutput.WriteLine(context,\r
- String.Format("{0} is not a valid System Error Code value.",\r
- winerrorText));\r
- return;\r
- }\r
- \r
- string description = GetWinerrorDescription(winerror);\r
- if (description != null)\r
- {\r
- TechBot.ServiceOutput.WriteLine(context,\r
- String.Format("{0} is {1}.",\r
- winerrorText,\r
- description));\r
- }\r
- else\r
- {\r
- TechBot.ServiceOutput.WriteLine(context,\r
- String.Format("I don't know about System Error Code {0}.",\r
- winerrorText));\r
- }\r
- }\r
-\r
- public override string Help()\r
- {\r
- return "!winerror <value>";\r
- }\r
- \r
- public string GetWinerrorDescription(long winerror)\r
- {\r
- XmlElement root = base.m_XmlDocument.DocumentElement;\r
- XmlNode node = root.SelectSingleNode(String.Format("Winerror[@value='{0}']",\r
- winerror));\r
- if (node != null)\r
- {\r
- XmlAttribute text = node.Attributes["text"];\r
- if (text == null)\r
- throw new Exception("Node has no text attribute.");\r
- return text.Value;\r
- }\r
- else\r
- return null;\r
- }\r
- }\r
-}\r
+using System;
+using System.Xml;
+
+namespace TechBot.Library
+{
+ [Command("winerror", Help = "!winerror <value>")]
+ public class WinErrorCommand : XmlLookupCommand
+ {
+ public WinErrorCommand()
+ {
+ }
+
+ public override string XmlFile
+ {
+ get { return Settings.Default.WinErrorXml; }
+ }
+
+ public override void ExecuteCommand()
+ {
+ if (Text.Equals(String.Empty))
+ {
+ TechBot.ServiceOutput.WriteLine(Context,
+ "Please provide a valid System Error Code value.");
+ return;
+ }
+
+ NumberParser np = new NumberParser();
+ long winerror = np.Parse(Text);
+ if (np.Error)
+ {
+ TechBot.ServiceOutput.WriteLine(Context,
+ String.Format("{0} is not a valid System Error Code value.",
+ Text));
+ return;
+ }
+
+ string description = GetWinerrorDescription(winerror);
+ if (description != null)
+ {
+ TechBot.ServiceOutput.WriteLine(Context,
+ String.Format("{0} is {1}.",
+ Text,
+ description));
+ }
+ else
+ {
+ TechBot.ServiceOutput.WriteLine(Context,
+ String.Format("I don't know about System Error Code {0}.",
+ Text));
+ }
+ }
+
+ public string GetWinerrorDescription(long winerror)
+ {
+ XmlElement root = base.m_XmlDocument.DocumentElement;
+ XmlNode node = root.SelectSingleNode(String.Format("Winerror[@value='{0}']",
+ Text));
+ if (node != null)
+ {
+ XmlAttribute text = node.Attributes["text"];
+ if (text == null)
+ throw new Exception("Node has no text attribute.");
+ return text.Value;
+ }
+ else
+ return null;
+ }
+ }
+}
-using System;\r
-using System.Xml;\r
-\r
-namespace TechBot.Library\r
-{\r
- public class WMCommand : XmlCommand\r
- {\r
- public WMCommand(TechBotService techBot)\r
- : base(techBot)\r
- {\r
- }\r
-\r
- public override string XmlFile\r
- {\r
- get { return Settings.Default.WMXml; }\r
- }\r
- \r
- public override string[] AvailableCommands\r
- {\r
- get { return new string[] { "wm" }; }\r
- }\r
-\r
- public override void Handle(MessageContext context,\r
- string commandName,\r
- string parameters)\r
- {\r
- string wmText = parameters;\r
- if (wmText.Equals(String.Empty))\r
- {\r
- TechBot.ServiceOutput.WriteLine(context,\r
- "Please provide a valid window message value or name.");\r
- return;\r
- }\r
-\r
- NumberParser np = new NumberParser();\r
- long wm = np.Parse(wmText);\r
- string output;\r
- if (np.Error)\r
- {\r
- // Assume "!wm <name>" form.\r
- output = GetWmNumber(wmText);\r
- }\r
- else\r
- {\r
- output = GetWmDescription(wm);\r
- }\r
-\r
- if (output != null)\r
- {\r
- TechBot.ServiceOutput.WriteLine(context,\r
- String.Format("{0} is {1}.",\r
- wmText,\r
- output));\r
- }\r
- else\r
- {\r
- TechBot.ServiceOutput.WriteLine(context,\r
- String.Format("I don't know about window message {0}.",\r
- wmText));\r
- }\r
- }\r
-\r
- public override string Help()\r
- {\r
- return "!wm <value> or !wm <name>";\r
- }\r
- \r
- private string GetWmDescription(long wm)\r
- {\r
- XmlElement root = base.m_XmlDocument.DocumentElement;\r
- XmlNode node = root.SelectSingleNode(String.Format("WindowMessage[@value='{0}']",\r
- wm));\r
- if (node != null)\r
- {\r
- XmlAttribute text = node.Attributes["text"];\r
- if (text == null)\r
- throw new Exception("Node has no text attribute.");\r
- return text.Value;\r
- }\r
- else\r
- return null;\r
- }\r
- \r
- private string GetWmNumber(string wmName)\r
- {\r
- XmlElement root = base.m_XmlDocument.DocumentElement;\r
- XmlNode node = root.SelectSingleNode(String.Format("WindowMessage[@text='{0}']",\r
- wmName));\r
- if (node != null)\r
- {\r
- XmlAttribute value = node.Attributes["value"];\r
- if (value == null)\r
- throw new Exception("Node has no value attribute.");\r
- return value.Value;\r
- }\r
- else\r
- return null;\r
- }\r
- }\r
-}\r
+using System;
+using System.Xml;
+
+namespace TechBot.Library
+{
+ [Command("wm" , Help = "!wm <value> or !wm <name>")]
+ public class WMCommand : XmlCommand
+ {
+ private string m_WMText = null;
+
+ public WMCommand()
+ {
+ }
+
+ public override string XmlFile
+ {
+ get { return Settings.Default.WMXml; }
+ }
+
+ [CommandParameter("wm", "The windows message to check")]
+ public string WMText
+ {
+ get { return m_WMText; }
+ set { m_WMText = value; }
+ }
+
+ public override void ExecuteCommand()
+ {
+ if (WMText.Equals(String.Empty))
+ {
+ TechBot.ServiceOutput.WriteLine(Context,
+ "Please provide a valid window message value or name.");
+ return;
+ }
+
+ NumberParser np = new NumberParser();
+ long wm = np.Parse(WMText);
+ string output;
+ if (np.Error)
+ {
+ // Assume "!wm <name>" form.
+ output = GetWmNumber(WMText);
+ }
+ else
+ {
+ output = GetWmDescription(wm);
+ }
+
+ if (output != null)
+ {
+ TechBot.ServiceOutput.WriteLine(Context,
+ String.Format("{0} is {1}.",
+ WMText,
+ output));
+ }
+ else
+ {
+ TechBot.ServiceOutput.WriteLine(Context,
+ String.Format("I don't know about window message {0}.",
+ WMText));
+ }
+ }
+
+ private string GetWmDescription(long wm)
+ {
+ XmlElement root = base.m_XmlDocument.DocumentElement;
+ XmlNode node = root.SelectSingleNode(String.Format("WindowMessage[@value='{0}']",
+ wm));
+ if (node != null)
+ {
+ XmlAttribute text = node.Attributes["text"];
+ if (text == null)
+ throw new Exception("Node has no text attribute.");
+ return text.Value;
+ }
+ else
+ return null;
+ }
+
+ private string GetWmNumber(string wmName)
+ {
+ XmlElement root = base.m_XmlDocument.DocumentElement;
+ XmlNode node = root.SelectSingleNode(String.Format("WindowMessage[@text='{0}']",
+ wmName));
+ if (node != null)
+ {
+ XmlAttribute value = node.Attributes["value"];
+ if (value == null)
+ throw new Exception("Node has no value attribute.");
+ return value.Value;
+ }
+ else
+ return null;
+ }
+ }
+}
--- /dev/null
+using System;
+using System.Reflection;
+using System.Collections.Generic;
+using System.Text;
+
+namespace TechBot.Library
+{
+ public class CommandBuilder
+ {
+ private Type m_CommandType;
+ private string m_CommandName;
+ private string m_CommandHelp;
+ private string m_CommandDesc;
+
+ public CommandBuilder(Type commandType)
+ {
+ m_CommandType = commandType;
+
+ CommandAttribute commandAttribute = (CommandAttribute)
+ Attribute.GetCustomAttribute(commandType, typeof(CommandAttribute));
+
+ m_CommandName = commandAttribute.Name;
+ m_CommandHelp = commandAttribute.Help;
+ m_CommandDesc = commandAttribute.Description;
+ }
+
+ public string Name
+ {
+ get { return m_CommandName; }
+ }
+
+ public string Help
+ {
+ get { return m_CommandHelp; }
+ }
+
+ public string Description
+ {
+ get { return m_CommandDesc; }
+ }
+
+ public Type Type
+ {
+ get { return m_CommandType; }
+ }
+
+ public Command CreateCommand()
+ {
+ return (Command)Type.Assembly.CreateInstance(Type.FullName, true);
+ }
+ }
+}
--- /dev/null
+using System;
+using System.IO;
+using System.Collections;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Reflection;
+
+namespace TechBot.Library
+{
+ public class CommandFactory
+ {
+ private static CommandBuilderCollection m_Commands = new CommandBuilderCollection();
+
+ private CommandFactory()
+ {
+ }
+
+ public static void LoadPlugins()
+ {
+ //get the file names of the dll files in the current directory.
+ FileInfo objExeInfo = new FileInfo(@"C:\Ros\current\irc\TechBot\TechBot.Console\bin\Debug\");
+
+ foreach (FileInfo objInfo in objExeInfo.Directory.GetFiles("*.dll"))
+ {
+ LoadPluginsFromDLLFile(objInfo.FullName);
+ }
+ }
+
+ private static void LoadPluginsFromDLLFile(string sFile)
+ {
+ Assembly assPlugin = Assembly.LoadFile(sFile);
+
+ if (assPlugin != null)
+ {
+ foreach (Type pluginType in assPlugin.GetTypes())
+ {
+ if (pluginType.IsSubclassOf(typeof(Command)))
+ {
+ if (pluginType.IsAbstract == false)
+ {
+ //Add it to the list.
+ Commands.Add(new CommandBuilder(pluginType));
+ }
+ }
+ }
+ }
+ }
+
+ public static CommandBuilderCollection Commands
+ {
+ get { return m_Commands; }
+ }
+ }
+}
+++ /dev/null
-using System;\r
-using System.Collections;\r
-\r
-namespace TechBot.Library\r
-{\r
- public class HelpCommand : Command\r
- {\r
- public HelpCommand(TechBotService techBot)\r
- : base(techBot)\r
- {\r
- }\r
-\r
- public override string[] AvailableCommands\r
- {\r
- get { return new string[] { "help" }; }\r
- }\r
-\r
- public override void Handle(\r
- MessageContext context,\r
- string commandName,\r
- string parameters)\r
- {\r
- TechBot.ServiceOutput.WriteLine(context, "I support the following commands:");\r
-\r
- foreach (Command command in TechBot.Commands)\r
- {\r
- TechBot.ServiceOutput.WriteLine(context,\r
- command.Help());\r
- }\r
- }\r
-\r
- public override string Help()\r
- {\r
- return "!help";\r
- }\r
- }\r
-}\r
{\r
}\r
\r
-\r
-\r
public class ChannelMessageContext : MessageContext\r
{\r
- private IrcChannel channel;\r
+ private IrcChannel m_IrcChannel;\r
\r
- public IrcChannel Channel\r
- {\r
- get\r
- {\r
- return channel;\r
- }\r
- }\r
+ public IrcChannel Channel\r
+ {\r
+ get { return m_IrcChannel; }\r
+ }\r
\r
public ChannelMessageContext(IrcChannel channel)\r
{\r
- this.channel = channel;\r
+ m_IrcChannel = channel;\r
}\r
}\r
-\r
- \r
\r
public class UserMessageContext : MessageContext\r
{\r
- private IrcUser user;\r
+ private IrcUser m_IrcUser;\r
\r
- public IrcUser User\r
- {\r
- get\r
- {\r
- return user;\r
- }\r
- }\r
+ public IrcUser User\r
+ {\r
+ get { return m_IrcUser; }\r
+ }\r
\r
public UserMessageContext(IrcUser user)\r
{\r
- this.user = user;\r
+ m_IrcUser = user;\r
}\r
}\r
}\r
--- /dev/null
+using System;
+using System.Text.RegularExpressions;
+
+//Code taken from : http://www.codeproject.com/KB/recipes/commandlineparser.aspx
+
+namespace TechBot.Library
+{
+ /// <summary>Implementation of a command-line parsing class. Is capable of
+ /// having switches registered with it directly or can examine a registered
+ /// class for any properties with the appropriate attributes appended to
+ /// them.</summary>
+ public class ParametersParser
+ {
+ /// <summary>A simple internal class for passing back to the caller
+ /// some information about the switch. The internals/implementation
+ /// of this class has privillaged access to the contents of the
+ /// SwitchRecord class.</summary>
+ public class SwitchInfo
+ {
+ #region Private Variables
+ private object m_Switch = null;
+ #endregion
+
+ #region Public Properties
+ public string Name { get { return (m_Switch as SwitchRecord).Name; } }
+ public string Description { get { return (m_Switch as SwitchRecord).Description; } }
+ public string[] Aliases { get { return (m_Switch as SwitchRecord).Aliases; } }
+ public System.Type Type { get { return (m_Switch as SwitchRecord).Type; } }
+ public object Value { get { return (m_Switch as SwitchRecord).Value; } }
+ public object InternalValue { get { return (m_Switch as SwitchRecord).InternalValue; } }
+ public bool IsEnum { get { return (m_Switch as SwitchRecord).Type.IsEnum; } }
+ public string[] Enumerations { get { return (m_Switch as SwitchRecord).Enumerations; } }
+ #endregion
+
+ /// <summary>
+ /// Constructor for the SwitchInfo class. Note, in order to hide to the outside world
+ /// information not necessary to know, the constructor takes a System.Object (aka
+ /// object) as it's registering type. If the type isn't of the correct type, an exception
+ /// is thrown.
+ /// </summary>
+ /// <param name="rec">The SwitchRecord for which this class store information.</param>
+ /// <exception cref="ArgumentException">Thrown if the rec parameter is not of
+ /// the type SwitchRecord.</exception>
+ public SwitchInfo( object rec )
+ {
+ if ( rec is SwitchRecord )
+ m_Switch = rec;
+ else
+ throw new ArgumentException();
+ }
+ }
+
+ /// <summary>
+ /// The SwitchRecord is stored within the parser's collection of registered
+ /// switches. This class is private to the outside world.
+ /// </summary>
+ private class SwitchRecord
+ {
+ #region Private Variables
+ private string m_name = "";
+ private string m_description = "";
+ private object m_value = null;
+ private System.Type m_switchType = typeof(bool);
+ private System.Collections.ArrayList m_Aliases = null;
+ private string m_Pattern = "";
+
+ // The following advanced functions allow for callbacks to be
+ // made to manipulate the associated data type.
+ private System.Reflection.MethodInfo m_SetMethod = null;
+ private System.Reflection.MethodInfo m_GetMethod = null;
+ private object m_PropertyOwner = null;
+ #endregion
+
+ #region Private Utility Functions
+ private void Initialize( string name, string description )
+ {
+ m_name = name;
+ m_description = description;
+
+ BuildPattern();
+ }
+
+ private void BuildPattern()
+ {
+ string matchString = Name;
+
+ if ( Aliases != null && Aliases.Length > 0 )
+ foreach( string s in Aliases )
+ matchString += "|" + s;
+
+ string strPatternStart = @"(\s|^)(?<match>(-{1,2}|/)(";
+ string strPatternEnd; // To be defined below.
+
+ // The common suffix ensures that the switches are followed by
+ // a white-space OR the end of the string. This will stop
+ // switches such as /help matching /helpme
+ //
+ string strCommonSuffix = @"(?=(\s|$))";
+
+ if ( Type == typeof(bool) )
+ strPatternEnd = @")(?<value>(\+|-){0,1}))";
+ else if ( Type == typeof(string) )
+ strPatternEnd = @")(?::|\s+))((?:"")(?<value>.+)(?:"")|(?<value>\S+))";
+ else if ( Type == typeof(int) )
+ strPatternEnd = @")(?::|\s+))((?<value>(-|\+)[0-9]+)|(?<value>[0-9]+))";
+ else if ( Type.IsEnum )
+ {
+ string[] enumNames = Enumerations;
+ string e_str = enumNames[0];
+ for ( int e=1; e<enumNames.Length; e++ )
+ e_str += "|" + enumNames[e];
+ strPatternEnd = @")(?::|\s+))(?<value>" + e_str + @")";
+ }
+ else
+ throw new System.ArgumentException();
+
+ // Set the internal regular expression pattern.
+ m_Pattern = strPatternStart + matchString + strPatternEnd + strCommonSuffix;
+ }
+ #endregion
+
+ #region Public Properties
+ public object Value
+ {
+ get
+ {
+ if ( ReadValue != null )
+ return ReadValue;
+ else
+ return m_value;
+ }
+ }
+
+ public object InternalValue
+ {
+ get { return m_value; }
+ }
+
+ public string Name
+ {
+ get { return m_name; }
+ set { m_name = value; }
+ }
+
+ public string Description
+ {
+ get { return m_description; }
+ set { m_description = value; }
+ }
+
+ public System.Type Type
+ {
+ get { return m_switchType; }
+ }
+
+ public string[] Aliases
+ {
+ get { return (m_Aliases != null) ? (string[])m_Aliases.ToArray(typeof(string)): null; }
+ }
+
+ public string Pattern
+ {
+ get { return m_Pattern; }
+ }
+
+ public System.Reflection.MethodInfo SetMethod
+ {
+ set { m_SetMethod = value; }
+ }
+
+ public System.Reflection.MethodInfo GetMethod
+ {
+ set { m_GetMethod = value; }
+ }
+
+ public object PropertyOwner
+ {
+ set { m_PropertyOwner = value; }
+ }
+
+ public object ReadValue
+ {
+ get
+ {
+ object o = null;
+ if ( m_PropertyOwner != null && m_GetMethod != null )
+ o = m_GetMethod.Invoke( m_PropertyOwner, null );
+ return o;
+ }
+ }
+
+ public string[] Enumerations
+ {
+ get
+ {
+ if ( m_switchType.IsEnum )
+ return System.Enum.GetNames( m_switchType );
+ else
+ return null;
+ }
+ }
+ #endregion
+
+ #region Constructors
+ public SwitchRecord( string name, string description )
+ {
+ Initialize( name, description );
+ }
+
+ public SwitchRecord( string name, string description, System.Type type )
+ {
+ if ( type == typeof(bool) ||
+ type == typeof(string) ||
+ type == typeof(int) ||
+ type.IsEnum )
+ {
+ m_switchType = type;
+ Initialize( name, description );
+ }
+ else
+ throw new ArgumentException("Currently only Ints, Bool and Strings are supported");
+ }
+ #endregion
+
+ #region Public Methods
+ public void AddAlias( string alias )
+ {
+ if ( m_Aliases == null )
+ m_Aliases = new System.Collections.ArrayList();
+ m_Aliases.Add( alias );
+
+ BuildPattern();
+ }
+
+ public void Notify( object value )
+ {
+ if ( m_PropertyOwner != null && m_SetMethod != null )
+ {
+ object[] parameters = new object[1];
+ parameters[0] = value;
+ m_SetMethod.Invoke( m_PropertyOwner, parameters );
+ }
+ m_value = value;
+ }
+
+ #endregion
+ }
+
+
+ #region Private Variables
+ private string m_commandLine = "";
+ private string m_workingString = "";
+ private string m_applicationName = "";
+ private string[] m_splitParameters = null;
+ private System.Collections.ArrayList m_switches = null;
+ #endregion
+
+ #region Private Utility Functions
+ private void ExtractApplicationName()
+ {
+ Regex r = new Regex(@"^(?<commandLine>("".+""|(\S)+))(?<remainder>.+)",
+ RegexOptions.ExplicitCapture);
+ Match m = r.Match(m_commandLine);
+ if ( m != null && m.Groups["commandLine"] != null )
+ {
+ m_applicationName = m.Groups["commandLine"].Value;
+ m_workingString = m.Groups["remainder"].Value;
+ }
+ }
+
+ private void SplitParameters()
+ {
+ // Populate the split parameters array with the remaining parameters.
+ // Note that if quotes are used, the quotes are removed.
+ // e.g. one two three "four five six"
+ // 0 - one
+ // 1 - two
+ // 2 - three
+ // 3 - four five six
+ // (e.g. 3 is not in quotes).
+ Regex r = new Regex(@"((\s*(""(?<param>.+?)""|(?<param>\S+))))",
+ RegexOptions.ExplicitCapture);
+ MatchCollection m = r.Matches( m_workingString );
+
+ if ( m != null )
+ {
+ m_splitParameters = new string[ m.Count ];
+ for ( int i=0; i < m.Count; i++ )
+ m_splitParameters[i] = m[i].Groups["param"].Value;
+ }
+ }
+
+ private void HandleSwitches()
+ {
+ if ( m_switches != null )
+ {
+ foreach ( SwitchRecord s in m_switches )
+ {
+ Regex r = new Regex( s.Pattern,
+ RegexOptions.ExplicitCapture
+ | RegexOptions.IgnoreCase );
+ MatchCollection m = r.Matches( m_workingString );
+ if ( m != null )
+ {
+ for ( int i=0; i < m.Count; i++ )
+ {
+ string value = null;
+ if ( m[i].Groups != null && m[i].Groups["value"] != null )
+ value = m[i].Groups["value"].Value;
+
+ if ( s.Type == typeof(bool))
+ {
+ bool state = true;
+ // The value string may indicate what value we want.
+ if ( m[i].Groups != null && m[i].Groups["value"] != null )
+ {
+ switch ( value )
+ {
+ case "+": state = true;
+ break;
+ case "-": state = false;
+ break;
+ case "": if ( s.ReadValue != null )
+ state = !(bool)s.ReadValue;
+ break;
+ default: break;
+ }
+ }
+ s.Notify( state );
+ break;
+ }
+ else if ( s.Type == typeof(string) )
+ s.Notify( value );
+ else if ( s.Type == typeof(int) )
+ s.Notify( int.Parse( value ) );
+ else if ( s.Type.IsEnum )
+ s.Notify( System.Enum.Parse(s.Type,value,true) );
+ }
+ }
+
+ m_workingString = r.Replace(m_workingString, " ");
+ }
+ }
+ }
+
+ #endregion
+
+ #region Public Properties
+ public string ApplicationName
+ {
+ get { return m_applicationName; }
+ }
+
+ public string[] Parameters
+ {
+ get { return m_splitParameters; }
+ }
+
+ public SwitchInfo[] Switches
+ {
+ get
+ {
+ if ( m_switches == null )
+ return null;
+ else
+ {
+ SwitchInfo[] si = new SwitchInfo[ m_switches.Count ];
+ for ( int i=0; i<m_switches.Count; i++ )
+ si[i] = new SwitchInfo( m_switches[i] );
+ return si;
+ }
+ }
+ }
+
+ public object this[string name]
+ {
+ get
+ {
+ if ( m_switches != null )
+ for ( int i=0; i<m_switches.Count; i++ )
+ if ( string.Compare( (m_switches[i] as SwitchRecord).Name, name, true )==0 )
+ return (m_switches[i] as SwitchRecord).Value;
+ return null;
+ }
+ }
+
+ /// <summary>This function returns a list of the unhandled switches
+ /// that the parser has seen, but not processed.</summary>
+ /// <remark>The unhandled switches are not removed from the remainder
+ /// of the command-line.</remark>
+ public string[] UnhandledSwitches
+ {
+ get
+ {
+ string switchPattern = @"(\s|^)(?<match>(-{1,2}|/)(.+?))(?=(\s|$))";
+ Regex r = new Regex( switchPattern,
+ RegexOptions.ExplicitCapture
+ | RegexOptions.IgnoreCase );
+ MatchCollection m = r.Matches( m_workingString );
+
+ if ( m != null )
+ {
+ string[] unhandled = new string[ m.Count ];
+ for ( int i=0; i < m.Count; i++ )
+ unhandled[i] = m[i].Groups["match"].Value;
+ return unhandled;
+ }
+ else
+ return null;
+ }
+ }
+ #endregion
+
+ #region Public Methods
+ public void AddSwitch( string name, string description )
+ {
+ if ( m_switches == null )
+ m_switches = new System.Collections.ArrayList();
+
+ SwitchRecord rec = new SwitchRecord( name, description );
+ m_switches.Add( rec );
+ }
+
+ public void AddSwitch( string[] names, string description )
+ {
+ if ( m_switches == null )
+ m_switches = new System.Collections.ArrayList();
+ SwitchRecord rec = new SwitchRecord( names[0], description );
+ for ( int s=1; s<names.Length; s++ )
+ rec.AddAlias( names[s] );
+ m_switches.Add( rec );
+ }
+
+ public bool Parse()
+ {
+ ExtractApplicationName();
+
+ // Remove switches and associated info.
+ HandleSwitches();
+
+ // Split parameters.
+ SplitParameters();
+
+ return true;
+ }
+
+ public object InternalValue(string name)
+ {
+ if ( m_switches != null )
+ for ( int i=0; i<m_switches.Count; i++ )
+ if ( string.Compare( (m_switches[i] as SwitchRecord).Name, name, true )==0 )
+ return (m_switches[i] as SwitchRecord).InternalValue;
+ return null;
+ }
+ #endregion
+
+ #region Constructors
+ public ParametersParser( string commandLine )
+ {
+ m_commandLine = commandLine;
+ }
+
+ public ParametersParser( string commandLine,
+ object classForAutoAttributes )
+ {
+ m_commandLine = commandLine;
+
+ Type type = classForAutoAttributes.GetType();
+ System.Reflection.MemberInfo[] members = type.GetMembers();
+
+ for(int i=0; i<members.Length; i++)
+ {
+ object[] attributes = members[i].GetCustomAttributes(false);
+ if(attributes.Length > 0)
+ {
+ SwitchRecord rec = null;
+
+ foreach ( Attribute attribute in attributes )
+ {
+ if ( attribute is CommandParameterAttribute )
+ {
+ CommandParameterAttribute switchAttrib =
+ (CommandParameterAttribute) attribute;
+
+ // Get the property information. We're only handling
+ // properties at the moment!
+ if ( members[i] is System.Reflection.PropertyInfo )
+ {
+ System.Reflection.PropertyInfo pi = (System.Reflection.PropertyInfo) members[i];
+
+ rec = new SwitchRecord( switchAttrib.Name,
+ switchAttrib.Description,
+ pi.PropertyType );
+
+ // Map in the Get/Set methods.
+ rec.SetMethod = pi.GetSetMethod();
+ rec.GetMethod = pi.GetGetMethod();
+ rec.PropertyOwner = classForAutoAttributes;
+
+ // Can only handle a single switch for each property
+ // (otherwise the parsing of aliases gets silly...)
+ break;
+ }
+ }
+ }
+
+ // See if any aliases are required. We can only do this after
+ // a switch has been registered and the framework doesn't make
+ // any guarantees about the order of attributes, so we have to
+ // walk the collection a second time.
+ if ( rec != null )
+ {
+ foreach ( Attribute attribute in attributes )
+ {
+ if (attribute is CommandParameterAliasAttribute)
+ {
+ CommandParameterAliasAttribute aliasAttrib =
+ (CommandParameterAliasAttribute)attribute;
+ rec.AddAlias( aliasAttrib.Alias );
+ }
+ }
+ }
+
+ // Assuming we have a switch record (that may or may not have
+ // aliases), add it to the collection of switches.
+ if ( rec != null )
+ {
+ if ( m_switches == null )
+ m_switches = new System.Collections.ArrayList();
+ m_switches.Add( rec );
+ }
+ }
+ }
+ }
+ #endregion
+ }
+}
+++ /dev/null
-using System;
-using System.Collections.Generic;
-using System.Text;
-
-namespace TechBot.Library
-{
- class SambaBugUrl : BugCommand
- {
- public SambaBugUrl(TechBotService techBot)
- : base(techBot)
- {
- }
-
- public override string[] AvailableCommands
- {
- get { return new string[] { "sambabug" }; }
- }
-
- protected override string BugUrl
- {
- get { return "https://bugzilla.samba.org/show_bug.cgi?id={0}"; }
- }
-
- public override string Help()
- {
- return "!sambabug <number>";
- }
- }
-}
\r
namespace TechBot.Library\r
{\r
- public interface IServiceOutput\r
- {\r
- void WriteLine(MessageContext context,\r
- string message);\r
- }\r
+ public interface IServiceOutput\r
+ {\r
+ void WriteLine(MessageContext context, string message);\r
+ }\r
}\r
+++ /dev/null
-using System;\r
-\r
-namespace TechBot.Library\r
-{\r
- public class SvnCommand : Command\r
- {\r
- private string m_SvnRoot;\r
-\r
- public SvnCommand(TechBotService techBot)\r
- : base(techBot)\r
- {\r
- m_SvnRoot = Settings.Default.SVNRoot;\r
- }\r
-\r
- public override string[] AvailableCommands\r
- {\r
- get { return new string[] { "svn" }; }\r
- }\r
- \r
- public override void Handle(MessageContext context,\r
- string commandName,\r
- string parameters)\r
- {\r
- TechBot.ServiceOutput.WriteLine(context, string.Format("svn co {0}" , m_SvnRoot));\r
- }\r
-\r
- public override string Help()\r
- {\r
- return "!svn";\r
- }\r
- }\r
-}\r
</Target>
-->
<ItemGroup>
- <Compile Include="ApiCommand.cs" />
- <Compile Include="BugCommand.cs" />
+ <Compile Include="Attributes\CommandAttribute.cs" />
+ <Compile Include="Attributes\CommandParameterAliasAttribute.cs" />
+ <Compile Include="Attributes\CommandParameterAttribute.cs" />
+ <Compile Include="Collections\CommandBuilderCollection.cs" />
+ <Compile Include="Commands\Base\XmlLookupCommand.cs" />
+ <Compile Include="Factory\CommandBuilder.cs" />
+ <Compile Include="Factory\CommandFactory.cs" />
+ <Compile Include="Commands\Base\Command.cs" />
<Compile Include="Commands\Base\XmlCommand.cs" />
- <Compile Include="SambaBugUrl.cs" />
- <Compile Include="WineBugUrl.cs" />
- <Compile Include="ErrorCommand.cs" />
- <Compile Include="HelpCommand.cs" />
- <Compile Include="HresultCommand.cs" />
- <Compile Include="Command.cs" />
- <Compile Include="IrcService.cs" />
+ <Compile Include="Commands\BugCommand.cs" />
+ <Compile Include="Commands\HelpCommand.cs" />
+ <Compile Include="Commands\HResultCommand.cs" />
+ <Compile Include="Commands\NtStatusCommand.cs" />
+ <Compile Include="Commands\ReactOSBugUrl.cs" />
+ <Compile Include="Commands\SambaBugUrl.cs" />
+ <Compile Include="Commands\SvnCommand.cs" />
+ <Compile Include="Commands\WineBugUrl.cs" />
+ <Compile Include="Commands\WinerrorCommand.cs" />
+ <Compile Include="Commands\WMCommand.cs" />
<Compile Include="MessageContext.cs" />
- <Compile Include="NtStatusCommand.cs" />
<Compile Include="NumberParser.cs" />
+ <Compile Include="ParametersParser.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
- <Compile Include="ReactOSBugUrl.cs" />
<Compile Include="ServiceOutput.cs" />
<Compile Include="Settings.cs" />
<Compile Include="Settings.Designer.cs">
<DesignTimeSharedInput>True</DesignTimeSharedInput>
<DependentUpon>Settings.settings</DependentUpon>
</Compile>
- <Compile Include="SvnCommand.cs" />
+ <Compile Include="TechBotIrcService.cs" />
<Compile Include="TechBotService.cs" />
- <Compile Include="WinerrorCommand.cs" />
- <Compile Include="WmCommand.cs" />
</ItemGroup>
<ItemGroup>
<Reference Include="System" />
-using System;\r
-using System.Text;\r
-using System.Collections;\r
-using System.Threading;\r
-\r
-using TechBot.IRCLibrary;\r
-\r
-namespace TechBot.Library\r
-{\r
- public class IrcService : IServiceOutput\r
- {\r
- private string hostname;\r
- private int port;\r
- private string channelnames;\r
- private string botname;\r
- private string password;\r
- private string chmPath;\r
- private string mainChm;\r
- private string ntstatusXml;\r
- private string winerrorXml;\r
- private string hresultXml;\r
- private string wmXml;\r
- private string svnCommand;\r
- private string bugUrl, WineBugUrl, SambaBugUrl;\r
- private IrcClient m_IrcClient;\r
- private ArrayList channels = new ArrayList(); /* IrcChannel */\r
- private TechBotService service;\r
- private bool isStopped = false;\r
-\r
- public IrcService(string hostname,\r
- int port,\r
- string channelnames,\r
- string botname,\r
- string password,\r
- string chmPath,\r
- string mainChm,\r
- //string ntstatusXml,\r
- //string winerrorXml,\r
- //string hresultXml,\r
- //string wmXml,\r
- //string svnCommand,\r
- string BugUrl,\r
- string WineBugUrl,\r
- string SambaBugUrl)\r
- {\r
- this.hostname = hostname;\r
- this.port = port;\r
- this.channelnames = channelnames;\r
- this.botname = botname;\r
- if (password == null || password.Trim() == "")\r
- this.password = null;\r
- else\r
- this.password = password;\r
- this.chmPath = chmPath;\r
- this.mainChm = mainChm;\r
- this.ntstatusXml = ntstatusXml;\r
- this.winerrorXml = winerrorXml;\r
- this.hresultXml = hresultXml;\r
- this.wmXml = wmXml;\r
- this.svnCommand = svnCommand;\r
- this.bugUrl = BugUrl;\r
- this.WineBugUrl = WineBugUrl;\r
- this.SambaBugUrl = SambaBugUrl;\r
- }\r
-\r
- public void Run()\r
- {\r
- service = new TechBotService(this,\r
- chmPath,\r
- mainChm);\r
- //ntstatusXml,\r
- //winerrorXml,\r
- //hresultXml,\r
- //wmXml,\r
- //svnCommand,\r
- //bugUrl,\r
- //WineBugUrl,\r
- //SambaBugUrl);\r
- service.Run();\r
-\r
- m_IrcClient = new IrcClient();\r
- m_IrcClient.Encoding = Encoding.GetEncoding("iso-8859-1");\r
- m_IrcClient.MessageReceived += new MessageReceivedHandler(client_MessageReceived);\r
- m_IrcClient.ChannelUserDatabaseChanged += new ChannelUserDatabaseChangedHandler(client_ChannelUserDatabaseChanged);\r
- Console.WriteLine("Connecting to {0} port {1}",\r
- hostname,\r
- port);\r
- m_IrcClient.Connect(hostname, port);\r
- Console.WriteLine("Connected...");\r
- m_IrcClient.Register(botname, password, null);\r
- Console.WriteLine("Registered as {0}...", botname);\r
- JoinChannels();\r
-\r
- while (!isStopped)\r
- {\r
- Thread.Sleep(1000);\r
- }\r
-\r
- PartChannels();\r
- m_IrcClient.Diconnect();\r
- Console.WriteLine("Disconnected...");\r
- }\r
-\r
- public void Stop()\r
- {\r
- isStopped = true;\r
- }\r
-\r
- private void JoinChannels()\r
- {\r
- foreach (string channelname in channelnames.Split(new char[] { ';' }))\r
- {\r
- IrcChannel channel = m_IrcClient.JoinChannel(channelname);\r
- channels.Add(channel);\r
- System.Console.WriteLine(String.Format("Joined channel #{0}...",\r
- channel.Name));\r
- }\r
- }\r
-\r
- private void PartChannels()\r
- {\r
- foreach (IrcChannel channel in channels)\r
- {\r
- m_IrcClient.PartChannel(channel, "Caught in the bitstream...");\r
- System.Console.WriteLine(String.Format("Parted channel #{0}...",\r
- channel.Name));\r
- }\r
- }\r
-\r
- private string GetMessageSource(MessageContext context)\r
- {\r
- if (context is ChannelMessageContext)\r
- {\r
- ChannelMessageContext channelContext = context as ChannelMessageContext;\r
- return String.Format("#{0}",\r
- channelContext.Channel.Name);\r
- }\r
- else if (context is UserMessageContext)\r
- {\r
- UserMessageContext userContext = context as UserMessageContext;\r
- return userContext.User.Nickname;\r
- }\r
- else\r
- {\r
- throw new InvalidOperationException(String.Format("Unhandled message context '{0}'",\r
- context.GetType()));\r
- }\r
- }\r
-\r
- public void WriteLine(MessageContext context,\r
- string message)\r
- {\r
- if (context is ChannelMessageContext)\r
- {\r
- ChannelMessageContext channelContext = context as ChannelMessageContext;\r
- channelContext.Channel.Talk(message);\r
- }\r
- else if (context is UserMessageContext)\r
- {\r
- UserMessageContext userContext = context as UserMessageContext;\r
- userContext.User.Talk(message);\r
- }\r
- else\r
- {\r
- throw new InvalidOperationException(String.Format("Unhandled message context '{0}'",\r
- context.GetType()));\r
- }\r
- }\r
-\r
- private void ExtractMessage(string parameters,\r
- out string message)\r
- {\r
- int startIndex = parameters.IndexOf(':');\r
- if (startIndex != -1)\r
- {\r
- message = parameters.Substring(startIndex + 1);\r
- }\r
- else\r
- {\r
- message = parameters;\r
- }\r
- }\r
-\r
- private bool GetChannelName(IrcMessage message,\r
- out string channelName)\r
- {\r
- if (message.Parameters == null || !message.Parameters.StartsWith("#"))\r
- {\r
- channelName = null;\r
- return false;\r
- }\r
-\r
- int index = message.Parameters.IndexOf(' ');\r
- if (index == -1)\r
- index = message.Parameters.Length;\r
- else\r
- index = index - 1;\r
- channelName = message.Parameters.Substring(1, index);\r
- return true;\r
- }\r
-\r
- private bool GetTargetNickname(IrcMessage message,\r
- out string nickname)\r
- {\r
- if (message.Parameters == null)\r
- {\r
- nickname = null;\r
- return false;\r
- }\r
-\r
- int index = message.Parameters.IndexOf(' ');\r
- if (index == -1)\r
- index = message.Parameters.Length;\r
- nickname = message.Parameters.Substring(0, index);\r
- Console.WriteLine("nickname: " + nickname);\r
- return true;\r
- }\r
-\r
- private bool ShouldAcceptMessage(IrcMessage message,\r
- out MessageContext context)\r
- {\r
- if (message.Command.ToUpper().Equals("PRIVMSG"))\r
- {\r
- string channelName;\r
- string nickname;\r
- if (GetChannelName(message,\r
- out channelName))\r
- {\r
- foreach (IrcChannel channel in channels)\r
- {\r
- if (String.Compare(channel.Name, channelName, true) == 0)\r
- {\r
- context = new ChannelMessageContext(channel);\r
- return true;\r
- }\r
- }\r
- }\r
- else if (GetTargetNickname(message,\r
- out nickname))\r
- {\r
- IrcUser targetUser = new IrcUser(m_IrcClient,\r
- nickname);\r
- if (String.Compare(targetUser.Nickname, botname, true) == 0)\r
- {\r
- IrcUser sourceUser = new IrcUser(m_IrcClient,\r
- message.PrefixNickname);\r
- context = new UserMessageContext(sourceUser);\r
- return true;\r
- }\r
- }\r
- }\r
- context = null;\r
- return false;\r
- }\r
- \r
- private void client_MessageReceived(IrcMessage message)\r
- {\r
- try\r
- {\r
- if (message.Command != null &&\r
- message.Parameters != null)\r
- {\r
- string injectMessage;\r
- ExtractMessage(message.Parameters,\r
- out injectMessage);\r
- MessageContext context;\r
- if (ShouldAcceptMessage(message,\r
- out context))\r
- {\r
- Console.WriteLine(String.Format("Injecting: {0} from {1}",\r
- injectMessage,\r
- GetMessageSource(context)));\r
- service.InjectMessage(context,\r
- injectMessage);\r
- }\r
- else\r
- {\r
- Console.WriteLine("Received: " + message.Line);\r
- }\r
- }\r
- else\r
- {\r
- Console.WriteLine("Received: " + message.Line);\r
- }\r
- }\r
- catch (Exception ex)\r
- {\r
- Console.WriteLine(String.Format("Exception: {0}", ex));\r
- }\r
- }\r
- \r
- private void client_ChannelUserDatabaseChanged(IrcChannel channel)\r
- {\r
- }\r
- }\r
-}\r
+using System;
+using System.Text;
+using System.Collections;
+using System.Threading;
+
+using TechBot.IRCLibrary;
+
+namespace TechBot.Library
+{
+ public class IrcServiceOutput : IServiceOutput
+ {
+ public void WriteLine(MessageContext context,
+ string 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()));
+ }
+ }
+ }
+
+ public class IrcTechBotService : TechBotService
+ {
+ private int port;
+ private string hostname;
+ private string channelnames;
+ private string botname;
+ private string password;
+ private string chmPath;
+ private string mainChm;
+ private IrcClient m_IrcClient;
+ private ArrayList channels = new ArrayList();
+ private bool isStopped = false;
+
+ public IrcTechBotService(string hostname,
+ int port,
+ string channelnames,
+ string botname,
+ string password,
+ string chmPath,
+ string mainChm)
+ : base (new IrcServiceOutput() , chmPath , mainChm)
+ {
+ this.hostname = hostname;
+ this.port = port;
+ this.channelnames = channelnames;
+ this.botname = botname;
+ if (password == null || password.Trim() == "")
+ this.password = null;
+ else
+ this.password = password;
+ this.chmPath = chmPath;
+ this.mainChm = mainChm;
+ }
+
+ public override void Run()
+ {
+ //Call the base class
+ base.Run();
+
+ m_IrcClient = new IrcClient();
+ m_IrcClient.Encoding = Encoding.GetEncoding("iso-8859-1");
+ m_IrcClient.MessageReceived += new MessageReceivedHandler(client_MessageReceived);
+ m_IrcClient.ChannelUserDatabaseChanged += new ChannelUserDatabaseChangedHandler(client_ChannelUserDatabaseChanged);
+ Console.WriteLine("Connecting to {0} port {1}",
+ hostname,
+ port);
+ m_IrcClient.Connect(hostname, port);
+ Console.WriteLine("Connected...");
+ m_IrcClient.Register(botname, password, null);
+ Console.WriteLine("Registered as {0}...", botname);
+ JoinChannels();
+
+ while (!isStopped)
+ {
+ Thread.Sleep(1000);
+ }
+
+ PartChannels();
+ m_IrcClient.Diconnect();
+ Console.WriteLine("Disconnected...");
+ }
+
+ public void Stop()
+ {
+ isStopped = true;
+ }
+
+ private void JoinChannels()
+ {
+ foreach (string channelname in channelnames.Split(new char[] { ';' }))
+ {
+ IrcChannel channel = m_IrcClient.JoinChannel(channelname);
+ channels.Add(channel);
+ System.Console.WriteLine(String.Format("Joined channel #{0}...",
+ channel.Name));
+ }
+ }
+
+ private void PartChannels()
+ {
+ foreach (IrcChannel channel in channels)
+ {
+ m_IrcClient.PartChannel(channel, "Caught in the bitstream...");
+ System.Console.WriteLine(String.Format("Parted channel #{0}...",
+ channel.Name));
+ }
+ }
+
+ 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()));
+ }
+ }
+
+ private void ExtractMessage(string parameters,
+ out string message)
+ {
+ int startIndex = parameters.IndexOf(':');
+ if (startIndex != -1)
+ {
+ message = parameters.Substring(startIndex + 1);
+ }
+ else
+ {
+ message = parameters;
+ }
+ }
+
+ private bool GetChannelName(IrcMessage message,
+ out string channelName)
+ {
+ if (message.Parameters == null || !message.Parameters.StartsWith("#"))
+ {
+ channelName = null;
+ return false;
+ }
+
+ int index = message.Parameters.IndexOf(' ');
+ if (index == -1)
+ index = message.Parameters.Length;
+ 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))
+ {
+ foreach (IrcChannel channel in channels)
+ {
+ if (String.Compare(channel.Name, channelName, true) == 0)
+ {
+ context = new ChannelMessageContext(channel);
+ return true;
+ }
+ }
+ }
+ else if (GetTargetNickname(message,
+ out nickname))
+ {
+ IrcUser targetUser = new IrcUser(m_IrcClient,
+ nickname);
+ if (String.Compare(targetUser.Nickname, botname, true) == 0)
+ {
+ IrcUser sourceUser = new IrcUser(m_IrcClient,
+ message.PrefixNickname);
+ context = new UserMessageContext(sourceUser);
+ return true;
+ }
+ }
+ }
+ context = null;
+ return false;
+ }
+
+ private void client_MessageReceived(IrcMessage message)
+ {
+ try
+ {
+ if (message.Command != null &&
+ message.Parameters != null)
+ {
+ string injectMessage;
+ ExtractMessage(message.Parameters,
+ out injectMessage);
+ MessageContext context;
+ if (ShouldAcceptMessage(message,
+ out context))
+ {
+ Console.WriteLine(String.Format("Injecting: {0} from {1}",
+ injectMessage,
+ GetMessageSource(context)));
+ InjectMessage(context,
+ injectMessage);
+ }
+ else
+ {
+ Console.WriteLine("Received: " + message.Line);
+ }
+ }
+ else
+ {
+ Console.WriteLine("Received: " + message.Line);
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine(String.Format("Exception: {0}", ex));
+ }
+ }
+
+ private void client_ChannelUserDatabaseChanged(IrcChannel channel)
+ {
+ }
+ }
+}
using System.IO;\r
using System.Data;\r
using System.Threading;\r
+\r
using TechBot.IRCLibrary;\r
\r
namespace TechBot.Library\r
{\r
- public class TechBotService\r
+ public abstract class TechBotService\r
{\r
- private IServiceOutput serviceOutput;\r
+ protected IServiceOutput serviceOutput;\r
private string chmPath;\r
private string mainChm;\r
- private string ntstatusXml;\r
- private string winerrorXml;\r
- private string hresultXml;\r
- private string wmXml;\r
- private string svnCommand;\r
- private string bugUrl, WineBugUrl, SambaBugUrl;\r
- private List<Command> commands = new List<Command>();\r
\r
public TechBotService(IServiceOutput serviceOutput,\r
string chmPath,\r
string mainChm)\r
- //string ntstatusXml,\r
- //string winerrorXml,\r
- //string hresultXml,\r
- //string wmXml,\r
- //string svnCommand,\r
- //string bugUrl,\r
- //string WineBugUrl,\r
- //string SambaBugUrl)\r
{\r
this.serviceOutput = serviceOutput;\r
this.chmPath = chmPath;\r
this.mainChm = mainChm;\r
- this.ntstatusXml = ntstatusXml;\r
- this.winerrorXml = winerrorXml;\r
- this.hresultXml = hresultXml;\r
- this.wmXml = wmXml;\r
- this.svnCommand = svnCommand;\r
- this.bugUrl = bugUrl;\r
- this.WineBugUrl = WineBugUrl;\r
- this.SambaBugUrl = SambaBugUrl;\r
}\r
\r
- public void Run()\r
+ public virtual void Run()\r
{\r
- commands.Add(new HelpCommand(this));\r
- /*commands.Add(new ApiCommand(serviceOutput,\r
- chmPath,\r
- mainChm));*/\r
- commands.Add(new NtStatusCommand(this));\r
- commands.Add(new WinerrorCommand(this));\r
- commands.Add(new HResultCommand(this));\r
- commands.Add(new ErrorCommand(this));\r
- commands.Add(new WMCommand(this));\r
- commands.Add(new SvnCommand(this));\r
- commands.Add(new ReactOSBugUrl(this));\r
- commands.Add(new SambaBugUrl(this));\r
- commands.Add(new WineBugUrl(this));\r
+ CommandFactory.LoadPlugins();\r
}\r
\r
public IServiceOutput ServiceOutput\r
get { return serviceOutput; }\r
}\r
\r
- public IList<Command> Commands\r
+ public CommandBuilderCollection Commands\r
{\r
- get { return commands; }\r
+ get { return CommandFactory.Commands; }\r
+ }\r
+\r
+ public void InjectMessage(MessageContext context, string message)\r
+ {\r
+ ParseCommandMessage(context,\r
+ message);\r
}\r
- \r
- public void InjectMessage(MessageContext context,\r
- string message)\r
- {\r
- if (message.StartsWith("!"))\r
- ParseCommandMessage(context,\r
- message);\r
- }\r
\r
private bool IsCommandMessage(string message)\r
{\r
else\r
commandName = message.Trim();\r
\r
- foreach (Command command in commands)\r
- {\r
- foreach (string cmd in command.AvailableCommands)\r
+ foreach (CommandBuilder command in Commands)\r
+ {\r
+ if (command.Name == commandName)\r
{\r
- if (cmd == commandName)\r
- {\r
- command.Handle(context,\r
- commandName, \r
- commandParams);\r
- return;\r
- }\r
+ //Create a new instance of the required command type\r
+ Command cmd = command.CreateCommand();\r
+\r
+ cmd.TechBot = this;\r
+ cmd.Context = context;\r
+ cmd.ParseParameters(message);\r
+ cmd.ExecuteCommand();\r
+\r
+ return;\r
}\r
- }\r
+ }\r
}\r
}\r
}\r
+++ /dev/null
-using System;
-using System.Collections.Generic;
-using System.Text;
-
-namespace TechBot.Library
-{
- class WineBugUrl : BugCommand
- {
- public WineBugUrl(TechBotService techBot)
- : base(techBot)
- {
- }
-
- public override string[] AvailableCommands
- {
- get { return new string[] { "winebug" }; }
- }
-
- protected override string BugUrl
- {
- get { return "http://bugs.winehq.org/show_bug.cgi?id={0}"; }
- }
-
- public override string Help()
- {
- return "!winebug <number>";
- }
- }
-}
+++ /dev/null
-<Combine fileversion="1.0" name="TechBot" description="">\r
- <StartMode startupentry="TechBot" single="True">\r
- <Execute entry="TechBot" type="None" />\r
- <Execute entry="TechBot.Library" type="None" />\r
- <Execute entry="CHMLibrary" type="None" />\r
- <Execute entry="Compression" type="None" />\r
- <Execute entry="TechBot.Console" type="None" />\r
- <Execute entry="TechBot.IRCLibrary" type="None" />\r
- </StartMode>\r
- <Entries>\r
- <Entry filename=".\TechBot\TechBot.prjx" />\r
- <Entry filename=".\TechBot.Library\TechBot.Library.prjx" />\r
- <Entry filename=".\CHMLibrary\CHMLibrary.prjx" />\r
- <Entry filename=".\Compression\Compression.prjx" />\r
- <Entry filename=".\TechBot.Console\TechBot.Console.prjx" />\r
- <Entry filename=".\TechBot.IRCLibrary\TechBot.IRCLibrary.prjx" />\r
- </Entries>\r
- <Configurations active="Debug">\r
- <Configuration name="Release">\r
- <Entry name="TechBot" configurationname="Debug" build="False" />\r
- <Entry name="TechBot.Library" configurationname="Debug" build="False" />\r
- <Entry name="CHMLibrary" configurationname="Debug" build="False" />\r
- <Entry name="Compression" configurationname="Debug" build="False" />\r
- <Entry name="TechBot.Console" configurationname="Debug" build="False" />\r
- <Entry name="TechBot.IRCLibrary" configurationname="Debug" build="False" />\r
- </Configuration>\r
- <Configuration name="Debug">\r
- <Entry name="TechBot" configurationname="Debug" build="False" />\r
- <Entry name="TechBot.Library" configurationname="Debug" build="False" />\r
- <Entry name="CHMLibrary" configurationname="Debug" build="False" />\r
- <Entry name="Compression" configurationname="Debug" build="False" />\r
- <Entry name="TechBot.Console" configurationname="Debug" build="False" />\r
- <Entry name="TechBot.IRCLibrary" configurationname="Debug" build="False" />\r
- </Configuration>\r
- </Configurations>\r
-</Combine>
\ No newline at end of file
--- /dev/null
+using System;
+using System.ComponentModel;
+using System.ServiceProcess;
+using System.Configuration.Install;
+using System.Collections.Generic;
+using System.Text;
+
+namespace TechBot
+{
+ [RunInstaller(true)]
+ public class ProjectInstaller : Installer
+ {
+ public ProjectInstaller()
+ {
+ ServiceProcessInstaller spi = null;
+ ServiceInstaller si = null;
+
+ spi = new ServiceProcessInstaller();
+ spi.Account = ServiceAccount.LocalSystem;
+
+ si = new ServiceInstaller();
+ si.ServiceName = "TechBot";
+ si.StartType = ServiceStartMode.Automatic;
+
+ Installers.AddRange(new Installer[] { spi, si });
+ }
+ }
+}
SetupConfiguration();\r
System.Console.WriteLine("TechBot irc service...");\r
\r
- IrcService ircService = new IrcService(IRCServerHostName,\r
+ IrcTechBotService ircService = new IrcTechBotService(IRCServerHostName,\r
IRCServerHostPort,\r
IRCChannelNames,\r
IRCBotName,\r
IRCBotPassword,\r
ChmPath,\r
- MainChm,\r
+ MainChm);\r
//NtstatusXml,\r
//WinerrorXml,\r
//HresultXml,\r
//WmXml,\r
//SvnCommand,\r
- BugUrl,\r
- WineBugUrl,\r
- SambaBugUrl);\r
+ //BugUrl,\r
+ //WineBugUrl,\r
+ //SambaBugUrl);\r
ircService.Run();\r
}\r
\r
</ItemGroup>
<ItemGroup>
<Compile Include="AssemblyInfo.cs" />
+ <Compile Include="ProjectInstaller.cs">
+ <SubType>Component</SubType>
+ </Compile>
<Compile Include="ServiceThread.cs" />
<Compile Include="TechBotService.cs">
<SubType>Component</SubType>
<Reference Include="System.Configuration.Install" />
<Reference Include="System.Data" />
<Reference Include="System.ServiceProcess" />
+ <Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\TechBot.IRCLibrary\TechBot.IRCLibrary.csproj">
}\r
}\r
}\r
-\r
-[RunInstaller(true)]\r
-public class ProjectInstaller : Installer\r
-{\r
- public ProjectInstaller()\r
- {\r
- ServiceProcessInstaller spi = new ServiceProcessInstaller();\r
- spi.Account = ServiceAccount.LocalSystem;\r
- \r
- ServiceInstaller si = new ServiceInstaller();\r
- si.ServiceName = "TechBot";\r
- si.StartType = ServiceStartMode.Automatic;\r
- Installers.AddRange(new Installer[] {spi, si});\r
- }\r
-}\r