Give Techbot the ability to check for and ghost existing bots, then rename itself
[reactos.git] / irc / TechBot / TechBot.Library / TechBotIrcService.cs
1 using System;
2 using System.Text;
3 using System.Collections;
4 using System.Threading;
5
6 using TechBot.IRCLibrary;
7
8 namespace TechBot.Library
9 {
10 public class IrcServiceOutput : IServiceOutput
11 {
12 public void WriteLine(MessageContext context,
13 string message)
14 {
15 if (context is ChannelMessageContext)
16 {
17 Thread.Sleep (500);
18 ChannelMessageContext channelContext = context as ChannelMessageContext;
19 channelContext.Channel.Talk(message);
20 }
21 else if (context is UserMessageContext)
22 {
23 UserMessageContext userContext = context as UserMessageContext;
24 userContext.User.Talk(message);
25 }
26 else
27 {
28 throw new InvalidOperationException(String.Format("Unhandled message context '{0}'",
29 context.GetType()));
30 }
31 }
32 }
33
34 public class IrcTechBotService : TechBotService
35 {
36 private int port;
37 private string hostname;
38 private string channelnames;
39 private string botname;
40 private string password;
41 private IrcClient m_IrcClient;
42 private ArrayList channels = new ArrayList();
43 private bool isStopped = false;
44
45 public IrcTechBotService(string hostname,
46 int port,
47 string channelnames,
48 string botname,
49 string password)
50 : base (new IrcServiceOutput())
51 {
52 this.hostname = hostname;
53 this.port = port;
54 this.channelnames = channelnames;
55 this.botname = botname;
56 if (password == null || password.Trim() == "")
57 this.password = null;
58 else
59 this.password = password;
60 }
61
62 public override void Run()
63 {
64 //Call the base class
65 base.Run();
66
67 m_IrcClient = new IrcClient();
68 m_IrcClient.Encoding = Encoding.GetEncoding("iso-8859-1");
69 m_IrcClient.OnConnect += new OnConnectHandler(m_IrcClient_OnConnect);
70 m_IrcClient.OnConnectionLost += new OnConnectionLostHandler(m_IrcClient_OnConnectionLost);
71 m_IrcClient.OnDisconnect += new OnDisconnectHandler(m_IrcClient_OnDisconnect);
72 m_IrcClient.MessageReceived += new MessageReceivedHandler(client_MessageReceived);
73 m_IrcClient.ChannelUserDatabaseChanged += new ChannelUserDatabaseChangedHandler(client_ChannelUserDatabaseChanged);
74
75 Connect();
76 }
77
78 void m_IrcClient_OnConnect()
79 {
80 Console.WriteLine("Connected...");
81 }
82
83 private void Connect()
84 {
85 Console.WriteLine("Connecting to {0} port {1}",
86 hostname,
87 port);
88 m_IrcClient.Connect(hostname, port);
89
90 m_IrcClient.Register(botname, password, null);
91 Console.WriteLine("Registered as {0}...", m_IrcClient.Nickname);
92
93 /* Did we get the nick we wanted? */
94 if (m_IrcClient.Nickname != botname)
95 {
96 /* there must have been an existing one, kill it */
97 m_IrcClient.GhostNick(botname, password);;
98 }
99
100 JoinChannels();
101
102 while (!isStopped)
103 {
104 Thread.Sleep(1000);
105 }
106
107 PartChannels();
108 m_IrcClient.Diconnect();
109 }
110
111 void m_IrcClient_OnDisconnect()
112 {
113 Console.WriteLine("Disconnected...");
114 }
115
116 void m_IrcClient_OnConnectionLost()
117 {
118 //Dispose old connection
119 Disconnect();
120
121 //Sleep for 1 minute
122 Thread.Sleep(1000 * 60);
123
124 //Try to reconnect
125 Connect();
126 }
127
128 private void Disconnect()
129 {
130 try
131 {
132 m_IrcClient.Diconnect();
133 }
134 catch (Exception)
135 {
136 //
137 }
138 }
139
140 public void Stop()
141 {
142 isStopped = true;
143 }
144
145 private void JoinChannels()
146 {
147 foreach (string channelname in channelnames.Split(new char[] { ';' }))
148 {
149 IrcChannel channel = m_IrcClient.JoinChannel(channelname);
150 channels.Add(channel);
151 System.Console.WriteLine(String.Format("Joined channel #{0}...",
152 channel.Name));
153 }
154 }
155
156 private void PartChannels()
157 {
158 foreach (IrcChannel channel in channels)
159 {
160 m_IrcClient.PartChannel(channel, "Caught in the bitstream...");
161 System.Console.WriteLine(String.Format("Parted channel #{0}...",
162 channel.Name));
163 }
164 }
165
166 private string GetMessageSource(MessageContext context)
167 {
168 if (context is ChannelMessageContext)
169 {
170 ChannelMessageContext channelContext = context as ChannelMessageContext;
171 return String.Format("#{0}",
172 channelContext.Channel.Name);
173 }
174 else if (context is UserMessageContext)
175 {
176 UserMessageContext userContext = context as UserMessageContext;
177 return userContext.User.Nickname;
178 }
179 else
180 {
181 throw new InvalidOperationException(String.Format("Unhandled message context '{0}'",
182 context.GetType()));
183 }
184 }
185
186 private void ExtractMessage(string parameters,
187 out string message)
188 {
189 int startIndex = parameters.IndexOf(':');
190 if (startIndex != -1)
191 {
192 message = parameters.Substring(startIndex + 1);
193 }
194 else
195 {
196 message = parameters;
197 }
198 }
199
200 private bool GetChannelName(IrcMessage message,
201 out string channelName)
202 {
203 if (message.Parameters == null || !message.Parameters.StartsWith("#"))
204 {
205 channelName = null;
206 return false;
207 }
208
209 int index = message.Parameters.IndexOf(' ');
210 if (index == -1)
211 index = message.Parameters.Length;
212 else
213 index = index - 1;
214 channelName = message.Parameters.Substring(1, index);
215 return true;
216 }
217
218 private bool GetTargetNickname(IrcMessage message,
219 out string nickname)
220 {
221 if (message.Parameters == null)
222 {
223 nickname = null;
224 return false;
225 }
226
227 int index = message.Parameters.IndexOf(' ');
228 if (index == -1)
229 index = message.Parameters.Length;
230 nickname = message.Parameters.Substring(0, index);
231 Console.WriteLine("nickname: " + nickname);
232 return true;
233 }
234
235 private bool ShouldAcceptMessage(IrcMessage message,
236 out MessageContext context)
237 {
238 if (message.Command.ToUpper().Equals("PRIVMSG"))
239 {
240 string channelName;
241 string nickname;
242 if (GetChannelName(message,
243 out channelName))
244 {
245 foreach (IrcChannel channel in channels)
246 {
247 if (String.Compare(channel.Name, channelName, true) == 0)
248 {
249 context = new ChannelMessageContext(channel);
250 return true;
251 }
252 }
253 }
254 else if (GetTargetNickname(message,
255 out nickname))
256 {
257 IrcUser targetUser = new IrcUser(m_IrcClient,
258 nickname);
259 if (String.Compare(targetUser.Nickname, botname, true) == 0)
260 {
261 IrcUser sourceUser = new IrcUser(m_IrcClient,
262 message.PrefixNickname);
263 context = new UserMessageContext(sourceUser);
264 return true;
265 }
266 }
267 }
268 context = null;
269 return false;
270 }
271
272 private void client_MessageReceived(IrcMessage message)
273 {
274 try
275 {
276 if (message.Command != null &&
277 message.Parameters != null)
278 {
279 string injectMessage;
280 ExtractMessage(message.Parameters,
281 out injectMessage);
282 MessageContext context;
283 if (ShouldAcceptMessage(message,
284 out context))
285 {
286 Console.WriteLine(String.Format("Injecting: {0} from {1}",
287 injectMessage,
288 GetMessageSource(context)));
289 InjectMessage(context,
290 injectMessage);
291 }
292 else
293 {
294 Console.WriteLine("Received: " + message.Line);
295 }
296 }
297 else
298 {
299 Console.WriteLine("Received: " + message.Line);
300 }
301 }
302 catch (Exception ex)
303 {
304 Console.WriteLine(String.Format("Exception: {0}", ex));
305 }
306 }
307
308 private void client_ChannelUserDatabaseChanged(IrcChannel channel)
309 {
310 }
311 }
312 }