]> jfr.im git - z_archive/kelsier.git/blob - Bot.cs
3384faa6564e90b38c898f161b189cd1d868bcbd
[z_archive/kelsier.git] / Bot.cs
1 // Kelsier project - Bot state and parser code (Bot.cs)
2 // Written by the Jobbig codeteam. <http://jobbig.eu/code/>
3 //
4 // Copyright 2013 John Runyon.
5 //
6 // This file is part of the Kelsier project.
7 //
8 // Kelsier is free software: you can redistribute it and/or modify
9 // it under the terms of the GNU Affero General Public License as published by
10 // the Free Software Foundation, either version 3 of the License, or
11 // (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU Affero General Public License for more details.
17 //
18 // You should have received a copy of the GNU Affero General Public License
19 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 //
21
22 using System;
23 using System.Collections.Generic;
24 using System.Linq;
25 using System.Text;
26 using MySql.Data.MySqlClient;
27 using System.Net;
28 using System.Net.Sockets;
29
30 namespace Kelsier.Common {
31 public class Bot {
32 public int id { get; private set; }
33
34 public string nick { get; private set; }
35 public string ident { get; private set; }
36 public string realname { get; private set; }
37 public string localip { get; private set; }
38 public string server { get; private set; }
39 public int serverport { get; private set; }
40
41 private IPEndPoint local;
42
43 private Socket s;
44 public bool online { get; private set; }
45
46 private Logger log;
47
48
49 public Bot(int id) {
50 this.id = id;
51
52 this.log = new Logger(id.ToString("0000"), Info.log);
53
54 MySqlDataReader rdr = Info.db.queryReader("SELECT nick, ident, realname, bindip, server, serverport FROM bots WHERE id = @id", new object[] { "@id", id });
55 rdr.Read();
56
57 this.nick = rdr.GetString("nick");
58 this.ident = rdr.GetString("ident");
59 this.realname = rdr.GetString("realname");
60
61 if (rdr.IsDBNull(rdr.GetOrdinal("bindip"))) {
62 this.localip = null;
63 this.local = new IPEndPoint(IPAddress.Any, 0);
64 } else {
65 this.localip = rdr.GetString("bindip");
66 this.local = new IPEndPoint(IPAddress.Parse(this.localip), 0);
67 }
68
69 this.server = rdr.GetString("server");
70 this.serverport = rdr.GetInt32("serverport");
71 }
72
73 public string connect() {
74 if (online) throw new InvalidStateException();
75
76 s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
77 s.Bind(local);
78 s.Connect(server, serverport);
79
80 register();
81
82 Stator rcvstate = new Stator();
83 s.BeginReceive(rcvstate.buffer, 0, 1, SocketFlags.None, new AsyncCallback(dataIn), rcvstate);
84
85 return "TODO";
86 }
87
88 public void dataIn(IAsyncResult ar) {
89 Stator rcvstate = (Stator)ar.AsyncState;
90 s.EndReceive(ar);
91
92 if (rcvstate.buffer[0] == '\n') {
93 string linein = rcvstate.buffersb.ToString();
94 processData(linein);
95 rcvstate = new Stator();
96 } else if (rcvstate.buffer[0] != '\r') {
97 rcvstate.buffersb.Append(Encoding.ASCII.GetString(rcvstate.buffer, 0, 1));
98 }
99 s.BeginReceive(rcvstate.buffer, 0, 1, SocketFlags.None, new AsyncCallback(dataIn), rcvstate);
100 }
101 private void send(string data, params object[] args) {
102 log.info(">>> " + data);
103 s.Send(Encoding.ASCII.GetBytes(data + "\n"));
104 }
105
106 private void processData(string data) {
107 log.info("<<< " + data);
108
109 string[] parts;
110 string source = null;
111 if (data.StartsWith(":")) {
112 parts = data.Split((char[])null, 2, StringSplitOptions.RemoveEmptyEntries);
113 source = parts[0].Substring(1);
114 data = parts[1];
115 }
116
117 parts = data.Split((char[])null, 2, StringSplitOptions.RemoveEmptyEntries);
118 if (parts[0] == "PRIVMSG") {
119 processMsg(source, parts[1]);
120 } else if (parts[0] == "376") {
121 send("JOIN #jobbig.kelsier");
122 } else if (parts[0] == "PING") {
123 send("PONG "+parts[1]);
124 }
125 }
126 // processMsg("DimeCadmium!dime@jobbig.eu", "#mustis :hi");
127 private void processMsg(string source, string data) {
128 string[] dataparts = data.Split((char[])null, 2, StringSplitOptions.RemoveEmptyEntries);
129
130 string nick = (source.Split(new char[] { '!' }))[0];
131 string target = dataparts[0];
132 string message = dataparts[1];
133 if (message.StartsWith(":"))
134 message = message.Substring(1);
135 string[] msgparts = message.Split((char[])null, StringSplitOptions.RemoveEmptyEntries);
136
137 // TODO check msgparts[0] first char for trigger
138 string cmdstr = msgparts[0].Substring(1);
139 string[] args;
140 bool chanmsg;
141 Channel chan;
142 if (target.StartsWith("#")) {
143 chanmsg = true;
144 args = new string[msgparts.Length - 1];
145 Array.Copy(msgparts, 1, args, 0, msgparts.Length - 1);
146 chan = new Channel(target);
147 } else {
148 chanmsg = false;
149 args = new string[msgparts.Length - 2];
150 Array.Copy(msgparts, 2, args, 0, msgparts.Length - 2);
151 chan = new Channel(msgparts[1]);
152 }
153
154 User user = new User(nick);
155
156 Command cmd = new Command(this, cmdstr, args, user, chan, chanmsg);
157 }
158
159 private void register() {
160 send(String.Format("NICK {0}", nick));
161 send(String.Format("USER {0} * * :{1}", ident, realname));
162 online = true;
163 }
164 }
165
166 public class InvalidStateException : Exception { }
167
168 public class Stator {
169 public byte[] buffer = new byte[1];
170 public StringBuilder buffersb = new StringBuilder();
171 }
172 }