public void VerifyAndCompile() { if (Identity == null) { throw new JsonException("Missing identity field"); } if (!Permissions.Any()) { throw new JsonException(string.Format("Permission list for '{0}' is empty.", Identity)); } foreach (var channel in Permissions) { if (channel.Key != "*" && !IrcValidation.IsChannelName(channel.Key)) { throw new JsonException(string.Format("Invalid channel '{0}' for user '{1}'", channel.Key, Identity)); } if (!channel.Value.Any()) { throw new JsonException(string.Format("Permission list for '{0}' in channel '{1}' is empty.", Identity, channel.Key)); } var pattern = @"^(" + string.Join("|", channel.Value.Select(Regex.Escape)).Replace(@"\*", @".*") + @")$"; CompiledPermissionsMatch.Add(channel.Key, new Regex(pattern, RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.ExplicitCapture)); } }
public BaseClient() { var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "config", "settings.json"); if (File.Exists(path)) { var data = File.ReadAllText(path); try { Settings = JsonConvert.DeserializeObject <Settings>(data, new JsonSerializerSettings { MissingMemberHandling = MissingMemberHandling.Error }); if (!IrcValidation.IsNickname(Settings.Nickname)) { throw new JsonException("Nickname is not valid."); } if (!IrcValidation.IsChannelName(Settings.RedirectChannel)) { throw new JsonException("Redirect channel is not valid."); } foreach (var channel in Settings.Channels) { if (!IrcValidation.IsChannelName(channel)) { throw new JsonException($"Channel '{channel}' is not valid."); } } } catch (JsonException e) { Log.WriteError("IRC", "Failed to parse settings.json file: {0}", e.Message); Environment.Exit(1); } } else { Log.WriteWarn("IRC", "File config/settings.json doesn't exist"); Environment.Exit(1); } Client = new IrcClient { ClientVersion = "Wendy# -- https://github.com/xPaw/WendySharp" }; Client.Connected += OnConnected; Client.Closed += OnDisconnected; Permissions = new Permissions(); Commands = new Commands(Client); LinkExpander = new LinkExpander(Client); ChannelList = new Channels(Client); Whois = new Whois(Client); }
/// <summary> /// Tries to parse a string to get an IRC identity. /// /// IRC identities are formatted as nickname!username@hostname. /// </summary> /// <param name="string">The string to parse.</param> /// <param name="identity">The identity, or <c>null</c> if parsing fails.</param> /// <returns><c>true</c> if parsing completed successfully.</returns> public static bool TryParse(IrcString @string, out IrcIdentity identity) { IrcString[] parts; identity = null; if (@string == null) { goto invalid; } identity = new IrcIdentity(); parts = @string.Split((byte)'@'); if (parts.Length >= 2) { identity.Hostname = parts[1]; @string = parts[0]; } parts = @string.Split((byte)'!'); if (parts.Length >= 2) { identity.Username = parts[1]; @string = parts[0]; } identity.Nickname = @string; string errorMessage; if (!IrcValidation.ValidateIdentity(identity, out errorMessage)) { goto invalid; } return(true); invalid: identity = null; return(false); }
private void Reply(string message, bool notice) { string recipient = Event.Recipient; var isChannelMessage = IrcValidation.IsChannelName(recipient); if (isChannelMessage) { if (!notice) { message = string.Format("{0}: {1}", Event.Sender.Nickname, message); } else { recipient = Event.Sender.Nickname.ToString(); } } else { notice = false; recipient = Event.Sender.Nickname.ToString(); } Bootstrap.Client.SendReply(recipient, message, notice); }
public override void OnCommand(CommandArguments command) { var target = command.Arguments.Groups["target"].Value; var text = command.Arguments.Groups["text"].Value; if (!IrcValidation.IsChannelName(target) && !IrcValidation.IsNickname(target)) { command.Reply("That doesn't look like a valid channel or nickname."); return; } Log.WriteInfo("Say", "'{0}' said to '{1}': {2}", command.Event.Sender, target, text); Bootstrap.Client.Client.Message(target, text); }
public override void OnCommand(CommandArguments command) { var channel = command.Arguments.Groups["channel"].Value; if (!IrcValidation.IsChannelName(channel)) { command.Reply("That doesn't look like a valid channel name."); return; } Log.WriteInfo("Join", "'{0}' made us join channel {1}", command.Event.Sender, channel); Bootstrap.Client.Client.Join(channel); command.Reply("See you in {0}!", channel); }
/// <summary> /// Converts an IRC identity into an IRC string. /// </summary> /// <returns>The IRC string.</returns> public IrcString ToIrcString() { string errorMessage; if (!IrcValidation.ValidateIdentity(this, out errorMessage)) { throw new InvalidOperationException(errorMessage); } var @string = Nickname; if (Username != null) { @string += "!" + Username; } if (Hostname != null) { @string += "@" + Hostname; } return(@string); }
protected virtual void OnCtcpCommandReceived(IrcIdentity sender, IrcString recipient, IrcString command, IrcString[] parameters, IrcString rawParameter) { switch ((string)command) { case "ACTION": OnGotChatAction(new ChatMessageEventArgs(sender, recipient, rawParameter)); break; case "DCC": if (parameters.Length >= 1) { OnDccCommandReceived(sender, recipient, parameters[0], parameters.Skip(1).ToArray()); } break; case "PING": if (parameters.Length >= 1 && !IrcValidation.IsChannelName(recipient)) { CtcpReply(sender.Nickname, "PING", new IrcString[] { parameters[0] }); } break; case "TIME": if (!IrcValidation.IsChannelName(recipient)) { CtcpReply(sender.Nickname, "TIME", new IrcString[] { CtcpTimeGetNow().ToString ("ddd MMM dd HH:mm:ss yyyy", DateTimeFormatInfo.InvariantInfo) }); } break; case "VERSION": if (!IrcValidation.IsChannelName(recipient)) { CtcpReply(sender.Nickname, "VERSION", new[] { ClientVersion }); } break; } }
public override void OnCommand(CommandArguments command) { var nick = command.Arguments.Groups["nick"].Value; if (!IrcIdentity.TryParse(nick, out var ident)) { command.Reply("Invalid identity."); return; } var channel = Bootstrap.Client.ChannelList.GetChannel(command.Event.Recipient); if (!channel.WeAreOpped) { if (channel.HasChanServ) { Bootstrap.Client.Client.Message("ChanServ", string.Format("op {0}", channel.Name)); } else { command.Reply("I'm not opped, send help."); return; } } Bootstrap.Client.Whois.Query(ident, whoisData => { if (whoisData.Identity.Nickname != null) { ident = whoisData.Identity; } var nickname = ident.Nickname; if (nickname.ToString().ToLowerInvariant() == Bootstrap.Client.TrueNickname.ToLowerInvariant()) { command.Reply("Don't you even dare."); return; } if (whoisData.Identity.Nickname != null) { Whois.NormalizeIdentity(ident); } else { if (ident.Username == null) { ident.Username = "******"; } if (ident.Hostname == null) { ident.Hostname = "*"; } } var targetChannel = command.Arguments.Groups["channel"].Value.Trim(); if (targetChannel.Length == 0) { targetChannel = Bootstrap.Client.Settings.RedirectChannel; } else if (!IrcValidation.IsChannelName(targetChannel)) { command.Reply("Invalid target channel."); return; } if (Bootstrap.Client.ModeList.Find(command.Event.Recipient, ident.ToString(), "-b") != null) { command.Reply("{0} is already banned in this channel.", ident); return; } Log.WriteInfo("Redirect", "'{0}' redirected '{1}' from {2} to {3}", command.Event.Sender, ident, command.Event.Recipient, targetChannel); var reason = string.Format("Redirected to {0} by {1} for 2 hours", targetChannel, command.Event.Sender.Nickname); Bootstrap.Client.Client.Mode(command.Event.Recipient, "+b", ident + "$" + targetChannel); if (channel.HasUser(nickname)) { Bootstrap.Client.Client.Kick(nickname, command.Event.Recipient, reason); } command.ReplyAsNotice("Redirected {0} to {1} for 2 hours", ident, targetChannel); Bootstrap.Client.ModeList.AddLateModeRequest( new LateModeRequest { Channel = command.Event.Recipient, Recipient = ident.ToString(), Sender = command.Event.Sender.ToString(), Mode = "-b", Time = DateTime.UtcNow.AddHours(2), Reason = reason } ); } ); }
public LinkExpander(IrcClient client) { TwitterToChannels = new Dictionary <long, List <string> >(); var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "config", "services.json"); if (!File.Exists(path)) { Log.WriteWarn("Twitter", "File config/services.json doesn't exist"); return; } var data = File.ReadAllText(path); try { Config = JsonConvert.DeserializeObject <LinkExpanderConfig>(data, new JsonSerializerSettings { MissingMemberHandling = MissingMemberHandling.Error }); if (Config.Twitter.AccessSecret == null || Config.Twitter.AccessToken == null || Config.Twitter.ConsumerKey == null || Config.Twitter.ConsumerSecret == null) { throw new JsonException("Twitter keys cannot be null"); } if (Config.Channels == null) { Config.Channels = new List <string>(); } else { foreach (var channel in Config.Channels) { if (!IrcValidation.IsChannelName(channel)) { throw new JsonException($"Invalid channel '{channel}'"); } } } } catch (JsonException e) { Log.WriteError("Twitter", "Failed to parse services.json file: {0}", e.Message); Environment.Exit(1); } LastMatches = new FixedSizedQueue <string> { Limit = Config.DontRepeatLastCount }; TwitterCompiledMatch = new Regex(@"(^|/|\.)twitter\.com/(.+?)/status/(?<status>[0-9]+)", RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.ExplicitCapture); client.GotMessage += OnMessage; TweetinviConfig.ApplicationSettings.TweetMode = TweetMode.Extended; // lul per thread or application credentials Auth.ApplicationCredentials = new TwitterCredentials( Config.Twitter.ConsumerKey, Config.Twitter.ConsumerSecret, Config.Twitter.AccessToken, Config.Twitter.AccessSecret ); if (Config.Twitter.AccountsToFollow.Count > 0) { var thread = new Thread(StartTwitterStream) { Name = "TwitterStream" }; thread.Start(); } }
private void OnMessage(object obj, ChatMessageEventArgs e) { // Don't do anything in a private message if (!IrcValidation.IsChannelName(e.Recipient)) { return; } var message = e.Message.ToString().TrimEnd(); if (string.IsNullOrEmpty(message)) { return; } var isDirect = false; if (message.StartsWith(Bootstrap.Client.TrueNickname, StringComparison.InvariantCulture)) { var length = Bootstrap.Client.TrueNickname.Length; // "Wendy: " // Allow pinging with any character following bots name if (message.Length < length + 2 || message[length] == ' ' || message[length + 1] != ' ') { return; } message = message.Substring(length + 2); isDirect = true; } else if (message[0] == Bootstrap.Client.Settings.Prefix && Bootstrap.Client.Settings.Channels.Contains(e.Recipient)) { message = message.Substring(1); } else { return; } var match = CompiledCommandMatch.Match(message); if (!match.Success) { return; } var i = 1; while (match.Groups[i].Value.Length == 0) { i++; } var command = RegisteredCommands[i - 1]; Log.WriteInfo("CommandHandler", "Matched command '{0}' (as {2}) for {1}", command.Match.First(), e.Sender, match.Value); var arguments = new CommandArguments { IsDirect = isDirect, MatchedCommand = match.Value.Trim(), Event = e }; if (command.Permission != null) { // If there is no such user, don't pass if (!Users.TryGetUser(e.Sender, out var user)) { Log.WriteInfo("CommandHandler", "'{0}' is not a user I know of, can't perform '{1}' ({2})", e.Sender, arguments.MatchedCommand, command.Permission); return; } // If this user doesn't have required permission, don't pass if (!user.HasPermission(e.Recipient, command.Permission)) { Log.WriteInfo("CommandHandler", "'{0}' has no permission to perform '{1}' ({2})", e.Sender, arguments.MatchedCommand, command.Permission); return; } Log.WriteInfo("CommandHandler", "'{0}' is authorized to perform '{1}' ({2})", e.Sender, arguments.MatchedCommand, command.Permission); } if (command.CompiledMatch != null) { arguments.Arguments = command.CompiledMatch.Match(message); if (!arguments.Arguments.Success) { Help.PrintUsage(arguments, command); return; } } command.OnCommand(arguments); }