--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using MySql.Data.MySqlClient;
+using System.Net;
+using System.Net.Sockets;
+
+namespace Kelsier {
+ class Bot {
+ public int id { get; private set; }
+
+ public string nick { get; private set; }
+ public string ident { get; private set; }
+ public string realname { get; private set; }
+ public string localip { get; private set; }
+ public string server { get; private set; }
+ public int serverport { get; private set; }
+
+ private IPEndPoint local;
+
+ private Socket s;
+ public bool online { get; private set; }
+
+ private Logger log;
+
+
+ public Bot(int id) {
+ this.id = id;
+
+ this.log = new Logger(id.ToString("0000"), Root.log);
+
+ MySqlDataReader rdr = Root.db.queryReader("SELECT nick, ident, realname, bindip, server, serverport FROM bots WHERE id = @id", new object[] { "@id", id });
+ rdr.Read();
+
+ this.nick = rdr.GetString("nick");
+ this.ident = rdr.GetString("ident");
+ this.realname = rdr.GetString("realname");
+
+ if (rdr.IsDBNull(rdr.GetOrdinal("bindip"))) {
+ this.localip = null;
+ this.local = new IPEndPoint(IPAddress.Any, 0);
+ } else {
+ this.localip = rdr.GetString("bindip");
+ this.local = new IPEndPoint(IPAddress.Parse(this.localip), 0);
+ }
+
+ this.server = rdr.GetString("server");
+ this.serverport = rdr.GetInt32("serverport");
+ }
+
+ public string connect() {
+ if (online) throw new InvalidStateException();
+
+ s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
+ s.Bind(local);
+ s.Connect(server, serverport);
+
+ Stator rcvstate = new Stator();
+ s.BeginReceive(rcvstate.buffer, 0, 1, SocketFlags.None, new AsyncCallback(dataIn), rcvstate);
+
+ return "TODO";
+ }
+
+ public void dataIn(IAsyncResult ar) {
+ Stator rcvstate = (Stator)ar.AsyncState;
+ s.EndReceive(ar);
+
+ if (rcvstate.buffer[0] == '\n') {
+ processData(rcvstate.buffersb.ToString());
+ rcvstate = new Stator();
+ } else {
+ rcvstate.buffersb.Append(Encoding.ASCII.GetString(rcvstate.buffer, 0, 1));
+ }
+ s.BeginReceive(rcvstate.buffer, 0, 1, SocketFlags.None, new AsyncCallback(dataIn), rcvstate);
+ }
+ private void send(string data, params object[] args) {
+ log.debug(">>> " + data);
+ s.Send(Encoding.ASCII.GetBytes(data + "\n"));
+ }
+
+ private void processData(string data) {
+ log.debug("<<< " + data);
+
+ if (!online) { register(); return; }
+
+ short numeric;
+ if (data.StartsWith(":") && Int16.TryParse(data.Substring(data.IndexOf(' ')+1, 3), out numeric)) {
+ if (numeric == 1) {
+ send("JOIN #mustis");
+ send("PRIVMSG #mustis :lolol!");
+ }
+ } else if (data.Substring(0, 4) == "PING") {
+ send("PONG" + data.Substring(4));
+ }
+ }
+
+ private void register() {
+ send(String.Format("NICK {0}", nick));
+ send(String.Format("USER {0} * * :{1}", ident, realname));
+ online = true;
+ }
+ }
+
+ class InvalidStateException : Exception { }
+
+ class Stator {
+ public byte[] buffer = new byte[1];
+ public StringBuilder buffersb = new StringBuilder();
+ }
+}
namespace Kelsier {
class Database {
- protected MySqlConnection _dbh = null;
- public MySqlConnection dbh { get { return _dbh; } }
+ public MySqlConnection dbh { get; private set; }
+
+ private string dbinfo;
/// <summary>
/// </summary>
/// <param name="dbinfo">Connector string</param>
public Database(string dbinfo) {
- _dbh = new MySqlConnection(dbinfo);
+ this.dbinfo = dbinfo;
+
+ dbh = new MySqlConnection(this.dbinfo);
+ dbh.Open();
+ }
+ public Database(Database copy) {
+ this.dbinfo = copy.dbinfo;
+
+ dbh = new MySqlConnection(this.dbinfo);
+ dbh.Open();
+ }
+
+ ~Database() {
+ dbh.Close();
}
- public void Connect() {
- try {
- dbh.Open();
- } catch (MySqlException e) {
- Root.log.error("Error: {0}", e.ToString());
+ public int execute(string query) {
+ MySqlCommand cmdo = new MySqlCommand(query, dbh);
+ return cmdo.ExecuteNonQuery();
+ }
+ public int execute(string query, object[] keys) {
+ MySqlCommand cmdo = new MySqlCommand();
+ cmdo.Connection = dbh;
+ cmdo.CommandText = query;
+ cmdo.Prepare();
+
+ for (int i = 0; i < keys.Length; i += 2) {
+ cmdo.Parameters.AddWithValue(keys[i].ToString(), keys[i + 1]);
}
+
+ return cmdo.ExecuteNonQuery();
}
public object queryScalar(string query) {
MySqlCommand cmdo = new MySqlCommand(query, dbh);
return cmdo.ExecuteScalar();
}
+ public object queryScalar(string query, object[] keys) {
+ MySqlCommand cmdo = new MySqlCommand();
+ cmdo.Connection = dbh;
+ cmdo.CommandText = query;
+ cmdo.Prepare();
+
+ for (int i = 0; i < keys.Length; i += 2) {
+ cmdo.Parameters.AddWithValue(keys[i].ToString(), keys[i + 1]);
+ }
+
+ return cmdo.ExecuteScalar();
+ }
public MySqlDataReader queryReader(string query) {
MySqlCommand cmdo = new MySqlCommand(query, dbh);
return cmdo.ExecuteReader();
}
+ public MySqlDataReader queryReader(string query, object[] keys) {
+ if (keys.Length % 2 != 0) {
+ throw new PlaceholdersException();
+ }
+ MySqlCommand cmdo = new MySqlCommand();
+ cmdo.Connection = dbh;
+ cmdo.CommandText = query;
+ cmdo.Prepare();
+
+ for (int i = 0; i < keys.Length; i += 2) {
+ cmdo.Parameters.AddWithValue(keys[i].ToString(), keys[i + 1]);
+ }
+ return cmdo.ExecuteReader();
+ }
}
+
+ class PlaceholdersException : Exception { }
}
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFrameworkProfile>Client</TargetFrameworkProfile>
<FileAlignment>512</FileAlignment>
+ <PublishUrl>publish\</PublishUrl>
+ <Install>true</Install>
+ <InstallFrom>Disk</InstallFrom>
+ <UpdateEnabled>false</UpdateEnabled>
+ <UpdateMode>Foreground</UpdateMode>
+ <UpdateInterval>7</UpdateInterval>
+ <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+ <UpdatePeriodically>false</UpdatePeriodically>
+ <UpdateRequired>false</UpdateRequired>
+ <MapFileExtensions>true</MapFileExtensions>
+ <ApplicationRevision>0</ApplicationRevision>
+ <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
+ <IsWebBootstrapper>false</IsWebBootstrapper>
+ <UseApplicationTrust>false</UseApplicationTrust>
+ <BootstrapperEnabled>true</BootstrapperEnabled>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<PlatformTarget>x86</PlatformTarget>
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
+ <Compile Include="Bot.cs" />
<Compile Include="Database.cs" />
<Compile Include="Logger.cs" />
<Compile Include="Program.cs" />
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
</ItemGroup>
+ <ItemGroup>
+ <BootstrapperPackage Include=".NETFramework,Version=v4.0,Profile=Client">
+ <Visible>False</Visible>
+ <ProductName>Microsoft .NET Framework 4 Client Profile %28x86 and x64%29</ProductName>
+ <Install>true</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.Net.Client.3.5">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
+ <Install>false</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 3.5 SP1</ProductName>
+ <Install>false</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
+ <Visible>False</Visible>
+ <ProductName>Windows Installer 3.1</ProductName>
+ <Install>true</Install>
+ </BootstrapperPackage>
+ </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <PropertyGroup>
+ <PostBuildEvent>
+ </PostBuildEvent>
+ </PropertyGroup>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
namespace Kelsier {
class Logger {
- protected TextWriter[] debugs, infos, errors;
+ public LogOutput[] debugs {get; private set; }
+ public LogOutput[] infos { get; private set; }
+ public LogOutput[] errors { get; private set; }
+ public string from { get; private set; }
/// <summary>
/// Construct a Logger, writing to the specified TextWriter objects. Use an empty array to disable an output.
/// <param name="debugs">Array of TextWriter's to use for debug output</param>
/// <param name="infos">...for info output</param>
/// <param name="errors">...for error output</param>
- public Logger(TextWriter[] debugs, TextWriter[] infos, TextWriter[] errors) {
+ public Logger(string from, LogOutput[] debugs, LogOutput[] infos, LogOutput[] errors) {
+ int fromid;
+ if (Int32.TryParse(from, out fromid)) {
+ this.from = fromid.ToString("0000");
+ } else {
+ this.from = from;
+ }
+
this.debugs = debugs;
this.infos = infos;
this.errors = errors;
- this.debug("Starting logging (debug) here at {0}", DateTime.Now.ToString("F"));
- this.info("Starting logging (info) here at {0}", DateTime.Now.ToString("F"));
- this.error("Starting logging (error) here at {0}", DateTime.Now.ToString("F"));
+ if (from == "Root") {
+ this.debug("Starting Root logging (debug) here at "+DateTime.Now.ToString("F"));
+ this.info("Starting Root logging (info) here at "+DateTime.Now.ToString("F"));
+ this.error("Starting Root logging (error) here at "+DateTime.Now.ToString("F"));
+ }
}
+ public Logger(string from, Logger copy) {
+ this.from = from;
- ~Logger() {
- this.debug("Stopping logging (debug) here at {0}", DateTime.Now.ToString("F"));
- this.info("Stopping logging (info) here at {0}", DateTime.Now.ToString("F"));
- this.error("Stopping logging (error) here at {0}", DateTime.Now.ToString("F"));
- foreach (TextWriter[] group in new TextWriter[][] { this.debugs, this.infos, this.errors }) {
- foreach (TextWriter outw in group) {
- outw.Close();
- }
- }
+ this.debugs = copy.debugs;
+ this.infos = copy.infos;
+ this.errors = copy.infos;
}
/// <summary>
/// </summary>
/// <param name="msg">Log message (with formatting placeholders, if desired)</param>
/// <param name="args">Formatting replacements.</param>
- public void debug(string msg, params object[] args) {
- foreach (TextWriter outw in this.debugs) {
- outw.WriteLine("(D@" + DateTime.Now.ToString("HH:mm:ss") + ")[MAIN] " + msg, args);
+ public void debug(object msg) {
+ foreach (LogOutput outw in debugs) {
+ if (outw.open)
+ outw.writer.WriteLine("(D@" + DateTime.Now.ToString("HH:mm:ss") + ")[" + from + "] " + msg.ToString());
}
}
/// </summary>
/// <param name="msg">Log message (with formatting placeholders, if desired)</param>
/// <param name="args">Formatting replacements.</param>
- public void info(string msg, params object[] args) {
- foreach (TextWriter outw in this.infos) {
- outw.WriteLine("(I@" + DateTime.Now.ToString("HH:mm:ss") + ")[MAIN] " + msg, args);
+ public void info(object msg) {
+ foreach (LogOutput outw in infos) {
+ if (outw.open)
+ outw.writer.WriteLine("(I@" + DateTime.Now.ToString("HH:mm:ss") + ")[" + from + "] " + msg.ToString());
}
}
/// </summary>
/// <param name="msg">Log message (with formatting placeholders, if desired)</param>
/// <param name="args">Formatting replacements.</param>
- public void error(string msg, params object[] args) {
- foreach (TextWriter outw in this.errors) {
- outw.WriteLine("(E@" + DateTime.Now.ToString("HH:mm:ss") + ")[MAIN] " + msg, args);
+ public void error(object msg) {
+ foreach (LogOutput outw in errors) {
+ if (outw.open)
+ outw.writer.WriteLine("(E@" + DateTime.Now.ToString("HH:mm:ss") + ")[" + from + "] " + msg.ToString());
}
}
}
+
+ class LogOutput {
+ public TextWriter writer { get; private set; }
+ public bool open;
+ public LogOutput(TextWriter writer) {
+ this.writer = writer;
+ this.open = true;
+ }
+ }
}
using System.Linq;
using System.Text;
using MySql.Data.MySqlClient;
+using System.IO;
namespace Kelsier {
class Root {
- static protected Database _db = null;
- static public Database db { get { return _db; } }
+ static public Database db { get; private set; }
+ static public Logger log { get; private set; }
- static protected Logger _log;
- static public Logger log { get { return _log; } }
+ static private Dictionary<int, Bot> bots; // accessed by this.bot(int id)
static void Main(string[] args) {
- System.IO.StreamWriter fileout = new System.IO.StreamWriter("kelsier.log", false);
+ StreamWriter fileout = new StreamWriter("kelsier.log", false);
fileout.AutoFlush = true;
- System.IO.TextWriter[] outputs = { Console.Out, fileout };
- _log = new Logger(outputs, outputs, outputs);
-
- _db = new Database(Properties.Settings.Default.dbstr);
-
- db.Connect();
-
- log.debug("1 + 3 = {0}", db.queryScalar("SELECT 1+3").ToString());
-
- _log = null;
- GC.Collect();
- GC.WaitForPendingFinalizers();
-
-#if DEBUG
- Console.Write("Key to end...");
- Console.ReadKey();
-#endif
+ LogOutput[] outputs = new LogOutput[] { new LogOutput(Console.Out), new LogOutput(fileout) };
+ log = new Logger("Root", new LogOutput[] { new LogOutput(Console.Out) }, outputs, outputs);
+
+ db = new Database(Properties.Settings.Default.dbstr);
+
+ List<int> botids = new List<int>();
+ MySqlDataReader rdr = db.queryReader("SELECT id FROM bots");
+ while (rdr.Read()) {
+ botids.Add(rdr.GetInt32("id"));
+ }
+ rdr.Close();
+
+ bots = new Dictionary<int, Bot>();
+ foreach (int key in botids) {
+ bots.Add(key, new Bot(key));
+ bots[key].connect();
+ }
+
+ while (true) {
+ System.Threading.Thread.Sleep(2000);
+ }
}
+
+ static Bot bot(int id) { return bots[id]; }
}
--- /dev/null
+/*!40101 SET @saved_cs_client = @@character_set_client */;
+/*!40101 SET character_set_client = utf8 */;
+CREATE TABLE `bots` (
+ `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
+ `nick` varchar(40) NOT NULL,
+ `ident` varchar(10) NOT NULL DEFAULT 'kelsier',
+ `realname` varchar(100) NOT NULL DEFAULT 'Kelsier IRC Bot',
+ `bindip` varchar(15) DEFAULT NULL,
+ `server` varchar(100) NOT NULL DEFAULT 'irc.quakenet.org',
+ `serverport` smallint(5) unsigned NOT NULL DEFAULT '6667',
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
+/*!40101 SET character_set_client = @saved_cs_client */;
+INSERT INTO `bots` VALUES (1,'Kelsier','kelsier','Kelsier IRC Bot',NULL,'irc.quakenet.org',6667);