PageRenderTime 24ms CodeModel.GetById 11ms app.highlight 10ms RepoModel.GetById 1ms app.codeStats 0ms

/SparkleLib/SparkleListenerIrc.cs

http://github.com/hbons/SparkleShare
C# | 219 lines | 146 code | 46 blank | 27 comment | 17 complexity | 49b21b59d3b438dae56d3b43b72c0124 MD5 | raw file
  1//   SparkleShare, a collaboration and sharing tool.
  2//   Copyright (C) 2010  Hylke Bons <hylkebons@gmail.com>
  3//
  4//   This program is free software: you can redistribute it and/or modify
  5//   it under the terms of the GNU General Public License as published by
  6//   the Free Software Foundation, either version 3 of the License, or
  7//   (at your option) any later version.
  8//
  9//   This program is distributed in the hope that it will be useful,
 10//   but WITHOUT ANY WARRANTY; without even the implied warranty of
 11//   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 12//   GNU General Public License for more details.
 13//
 14//   You should have received a copy of the GNU General Public License
 15//   along with this program. If not, see <http://www.gnu.org/licenses/>.
 16
 17
 18using System;
 19using System.Text;
 20using System.Threading;
 21using System.Security.Cryptography;
 22
 23using Meebey.SmartIrc4net;
 24
 25namespace SparkleLib {
 26
 27    public class SparkleListenerIrc : SparkleListenerBase {
 28
 29        private Thread thread;
 30        private IrcClient client;
 31        private string nick;
 32        private string announcements_password;
 33        private bool allow_passwordless_join;
 34
 35
 36        public SparkleListenerIrc (Uri server, string folder_identifier) :
 37            base (server, folder_identifier)
 38        {
 39            // Try to get a uniqueish nickname
 40            this.nick = SHA1 (DateTime.Now.ToString ("ffffff") + "sparkles");
 41
 42            // Most irc servers don't allow nicknames starting
 43            // with a number, so prefix an alphabetic character
 44            this.nick = "s" + this.nick.Substring (0, 7);
 45
 46            // Optional password to make the channel access more safe
 47            this.announcements_password =
 48                SparkleConfig.DefaultConfig.GetConfigOption ("announcements_password");
 49
 50            // Option to allow access to channel when no password is defined
 51            try {
 52                string option = SparkleConfig.DefaultConfig.GetConfigOption ("allow_passwordless_join");
 53                this.allow_passwordless_join = (option == null || Convert.ToBoolean (option));
 54            } catch (Exception) {
 55                this.allow_passwordless_join = true;
 56            }
 57
 58            base.channels.Add ("#" + folder_identifier);
 59
 60            this.client = new IrcClient () {
 61                PingTimeout  = 180,
 62                PingInterval = 60
 63            };
 64
 65            string proxy  = Environment.GetEnvironmentVariable ("http_proxy");
 66            Uri proxy_uri = null;
 67            if (!String.IsNullOrEmpty (proxy) &&
 68                Uri.TryCreate (proxy, UriKind.Absolute, out proxy_uri)) {
 69
 70                if (proxy_uri.Scheme == "http") {
 71                    this.client.ProxyType = ProxyType.Http;
 72                    this.client.ProxyHost = proxy_uri.Host;
 73                    this.client.ProxyPort = proxy_uri.Port;
 74                }
 75            }
 76
 77            this.client.OnConnected += delegate {
 78                base.is_connecting = false;
 79                OnConnected ();
 80            };
 81
 82            this.client.OnDisconnected += delegate {
 83                base.is_connecting = false;
 84                OnDisconnected ();
 85            };
 86
 87            this.client.OnError += delegate {
 88                base.is_connecting = false;
 89                OnDisconnected ();
 90            };
 91
 92            this.client.OnChannelMessage += delegate (object o, IrcEventArgs args) {
 93                string message = args.Data.Message.Trim ();
 94                string folder_id = args.Data.Channel.Substring (1); // remove the starting hash
 95                OnAnnouncement (new SparkleAnnouncement (folder_id, message));
 96            };
 97        }
 98
 99
100        public override bool IsConnected {
101            get {
102              return this.client.IsConnected;
103            }
104        }
105
106
107        // Starts a new thread and listens to the channel
108        public override void Connect ()
109        {
110            SparkleHelpers.DebugInfo ("ListenerIrc", "Connecting to " + Server);
111
112            base.is_connecting = true;
113
114            this.thread = new Thread (
115                new ThreadStart (delegate {
116                    try {
117                        // Connect, login, and join the channel
118                        int port = base.server.Port;
119
120                        if (port < 0)
121                            port = 6667;
122
123                        this.client.Connect (base.server.Host, port);
124                        this.client.Login (this.nick, this.nick, 8, this.nick);
125
126                        foreach (string channel in base.channels) {
127                            SparkleHelpers.DebugInfo ("ListenerIrc", "Joining channel " + channel);
128
129                            if (!string.IsNullOrEmpty (this.announcements_password)) {
130                                SparkleHelpers.DebugInfo ("ListenerIrc", "Password set to access the channel");
131                                this.client.RfcJoin (channel, this.announcements_password);
132                                this.client.RfcMode (channel, "+k " + this.announcements_password);
133
134                            } else {
135                                if (this.allow_passwordless_join) {
136                                    SparkleHelpers.DebugInfo ("ListenerIrc", "Accessing unprotected channel, change the setting to not access");
137                                    this.client.RfcJoin (channel);
138                                
139                                } else {
140                                    SparkleHelpers.DebugInfo ("ListenerIrc", "Unprotected channel, change the setting to access");
141                                    base.is_connecting = false;
142                                    OnDisconnected ();
143                                    throw new ConnectionException ("Unprotected channel, change the setting to access");
144                                }
145                            }
146
147                            this.client.RfcMode (channel, "+s");
148                        }
149
150                        // List to the channel, this blocks the thread
151                        this.client.Listen ();
152
153                        // Disconnect when we time out
154                        this.client.Disconnect ();
155
156                    } catch (ConnectionException e) {
157                        SparkleHelpers.DebugInfo ("ListenerIrc", "Could not connect to " + Server + ": " + e.Message);
158                    }
159                })
160            );
161
162            this.thread.Start ();
163        }
164
165
166        public override void AlsoListenTo (string folder_identifier)
167        {
168            string channel = "#" + folder_identifier;
169            if (!base.channels.Contains (channel)) {
170                base.channels.Add (channel);
171
172                if (IsConnected) {
173                    SparkleHelpers.DebugInfo ("ListenerIrc", "Joining channel " + channel);
174                    if (this.announcements_password != null) {
175                        SparkleHelpers.DebugInfo ("ListenerIrc", "Password set to access the channel");
176                        this.client.RfcJoin (channel, this.announcements_password);
177                        this.client.RfcMode (channel, "+k " + this.announcements_password);
178                    } else {
179                        if (allow_passwordless_join) {
180                            SparkleHelpers.DebugInfo ("ListenerIrc", "Accessing a dangerous channel change the setting to not access");
181                            this.client.RfcJoin (channel);
182                        } else {
183                            SparkleHelpers.DebugInfo ("ListenerIrc", "Dangerous channel, change the setting to access");
184                        }
185                    }
186                    this.client.RfcMode (channel, "+s");
187                }
188            }
189        }
190
191
192        public override void Announce (SparkleAnnouncement announcement)
193        {
194            string channel = "#" + announcement.FolderIdentifier;
195            this.client.SendMessage (SendType.Message, channel, announcement.Message);
196
197            // Also announce to ourselves for debugging purposes
198            // base.OnAnnouncement (announcement);
199        }
200
201
202        public override void Dispose ()
203        {
204            this.thread.Abort ();
205            this.thread.Join ();
206            base.Dispose ();
207        }
208
209
210        // Creates a SHA-1 hash of input
211        private string SHA1 (string s)
212        {
213            SHA1 sha1 = new SHA1CryptoServiceProvider ();
214            Byte[] bytes = ASCIIEncoding.Default.GetBytes (s);
215            Byte[] encoded_bytes = sha1.ComputeHash (bytes);
216            return BitConverter.ToString (encoded_bytes).ToLower ().Replace ("-", "");
217        }
218    }
219}