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