Beispiel #1
0
 public SelectableModAction(ModAction action, Action <ModAction> select, bool isSelected, bool isEnabled)
 {
     _select     = select;
     _isSelected = isSelected;
     IsEnabled   = isEnabled;
     Action      = action;
 }
Beispiel #2
0
        public override void Use(Player p, string message, CommandData data)
        {
            string[] args = message.SplitSpaces(3);
            if (args.Length < 2)
            {
                Help(p); return;
            }
            string rankName, target;
            string reason = args.Length > 2 ? args[2] : null;

            if (args[0].CaselessEq("+up"))
            {
                rankName = args[0];
                target   = ModActionCmd.FindName(p, "promote", "Promote", "", args[1], ref reason);
            }
            else if (args[0].CaselessEq("-down"))
            {
                rankName = args[0];
                target   = ModActionCmd.FindName(p, "demote", "Demote", "", args[1], ref reason);
            }
            else
            {
                rankName = args[1];
                target   = ModActionCmd.FindName(p, "rank", "Rank", " " + rankName, args[0], ref reason);
            }

            if (target == null)
            {
                return;
            }
            if (p.name.CaselessEq(target))
            {
                p.Message("Cannot change your own rank."); return;
            }

            Group curRank = PlayerInfo.GetGroup(target);
            Group newRank = TargetRank(p, rankName, curRank);

            if (newRank == null)
            {
                return;
            }

            if (curRank == newRank)
            {
                p.Message("{0} %Sis already ranked {1}",
                          p.FormatNick(target), curRank.ColoredName);
                return;
            }
            if (!CanChangeRank(target, curRank, newRank, p, data, ref reason))
            {
                return;
            }

            ModAction action = new ModAction(target, p, ModActionType.Rank, reason);

            action.targetGroup = curRank;
            action.Metadata    = newRank;
            OnModActionEvent.Call(action);
        }
Beispiel #3
0
        public override void Use(Player p, string message, CommandData data)
        {
            if (message.Length == 0)
            {
                Help(p); return;
            }
            string[] args = message.SplitSpaces(2);

            Player who = PlayerInfo.FindMatches(p, args[0]);

            if (who == null)
            {
                return;
            }
            string kickMsg = "by " + p.truename, reason = null;

            if (args.Length > 1)
            {
                reason = ModActionCmd.ExpandReason(p, args[1]);
                if (message == null)
                {
                    return;
                }
                kickMsg += "&f: " + reason;
            }

            ModAction action = new ModAction(who.name, p, ModActionType.Kicked, reason);

            OnModActionEvent.Call(action);
            who.Kick(kickMsg, "Kicked " + kickMsg);
        }
Beispiel #4
0
        static void Delete(Player p, string target)
        {
            string line = Server.tempRanks.FindData(target);

            if (line == null)
            {
                Player.Message(p, "{0}&c has not been assigned a temp rank.",
                               PlayerInfo.GetColoredName(p, target));
                return;
            }

            string[] parts   = line.SplitSpaces();
            Player   who     = PlayerInfo.FindExact(target);
            Group    curRank = who != null ? who.group : Group.GroupIn(target);

            Group oldRank = Group.Find(parts[4 - 1]); // -1 because data, not whole line

            if (oldRank == null)
            {
                return;
            }

            string reason = "temp rank unassigned";

            if (!CmdSetRank.CanChangeRank(target, curRank, oldRank, who, p, ref reason))
            {
                return;
            }

            ModAction action = new ModAction(target, p, ModActionType.Rank, reason);

            action.Metadata    = oldRank;
            action.targetGroup = curRank;
            OnModActionEvent.Call(action);
        }
Beispiel #5
0
        static void LogAction(ModAction e, Player target, string action)
        {
            if (e.Announce)
            {
                // TODO: Chat.MessageFrom if target is online?
                Player who = PlayerInfo.FindExact(e.Target);
                // TODO: who.SharesChatWith
                Chat.Message(ChatScope.Global, e.FormatMessage(e.TargetName, action),
                             null, null, true);
            }
            else
            {
                Chat.MessageOps(e.FormatMessage(e.TargetName, action));
            }

            action = Colors.Strip(action);
            string suffix = "";

            if (e.Duration.Ticks != 0)
            {
                suffix = " &Sfor " + e.Duration.Shorten();
            }

            Logger.Log(LogType.UserActivity, "{0} was {1} by {2}",
                       e.Target, action, e.Actor.name + suffix);
        }
Beispiel #6
0
        void DoFreeze(Player p, string target, string[] args)
        {
            if (args.Length < 2)
            {
                Help(p); return;
            }
            TimeSpan duration = TimeSpan.Zero;

            if (!CommandParser.GetTimespan(p, args[1], ref duration, "freeze for", "m"))
            {
                return;
            }

            string reason = args.Length > 2 ? args[2] : "";

            reason = ModActionCmd.ExpandReason(p, reason);
            if (reason == null)
            {
                return;
            }

            ModAction action = new ModAction(target, p, ModActionType.Frozen, reason, duration);

            OnModActionEvent.Call(action);
        }
Beispiel #7
0
        public override void Use(Player p, string message)
        {
            if (message.Length == 0)
            {
                Help(p); return;
            }

            string[] args   = message.SplitSpaces(2);
            string   reason = args.Length > 1 ? args[1] : "";
            string   target = ModActionCmd.FindName(p, "ban", "Ban", "", args[0], ref reason);

            if (target == null)
            {
                return;
            }

            reason = ModActionCmd.ExpandReason(p, reason);
            if (reason == null)
            {
                return;
            }

            Player who   = PlayerInfo.FindExact(target);
            Group  group = who != null ? who.group : Group.GroupIn(target);

            if (!CheckPerms(target, group, p))
            {
                return;
            }

            ModAction action = new ModAction(target, p, ModActionType.Ban, reason);

            action.targetGroup = group;
            OnModActionEvent.Call(action);
        }
Beispiel #8
0
 static void DoUnbanIP(ModAction e)
 {
     LogIPAction(e, "&8IP unbanned");
     Logger.Log(LogType.UserActivity, "IP-UNBANNED: {0} by {1}.", e.Target, e.Actor.name);
     Server.bannedIP.Remove(e.Target);
     Server.bannedIP.Save();
 }
Beispiel #9
0
        static void DoRank(ModAction e)
        {
            Player who     = PlayerInfo.FindExact(e.Target);
            Group  newRank = (Group)e.Metadata;
            string action  = newRank.Permission >= e.TargetGroup.Permission ? "promoted to " : "demoted to ";

            LogAction(e, who, action + newRank.ColoredName);

            if (who != null && e.Announce)
            {
                who.Message("You are now ranked " + newRank.ColoredName + "&S, type /Help for your new set of commands.");
            }
            if (Server.tempRanks.Remove(e.Target))
            {
                ModerationTasks.TemprankCalcNextRun();
                Server.tempRanks.Save();
            }

            WriteRankInfo(e, newRank);
            if (e.Duration != TimeSpan.Zero)
            {
                AddTempRank(e, newRank);
            }
            ModActionCmd.ChangeRank(e.Target, e.TargetGroup, newRank, who);
        }
Beispiel #10
0
        private InstallationStatus CopyFile(ModAction <CopyFileAction> modAction)
        {
            var physicalTargetPath      = ResolvePath(modAction.action.TargetFile, modAction.mod, configuration);
            var physicalDestinationPath = ResolvePath(modAction.action.DestinationPath, modAction.mod, configuration);

            return(CopyFile(physicalTargetPath, physicalDestinationPath, modAction.mod));
        }
Beispiel #11
0
        static void DoUnban(ModAction e)
        {
            Player who = PlayerInfo.FindExact(e.Target);

            LogAction(e, who, "&8unbanned");

            if (Server.tempBans.Remove(e.Target))
            {
                Server.tempBans.Save();
            }
            if (!Group.BannedRank.Players.Contains(e.Target))
            {
                return;
            }

            Ban.DeleteUnban(e.Target);
            Ban.UnbanPlayer(e.Actor, e.Target, e.Reason);
            ModActionCmd.ChangeRank(e.Target, Group.BannedRank, Group.DefaultRank, who, false);

            string ip = PlayerDB.FindIP(e.Target);

            if (ip != null && Server.bannedIP.Contains(ip))
            {
                e.Actor.Message("NOTE: Their IP is still banned.");
            }
        }
Beispiel #12
0
        private async Task UnluacDecompile(ModAction <UnluacDecompileAction> modAction, string tempFolder)
        {
            foreach (var file in modAction.action.TargetFiles)
            {
                var physicalTargetPath = ResolvePath(file, modAction.mod, configuration);
                var fileInfo           = new FileInfo(physicalTargetPath);

                var targetPath = Path.Combine(tempFolder, $"{Path.GetFileNameWithoutExtension(fileInfo.Name)}_decomp{fileInfo.Extension}");

                // Check if this has already been decompiled
                if (decompiledFiles.Contains(physicalTargetPath))
                {
                    continue;
                }

                if (!File.Exists(physicalTargetPath))
                {
                    throw new Exception($"Unable to find target path: {physicalTargetPath}");
                }

                // Decompile the file, and replace the file
                await UnluacUtility.Decompile(physicalTargetPath, targetPath);

                MoveFile_Internal(targetPath, physicalTargetPath, modAction.mod);

                decompiledFiles.Add(physicalTargetPath);
            }
        }
Beispiel #13
0
        private InstallationStatus ReplaceFile(ModAction <ReplaceFileAction> modAction)
        {
            var physicalTargetPath      = ResolvePath(modAction.action.TargetFile, modAction.mod, configuration);
            var physicalReplacementPath = ResolvePath(modAction.action.ReplacementFile, modAction.mod, configuration);

            return(ReplaceFile(physicalReplacementPath, physicalTargetPath, modAction.mod));
        }
Beispiel #14
0
        static string GetRankAction(ModAction action)
        {
            Group  newRank = (Group)action.Metadata;
            string prefix  = newRank.Permission >= action.TargetGroup.Permission ? "promoted to " : "demoted to ";

            return(prefix + newRank.ColoredName);
        }
Beispiel #15
0
        void HandleModerationAction(ModAction e)
        {
            if (!Server.IRC.Enabled || !e.Announce)
            {
                return;
            }

            switch (e.Type)
            {
            case ModActionType.Warned:
                Bot.Say(e.FormatMessage(e.TargetName, "&ewarned")); break;

            case ModActionType.Ban:
                Bot.Say(e.FormatMessage(e.TargetName, "&8banned")); break;

            case ModActionType.Unban:
                Bot.Say(e.FormatMessage(e.TargetName, "&8unbanned")); break;

            case ModActionType.BanIP:
                Bot.Say(e.FormatMessage(e.TargetName, "&8IP banned"), true);
                Bot.Say(e.FormatMessage("An IP", "&8IP banned")); break;

            case ModActionType.UnbanIP:
                Bot.Say(e.FormatMessage(e.TargetName, "&8IP unbanned"), true);
                Bot.Say(e.FormatMessage("An IP", "&8IP unbanned")); break;

            case ModActionType.Rank:
                Bot.Say(e.FormatMessage(e.TargetName, GetRankAction(e))); break;
            }
        }
Beispiel #16
0
        public override void Use(Player p, string message, CommandData data)
        {
            if (message.Length == 0)
            {
                Help(p); return;
            }
            string[] args = message.SplitSpaces(2);

            string reason = args.Length == 1 ? "you know why." : args[1];
            string target = ModActionCmd.FindName(p, "warn", "Warn", "", args[0], ref reason);

            if (target == null)
            {
                return;
            }

            reason = ModActionCmd.ExpandReason(p, reason);
            if (reason == null)
            {
                return;
            }

            Group group = ModActionCmd.CheckTarget(p, data, "warn", target);

            if (group == null)
            {
                return;
            }

            ModAction action = new ModAction(target, p, ModActionType.Warned, reason);

            OnModActionEvent.Call(action);
        }
Beispiel #17
0
        static void LogAction(ModAction e, Player who, string action)
        {
            if (e.Announce)
            {
                if (who != null)
                {
                    Chat.MessageGlobal(who, e.FormatMessage(e.TargetName, action), false);
                }
                else
                {
                    Chat.MessageGlobal(e.FormatMessage(e.TargetName, action));
                }
            }
            else
            {
                Chat.MessageOps(e.FormatMessage(e.TargetName, action));
            }

            action = Colors.Strip(action);
            string suffix = "";

            if (e.Duration.Ticks != 0)
            {
                suffix = " %Sfor " + e.Duration.Shorten();
            }

            Logger.Log(LogType.UserActivity, "{0} was {1} by {2}",
                       e.Target, action, e.ActorName + suffix);
        }
Beispiel #18
0
        internal static void Delete(Player p, string target, CommandData data)
        {
            string line = Server.tempRanks.FindData(target);

            if (line == null)
            {
                p.Message("{0} &Whas not been assigned a temp rank.", p.FormatNick(target));
                return;
            }

            string[] parts   = line.SplitSpaces();
            Group    curRank = PlayerInfo.GetGroup(target);

            Group oldRank = Group.Find(parts[4 - 1]); // -1 because data, not whole line

            if (oldRank == null)
            {
                return;
            }

            string reason = "temp rank unassigned";

            if (!CmdSetRank.CanChangeRank(target, curRank, oldRank, p, data, ref reason))
            {
                return;
            }

            ModAction action = new ModAction(target, p, ModActionType.Rank, reason);

            action.Metadata    = oldRank;
            action.targetGroup = curRank;
            OnModActionEvent.Call(action);
        }
Beispiel #19
0
        static void DoBan(ModAction e)
        {
            Player who = PlayerInfo.FindExact(e.Target);

            LogAction(e, who, "&8banned");

            if (e.Duration.Ticks != 0)
            {
                string   banner = e.Actor.truename;
                DateTime end    = DateTime.UtcNow.Add(e.Duration);
                Server.tempBans.Update(e.Target, Ban.PackTempBanData(e.Reason, banner, end));
                Server.tempBans.Save();

                if (who != null)
                {
                    who.Kick("Banned for " + e.Duration.Shorten(true) + "." + e.ReasonSuffixed);
                }
            }
            else
            {
                Ban.DeleteBan(e.Target);
                Ban.BanPlayer(e.Actor, e.Target, e.Reason, !e.Announce, e.TargetGroup.Name);
                ModActionCmd.ChangeRank(e.Target, e.targetGroup, Group.BannedRank, who);

                if (who != null)
                {
                    string msg = e.Reason.Length == 0 ? Server.Config.DefaultBanMessage : e.Reason;
                    who.Kick("Banned by " + e.Actor.ColoredName + ": &S" + msg,
                             "Banned by " + e.Actor.ColoredName + ": &f" + msg);
                }
            }
        }
Beispiel #20
0
        public override void Use(Player p, string message)
        {
            if (message.Length == 0)
            {
                Help(p); return;
            }
            string[] args = message.SplitSpaces(2);
            Player   who  = PlayerInfo.FindMatches(p, args[0]);

            string reason = args.Length == 1 ? "you know why." : args[1];

            reason = ModActionCmd.ExpandReason(p, reason);
            if (reason == null)
            {
                return;
            }

            if (who == null)
            {
                WarnOffline(p, args, reason); return;
            }
            if (who == p)
            {
                Player.Message(p, "you can't warn yourself"); return;
            }
            if (p != null && p.Rank <= who.Rank)
            {
                MessageTooHighRank(p, "warn", false); return;
            }

            ModAction action = new ModAction(who.name, p, ModActionType.Warned, reason);

            OnModActionEvent.Call(action);
        }
Beispiel #21
0
        internal static void HandleModAction(ModAction action)
        {
            switch (action.Type)
            {
            case ModActionType.Frozen: DoFreeze(action); break;

            case ModActionType.Unfrozen: DoUnfreeze(action); break;

            case ModActionType.Muted: DoMute(action); break;

            case ModActionType.Unmuted: DoUnmute(action); break;

            case ModActionType.Ban: DoBan(action); break;

            case ModActionType.Unban: DoUnban(action); break;

            case ModActionType.BanIP: DoBanIP(action); break;

            case ModActionType.UnbanIP: DoUnbanIP(action); break;

            case ModActionType.Warned: DoWarn(action); break;

            case ModActionType.Rank: DoRank(action); break;
            }
        }
Beispiel #22
0
        public override void Use(Player p, string message, CommandData data)
        {
            if (message.Length == 0)
            {
                Help(p); return;
            }
            string[] args = message.SplitSpaces(2);

            string reason = args.Length > 1 ? args[1] : "";

            reason = ModActionCmd.ExpandReason(p, reason);
            if (reason == null)
            {
                return;
            }

            if (!Server.tempBans.Contains(args[0]))
            {
                int matches;
                args[0] = Group.BannedRank.Players.FindMatches(p, args[0], "banned players", out matches);
                if (args[0] == null)
                {
                    return;
                }
            }

            ModAction action = new ModAction(args[0], p, ModActionType.Unban, reason);

            OnModActionEvent.Call(action);
        }
Beispiel #23
0
        static void DoWarn(ModAction e)
        {
            Player who = PlayerInfo.FindExact(e.Target);

            if (who != null)
            {
                LogAction(e, who, "&ewarned");
                if (who.warn == 0)
                {
                    who.Message("Do it again twice and you will get kicked!");
                }
                else if (who.warn == 1)
                {
                    who.Message("Do it one more time and you will get kicked!");
                }
                else if (who.warn == 2)
                {
                    Chat.MessageGlobal("{0} &Swas warn-kicked by {1}", who.ColoredName, e.Actor.ColoredName);
                    string chatMsg = "by " + e.Actor.ColoredName + "&S: " + e.Reason;
                    string kickMsg = "Kicked by " + e.Actor.ColoredName + ": &f" + e.Reason;
                    who.Kick(chatMsg, kickMsg);
                }
                who.warn++;
            }
            else
            {
                if (!Server.Config.LogNotes)
                {
                    e.Actor.Message("Notes logging must be enabled to warn offline players."); return;
                }
                LogAction(e, who, "&ewarned");
            }
        }
Beispiel #24
0
    /// <summary>
    /// Gos the button click.
    /// </summary>
    public static void BtnClick(Modifier pModifier, ModAction pAction)
    {
        auto = instance.tAuto.isOn;
        switch (pAction)
        {
        case  ModAction.Go:
            instance.curModifier = pModifier;
            instance.StepLogic();
            break;

        case ModAction.Add:
            Modifier m = instance.pool.InstantiateElement().GetComponent <Modifier> ();
            m.gameObject.transform.SetSiblingIndex(pModifier.transform.GetSiblingIndex() + 1);
            m.Serialized = pModifier.Serialized;
            break;

        case ModAction.Del:
            instance.pool.DestroyElement(pModifier.GetComponent <LayoutElement>());
            break;

        default:
            Debug.LogError("Unknown action " + pAction.ToString());
            break;
        }
    }
Beispiel #25
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="ci"></param>
        /// <returns></returns>
        /// <remarks>
        /// Here we require a placeID because climbs belong to a place so OnObjectID is not a place, it just so happens that
        /// when we're adding areas and locations placeID == o.OnObjectID
        /// </remarks>
        internal Post CreateContentAddPost(ModAction o, Guid placeID, bool isPublic)
        {
            var     place   = AppLookups.GetCacheIndexEntry(placeID);
            var     postMgr = new cf.Content.Feed.V0.ContentAddPostManager();
            dynamic data    = postMgr.CreateTemplateDynamicData(GetPostPlace(o.OnObjectID));

            return(postMgr.CreatePost(o.OnObjectID, o.UserID, place, isPublic, data));
        }
Beispiel #26
0
        static void AddTempRank(ModAction e, Group newRank)
        {
            string data = FormatModTaskData(e) + " " + e.TargetGroup.Name + " " + newRank.Name;

            Server.tempRanks.Update(e.Target, data);
            ModerationTasks.TemprankCalcNextRun();
            Server.tempRanks.Save();
        }
Beispiel #27
0
        public override void Use(Player p, string message)
        {
            if (message.Length == 0)
            {
                Help(p); return;
            }
            string[] args = message.SplitSpaces(3);

            Player who = PlayerInfo.FindMatches(p, args[0]);

            if (who == null)
            {
                return;
            }
            if (p != null && p == who)
            {
                Player.Message(p, "Cannot freeze yourself."); return;
            }
            if (p != null && who.Rank >= p.Rank)
            {
                MessageTooHighRank(p, "freeze", false); return;
            }

            if (who.frozen)
            {
                string reason = args.Length > 1 ? args[1] : "";
                reason = ModActionCmd.ExpandReason(p, reason);
                if (reason == null)
                {
                    return;
                }

                ModAction action = new ModAction(who.name, p, ModActionType.Unfrozen, reason);
                OnModActionEvent.Call(action);
            }
            else
            {
                if (args.Length < 2)
                {
                    Help(p); return;
                }
                TimeSpan duration = TimeSpan.Zero;
                if (!CommandParser.GetTimespan(p, args[1], ref duration, "freeze for", "m"))
                {
                    return;
                }

                string reason = args.Length > 2 ? args[2] : "";
                reason = ModActionCmd.ExpandReason(p, reason);
                if (reason == null)
                {
                    return;
                }

                ModAction action = new ModAction(who.name, p, ModActionType.Frozen, reason, duration);
                OnModActionEvent.Call(action);
            }
        }
Beispiel #28
0
        public override void Use(Player p, string message, CommandData data)
        {
            if (message.Length == 0)
            {
                Help(p); return;
            }
            string[] args = message.SplitSpaces(3);

            Player who = PlayerInfo.FindMatches(p, args[0]);

            if (who == null)
            {
                return;
            }

            Group group = ModActionCmd.CheckTarget(p, data, "freeze", who.name);

            if (group == null)
            {
                return;
            }

            if (who.frozen)
            {
                string reason = args.Length > 1 ? args[1] : "";
                reason = ModActionCmd.ExpandReason(p, reason);
                if (reason == null)
                {
                    return;
                }

                ModAction action = new ModAction(who.name, p, ModActionType.Unfrozen, reason);
                OnModActionEvent.Call(action);
            }
            else
            {
                if (args.Length < 2)
                {
                    Help(p); return;
                }
                TimeSpan duration = TimeSpan.Zero;
                if (!CommandParser.GetTimespan(p, args[1], ref duration, "freeze for", "m"))
                {
                    return;
                }

                string reason = args.Length > 2 ? args[2] : "";
                reason = ModActionCmd.ExpandReason(p, reason);
                if (reason == null)
                {
                    return;
                }

                ModAction action = new ModAction(who.name, p, ModActionType.Frozen, reason, duration);
                OnModActionEvent.Call(action);
            }
        }
Beispiel #29
0
        static void LogIPAction(ModAction e, string type)
        {
            ItemPerms perms = CommandExtraPerms.Find("WhoIs", 1);

            Chat.Message(ChatScope.Global, e.FormatMessage("An IP", type), perms,
                         FilterNotItemPerms, true);
            Chat.Message(ChatScope.Global, e.FormatMessage(e.Target, type), perms,
                         Chat.FilterPerms, true);
        }
Beispiel #30
0
        public void OnNext(ModAction value)
        {
            if (value.ModeratorName == "AutoModerator" && value.Details.ToLower().Contains("spez_that"))
            {
                bool   isPost = value.TargetThingFullname.StartsWith("t3_");
                string reason = value.Details.Substring(value.Details.ToLower().IndexOf("spez_that") + 10);
                subTweeter.SendTweet(sub.Name, (isPost ? "post" : "comment"), value.TargetAuthorName, reason, (isPost ? value.TargetTitle : value.TargetBody), value.TargetThingPermalink);
            }
            else if (value.Action == ModActionType.Distinguish && value.TargetThingFullname.StartsWith("t1_") && value.TargetBody.ToLower().Contains("spez_that"))
            {
                var              modcomment = (ModeratableThing)value.GetTargetThing().Result;
                string           reason     = "";
                ModeratableThing thing      = null;
                if (modcomment.Kind == "t4")
                {
                    var pm = (PrivateMessage)modcomment;
                    thing  = pm.GetParent() as ModeratableThing;
                    reason = pm.Body.Substring(pm.Body.ToLower().IndexOf("spez_that") + 10);
                }
                else
                {
                    var c = (Comment)modcomment;
                    thing = new Reddit(sub.WebAgent, false).GetThingByFullnameAsync(c.ParentId).Result as ModeratableThing;
                    c.RemoveAsync().Wait();
                    reason = c.Body.Substring(c.Body.ToLower().IndexOf("spez_that") + 10);
                }
                string type    = "thing";
                string message = "";
                string url     = "";
                switch (thing.Kind)
                {
                case "t3":
                    type    = "post";
                    message = ((Post)thing).Title;
                    url     = ((Post)thing).Permalink.ToString();
                    break;

                case "t1":
                    type    = "comment";
                    message = ((Comment)thing).Body;
                    url     = ((Comment)thing).Permalink.ToString();
                    break;

                case "t4":
                    type    = "message";
                    message = ((PrivateMessage)thing).Body;
                    url     = "";
                    break;
                }
                if (!string.IsNullOrWhiteSpace(url) && !url.ToLower().StartsWith("https://reddit.com/"))
                {
                    url = "https://reddit.com" + (url.StartsWith("/") ? "" : "/") + url;
                }
                subTweeter.SendTweet(sub.Name, type, thing.AuthorName, reason, message, url);
            }
        }