Our server pr0vider carried out maintenance on 15 January 2020 but it corrupted some files in the process. If you notice anything out of the ordinary (partial files, pages not loading, that kind of shit) then let us know at:

Browse Source

Ported all remaining fucking m0ds over to U5, including templ8s y0 (doing some misc optimisation/bugfixing in the pr0cess), also m_forward's OperOverride hecks is now implemented in operoverride_ext.c =]]]]]]]]]]]]]]]]]

Wazakindjes 1 year ago
parent
commit
2780c71229
58 changed files with 5393 additions and 5166 deletions
  1. 1 0
      .gitignore
  2. 62 52
      malv/holidays.c
  3. 231 255
      malv/mshun.c
  4. 269 285
      malv/otkl.c
  5. 41 34
      malv/reportlol.c
  6. 53 49
      malv/sajoin_chan.c
  7. 86 91
      malv/saprivmsg.c
  8. 53 45
      spec/block_notlsident.c
  9. 76 72
      spec/mafiareturns.c
  10. 63 61
      spec/nicksuffix.c
  11. 51 42
      spec/nopmchannel.c
  12. 220 232
      spec/signore.c
  13. 63 55
      spec/topicgreeting.c
  14. 31 24
      templates/bare.c
  15. 58 42
      templates/chmode.c
  16. 60 36
      templates/cmdoverride.c
  17. 122 66
      templates/conf.c
  18. 37 46
      templates/hook.c
  19. 65 53
      templates/newcmd.c
  20. 44 27
      templates/umode.c
  21. 67 72
      u4/anti_amsg.c
  22. 63 49
      u4/anticaps.c
  23. 60 60
      u4/auditorium.c
  24. 49 44
      u4/autojoin_byport.c
  25. 53 65
      u4/autovhost.c
  26. 56 47
      u4/banfix_voice.c
  27. 115 121
      u4/block_masshighlight.c
  28. 238 215
      u4/chansno.c
  29. 80 82
      u4/clearlist.c
  30. 70 58
      u4/clones.c
  31. 74 83
      u4/commandsno.c
  32. 98 85
      u4/denyban.c
  33. 43 26
      u4/extwarn.c
  34. 93 101
      u4/fantasy.c
  35. 52 48
      u4/getlegitusers.c
  36. 106 92
      u4/joinmute.c
  37. 90 99
      u4/kickjoindelay.c
  38. 107 105
      u4/listrestrict.c
  39. 49 68
      u4/message_commonchans.c
  40. 50 60
      u4/noghosts.c
  41. 48 68
      u4/noinvite.c
  42. 108 0
      u4/operoverride_ext.c
  43. 73 77
      u4/operpasswd.c
  44. 48 54
      u4/plainusers.c
  45. 177 200
      u4/pmlist.c
  46. 138 131
      u4/rtkl.c
  47. 168 163
      u4/sacmds.c
  48. 54 55
      u4/uline_nickhost.c
  49. 90 85
      u4/websocket_restrict.c
  50. 127 106
      uncommon/bancheck_access.c
  51. 81 93
      uncommon/block_no_tls.c
  52. 77 76
      uncommon/debug.c
  53. 229 213
      uncommon/fixhop.c
  54. 150 111
      uncommon/portsifresi.c
  55. 67 55
      uncommon/pubnetinfo.c
  56. 42 55
      uncommon/rehashgem.c
  57. 195 219
      uncommon/repeatprot.c
  58. 222 258
      uncommon/textshun.c

+ 1 - 0
.gitignore

@@ -3,3 +3,4 @@
 .*.swp
 /test
 /appveyor-*.yml
+/_*

+ 62 - 52
malv/holidays.c

@@ -1,7 +1,23 @@
 /* Copyright (C) All Rights Reserved
 ** Written by Gottem <support@gottem.nl>
-** Website: https://gitgud.malvager.net/Wazakindjes/unrealircd_mods
-** License: https://gitgud.malvager.net/Wazakindjes/unrealircd_mods/raw/master/LICENSE
+** Website: https://gottem.nl/unreal
+** License: https://gottem.nl/unreal/license
+*/
+
+/*** <<<MODULE MANAGER START>>>
+module {
+	documentation "https://gottem.nl/unreal/man/holidays";
+	troubleshooting "In case of problems, check the FAQ at https://gottem.nl/unreal/halp or e-mail me at support@gottem.nl";
+	min-unrealircd-version "5.*";
+	//max-unrealircd-version "5.*";
+	post-install-text {
+		"The module is installed, now all you need to do is add a 'loadmodule' line to your config file:";
+		"loadmodule \"third/holidays\";";
+		"Then /rehash the IRCd.";
+		"For usage information, refer to the module's documentation found at: https://gottem.nl/unreal/man/holidays";
+	}
+}
+*** <<<MODULE MANAGER END>>>
 */
 
 // One include for all cross-platform compatibility thangs
@@ -10,45 +26,41 @@
 // Command to override
 #define OVR_PRIVMSG "PRIVMSG"
 
+#define CheckAPIError(apistr, apiobj) \
+	do { \
+		if(!(apiobj)) { \
+			config_error("A critical error occurred on %s for %s: %s", (apistr), MOD_HEADER.name, ModuleGetErrorStr(modinfo->handle)); \
+			return MOD_FAILED; \
+		} \
+	} while(0)
+
 // Quality fowod declarations
 char *replaceem(char *str, char *search, char *replace);
-static int holidays_override(Cmdoverride *ovr, aClient *cptr, aClient *sptr, int parc, char *parv[]);
-
-// Muh globals
-static ModuleInfo *holidaysMI = NULL; // Store ModuleInfo so we can use it to check for errors in MOD_LOAD
-Cmdoverride *holidaysOvr; // Pointer to the override we're gonna add
+CMD_OVERRIDE_FUNC(holidays_override);
 
 // Dat dere module header
-ModuleHeader MOD_HEADER(m_holidays) = {
-	"m_holidays", // Module name
-	"$Id: v1.02 2018/05/21 Gottem$", // Version
+ModuleHeader MOD_HEADER = {
+	"third/holidays", // Module name
+	"2.0", // Version
 	"HAPPY HOLIDAYS FROM MALFAJUR", // Description
-	"3.2-b8-1", // Modversion, not sure wat do
-	NULL
+	"Gottem", // Author
+	"unrealircd-5", // Modversion
 };
 
 // Initialisation routine (register hooks, commands and modes or create structs etc)
-MOD_INIT(m_holidays) {
-	holidaysMI = modinfo; // Store module info yo
-	return MOD_SUCCESS; // Let MOD_LOAD handle errors and registering of overrides
+MOD_INIT() {
+	MARK_AS_GLOBAL_MODULE(modinfo);
+	return MOD_SUCCESS;
 }
 
 // Actually load the module here (also command overrides as they may not exist in MOD_INIT yet)
-MOD_LOAD(m_holidays) {
-	holidaysOvr = CmdoverrideAdd(holidaysMI->handle, OVR_PRIVMSG, holidays_override); // Attempt to add command override
-
-	// Did the module throw an error when adding override(s), or is holidaysOvr null even?
-	if(ModuleGetError(holidaysMI->handle) != MODERR_NOERROR || !holidaysOvr) {
-		// Display error string kek
-		config_error("A critical error occurred when loading module %s: %s", MOD_HEADER(m_holidays).name, ModuleGetErrorStr(holidaysMI->handle));
-		return MOD_FAILED; // No good
-	}
-
+MOD_LOAD() {
+	CheckAPIError("CommandOverrideAdd(PRIVMSG)", CommandOverrideAdd(modinfo->handle, OVR_PRIVMSG, holidays_override));
 	return MOD_SUCCESS; // We good
 }
 
 // Called on unload/rehash obv
-MOD_UNLOAD(m_holidays) {
+MOD_UNLOAD() {
 	return MOD_SUCCESS; // We good
 }
 
@@ -81,40 +93,36 @@ char *replaceem(char *str, char *search, char *replace) {
 }
 
 // Now for the actual override
-static int holidays_override(Cmdoverride *ovr, aClient *cptr, aClient *sptr, int parc, char *parv[]) {
-	/* Gets args: Cmdoverride *ovr, aClient *cptr, aClient *sptr, int parc, char *parv[]
-	**
-	** ovr: Pointer to the override we're attached to
-	** cptr: Pointer to directly attached client -- if remote user this is the remote server instead
-	** sptr: Pointer to user executing command
-	** parc: Amount of arguments (also includes the command in the count)
-	** parv: Contains the actual args, first one starts at parv[1]
-	**
-	** So "PRIVMSG test" would result in parc = 2 and parv[1] = "test"
-	** Also, parv[0] seems to always be NULL, so better not rely on it fam
-	*/
+CMD_OVERRIDE_FUNC(holidays_override) {
+	// Gets args: CommandOverride *ovr, Client *client, MessageTag *recv_mtags, int parc, char *parv[]
 	char *search = "kys"; // Replace this
 	char *replace = NULL; // With this
-	aClient *acptr; // Store /message target
-	aChannel *chptr;
+	Client *acptr; // Store /message target
+	Channel *channel;
 
 	time_t t; // Store time cuz we need to point to it latur
 	struct tm dt; // Store time inf0z
 	int i;
-	int wday, day, month, year; // Only care about DMY, also wat week day
+	int wday, day, month; // Only care about DMY, also wat week day
 
-	if(BadPtr(parv[1]) || BadPtr(parv[2]) || IsServer(sptr) || IsMe(sptr) || IsULine(sptr) || !MyClient(sptr))
-		return CallCmdoverride(ovr, cptr, sptr, parc, parv); // Run original function yo
+	if(BadPtr(parv[1]) || BadPtr(parv[2]) || !MyUser(client) || IsULine(client)) {
+		CallCommandOverride(ovr, client, recv_mtags, parc, parv); // Run original function yo
+		return;
+	}
 
 	if(parv[1][0] != '#') {
 		acptr = find_person(parv[1], NULL); // Attempt to find message target
-		if(!acptr || IsULine(acptr))
-			return CallCmdoverride(ovr, cptr, sptr, parc, parv); // Run original function yo
+		if(!acptr || IsULine(acptr)) {
+			CallCommandOverride(ovr, client, recv_mtags, parc, parv); // Run original function yo
+			return;
+		}
 	}
 	else {
-		chptr = find_channel(parv[1], NULL); // Attempt to find message target
-		if(!chptr)
-			return CallCmdoverride(ovr, cptr, sptr, parc, parv); // Run original function yo
+		channel = find_channel(parv[1], NULL); // Attempt to find message target
+		if(!channel) {
+			CallCommandOverride(ovr, client, recv_mtags, parc, parv); // Run original function yo
+			return;
+		}
 	}
 
 	t = TStime();
@@ -122,7 +130,7 @@ static int holidays_override(Cmdoverride *ovr, aClient *cptr, aClient *sptr, int
 	wday = dt.tm_wday;
 	day = dt.tm_mday;
 	month = dt.tm_mon + 1;
-	year = dt.tm_year + 1900;
+	//year = dt.tm_year + 1900;
 
 	switch(month) {
 		case 1:
@@ -161,10 +169,12 @@ static int holidays_override(Cmdoverride *ovr, aClient *cptr, aClient *sptr, int
 	}
 
 	// Ain't got nuffin
-	if(!replace)
-		return CallCmdoverride(ovr, cptr, sptr, parc, parv); // Run original function yo
+	if(!replace) {
+		CallCommandOverride(ovr, client, recv_mtags, parc, parv); // Run original function yo
+		return;
+	}
 
 	for(i = 2; i < parc; i++)
 		parv[i] = replaceem(parv[i], search, replace);
-	return CallCmdoverride(ovr, cptr, sptr, parc, parv); // Run original function yo
+	CallCommandOverride(ovr, client, recv_mtags, parc, parv); // Run original function yo
 }

+ 231 - 255
malv/mshun.c

@@ -1,25 +1,32 @@
 /* Copyright (C) All Rights Reserved
 ** Written by Gottem <support@gottem.nl>
-** Website: https://gitgud.malvager.net/Wazakindjes/unrealircd_mods
-** License: https://gitgud.malvager.net/Wazakindjes/unrealircd_mods/raw/master/LICENSE
+** Website: https://gottem.nl/unreal
+** License: https://gottem.nl/unreal/license
+*/
+
+/*** <<<MODULE MANAGER START>>>
+module {
+	documentation "https://gottem.nl/unreal/man/mshun";
+	troubleshooting "In case of problems, check the FAQ at https://gottem.nl/unreal/halp or e-mail me at support@gottem.nl";
+	min-unrealircd-version "5.*";
+	//max-unrealircd-version "5.*";
+	post-install-text {
+		"The module is installed, now all you need to do is add a 'loadmodule' line to your config file:";
+		"loadmodule \"third/mshun\";";
+		"Then /rehash the IRCd.";
+		"For usage information, refer to the module's documentation found at: https://gottem.nl/unreal/man/mshun";
+	}
+}
+*** <<<MODULE MANAGER END>>>
 */
 
 // One include for all cross-platform compatibility thangs
 #include "unrealircd.h"
 
-#define BACKPORT (UNREAL_VERSION_GENERATION == 4 && UNREAL_VERSION_MAJOR == 0 && UNREAL_VERSION_MINOR <= 15)
-
 // Command strings
 #define MSG_MSHUN "MSHUN"
 #define MSG_MSHUN_ALT "MLINE"
 
-// Hewktypez
-#define SCONNECT_HOOK HOOKTYPE_SERVER_CONNECT
-#define PRCHANMSG_HOOK HOOKTYPE_PRE_CHANMSG
-#define PRUSERMSG_HOOK HOOKTYPE_PRE_USERMSG
-#define PRKNOCK_HOOK HOOKTYPE_PRE_KNOCK
-#define PRINVITE_HOOK HOOKTYPE_PRE_INVITE
-
 // Big hecks go here
 typedef struct t_mshun MShun;
 struct t_mshun {
@@ -32,44 +39,37 @@ struct t_mshun {
 };
 
 // Dem macros yo
-CMD_FUNC(m_mshun); // Register command function
+CMD_FUNC(mshun); // Register command function
 
-#define IsMDErr(x, y, z) \
+#define CheckAPIError(apistr, apiobj) \
 	do { \
-		if(!(x)) { \
-			config_error("A critical error occurred when registering ModData for %s: %s", MOD_HEADER(y).name, ModuleGetErrorStr((z)->handle)); \
+		if(!(apiobj)) { \
+			config_error("A critical error occurred on %s for %s: %s", (apistr), MOD_HEADER.name, ModuleGetErrorStr(modinfo->handle)); \
 			return MOD_FAILED; \
 		} \
 	} while(0)
 
 // Quality fowod declarations
-static int dumpit(aClient *sptr, char **p);
+static void dumpit(Client *client, char **p);
 EVENT(mshun_event); // For expiring that shit fam
 void mshun_moddata_free(ModData *md);
 void check_mlines(void);
 void add_mline(MShun *newms);
 void del_mline(MShun *muhms);
+void free_all_mlines(MShun *MShunList);
 MShun *get_mlines(void);
 MShun *find_mline(char *mask);
-MShun *match_mline(aClient *sptr);
-int mshun_hook_serverconnect(aClient *sptr);
-int _check_premsg(aClient *sptr);
-char *mshun_hook_prechanmsg(aClient *sptr, aChannel *chptr, char *text, int notice);
-char *mshun_hook_preusermsg(aClient *sptr, aClient *to, char *text, int notice);
-int mshun_hook_preknock(aClient *sptr, aChannel *chptr);
-
-#if BACKPORT
-	int mshun_hook_preinvite(aClient *sptr, aChannel *chptr);
-#else
-	int mshun_hook_preinvite(aClient *sptr, aClient *target, aChannel *chptr, int *override);
-#endif
+MShun *match_mline(Client *client);
+int mshun_hook_serverconnect(Client *client);
+int _check_premsg_isshunned(Client *client, int from_cansend, char **text, char **errmsg);
+int mshun_hook_cansend_chan(Client *client, Channel *channel, Membership *lp, char **text, char **errmsg, int notice);
+int mshun_hook_cansend_user(Client *client, Client *to, char **text, char **errmsg, int notice);
+int mshun_hook_preknock(Client *client, Channel *channel);
+int mshun_hook_preinvite(Client *client, Client *target, Channel *channel, int *override);
 
 // Muh globals
-ModDataInfo *mshunMDI; // To store the M:Lines with &me lol (hack so we don't have to use a .db file or some shit)
-static ModuleInfo *mshunMI = NULL; // Store ModuleInfo so we can use it to check for errors in MOD_LOAD
-Command *mshunCmd, *mshunCmdAlt; // Pointers to the commands we're gonna add
-Hook *serverConnectHook, *preChanMsgHook, *preUserMsgHook, *preKnockHook, *preInviteHook; // Dem hewks lol
-int MSC; // A counter for M:Lines so we can change the moddata back to NULL
+ModDataInfo *mshunMDI; // To store the M-Lines with &me lol (hack so we don't have to use a .db file or some shit)
+int mshunCount; // A counter for M-Lines so we can change the moddata back to NULL
 
 // Help string in case someone does just /MSHUN
 static char *muhhalp[] = {
@@ -81,7 +81,7 @@ static char *muhhalp[] = {
 	"Enables opers to set shuns that only affect \002PRIVMSG\002/\002NOTICE\002/\002KNOCK\002/\002INVITE\002.",
 	"This means affected users can still do nick changes and join/part channels etc,",
 	"but Unreal normally has flood control in place to prevent them from spamming",
-	"that shit. It requires an \037ident@host\037 mask (as is usual with X:Lines).",
+	"that shit. It requires an \037ident@host\037 mask (as is usual with *-Lines).",
 	"The wildcards * and ? are also supported.",
 	" ",
 	"Syntax:",
@@ -90,104 +90,90 @@ static char *muhhalp[] = {
 	"Examples:",
 	"    \002/mshun guest*@* 0 nope\002",
 	"    \002/mline -guest*@*\002",
-	"        Adds/deletes the same M:Line, with no expiration",
+	"        Adds/deletes the same M-Line, with no expiration",
 	"    \002/mshun guest*@* 3600 ain't gonna happen\002",
 	"    \002/mline guest*@* 1h ain't gonna happen\002",
-	"        Add an M:Line that expires in an hour",
+	"        Add an M-Line that expires in an hour",
 	"    \002/mshun fegget 1h kek\002",
-	"        Add an M:Line for the user \037fegget\037 (resolves their \002id@ho\002 mask if they're online)",
+	"        Add an M-Line for the user \037fegget\037 (resolves their \002id@ho\002 mask if they're online)",
 	"    \002/mshun\002",
-	"        Show all M:Lines",
+	"        Show all M-Lines",
 	NULL
 };
 
 // Dat dere module header
-ModuleHeader MOD_HEADER(m_mshun) = {
-	"m_mshun", // Module name
-	"$Id: v1.02 2019/01/24 Gottem$", // Version
-	"Implements an M:Line for special shuns", // Description
-	"3.2-b8-1", // Modversion, not sure wat do
-	NULL
+ModuleHeader MOD_HEADER = {
+	"third/mshun", // Module name
+	"2.0", // Version
+	"Implements an M-Line for special shuns", // Description
+	"Gottem", // Author
+	"unrealircd-5", // Modversion
 };
 
 // Initialisation routine (register hooks, commands and modes or create structs etc)
-MOD_INIT(m_mshun) {
-	MShun *MShunList, *msEntry; // To initialise the MSC counter imo tbh fam
-	// If command(s) already exist(s) for some reason, bail out
-	if(CommandExists(MSG_MSHUN)) {
-		config_error("Command %s already exists", MSG_MSHUN);
-		return MOD_FAILED;
-	}
-	if(CommandExists(MSG_MSHUN_ALT)) {
-		config_error("Command %s already exists", MSG_MSHUN_ALT);
-		return MOD_FAILED;
-	}
+MOD_INIT() {
+	MShun *MShunList, *msEntry; // To initialise the mshunCount counter imo tbh fam
+
+	// Dem commands fam
+	CheckAPIError("CommandAdd(MSHUN)", CommandAdd(modinfo->handle, MSG_MSHUN, mshun, MAXPARA, CMD_SERVER | CMD_USER));
+	CheckAPIError("CommandAdd(MLINE)", CommandAdd(modinfo->handle, MSG_MSHUN_ALT, mshun, MAXPARA, CMD_SERVER | CMD_USER));
+
+	// Run event every 10 seconds, indefinitely and without any additional data (void *NULL etc)
+	CheckAPIError("EventAdd(mshun_event)", EventAdd(modinfo->handle, "mshun_event", mshun_event, NULL, 10000, 0));
 
-	MSC = 0; // Start with 0 obv lmao
-	if(!(mshunMDI = findmoddata_byname("mshun_list", MODDATATYPE_CLIENT))) { // Attempt to find active moddata (like in case of a rehash)
+	mshunCount = 0; // Start with 0 obv lmao
+	if(!(mshunMDI = findmoddata_byname("mshun_list", MODDATATYPE_LOCAL_VARIABLE))) { // Attempt to find active moddata (like in case of a rehash)
 		ModDataInfo mreq; // No moddata, let's request that shit
 		memset(&mreq, 0, sizeof(mreq)); // Set 'em lol
-		mreq.type = MODDATATYPE_CLIENT; // Apply to servers only (CLIENT actually includes users but we'll disregard that =])
+		mreq.type = MODDATATYPE_LOCAL_VARIABLE;
 		mreq.name = "mshun_list"; // Name it
 		mreq.free = mshun_moddata_free; // Function to free 'em
 		mreq.serialize = NULL;
 		mreq.unserialize = NULL;
 		mreq.sync = 0;
 		mshunMDI = ModDataAdd(modinfo->handle, mreq); // Add 'em yo
-		IsMDErr(mshunMDI, m_mshun, modinfo);
+		CheckAPIError("ModDataAdd(mshun_list)", mshunMDI);
 	}
 	else { // We did get moddata
 		if((MShunList = get_mlines())) { // So load 'em
 			for(msEntry = MShunList; msEntry; msEntry = msEntry->next) // and iter8 m8
-				MSC++; // Ayyy premium countur
+				mshunCount++; // Ayyy premium countur
 		}
 	}
 
-	// Add muh hooks with (mostly) high prio lol
-	serverConnectHook = HookAdd(modinfo->handle, SCONNECT_HOOK, 0, mshun_hook_serverconnect);
-	preChanMsgHook  = HookAddPChar(modinfo->handle, PRCHANMSG_HOOK, -100, mshun_hook_prechanmsg);
-	preUserMsgHook = HookAddPChar(modinfo->handle, PRUSERMSG_HOOK, -100, mshun_hook_preusermsg);
-	preKnockHook = HookAdd(modinfo->handle, PRKNOCK_HOOK, -100, mshun_hook_preknock);
-	preInviteHook = HookAdd(modinfo->handle, PRINVITE_HOOK, -100, mshun_hook_preinvite);
-
-	// Dem commands fam
-	mshunCmd = CommandAdd(modinfo->handle, MSG_MSHUN, m_mshun, MAXPARA, M_SERVER | M_USER);
-	mshunCmdAlt = CommandAdd(modinfo->handle, MSG_MSHUN_ALT, m_mshun, MAXPARA, M_SERVER | M_USER);
+	MARK_AS_GLOBAL_MODULE(modinfo);
 
-	mshunMI = modinfo; // Store module info yo
-	return MOD_SUCCESS; // Let MOD_LOAD handle module errors
+	// Add muh hooks with (mostly) high prio lol
+	HookAdd(modinfo->handle, HOOKTYPE_SERVER_CONNECT, 0, mshun_hook_serverconnect);
+	HookAdd(modinfo->handle, HOOKTYPE_CAN_SEND_TO_CHANNEL, -100, mshun_hook_cansend_chan);
+	HookAdd(modinfo->handle, HOOKTYPE_CAN_SEND_TO_USER, -100, mshun_hook_cansend_user);
+	HookAdd(modinfo->handle, HOOKTYPE_PRE_KNOCK, -100, mshun_hook_preknock);
+	HookAdd(modinfo->handle, HOOKTYPE_PRE_INVITE, -100, mshun_hook_preinvite);
+	return MOD_SUCCESS;
 }
 
 // Actually load the module here (also command overrides as they may not exist in MOD_INIT yet)
-MOD_LOAD(m_mshun) {
-	EventAddEx(mshunMI->handle, "mshun_event", 10, 0, mshun_event, NULL); // Run event every 10 seconds, indefinitely and without any additional data (void *NULL etc)
-
-	// Did the module throw an error during initialisation, or is one of the h00k/command pointers null even?
-	if(ModuleGetError(mshunMI->handle) != MODERR_NOERROR || !serverConnectHook || !preChanMsgHook || !preUserMsgHook || !preKnockHook || !preInviteHook || !mshunCmd || !mshunCmdAlt) {
-		// Display error string kek
-		config_error("A critical error occurred when loading module %s: %s", MOD_HEADER(m_mshun).name, ModuleGetErrorStr(mshunMI->handle));
-		return MOD_FAILED; // No good
-	}
-
+MOD_LOAD() {
 	return MOD_SUCCESS; // We good
 }
 
 // Called on unload/rehash obv
-MOD_UNLOAD(m_mshun) {
+MOD_UNLOAD() {
 	// Not clearing the moddata structs here so we can re-use them easily ;];]
 	return MOD_SUCCESS; // We good
 }
 
-// Dump a NULL-terminated array of strings to user sptr using the numeric rplnum, and then return 0 (taken from DarkFire IRCd)
-static int dumpit(aClient *sptr, char **p) {
-	if(IsServer(sptr)) // Bail out early and silently if it's a server =]
-		return 0;
+// Dump a NULL-terminated array of strings to the user (taken from DarkFire IRCd)
+static void dumpit(Client *client, char **p) {
+	if(IsServer(client)) // Bail out early and silently if it's a server =]
+		return;
 
+	// Using sendto_one() instead of sendnumericfmt() because the latter strips indentation and stuff ;]
 	for(; *p != NULL; p++)
-		sendto_one(sptr, ":%s %03d %s :%s", me.name, RPL_TEXT, sptr->name, *p);
+		sendto_one(client, NULL, ":%s %03d %s :%s", me.name, RPL_TEXT, client->name, *p);
+
 	// Let user take 8 seconds to read it
-	sptr->local->since += 8;
-	return 0;
+	client->local->since += 8;
 }
 
 EVENT(mshun_event) {
@@ -198,23 +184,16 @@ EVENT(mshun_event) {
 // The free shit here normally only happens when the client attached to the moddata quits (afaik), but that's us =]
 void mshun_moddata_free(ModData *md) {
 	if(md->ptr) { // r u insaiyan?
-		MShun *msEntry = md->ptr; // Cast em
-		if(msEntry->mask) free(msEntry->mask); // Gotta
-		if(msEntry->raisin) free(msEntry->raisin); // free
-		if(msEntry->setby) free(msEntry->setby); // 'em
-		msEntry->set = 0; // Just in case lol
-		msEntry->expire = 0L; // ditt0
-		md->ptr = NULL; // d-d-ditt0
+		free_all_mlines(md->ptr);
+		md->ptr = NULL; // Prolly a good idea too =]
 	}
 }
 
-// Check for expiring M:Lines
+// Check for expiring M-Lines
 void check_mlines(void) {
 	MShun *MShunList, *head, *last, **msEntry;
-	char gmt[256]; // For a pretty timestamp instead of UNIX time lol
-	char *timeret; // Ditto
-	TS setat; // For use with the pretty timestamp
-	if(!(MShunList = get_mlines())) // Ayyy no M:Lines known
+	char gmt[128]; // For a pretty timestamp instead of UNIX time lol
+	if(!(MShunList = get_mlines())) // Ayyy no M-Lines known
 		return;
 
 	msEntry = &MShunList; // Hecks so the ->next chain stays intact
@@ -225,62 +204,60 @@ void check_mlines(void) {
 			*msEntry = last->next; // Set the iterat0r to the next one
 
 			if(last == head) { // If it's the first entry, need to take special precautions ;]
-				moddata_client((&me), mshunMDI).ptr = *msEntry; // Cuz shit rips if we don't do dis
+				moddata_local_variable(mshunMDI).ptr = *msEntry; // Cuz shit rips if we don't do dis
 				head = *msEntry; // Move head up
 			}
 
 			// Get pretty timestamp =]
-			setat = last->set;
-			timeret = asctime(gmtime((TS *)&setat));
-			strlcpy(gmt, timeret, sizeof(gmt));
-			iCstrip(gmt);
+			*gmt = '\0';
+			short_date(last->set, gmt);
 
 			// Send expiration notice to all _local_ opers lol (every server checks expirations itself newaysz y0)
-			sendto_snomask(SNO_TKL, "*** Expiring M:Line set by %s at %s GMT for mask %s [reason: %s]", last->setby, gmt, last->mask, last->raisin);
+			sendto_snomask(SNO_TKL, "*** Expiring M-Line set by %s (set at %s GMT) for %s [reason: %s]", last->setby, gmt, last->mask, last->raisin);
 
-			if(last->mask) free(last->mask); // Gotta
-			if(last->raisin) free(last->raisin); // free
-			if(last->setby) free(last->setby); // 'em
-			free(last); // all
-			MSC--;
+			safe_free(last->mask); // Gotta
+			safe_free(last->raisin); // free
+			safe_free(last->setby); // 'em
+			safe_free(last); // all
+			mshunCount--;
 		}
 		else {
 			msEntry = &(*msEntry)->next; // No need for expiration, go to the next one
 		}
 	}
-	if(MSC <= 0) // Cuz shit rips if we don't do dis
-		moddata_client((&me), mshunMDI).ptr = NULL;
+	if(mshunCount <= 0) // Cuz shit rips if we don't do dis
+		moddata_local_variable(mshunMDI).ptr = NULL;
 }
 
-// Add new M:Line obv fam
+// Add new M-Line obv fam
 void add_mline(MShun *newms) {
 	MShun *MShunList, *msEntry; // Head + iter8or imo tbh
-	MSC++; // Always increment count
+	mshunCount++; // Always increment count
 	if(!(MShunList = get_mlines())) { // If MShunList is NULL...
 		MShunList = newms; // ...simply have it point to the newly alloc8ed entry
-		moddata_client((&me), mshunMDI).ptr = MShunList; // And st0re em
+		moddata_local_variable(mshunMDI).ptr = MShunList; // And st0re em
 		return;
 	}
-	for(msEntry = MShunList; msEntry && msEntry->next; msEntry = msEntry->next) { } // Dirty shit to get teh last entray
+	for(msEntry = MShunList; msEntry && msEntry->next; msEntry = msEntry->next) { } // Get teh last entray
 	msEntry->next = newms; // Append lol
 }
 
 // Delete em fam
 void del_mline(MShun *muhms) {
 	MShun *MShunList, *last, **msEntry;
-	if(!(MShunList = get_mlines())) // Ayyy no M:Lines known
+	if(!(MShunList = get_mlines())) // Ayyy no M-Lines known
 		return;
 
 	msEntry = &MShunList; // Hecks so the ->next chain stays intact
 	if(*msEntry == muhms) { // If it's the first entry, need to take special precautions ;]
 		last = *msEntry; // Get the entry pointur
 		*msEntry = last->next; // Set the iterat0r to the next one
-		if(last->mask) free(last->mask); // Gotta
-		if(last->raisin) free(last->raisin); // free
-		if(last->setby) free(last->setby); // 'em
-		free(last); // all
-		moddata_client((&me), mshunMDI).ptr = *msEntry; // Cuz shit rips if we don't do dis
-		MSC--;
+		safe_free(last->mask); // Gotta
+		safe_free(last->raisin); // free
+		safe_free(last->setby); // 'em
+		safe_free(last); // all
+		moddata_local_variable(mshunMDI).ptr = *msEntry; // Cuz shit rips if we don't do dis
+		mshunCount--;
 		return;
 	}
 
@@ -288,45 +265,62 @@ void del_mline(MShun *muhms) {
 		if(*msEntry == muhms) { // Do we need to delete em?
 			last = *msEntry; // Get the entry pointur
 			*msEntry = last->next; // Set the iterat0r to the next one
-			if(last->mask) free(last->mask); // Gotta
-			if(last->raisin) free(last->raisin); // free
-			if(last->setby) free(last->setby); // 'em
-			free(last); // all
-			MSC--;
+			safe_free(last->mask); // Gotta
+			safe_free(last->raisin); // free
+			safe_free(last->setby); // 'em
+			safe_free(last); // all
+			mshunCount--;
 			break;
 		}
 		else {
 			msEntry = &(*msEntry)->next; // No need, go to the next one
 		}
 	}
-	if(MSC <= 0) // Cuz shit rips if we don't do dis
-		moddata_client((&me), mshunMDI).ptr = NULL;
+	if(mshunCount <= 0) // Cuz shit rips if we don't do dis
+		moddata_local_variable(mshunMDI).ptr = NULL;
+}
+
+void free_all_mlines(MShun *MShunList) {
+	MShun *last, **msEntry;
+	if(!MShunList)
+		return;
+
+	msEntry = &MShunList; // Hecks so the ->next chain stays intact
+	while(*msEntry) { // Loop while we have entries obv
+		last = *msEntry; // Get the entry pointur
+		*msEntry = last->next; // Set the iterat0r to the next one
+		safe_free(last->mask); // Gotta
+		safe_free(last->raisin); // free
+		safe_free(last->setby); // 'em
+		safe_free(last); // all
+		mshunCount--;
+	}
 }
 
-// Get (head of) the M:Line list
+// Get (head of) the M-Line list
 MShun *get_mlines(void) {
-	MShun *MShunList = moddata_client((&me), mshunMDI).ptr; // Get mod data
+	MShun *MShunList = moddata_local_variable(mshunMDI).ptr; // Get mod data
 	// Sanity check lol
 	if(MShunList && MShunList->mask)
 		return MShunList;
 	return NULL;
 }
 
-// Find a specific M:Line by mask
+// Find a specific M-Line by mask
 MShun *find_mline(char *mask) {
 	MShun *MShunList, *msEntry; // Head and iter8or fam
 	if((MShunList = get_mlines())) { // Check if the list even has entries kek
 		for(msEntry = MShunList; msEntry; msEntry = msEntry->next) { // Iter8 em
-			if(!match(msEntry->mask, mask)) // Checkemmmm
+			if(match_simple(msEntry->mask, mask)) // Checkemmmm
 				return msEntry;
 		}
 	}
 	return NULL; // Not found m8
 }
 
-// For matching a user to an M:Line
-MShun *match_mline(aClient *sptr) {
-	char *mask = make_user_host(sptr->user->username, sptr->user->realhost); // Get user@host with the real hostnaem
+// For matching a user to an M-Line
+MShun *match_mline(Client *client) {
+	char *mask = make_user_host(client->user->username, client->user->realhost); // Get user@host with the real hostnaem
 
 	if(!mask) // r u insaiyan lol?
 		return NULL;
@@ -334,117 +328,108 @@ MShun *match_mline(aClient *sptr) {
 	return find_mline(mask); // Returns NULL if n0, gg ez
 }
 
-// Internal function called by the PRE* hooks ;];]
-int _check_premsg(aClient *sptr) {
-	if(MyClient(sptr) && !IsServer(sptr) && !IsMe(sptr) && !IsULine(sptr) && !IsOper(sptr) && match_mline(sptr)) // Servers, U:Lines and opers are exempt for obv raisins
-		return 1; // And return 1 to simply discard the entire command (quality shun imo tbh)
-	return 0; // Allowed, 0 = no error etc
+// Internal function called by the PRE_CHANMSG and CAN_SEND_TO_USER hooks ;];]
+int _check_premsg_isshunned(Client *client, int from_cansend, char **text, char **errmsg) {
+	if(MyUser(client) && !IsServer(client) && !IsMe(client) && !IsULine(client) && !IsOper(client) && match_mline(client)) { // Servers, U-Lines and opers are exempt for obv raisins
+		// This is a CAN_SEND type thing, so set text to NULL to drop em ;];];];]
+		if(from_cansend) {
+			*text = NULL;
+			return HOOK_CONTINUE; // Can't return HOOK_DENY here cuz Unreal will abort() in that case :D
+		}
+		return HOOK_DENY;
+	}
+	return HOOK_CONTINUE;
 }
 
 // Server connect hewk familia
-int mshun_hook_serverconnect(aClient *sptr) {
-	// Sync M:Lines fam
+int mshun_hook_serverconnect(Client *client) {
+	// Sync M-Lines fam
 	MShun *MShunList, *msEntry; // Head and iter8or ;];]
 	if((MShunList = get_mlines())) { // Gettem list
 		for(msEntry = MShunList; msEntry; msEntry = msEntry->next) {
 			if(!msEntry || !msEntry->mask) // Sanity check imo ;]
 				continue;
 			// Syntax for servers is a bit different (namely the setby arg and the : before reason (makes the entire string after be considered one arg ;];])
-			sendto_one(sptr, ":%s %s ADD %s %ld %ld %s :%s", me.name, MSG_MSHUN, msEntry->mask, msEntry->set, msEntry->expire, msEntry->setby, msEntry->raisin);
+			sendto_one(client, NULL, ":%s %s ADD %s %ld %ld %s :%s", me.id, MSG_MSHUN, msEntry->mask, msEntry->set, msEntry->expire, msEntry->setby, msEntry->raisin);
 		}
 	}
 	return HOOK_CONTINUE;
 }
 
 // Pre message hewks lol
-char *mshun_hook_prechanmsg(aClient *sptr, aChannel *chptr, char *text, int notice) {
-	return (_check_premsg(sptr) ? NULL : text);
+int mshun_hook_cansend_chan(Client *client, Channel *channel, Membership *lp, char **text, char **errmsg, int notice) {
+	return _check_premsg_isshunned(client, 1, text, errmsg);
 }
 
-char *mshun_hook_preusermsg(aClient *sptr, aClient *to, char *text, int notice) {
-	if(IsULine(to)) // Allow sending to U:Lines (NickServ etc famiglia) ;]
-		return text;
-	return (_check_premsg(sptr) ? NULL : text);
+int mshun_hook_cansend_user(Client *client, Client *to, char **text, char **errmsg, int notice) {
+	if(IsULine(to)) // Allow sending to U-Lines (NickServ etc famiglia) ;]
+		return HOOK_CONTINUE;
+	return _check_premsg_isshunned(client, 1, text, errmsg);
 }
 
 // Also /knock
-int mshun_hook_preknock(aClient *sptr, aChannel *chptr) {
-	return (_check_premsg(sptr) ? HOOK_DENY : HOOK_CONTINUE); // Need to return a slightly different variable here lol
+int mshun_hook_preknock(Client *client, Channel *channel) {
+	return _check_premsg_isshunned(client, 0, NULL, NULL);
 }
 
 // And /invite lol
-#if BACKPORT
-	int mshun_hook_preinvite(aClient *sptr, aChannel *chptr) {
-		return (_check_premsg(sptr) ? HOOK_DENY : HOOK_CONTINUE); // Ditt0
-	}
-#else
-	int mshun_hook_preinvite(aClient *sptr, aClient *target, aChannel *chptr, int *override) {
-		return (_check_premsg(sptr) ? HOOK_DENY : HOOK_CONTINUE); // Same here yo
-	}
-#endif
+int mshun_hook_preinvite(Client *client, Client *target, Channel *channel, int *override) {
+	return _check_premsg_isshunned(client, 0, NULL, NULL);
+}
 
 // Function for /MSHUN etc
-CMD_FUNC(m_mshun) {
-	/* Gets args: aClient *cptr, aClient *sptr, int parc, char *parv[]
-	**
-	** cptr: Pointer to directly attached client -- if remote user this is the remote server instead
-	** sptr: Pointer to user executing command
-	** parc: Amount of arguments (also includes the command in the count)
-	** parv: Contains the actual args, first one starts at parv[1]
-	**
-	** So "MSHUN test" would result in parc = 2 and parv[1] = "test"
-	** Also, parv[0] seems to always be NULL, so better not rely on it fam
-	*/
+CMD_FUNC(mshun) {
+	// Gets args: Client *client, MessageTag *recv_mtags, int parc, char *parv[]
 	MShun *MShunList, *newms, *msEntry; // Quality struct pointers
 	char *mask, *exptmp, *setby; // Muh args
 	char raisin[BUFSIZE]; // Reasons may or may not be pretty long
-	char gmt[256], gmt2[256]; // For a pretty timestamp instead of UNIX time lol
-	char *timeret; // Ditto
+	char gmt[128], gmt2[128]; // For a pretty timestamp instead of UNIX time lol
 	char cur, prev, prev2; // For checking time strings
-	long setat, expire; // After how many seconds the M:Line should expire
-	TS expiry; // For use with the pretty timestamps
+	long setat, expire; // After how many seconds the M-Line should expire
 	int i, adoffset, rindex, del; // Iterat0rs, indices and "booleans" =]
-	aClient *acptr; // To check if the mask is a nick instead =]
+	Client *acptr; // To check if the mask is a nick instead =]
 
-	// Gotta be at least a server, U:Line or oper with correct privs lol
-	if((!IsServer(sptr) && !IsMe(sptr) && !IsULine(sptr) && !IsOper(sptr)) || !ValidatePermissionsForPath("mshun", sptr, NULL, NULL, NULL)) {
-		sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, sptr->name); // Check ur privilege fam
-		return -1; // Ain't gonna happen lol
+	// Gotta be at least a server, U-Line or oper with correct privs lol
+	if((!IsServer(client) && !IsULine(client) && !IsOper(client)) || !ValidatePermissionsForPath("mshun", client, NULL, NULL, NULL)) {
+		sendnumeric(client, ERR_NOPRIVILEGES); // Check ur privilege fam
+		return; // Ain't gonna happen lol
 	}
 
+	if(IsServer(client) && parc < 7)
+		return;
+
 	// If no args given (or we got /mshun list)
-	if(BadPtr(parv[1]) || !stricmp(parv[1], "list")) {
-		if(IsServer(cptr)) // No need to list shit for servers =]
-			return 0;
+	if(BadPtr(parv[1]) || !strcasecmp(parv[1], "list")) {
+		if(IsServer(client)) // No need to list shit for servers =]
+			return;
 		if(!(MShunList = get_mlines())) // Attempt to get list
-			sendnotice(sptr, "*** No M:Lines found");
+			sendnotice(client, "*** No M-Lines found");
 		else {
 			for(msEntry = MShunList; msEntry; msEntry = msEntry->next) {
-				timeret = asctime(gmtime((TS *)&msEntry->set));
-				strlcpy(gmt2, timeret, sizeof(gmt2));
-				iCstrip(gmt2);
-				if(msEntry->expire == 0) // Let's show "permanent" for permanent M:Lines, n0? =]
-					sendnotice(sptr, "*** Permanent M:Line set by %s at %s GMT for mask %s [reason: %s]", msEntry->setby, gmt2, msEntry->mask, msEntry->raisin);
+				*gmt2 = '\0';
+				short_date(msEntry->set, gmt2);
+				if(msEntry->expire == 0) // Let's show "permanent" for permanent M-Lines, n0? =]
+					sendnotice(client, "*** Permanent M-Line by %s (set at %s GMT) for %s [reason: %s]", msEntry->setby, gmt2, msEntry->mask, msEntry->raisin);
 				else {
 					// Get pretty timestamp for expiring lines =]
-					expiry = msEntry->set + msEntry->expire;
-					timeret = asctime(gmtime((TS *)&expiry));
-					strlcpy(gmt, timeret, sizeof(gmt));
-					iCstrip(gmt);
-					sendnotice(sptr, "*** M:Line set by %s at %s GMT for mask %s, expiring at %s GMT [reason: %s]", msEntry->setby, gmt2, msEntry->mask, gmt, msEntry->raisin);
+					*gmt = '\0';
+					short_date(msEntry->set + msEntry->expire, gmt);
+					sendnotice(client, "*** M-Line by %s (set at %s GMT) for %s, expiring at %s GMT [reason: %s]", msEntry->setby, gmt2, msEntry->mask, gmt, msEntry->raisin);
 				}
 			}
 		}
-		return 0;
+		return;
 	}
 
-	if(!stricmp(parv[1], "help") || !stricmp(parv[1], "halp")) // Or first arg is halp
-		return dumpit(sptr, muhhalp); // Return help string instead
+	if(!strcasecmp(parv[1], "help") || !strcasecmp(parv[1], "halp")) { // Or first arg is halp
+		dumpit(client, muhhalp); // Return help string instead
+		return;
+	}
 
 	// Need to offset parv to the left if we got a shorthand like /mshun -dick@butt
 	adoffset = 0;
 	del = 0;
-	if(IsPerson(cptr)) { // Regular clients always use a shorter form =]
+	if(IsUser(client)) { // Regular clients always use a shorter form =]
 		mask = parv[1]; // First arg is the mask hur
 		if(strchr("+-", *mask)) { // Check if it starts with either + or - fam
 			del = (*mask == '-' ? 1 : 0); // We deleting shyte?
@@ -458,25 +443,21 @@ CMD_FUNC(m_mshun) {
 
 	// Servers always use the full/long form
 	else {
-		if(stricmp(parv[1], "add") && stricmp(parv[1], "del")) // If first arg is neither add nor del, fuck off
-			return -1;
-		del = (!stricmp(parv[1], "del") ? 1 : 0); // Are we deleting?
+		if(strcasecmp(parv[1], "add") && strcasecmp(parv[1], "del")) // If first arg is neither add nor del, fuck off
+			return;
+		del = (!strcasecmp(parv[1], "del") ? 1 : 0); // Are we deleting?
 		mask = parv[2];
 	}
 
 	if((!del && (parc + adoffset) < 4) || (del && (parc + adoffset) < 3)) { // Delete doesn't require the expire and reason fields
-		sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, sptr->name, MSG_MSHUN); // Need m0ar lol
-		return -1;
+		sendnumeric(client, ERR_NEEDMOREPARAMS, MSG_MSHUN); // Need m0ar lol
+		return;
 	}
 
-	// Extra args required for servers (setby and setat fields, used during linking yo)
-	if(IsServer(cptr) && parc <= 6)
-		return -1; // Return silently
-
 	// Check for the sanity of the passed mask
-	if(!match("*!*@*", mask) || match("*@*", mask) || strlen(mask) < 3) {
-		sendnotice(sptr, "*** [mshun] The mask should be of the format ident@host");
-		return -1; // Let's bail lol
+	if(match_simple("*!*@*", mask) || !match_simple("*@*", mask) || strlen(mask) < 3) {
+		sendnotice(client, "*** The mask should be of the format ident@host");
+		return; // Let's bail lol
 	}
 
 	// Initialise a bunch of shit
@@ -485,33 +466,33 @@ CMD_FUNC(m_mshun) {
 	expire = DEFAULT_BANTIME;
 	setat = TStime();
 	rindex = 0;
-	setby = sptr->name;
-	msEntry = find_mline(mask); // Attempt to find existing M:Line
+	setby = client->name;
+	msEntry = find_mline(mask); // Attempt to find existing M-Line
 
 	// Most shit is silent for servers
-	if(IsServer(cptr)) {
-		if(!del && msEntry) // Adding an M:Line but it already exists
-			return -1; // Return silently
+	if(IsServer(client)) {
+		if(!del && msEntry) // Adding an M-Line but it already exists
+			return; // Return silently
 		else if(del && !msEntry) // Deleting but doesn't exist
-			return -1; // Return silently
+			return; // Return silently
 
 		strlcpy(raisin, parv[6], sizeof(raisin)); // Copy the reason field imo tbh
 		setat = atol(parv[3]); // Extra arg yo
 		expire = atol(parv[4]); // Set expiration
 		setby = parv[5]; // Extra arg yo
 		if(setat <= 0) // Some error occured lol
-			return -1; // Gtfo silently
+			return; // Gtfo silently
 	}
 
 	// Command came from a user
 	else {
-		if(!del && msEntry) { // Adding an M:Line but it already exists
-			sendnotice(sptr, "*** M:Line for mask %s already exists", mask);
-			return -1; // Lolnope
+		if(!del && msEntry) { // Adding an M-Line but it already exists
+			sendnotice(client, "*** M-Line for mask %s already exists", mask);
+			return; // Lolnope
 		}
 		else if(del && !msEntry) { // Deleting but doesn't exist
-			sendnotice(sptr, "*** M:Line for mask %s doesn't exist", mask);
-			return -1; // Lolnope
+			sendnotice(client, "*** M-Line for mask %s doesn't exist", mask);
+			return; // Lolnope
 		}
 
 		// If adding, check for expiration and reason fields
@@ -539,8 +520,8 @@ CMD_FUNC(m_mshun) {
 			}
 
 			if(!rindex || BadPtr(parv[rindex]) || !strlen(parv[rindex])) { // If rindex is 0 it means the arg is missing
-				sendnotice(sptr, "*** [mshun] The reason field is required");
-				return -1; // No good fam
+				sendnotice(client, "*** The reason field is required");
+				return; // No good fam
 			}
 
 			// Now start from rindex and copy dem remaining args
@@ -558,47 +539,42 @@ CMD_FUNC(m_mshun) {
 	// For both servers and users ;]
 	if(!del) {
 		// Allocate/initialise mem0ry for the new entry
-		newms = malloc(sizeof(MShun));
-		newms->mask = strdup(mask);
+		newms = safe_alloc(sizeof(MShun));
+		safe_strdup(newms->mask, mask);
 		newms->set = setat;
 		newms->expire = expire;
-		newms->raisin = strdup(raisin);
-		newms->setby = strdup(setby);
-		newms->next = NULL;
+		safe_strdup(newms->raisin, raisin);
+		safe_strdup(newms->setby, setby);
 		msEntry = newms;
 		add_mline(newms); // Add em
 	}
 
-	// Propagate the M:Line to other servers if it came from a user only (when servers link they sync it themselves)
-	if(!IsServer(sptr))
-		sendto_server(&me, 0, 0, ":%s %s %s %s %ld %ld %s :%s", sptr->name, MSG_MSHUN, (del ? "DEL" : "ADD"), mask, msEntry->set, msEntry->expire, setby, msEntry->raisin); // Muh raw command
-	else { // If it did come from a server, let's make a "set at" timestamp =]
-		timeret = asctime(gmtime((TS *)&msEntry->set));
-		strlcpy(gmt2, timeret, sizeof(gmt2));
-		iCstrip(gmt2);
-	}
+	// Propagate the M-Line to other local servers fam (excluding the direction it came from ;])
+	sendto_server(client, 0, 0, NULL, ":%s %s %s %s %ld %ld %s :%s", me.id, MSG_MSHUN, (del ? "DEL" : "ADD"), mask, msEntry->set, msEntry->expire, setby, msEntry->raisin); // Muh raw command
+
+	// Also send snomask notices to all local opers =]
+	// Make pretty set timestamp first tho
+	*gmt2 = '\0';
+	short_date(msEntry->set, gmt2);
+
 	// Also send snomask notices to all local opers =]
 	if(msEntry->expire == 0) { // Permanent lol
-		if(IsServer(sptr)) // Show "set at" during sync phase ;]
-			sendto_snomask(SNO_TKL, "*** Permanent M:Line %sed by %s at %s GMT for mask %s [reason: %s]", (del ? "delet" : "add"), setby, gmt2, mask, msEntry->raisin);
+		if(IsServer(client)) // Show "set at" during sync phases ;]
+			sendto_snomask(SNO_TKL, "*** Permanent M-Line %sed by %s (set at %s GMT) for %s [reason: %s]", (del ? "delet" : "add"), setby, gmt2, mask, msEntry->raisin);
 		else
-			sendto_snomask(SNO_TKL, "*** Permanent M:Line %sed by %s for mask %s [reason: %s]", (del ? "delet" : "add"), setby, mask, msEntry->raisin);
+			sendto_snomask(SNO_TKL, "*** Permanent M-Line %sed by %s for %s [reason: %s]", (del ? "delet" : "add"), setby, mask, msEntry->raisin);
 	}
 	else {
-		// Make pretty expiration timestamp if not a permanent M:Line
-		expiry = msEntry->set + msEntry->expire;
-		timeret = asctime(gmtime((TS *)&expiry));
-		strlcpy(gmt, timeret, sizeof(gmt));
-		iCstrip(gmt);
-		if(IsServer(sptr)) // Show "set at" during sync phase ;]
-			sendto_snomask(SNO_TKL, "*** M:Line %sed by %s at %s GMT for mask %s, expiring at %s GMT [reason: %s]", (del ? "delet" : "add"), setby, gmt2, mask, gmt, msEntry->raisin);
+		// Make pretty expiration timestamp if not a permanent M-Line
+		*gmt = '\0';
+		short_date(msEntry->set + msEntry->expire, gmt);
+		if(IsServer(client)) // Show "set at" during sync phases ;]
+			sendto_snomask(SNO_TKL, "*** M-Line %sed by %s (set at %s GMT) for %s, expiring at %s GMT [reason: %s]", (del ? "delet" : "add"), setby, gmt2, mask, gmt, msEntry->raisin);
 		else
-			sendto_snomask(SNO_TKL, "*** M:Line %sed by %s for mask %s, expiring at %s GMT [reason: %s]", (del ? "delet" : "add"), setby, mask, gmt, msEntry->raisin);
+			sendto_snomask(SNO_TKL, "*** M-Line %sed by %s for %s, expiring at %s GMT [reason: %s]", (del ? "delet" : "add"), setby, mask, gmt, msEntry->raisin);
 	}
 
 	// Delete em famamlamlamlmal
 	if(del)
 		del_mline(msEntry);
-
-	return 0; // All good
 }

+ 269 - 285
malv/otkl.c

@@ -1,29 +1,42 @@
 /* Copyright (C) All Rights Reserved
 ** Written by Gottem <support@gottem.nl>
-** Website: https://gitgud.malvager.net/Wazakindjes/unrealircd_mods
-** License: https://gitgud.malvager.net/Wazakindjes/unrealircd_mods/raw/master/LICENSE
+** Website: https://gottem.nl/unreal
+** License: https://gottem.nl/unreal/license
+*/
+
+/*** <<<MODULE MANAGER START>>>
+module {
+	documentation "https://gottem.nl/unreal/man/otkl";
+	troubleshooting "In case of problems, check the FAQ at https://gottem.nl/unreal/halp or e-mail me at support@gottem.nl";
+	min-unrealircd-version "5.*";
+	//max-unrealircd-version "5.*";
+	post-install-text {
+		"The module is installed, now all you need to do is add a 'loadmodule' line to your config file:";
+		"loadmodule \"third/otkl\";";
+		"Then /rehash the IRCd.";
+		"For usage information, refer to the module's documentation found at: https://gottem.nl/unreal/man/otkl";
+	}
+}
+*** <<<MODULE MANAGER END>>>
 */
 
 // One include for all cross-platform compatibility thangs
 #include "unrealircd.h"
 
-// Hewktypez
-#define SCONNECT_HOOK HOOKTYPE_SERVER_CONNECT
-#define PRECONNECT_HOOK HOOKTYPE_PRE_LOCAL_CONNECT
-
 // Command strings
-#define MSG_OGLINE "OGLINE" // Regular G:Lines
-#define MSG_OZLINE "OZLINE" // Actually a GZ:Line ;]
+#define MSG_OGLINE "OGLINE" // Regular G-Lines
+#define MSG_OZLINE "OZLINE" // Actually a GZ-Line ;]
 
 #define DEF_NORAISIN "no reason" // Default message y0
 
 // Dem macros yo
-CMD_FUNC(m_ogline); // Register command function
-CMD_FUNC(m_ozline); // Register command function
-#define IsMDErr(x, y, z) \
+CMD_FUNC(cmd_ogline); // Register command function
+CMD_FUNC(cmd_ozline); // Register command function
+
+#define CheckAPIError(apistr, apiobj) \
 	do { \
-		if(!(x)) { \
-			config_error("A critical error occurred when registering ModData for %s: %s", MOD_HEADER(y).name, ModuleGetErrorStr((z)->handle)); \
+		if(!(apiobj)) { \
+			config_error("A critical error occurred on %s for %s: %s", (apistr), MOD_HEADER.name, ModuleGetErrorStr(modinfo->handle)); \
 			return MOD_FAILED; \
 		} \
 	} while(0)
@@ -37,31 +50,29 @@ struct t_otkline {
 	char *host; // Hostname or IP
 	char *raisin; // Raisin lel
 	char *setby; // Set by who
-	TS setat; // UNIX time of when it's set
+	time_t setat; // UNIX time of when it's set
 	OTKLine *next; // Quality linked list
 };
 
 // Quality fowod declarations
-static int dumpit(aClient *sptr, char **p);
+static void dumpit(Client *client, char **p);
 void otkl_identmd_free(ModData *md);
 void otkl_moddata_free(ModData *md);
+OTKLine *get_otklines(void);
 OTKLine *find_otkline(char *user, char *host, char flag);
 void add_otkline(OTKLine *newotkl);
 void del_otkline(OTKLine *muhotkl);
-int match_otkline(aClient *sptr, OTKLine *otkl, char flag);
-void free_otkline(OTKLine *otkl);
-OTKLine *get_otklines(void);
-int otkl_main(aClient *cptr, aClient *sptr, int parc, char *parv[], char flag);
-int otkl_hook_serverconnect(aClient *sptr);
-int otkl_hook_pre_localconnect(aClient *sptr);
+void free_all_otklines(OTKLine *OTKList);
+int match_otkline(Client *client, OTKLine *otkline, char flag);
+void free_otkline(OTKLine *otkline);
+void otkl_main(Client *client, int parc, char *parv[], char flag);
+int otkl_hook_serverconnect(Client *client);
+int otkl_hook_pre_localconnect(Client *client);
 int ban_too_broad(char *usermask, char *hostmask);
 
 // Muh globals
 ModDataInfo *otklMDI; // To store the OTKLines with &me lol (hack so we don't have to use a .db file or some shit)
-static ModuleInfo *otklMI = NULL; // Store ModuleInfo so we can use it to check for errors in MOD_LOAD
 ModDataInfo *otklIdentMDI; // Moddata for the original ident =]
-Command *oglineCmd, *ozlineCmd; // Pointers to the command we're gonna add
-Hook *serverConnHook, *preConnHook; // Dem hewks yo
 int OTKCount; // Count em
 
 // Help string in case someone does just /OGLINE
@@ -71,9 +82,9 @@ static char *muhHalp[] = {
 	** \037 = underlined -- \x1F
 	*/
 	"*** \002Help on /OGLINE and /OZLINE\002 ***",
-	"Allows privileged opers to set one-time G/GZ:Lines.",
-	"Local Z:Lines are not supported because they seem fairly useless.",
-	"The rules for hostmasks etc are the same as for regular G/GZ:Lines.",
+	"Allows privileged opers to set one-time G/GZ-Lines.",
+	"Local Z-Lines are not supported because they seem fairly useless.",
+	"The rules for hostmasks etc are the same as for regular G/GZ-Lines.",
 	"These \"OTKLines\" persist through a rehash, plus servers will",
 	"sync everything they know at link-time too. If any online users",
 	"match a newly added OTKLine, they will be killed first. Then once",
@@ -82,11 +93,11 @@ static char *muhHalp[] = {
 	" ",
 	"Syntax:",
 	"    \002/OGLINE\002 or \002/OZLINE\002",
-	"        List the currently known OG/OZ:Lines (two different lists)",
+	"        List the currently known OG/OZ-Lines (two different lists)",
 	"    \002/OGLINE\002 [-]\037identmask@hostmask\037 {\037reason\037}",
-	"        Set/remove an OG:Line (reason is required for adding)",
+	"        Set/remove an OG-Line (reason is required for adding)",
 	"    \002/OZLINE\002 [-]\037identmask@ipmask\037 {\037reason\037}",
-	"        Set/remove an OZ:Line (reason is required for adding)",
+	"        Set/remove an OZ-Line (reason is required for adding)",
 	"    \002/OGLINE\002 \037help\037",
 	"    \002/OZLINE\002 \037help\037",
 	"       View this built-in help",
@@ -102,228 +113,211 @@ static char *muhHalp[] = {
 };
 
 // Dat dere module header
-ModuleHeader MOD_HEADER(m_otkl) = {
-	"m_otkl", // Module name
-	"$Id: v1.06 2018/04/16 Gottem$", // Version
+ModuleHeader MOD_HEADER = {
+	"third/otkl", // Module name
+	"2.0", // Version
 	"Implements one-time TKLines", // Description
-	"3.2-b8-1", // Modversion, not sure wat do
-	NULL
+	"Gottem", // Author
+	"unrealircd-5", // Modversion
 };
 
 // Initialisation routine (register hooks, commands and modes or create structs etc)
-MOD_INIT(m_otkl) {
-	OTKLine *OTKList, *otkl; // To initialise the OTKL counter imo tbh fam
-	// If command already exists for some reason, bail out
-	if(CommandExists(MSG_OGLINE)) {
-		config_error("Command %s already exists", MSG_OGLINE);
-		return MOD_FAILED;
-	}
-	if(CommandExists(MSG_OZLINE)) {
-		config_error("Command %s already exists", MSG_OZLINE);
-		return MOD_FAILED;
-	}
+MOD_INIT() {
+	OTKLine *OTKList, *cur; // To initialise the OTKL counter imo tbh fam
+
+	CheckAPIError("CommandAdd(OGLINE)", CommandAdd(modinfo->handle, MSG_OGLINE, cmd_ogline, MAXPARA, CMD_USER | CMD_SERVER));
+	CheckAPIError("CommandAdd(OZLINE)", CommandAdd(modinfo->handle, MSG_OZLINE, cmd_ozline, MAXPARA, CMD_USER | CMD_SERVER));
+
+	// Request moddata for storing the original nick
+	ModDataInfo mreq2;
+	memset(&mreq2, 0, sizeof(mreq2));
+	mreq2.type = MODDATATYPE_LOCAL_CLIENT;
+	mreq2.name = "otkl_lastidents"; // Name it
+	mreq2.free = otkl_identmd_free; // Function to free 'em
+	otklIdentMDI = ModDataAdd(modinfo->handle, mreq2);
+	CheckAPIError("ModDataAdd(otkl_lastidents)", otklIdentMDI);
 
 	OTKCount = 0;
-	if(!(otklMDI = findmoddata_byname("otkl", MODDATATYPE_CLIENT))) { // Attempt to find active moddata (like in case of a rehash)
+	if(!(otklMDI = findmoddata_byname("otkl", MODDATATYPE_LOCAL_VARIABLE))) { // Attempt to find active moddata (like in case of a rehash)
 		ModDataInfo mreq; // No moddata, let's request that shit
 		memset(&mreq, 0, sizeof(mreq)); // Set 'em lol
-		mreq.type = MODDATATYPE_CLIENT; // Apply to servers only (CLIENT actually includes users but we'll disregard that =])
-		mreq.name = "otkl"; // Name it
+		mreq.type = MODDATATYPE_LOCAL_VARIABLE;
+		mreq.name = "otkl_list"; // Name it
 		mreq.free = otkl_moddata_free; // Function to free 'em
 		mreq.serialize = NULL;
 		mreq.unserialize = NULL;
 		mreq.sync = 0;
 		otklMDI = ModDataAdd(modinfo->handle, mreq); // Add 'em yo
-		IsMDErr(otklMDI, m_textshun, modinfo);
+		CheckAPIError("ModDataAdd(otkl_list)", otklMDI);
 	}
 	else { // We did get moddata
 		if((OTKList = get_otklines())) { // So load 'em
-			for(otkl = OTKList; otkl; otkl = otkl->next) // and iter8 m8
+			for(cur = OTKList; cur; cur = cur->next) // and iter8 m8
 				OTKCount++; // Ayyy premium countur
 		}
 	}
 
-	// Request moddata for storing the original nick
-	ModDataInfo mreq2;
-	memset(&mreq2, 0, sizeof(mreq2));
-	mreq2.type = MODDATATYPE_CLIENT; // Apply to users only (CLIENT actually includes servers but we'll disregard that here =])
-	mreq2.name = "otkl_lastidents"; // Name it
-	mreq2.free = otkl_identmd_free; // Function to free 'em
-	otklIdentMDI = ModDataAdd(modinfo->handle, mreq2);
-	IsMDErr(otklIdentMDI, m_otkl, modinfo);
+	MARK_AS_GLOBAL_MODULE(modinfo);
 
 	// Add 'em hewks
-	serverConnHook = HookAdd(modinfo->handle, SCONNECT_HOOK, 0, otkl_hook_serverconnect);
-	preConnHook = HookAdd(modinfo->handle, PRECONNECT_HOOK, 0, otkl_hook_pre_localconnect);
-
-	// Und commands, servers can use 'em too ;];]
-	oglineCmd = CommandAdd(modinfo->handle, MSG_OGLINE, m_ogline, MAXPARA, M_USER | M_SERVER);
-	ozlineCmd = CommandAdd(modinfo->handle, MSG_OZLINE, m_ozline, MAXPARA, M_USER | M_SERVER);
-
-	otklMI = modinfo; // Store module info yo
-
-	return MOD_SUCCESS; // Let MOD_LOAD handle errors
+	HookAdd(modinfo->handle, HOOKTYPE_SERVER_CONNECT, 0, otkl_hook_serverconnect);
+	HookAdd(modinfo->handle, HOOKTYPE_PRE_LOCAL_CONNECT, 0, otkl_hook_pre_localconnect);
+	return MOD_SUCCESS;
 }
 
 // Actually load the module here (also command overrides as they may not exist in MOD_INIT yet)
-MOD_LOAD(m_otkl) {
-	// Did the module throw an error during initialisation, or is one of the commands/hewks null even?
-	if(ModuleGetError(otklMI->handle) != MODERR_NOERROR || !oglineCmd || !ozlineCmd | !preConnHook || !serverConnHook) {
-		// Display error string kek
-		config_error("A critical error occurred when loading module %s: %s", MOD_HEADER(m_otkl).name, ModuleGetErrorStr(otklMI->handle));
-		return MOD_FAILED; // No good
-	}
+MOD_LOAD() {
 	return MOD_SUCCESS; // We good
 }
 
 // Called on unload/rehash obv
-MOD_UNLOAD(m_otkl) {
+MOD_UNLOAD() {
 	// Not clearing the moddata structs here so we can re-use them easily ;];]
 	return MOD_SUCCESS; // We good
 }
 
-// Dump a NULL-terminated array of strings to user sptr using the numeric rplnum, and then return 0 (taken from DarkFire IRCd)
-static int dumpit(aClient *sptr, char **p) {
-	if(IsServer(sptr)) // Bail out early and silently if it's a server =]
-		return 0;
+// Dump a NULL-terminated array of strings to the user (taken from DarkFire IRCd)
+static void dumpit(Client *client, char **p) {
+	if(IsServer(client)) // Bail out early and silently if it's a server =]
+		return;
 
+	// Using sendto_one() instead of sendnumericfmt() because the latter strips indentation and stuff ;]
 	for(; *p != NULL; p++)
-		sendto_one(sptr, ":%s %03d %s :%s", me.name, RPL_TEXT, sptr->name, *p);
+		sendto_one(client, NULL, ":%s %03d %s :%s", me.name, RPL_TEXT, client->name, *p);
 
 	// Let user take 8 seconds to read it
-	sptr->local->since += 8;
-	return 0;
+	client->local->since += 8;
 }
 
 void otkl_identmd_free(ModData *md) {
-	if(md->ptr) // r u insaiyan?
-		free(md->ptr);
-	md->ptr = NULL;
+	safe_free(md->ptr);
 }
 
 // Probably never called but it's a required function
 // The free shit here normally only happens when the client attached to the moddata quits (afaik), but that's us =]
 void otkl_moddata_free(ModData *md) {
 	if(md->ptr) { // r u insaiyan?
-		OTKLine *otkl = md->ptr; // Cast em
-		free_otkline(otkl); // Free that shit
+		free_all_otklines(md->ptr); // Free that shit
 		md->ptr = NULL; // Just in case lol
 	}
 }
 
-CMD_FUNC(m_ogline) {
-	return otkl_main(cptr, sptr, parc, parv, 'G');
+CMD_FUNC(cmd_ogline) {
+	otkl_main(client, parc, parv, 'G');
+}
+
+CMD_FUNC(cmd_ozline) {
+	otkl_main(client, parc, parv, 'Z');
 }
 
-CMD_FUNC(m_ozline) {
-	return otkl_main(cptr, sptr, parc, parv, 'Z');
+OTKLine *get_otklines(void) {
+	OTKLine *OTKList = moddata_local_variable(otklMDI).ptr; // Get mod data
+	if(OTKList && OTKList->user) // Sanity check lol
+		return OTKList;
+	return NULL;
 }
 
 OTKLine *find_otkline(char *user, char *host, char flag) {
-	OTKLine *OTKList, *otkl; // Head and iter8or fam
+	OTKLine *OTKList, *otkline; // Head and iter8or fam
 	if((OTKList = get_otklines())) { // Check if the list even has entries kek
-		for(otkl = OTKList; otkl; otkl = otkl->next) { // Iter8 em
-			// Let's do stricmp() just in case =]
-			if(otkl->flag == flag && !stricmp(otkl->user, user) && !stricmp(otkl->host, host))
-				return otkl;
+		for(otkline = OTKList; otkline; otkline = otkline->next) { // Iter8 em
+			// Let's do strcasecmp() just in case =]
+			if(otkline->flag == flag && !strcasecmp(otkline->user, user) && !strcasecmp(otkline->host, host))
+				return otkline;
 		}
 	}
 	return NULL; // Not found m8
 }
 
 void add_otkline(OTKLine *newotkl) {
-	OTKLine *OTKList, *otkl; // Head + iter8or imo tbh
+	OTKLine *OTKList, *otkline; // Head + iter8or imo tbh
 	newotkl->next = NULL; // Cuz inb4rip linked list
 	OTKCount++; // Always increment count
 	if(!(OTKList = get_otklines())) { // If OTKList is NULL...
 		OTKList = newotkl; // ...simply have it point to the newly alloc8ed entry
-		moddata_client((&me), otklMDI).ptr = OTKList; // And st0re em
+		moddata_local_variable(otklMDI).ptr = OTKList; // And st0re em
 		return;
 	}
-	for(otkl = OTKList; otkl && otkl->next; otkl = otkl->next) { } // Dirty shit to get teh last entray
-	otkl->next = newotkl; // Append lol
+	for(otkline = OTKList; otkline && otkline->next; otkline = otkline->next) { } // Get teh last entray
+	otkline->next = newotkl; // Append lol
 }
 
 void del_otkline(OTKLine *muhotkl) {
-	OTKLine *OTKList, *last, **otkl;
+	OTKLine *OTKList, *last, **otkline;
 	if(!(OTKList = get_otklines())) // Ayyy no OTKLines known
 		return;
 
-	otkl = &OTKList; // Hecks so the ->next chain stays intact
-	if(*otkl == muhotkl) { // If it's the first entry, need to take special precautions ;]
-		last = *otkl; // Get the entry pointur
-		*otkl = last->next; // Set the iterat0r to the next one
+	otkline = &OTKList; // Hecks so the ->next chain stays intact
+	if(*otkline == muhotkl) { // If it's the first entry, need to take special precautions ;]
+		last = *otkline; // Get the entry pointur
+		*otkline = last->next; // Set the iterat0r to the next one
 		free_otkline(last); // Free that shit
-		moddata_client((&me), otklMDI).ptr = *otkl; // Cuz shit rips if we don't do dis
+		moddata_local_variable(otklMDI).ptr = *otkline; // Cuz shit rips if we don't do dis
 		OTKCount--;
 		return;
 	}
 
-	while(*otkl) { // Loop while we have entries obv
-		if(*otkl == muhotkl) { // Do we need to delete em?
-			last = *otkl; // Get the entry pointur
-			*otkl = last->next; // Set the iterat0r to the next one
+	while(*otkline) { // Loop while we have entries obv
+		if(*otkline == muhotkl) { // Do we need to delete em?
+			last = *otkline; // Get the entry pointur
+			*otkline = last->next; // Set the iterat0r to the next one
 			free_otkline(last); // Free that shit
 			OTKCount--;
 			break;
 		}
 		else {
-			otkl = &(*otkl)->next; // No need, go to the next one
+			otkline = &(*otkline)->next; // No need, go to the next one
 		}
 	}
 	if(OTKCount <= 0) // Cuz shit rips if we don't do dis
-		moddata_client((&me), otklMDI).ptr = NULL;
+		moddata_local_variable(otklMDI).ptr = NULL;
 }
 
-int match_otkline(aClient *sptr, OTKLine *otkl, char flag) {
+void free_all_otklines(OTKLine *OTKList) {
+	OTKLine *last, **otkline;
+	if(!OTKList)
+		return;
+
+	otkline = &OTKList; // Hecks so the ->next chain stays intact
+	while(*otkline) { // Loop while we have entries obv
+		last = *otkline; // Get the entry pointur
+		*otkline = last->next; // Set the iterat0r to the next one
+		free_otkline(last); // Free that shit
+		OTKCount--;
+	}
+}
+
+int match_otkline(Client *client, OTKLine *otkline, char flag) {
 	int gottem = 0; // Equals 2 when we got a solid match
-	char *orig = moddata_client(sptr, otklIdentMDI).ptr;
+	char *orig = moddata_local_client(client, otklIdentMDI).ptr;
 
 	// Check current and stored idents ;]
-	if(!match(otkl->user, sptr->user->username))
+	if(match_simple(otkline->user, client->user->username))
 		gottem++;
-	else if(orig && !match(otkl->user, orig))
+	else if(orig && match_simple(otkline->user, orig))
 		gottem++;
 
 	// Check IP or host based shit ;]
-	if(flag == 'Z' && !match(otkl->host, GetIP(sptr)))
+	if(flag == 'Z' && match_simple(otkline->host, GetIP(client)))
 		gottem++;
-	else if(flag == 'G' && !match(otkl->host, sptr->user->realhost))
+	else if(flag == 'G' && match_simple(otkline->host, client->user->realhost))
 		gottem++;
 
 	return (gottem == 2 ? 1 : 0);
 }
 
-void free_otkline(OTKLine *otkl) {
-	if(otkl) {
-		if(otkl->user) free(otkl->user); // Gotta
-		if(otkl->host) free(otkl->host); // free
-		if(otkl->raisin) free(otkl->raisin); // em
-		if(otkl->setby) free(otkl->setby); // all
-		free(otkl); // lol
-		otkl = NULL; // Just in case imo
+void free_otkline(OTKLine *otkline) {
+	if(otkline) {
+		safe_free(otkline->user); // Gotta
+		safe_free(otkline->host); // free
+		safe_free(otkline->raisin); // em
+		safe_free(otkline->setby); // all
+		safe_free(otkline); // lol
+		otkline = NULL; // Just in case imo
 	}
 }
 
-OTKLine *get_otklines(void) {
-	OTKLine *OTKList = moddata_client((&me), otklMDI).ptr; // Get mod data
-	if(OTKList && OTKList->user) // Sanity check lol
-		return OTKList;
-	return NULL;
-}
-
-int otkl_main(aClient *cptr, aClient *sptr, int parc, char *parv[], char flag) {
-	/* Gets args from CMD_FUNC: aClient *cptr, aClient *sptr, int parc, char *parv[], char flag
-	**
-	** cptr: Pointer to directly attached client -- if remote user this is the remote server instead
-	** sptr: Pointer to user executing command
-	** parc: Amount of arguments (also includes the command in the count)
-	** parv: Contains the actual args, first one starts at parv[1]
-	** flag: 'G' or 'Z' to distinguish between host or IP based shit =]
-	**
-	** So "OGLINE test" would result in parc = 2 and parv[1] = "test"
-	** Also, parv[0] seems to always be NULL, so better not rely on it fam
-	*/
+void otkl_main(Client *client, int parc, char *parv[], char flag) {
 	char *otxt; // Get command name =]
 	char *mask, *usermask, *hostmask; // Some mask pointers yo
 	char prevmask[USERLEN + HOSTLEN + 1]; // When replacing, show the old one in the notice lel
@@ -331,60 +325,63 @@ int otkl_main(aClient *cptr, aClient *sptr, int parc, char *parv[], char flag) {
 	char *lineby; // When deleted by someone else =]
 	char *setby; // Set by who (just a nick imo tbh)
 	char *raisin; // Cleaned reason (like no colours and shit)
-	TS setat; // UNIX time
-	char gmt[256]; // For a pretty timestamp instead of UNIX time lol
-	char *timeret; // Ditto
+	time_t setat; // UNIX time
+	char gmt[128]; // For a pretty timestamp instead of UNIX time lol
 	int del; // In case it's -id@host shit
 	int repl; // Or replacing one
-	OTKLine *otkl; // To check for existing OTKLines yo
+	OTKLine *otkline; // To check for existing OTKLines yo
 	OTKLine *newotkl; // For adding one =]
 	OTKLine *OTKList; // For listing that shit
-	aClient *acptr; // The mask may also be a nick, so let's store the user pointer for it =]
-	aClient *victim, *vnext; // Iterate online users to see if we need to kill any ;];]
-	int flushem; // If the killed person happens to be the user doing /OGLINE etc =]
+	Client *acptr; // The mask may also be a nick, so let's store the user pointer for it =]
+	Client *victim, *vnext; // Iterate online users to see if we need to kill any ;];]
 	int i; // Iter8or for reason concaten8ion m8 =]
 	int c; // To send a notice bout not having ne OTKLines
-	int locuser; // Is local user? (to store result of (IsPerson(sptr) && MyClient(sptr)) lol
+	int locuser; // Is local user (to store result of MyUser(client) lol)
+
+	if(IsServer(client) && parc < 6)
+		return;
 
 	otxt = (flag == 'Z' ? MSG_OZLINE : MSG_OGLINE);
-	locuser = (IsPerson(sptr) && MyClient(sptr));
+	locuser = (MyUser(client));
+
 	// Servers can always use it (in order to sync that shit lol)
-	if(IsPerson(sptr) && (!IsOper(sptr) || !ValidatePermissionsForPath("otkl", sptr, NULL, NULL, NULL))) {
+	if(IsUser(client) && (!IsOper(client) || !ValidatePermissionsForPath("otkl", client, NULL, NULL, NULL))) {
 		if(locuser) // We allow remote clients as part of a hack, so only print errors for l0qal users for een bit ;]
-			sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, otxt);
-		return -1;
+			sendnumeric(client, ERR_NOPRIVILEGES); // Check ur privilege fam
+		return;
 	}
 
 	if(!strchr("GZ", flag)) { // Should't happen tho tbh
 		if(locuser) // A bunch of shit is silent for servers and rem0te users =]
-			sendnotice(sptr, "*** [otkl] Invalid OTKL type '%c'", flag);
-		return -1;
+			sendnotice(client, "*** Invalid OTKL type '%c'", flag);
+		return;
 	}
 
 	c = 0;
 	if(BadPtr(parv[1])) { // If first argument is a bad pointer, dump known OTKLines of this type instead
 		if(locuser) { // Only shit out the list if we're talking to a local user here
 			if((OTKList = get_otklines())) { // We gottem list?
-				for(otkl = OTKList; otkl; otkl = otkl->next) { // Checkem
-					if(otkl->flag != flag) // Can only one of the types we carry
+				for(otkline = OTKList; otkline; otkline = otkline->next) { // Checkem
+					if(otkline->flag != flag) // Can only one of the types we carry
 						continue;
-					timeret = asctime(gmtime((TS *)&otkl->setat)); // Make pwetti~~ timestamp imo
-					strlcpy(gmt, timeret, sizeof(gmt));
-					iCstrip(gmt);
-					sendnotice(sptr, "*** [otkl] %s set by %s at %s GMT for %s@%s [%s]", otxt, otkl->setby, gmt, otkl->user, otkl->host, otkl->raisin);
+					// Make pwetti~~ timestamp imo
+					*gmt = '\0';
+					short_date(otkline->setat, gmt);
+					sendnotice(client, "*** %s by %s (set at %s GMT) for %s@%s [reason: %s]", otxt, otkline->setby, gmt, otkline->user, otkline->host, otkline->raisin);
 					c++; // For the if below, required for if OGLINE list is empty but OZLINE isn't etc
 				}
 			}
 			if(!c)
-				sendnotice(sptr, "*** [otkl] No %sS found", otxt);
+				sendnotice(client, "*** No %sS found", otxt);
 		}
-		return 0;
+		return;
 	}
 
-	if(!stricmp(parv[1], "help") || !stricmp(parv[1], "halp")) { // If first argument is "halp" or "help"
-		if(!locuser || IsServer(sptr)) // El silenci0
-			return 0;
-		return dumpit(sptr, muhHalp); // Return halp string for l0cal users only rly =]
+	if(!strcasecmp(parv[1], "help") || !strcasecmp(parv[1], "halp")) { // If first argument is "halp" or "help"
+		if(!locuser || IsServer(client)) // El silenci0
+			return;
+		dumpit(client, muhHalp); // Return halp string for l0cal users only rly =]
+		return;
 	}
 
 	// Initialise some shit here =]
@@ -392,14 +389,14 @@ int otkl_main(aClient *cptr, aClient *sptr, int parc, char *parv[], char flag) {
 	usermask = NULL;
 	hostmask = NULL;
 	p = NULL;
-	lineby = sptr->name;
-	setby = sptr->name;
+	lineby = client->name;
+	setby = client->name;
 	raisin = NULL;
-	flushem = 0;
+	setat = 0;
 	repl = 0;
 	acptr = NULL;
 
-	if(IsServer(sptr)) { // It's a lil' different for servers yo
+	if(IsServer(client)) {
 		setat = atol(parv[2]);
 		setby = parv[3];
 		lineby = parv[4];
@@ -409,56 +406,53 @@ int otkl_main(aClient *cptr, aClient *sptr, int parc, char *parv[], char flag) {
 	if((del = (*mask == '-')) || *mask == '+') // Check for +hue@hue and -hue@hue etc
 		mask++; // Skip that shit
 
-	if(IsServer(sptr) && parc < 6) // If not enough args from a server
-		return -1; // Drop silently
-
 	// Check for the sanity of the passed mask
-	// Ripped from src/modules/m_tkl.c with some edits =]
+	// Ripped from src/modules/tkl.c with some edits =]
 	if(strchr(mask, '!')) {
 		if(locuser)
-			sendnotice(sptr, "*** [otkl] The mask should be either a nick or of the format ident@host");
-		return -1;
+			sendnotice(client, "*** The mask should be either a nick or of the format ident@host");
+		return;
 	}
 	if(*mask == ':') {
 		if(locuser)
-			sendnotice(sptr, "*** [otkl] Masks cannot start with a ':'");
-		return -1;
+			sendnotice(client, "*** Masks cannot start with a ':'");
+		return;
 	}
 	if(strchr(mask, ' ')) // Found a space in the mask, that should be impossibru ;];]
-		return -1;
+		return;
 
 	// Check if it's a hostmask and legal
 	p = strchr(mask, '@');
 	if(p) {
 		if((p == mask) || !p[1]) {
 			if(locuser)
-				sendnotice(sptr, "*** [otkl] No user@host mask specified");
-			return 0;
+				sendnotice(client, "*** No (valid) user@host mask specified");
+			return;
 		}
 		usermask = strtok(mask, "@");
 		hostmask = strtok(NULL, "");
 		if(BadPtr(hostmask)) {
 			if(BadPtr(usermask))
-				return 0;
+				return;
 			hostmask = usermask;
 			usermask = "*";
 		}
 		if(*hostmask == ':') {
 			if(locuser)
-				sendnotice(sptr, "*** [otkl] For (weird) technical reasons you cannot start the host with a ':'");
-			return 0;
+				sendnotice(client, "*** For (weird) technical reasons you cannot start the host with a ':'");
+			return;
 		}
 		else if(strchr(hostmask, '/')) {
 			if(locuser)
-				sendnotice(sptr, "*** [otkl] CIDR notation for hostmasks is not supported"); // Cbf
-			return 0;
+				sendnotice(client, "*** CIDR notation for hostmasks is not supported"); // Cbf
+			return;
 		}
 		if(flag == 'Z' && !del) {
 			for(p = hostmask; *p; p++) {
 				if(isalpha(*p) && !isxdigit(*p)) {
 					if(locuser)
-						sendnotice(sptr, "*** [otkl] (G)Z:Lines must be placed at ident@\037IPMASK\037, not ident@\037HOSTMASK\037");
-					return -1;
+						sendnotice(client, "*** O(G)Z-Lines must be placed at ident@\037IPMASK\037, not ident@\037HOSTMASK\037");
+					return;
 				}
 			}
 		}
@@ -466,35 +460,34 @@ int otkl_main(aClient *cptr, aClient *sptr, int parc, char *parv[], char flag) {
 	}
 	else { // Might be a nick
 		if((acptr = find_person(mask, NULL))) { // Try to find the user
-			if(!(usermask = moddata_client(acptr, otklIdentMDI).ptr))
+			if(!(usermask = moddata_local_client(acptr, otklIdentMDI).ptr))
 				usermask = (acptr->user->username ? acptr->user->username : "*"); // Let's set an ident@host/ip ban lel
 
 			if(flag == 'Z') { // We got OZLINE
 				hostmask = GetIP(acptr); // So gettem IP lol
 				if(!hostmask) {
 					if(locuser)
-						sendnotice(sptr, "*** [otkl] Could not get IP for user '%s'", acptr->name);
-					return 0;
+						sendnotice(client, "*** Could not get IP for user '%s'", acptr->name);
+					return;
 				}
 			}
-			else {
+			else
 				hostmask = acptr->user->realhost; // Get _real_ hostname (not masked/cloaked)
-			}
 			p = hostmask - 1;
 		}
 		else { // No such nick found lel
 			if(locuser)
-				sendto_one(sptr, rpl_str(ERR_NOSUCHNICK), me.name, sptr->name, mask);
-			return 0;
+				sendnumeric(client, ERR_NOSUCHNICK, mask);
+			return;
 		}
 	}
 	if(!del && ban_too_broad(usermask, hostmask)) { // If we adding but the ban is too broad
 		if(locuser)
-			sendnotice(sptr, "*** [otkl] Too broad mask");
-		return 0;
+			sendnotice(client, "*** Too broad mask");
+		return;
 	}
 
-	if(IsPerson(sptr) && !del) { // If a user is adding an OTKLine, we need to concat the reason params =]
+	if(IsUser(client) && !del) { // If a user is adding an OTKLine, we need to concat the reason params =]
 		setat = TStime(); // Get the "setat" time only here for accuracy etc
 		if(!BadPtr(parv[2])) {
 			char rbuf[256]; // Reason buffer, 256 shud b enough xd
@@ -515,159 +508,150 @@ int otkl_main(aClient *cptr, aClient *sptr, int parc, char *parv[], char flag) {
 		raisin = DEF_NORAISIN;
 
 	// Mite need2fow0d the OTKLine to another server (like if the id@ho mask is an online remote nickname instead)
-	if(acptr && !MyClient(acptr)) {
+	if(acptr && !MyUser(acptr)) {
 		// Forward as the user lol (the receiving server will re-parse and rebroadcast em proper OTKLine)
-		sendto_one(acptr->from, ":%s %s %s%s :%s", sptr->name, otxt, (del ? "-" : ""), acptr->name, raisin); // Muh raw command
-		return 0; // We done for nao
+		sendto_one(acptr->direction, NULL, ":%s %s %s%s :%s", client->name, otxt, (del ? "-" : ""), acptr->name, raisin); // Muh raw command
+		return; // We done for nao
 	}
 
 	// After all the sanity checks, see if we have an OTKLine alredy
-	otkl = find_otkline(usermask, hostmask, flag); // Attempt to find that shit
-	if(del && !otkl) { // See if the OTKLine even exists when deleting
-		if(IsPerson(sptr))
-			sendnotice(sptr, "*** [otkl] %s for %s@%s was not found", otxt, usermask, hostmask);
-		return 0; // We done
+	otkline = find_otkline(usermask, hostmask, flag); // Attempt to find that shit
+	if(del && !otkline) { // See if the OTKLine even exists when deleting
+		if(IsUser(client))
+			sendnotice(client, "*** %s for %s@%s was not found", otxt, usermask, hostmask);
+		return; // We done
 	}
-	else if(!del && otkl) { // Adding, but already exists kek
-		snprintf(prevmask, sizeof(prevmask), "%s@%s", otkl->user, otkl->host);
+	else if(!del && otkline) { // Adding, but already exists kek
+		ircsnprintf(prevmask, sizeof(prevmask), "%s@%s", otkline->user, otkline->host);
 
-		if(stricmp(otkl->user, usermask)) {
-			free(otkl->user);
-			otkl->user = strdup(usermask);
+		if(strcasecmp(otkline->user, usermask)) {
+			safe_strdup(otkline->user, usermask);
 			repl = 1;
 		}
 
-		if(stricmp(otkl->host, hostmask)) {
-			free(otkl->host);
-			otkl->host = strdup(hostmask);
+		if(strcasecmp(otkline->host, hostmask)) {
+			safe_strdup(otkline->host, hostmask);
 			repl = 1;
 		}
 
-		if(stricmp(otkl->raisin, raisin)) {
-			free(otkl->raisin);
-			otkl->raisin = strdup(raisin);
+		if(strcasecmp(otkline->raisin, raisin)) {
+			safe_strdup(otkline->raisin, raisin);
 			repl = 1;
 		}
 
-		if(IsPerson(sptr))
-			sendnotice(sptr, "*** [otkl] Matching %s for %s@%s already exists%s", otxt, usermask, hostmask, (repl ? ", replacing it" : " (no change detected)"));
+		if(IsUser(client))
+			sendnotice(client, "*** Matching %s for %s@%s already exists%s", otxt, usermask, hostmask, (repl ? ", replacing it" : " (no change detected)"));
 
 		if(!repl)
-			return 0; // We done
+			return; // We done
 
-		if(stricmp(otkl->setby, setby)) {
-			free(otkl->setby);
-			otkl->setby = strdup(setby);
+		if(strcasecmp(otkline->setby, setby)) {
+			free(otkline->setby);
+			safe_strdup(otkline->setby, setby);
 		}
-		otkl->setat = setat;
+		otkline->setat = setat;
 	}
-	else if(!del && !otkl) { // Adding a new one
+	else if(!del && !otkline) { // Adding a new one
 		// Es fer b0th servers and users ;]
 		// Allocate/initialise mem0ry for the new entry
-		newotkl = malloc(sizeof(OTKLine));
+		newotkl = safe_alloc(sizeof(OTKLine));
 		newotkl->flag = flag; // Set flag ('G', 'Z')
-		newotkl->user = strdup(usermask); // Gotta
-		newotkl->host = strdup(hostmask); // dup
-		newotkl->raisin = strdup(raisin); // 'em
-		newotkl->setby = strdup(setby); // all
+		safe_strdup(newotkl->user, usermask); // Gotta
+		safe_strdup(newotkl->host, hostmask); // dup
+		safe_strdup(newotkl->raisin, raisin); // 'em
+		safe_strdup(newotkl->setby, setby); // all
 		newotkl->setat = setat; // Set timestampus
 		add_otkline(newotkl); // Add to the linked list
-		otkl = newotkl; // Set the main iteration pointer to the new entry ;]
+		otkline = newotkl; // Set the main iteration pointer to the new entry ;]
 	}
 
-	// Propagate the OTKLine to other servers fam (excluding the direction it came from ;])
-	sendto_server((IsPerson(sptr) ? &me : sptr->from), 0, 0, ":%s %s %s%s@%s %ld %s %s :%s", me.name, otxt, (del ? "-" : ""), otkl->user, otkl->host, otkl->setat, otkl->setby, lineby, otkl->raisin);
+	// Propagate the M-Line to other local servers fam (excluding the direction it came from ;])
+	sendto_server(client, 0, 0, NULL, ":%s %s %s%s@%s %ld %s %s :%s", me.id, otxt, (del ? "-" : ""), otkline->user, otkline->host, otkline->setat, otkline->setby, lineby, otkline->raisin);
 
 	// Also send snomask notices to all local opers =]
 	// Make pretty setat timestamp first tho
-	timeret = asctime(gmtime((TS *)&otkl->setat));
-	strlcpy(gmt, timeret, sizeof(gmt));
-	iCstrip(gmt);
+	*gmt = '\0';
+	short_date(otkline->setat, gmt);
 
-	if(del && *lineby == '*' && IsServer(sptr)) // This condition is true if someone reconnects and hits an OTKLine on a diff server
-		sendto_snomask(SNO_TKL, "*** %s set by %s at %s GMT for %s@%s was matched, so removing it now [%s]", otxt, otkl->setby, gmt, otkl->user, otkl->host, otkl->raisin);
+	if(del && *lineby == '*' && IsServer(client)) // This condition is true if someone reconnects and hits an OTKLine on a diff server
+		sendto_snomask(SNO_TKL, "*** %s by %s (set at %s GMT) for %s@%s was matched, so removing it now [reason: %s]", otxt, otkline->setby, gmt, otkline->user, otkline->host, otkline->raisin);
 	else if(repl)
-		sendto_snomask(SNO_TKL, "*** %s replaced %s for %s with %s@%s [%s]", (*lineby == '*' ? otkl->setby : lineby), otxt, prevmask, otkl->user, otkl->host, otkl->raisin);
+		sendto_snomask(SNO_TKL, "*** %s replaced %s for %s with %s@%s [reason: %s]", (*lineby == '*' ? otkline->setby : lineby), otxt, prevmask, otkline->user, otkline->host, otkline->raisin);
 	else
-		sendto_snomask(SNO_TKL, "*** %s %sed by %s (set at %s GMT) for %s@%s [%s]", otxt, (del ? "delet" : "add"), (*lineby == '*' ? otkl->setby : lineby), gmt, otkl->user, otkl->host, otkl->raisin);
+		sendto_snomask(SNO_TKL, "*** %s %sed by %s (set at %s GMT) for %s@%s [reason: %s]", otxt, (del ? "delet" : "add"), (*lineby == '*' ? otkline->setby : lineby), gmt, otkline->user, otkline->host, otkline->raisin);
 
 	if(del) // Delete em famamlamlamlmal
-		del_otkline(otkl);
+		del_otkline(otkline);
 	else {
 		// Let's kill online (local) users that match this OTKLine =]
 		list_for_each_entry_safe(victim, vnext, &lclient_list, lclient_node) { // Iterate over all local users
-			if(!victim || !MyClient(victim) || !IsPerson(victim) || IsULine(victim)) // Just some sanity checks imo
+			if(!victim || !MyUser(victim) || !IsUser(victim) || IsULine(victim)) // Just some sanity checks imo
 				continue;
 
-			if(match_otkline(victim, otkl, flag)) { // Check if victim's user@host matches the OTKLine
-				char banmsg[BUFSIZE]; // Let's construct an exit message similar to G:Lines etc =]
-				ircsnprintf(banmsg, sizeof(banmsg), "User has been permanently banned from %s (%s)", ircnetwork, otkl->raisin);
-				if(victim == sptr) // Have to check for the user executing the command to return a proper value in the end
-					flushem = FLUSH_BUFFER; // Otherwise it's rip IRCd
-				exit_client(victim, victim, victim, banmsg); // Exit the client y0 =]
+			if(match_otkline(victim, otkline, flag)) { // Check if victim's user@host matches the OTKLine
+				char banmsg[BUFSIZE]; // Let's construct an exit message similar to G-Lines etc =]
+				ircsnprintf(banmsg, sizeof(banmsg), "User has been permanently banned from %s (%s)", ircnetwork, otkline->raisin);
+				exit_client(victim, NULL, banmsg); // Exit the client y0 =]
 			}
 		}
 	}
-
-	return flushem; // All good
 }
 
-int otkl_hook_serverconnect(aClient *sptr) {
+int otkl_hook_serverconnect(Client *client) {
 	// Sync OTKLines fam =]
-	OTKLine *OTKList, *otkl; // Head and iter8or ;];]
+	OTKLine *OTKList, *otkline; // Head and iter8or ;];]
 	char *otxt; // Get text OGLINE for 'G' etc
 	if((OTKList = get_otklines())) { // Gettem list
-		for(otkl = OTKList; otkl; otkl = otkl->next) {
-			if(!otkl || !otkl->user) // Sanity check imo ;]
+		for(otkline = OTKList; otkline; otkline = otkline->next) {
+			if(!otkline || !otkline->user) // Sanity check imo ;]
 				continue;
-			otxt = (otkl->flag == 'Z' ? MSG_OZLINE : MSG_OGLINE);
+			otxt = (otkline->flag == 'Z' ? MSG_OZLINE : MSG_OGLINE);
 			// Syntax for servers is a bit different (namely the setat/by args and the : before reason (makes the entire string after be considered one arg ;];])
-			sendto_one(sptr, ":%s %s %s@%s %ld %s * :%s", me.name, otxt, otkl->user, otkl->host, otkl->setat, otkl->setby, otkl->raisin); // Muh raw command
+			sendto_one(client, NULL, ":%s %s %s@%s %ld %s * :%s", me.id, otxt, otkline->user, otkline->host, otkline->setat, otkline->setby, otkline->raisin); // Muh raw command
 		}
 	}
 	return HOOK_CONTINUE;
 }
 
-int otkl_hook_pre_localconnect(aClient *sptr) {
-	OTKLine *OTKList, *otkl; // Head and iter8or fam
-	int flushem = 0; // May need to pass on FLUSH_BUFFER
+int otkl_hook_pre_localconnect(Client *client) {
+	OTKLine *OTKList, *otkline; // Head and iter8or fam
+	int banned = 0;
 	char *otxt; // Get text OGLINE from 'G' etc
-	char *timeret; // Ditto
+	char gmt[128];
 
 	if((OTKList = get_otklines())) { // Check if the list even has entries kek
-		for(otkl = OTKList; otkl; otkl = otkl->next) { // Iter8 em
-			if(match_otkline(sptr, otkl, otkl->flag)) { // If connecting user matches the OTKLine
+		for(otkline = OTKList; otkline; otkline = otkline->next) { // Iter8 em
+			if(match_otkline(client, otkline, otkline->flag)) { // If connecting user matches the OTKLine
 				char banmsg[BUFSIZE]; // Construct the same ban message
-				ircsnprintf(banmsg, sizeof(banmsg), "User has been permanently banned from %s (%s)", ircnetwork, otkl->raisin);
-				otxt = (otkl->flag == 'Z' ? MSG_OZLINE : MSG_OGLINE);
-				flushem = exit_client(sptr, sptr, sptr, banmsg); // And kill them =]
+				ircsnprintf(banmsg, sizeof(banmsg), "User has been permanently banned from %s (%s)", ircnetwork, otkline->raisin);
+				otxt = (otkline->flag == 'Z' ? MSG_OZLINE : MSG_OGLINE);
+				exit_client(client, NULL, banmsg); // And kill them =]
+				banned = 1;
 				break; // No need to check any further
 			}
 		}
 	}
 
-	if(flushem && otkl) { // We gottem match =]
-		char gmt[256]; // Make pretty timestamp yet again =3
-		timeret = asctime(gmtime((TS *)&otkl->setat));
-		strlcpy(gmt, timeret, sizeof(gmt));
-		iCstrip(gmt);
+	if(banned) { // We gottem match =]
+		// Make pretty timestamp yet again =3
+		*gmt = '\0';
+		short_date(otkline->setat, gmt);
 
 		// Notify other servers to delete their copy of the OTKLine, who in turn will also notify their local opers
-		sendto_server(&me, 0, 0, ":%s %s -%s@%s %ld %s * :%s", me.name, otxt, otkl->user, otkl->host, otkl->setat, otkl->setby, otkl->raisin); // Muh raw command
+		sendto_server(NULL, 0, 0, NULL, ":%s %s -%s@%s %ld %s * :%s", me.id, otxt, otkline->user, otkline->host, otkline->setat, otkline->setby, otkline->raisin); // Muh raw command
 
 		// And notify online (local) opers about the hit
-		sendto_snomask(SNO_TKL, "*** %s set by %s at %s GMT for %s@%s was matched, so removing it now [%s]", otxt, otkl->setby, gmt, otkl->user, otkl->host, otkl->raisin);
+		sendto_snomask(SNO_TKL, "*** %s by %s (set at %s GMT) for %s@%s was matched, so removing it now [reason: %s]", otxt, otkline->setby, gmt, otkline->user, otkline->host, otkline->raisin);
 
-		del_otkline(otkl); // Then actually remove it from the list
-	}
-	else { // No match, git dat ident fam ;];]
-		moddata_client(sptr, otklIdentMDI).ptr = strdup(sptr->user->username); // Dup that shit
+		del_otkline(otkline); // Then actually remove it from the list
 	}
+	else // No match, git dat ident fam ;];]
+		moddata_local_client(client, otklIdentMDI).ptr = strdup(client->user->username);
 
-	return flushem; // Need to pass FLUSH_BUFFER along cuz inb4rip IRC
+	return (banned ? HOOK_DENY : HOOK_CONTINUE);
 }
 
-// Ripped from src/modules/m_tkl.c with some edits =]
+// Ripped from src/modules/tkl.c with some edits =]
 int ban_too_broad(char *usermask, char *hostmask) {
 	char *p;
 	int cnt = 0;

+ 41 - 34
malv/reportlol.c

@@ -1,7 +1,23 @@
 /* Copyright (C) All Rights Reserved
 ** Written by Gottem <support@gottem.nl>
-** Website: https://gitgud.malvager.net/Wazakindjes/unrealircd_mods
-** License: https://gitgud.malvager.net/Wazakindjes/unrealircd_mods/raw/master/LICENSE
+** Website: https://gottem.nl/unreal
+** License: https://gottem.nl/unreal/license
+*/
+
+/*** <<<MODULE MANAGER START>>>
+module {
+	documentation "https://gottem.nl/unreal/man/reportlol";
+	troubleshooting "In case of problems, check the FAQ at https://gottem.nl/unreal/halp or e-mail me at support@gottem.nl";
+	min-unrealircd-version "5.*";
+	//max-unrealircd-version "5.*";
+	post-install-text {
+		"The module is installed, now all you need to do is add a 'loadmodule' line to your config file:";
+		"loadmodule \"third/reportlol\";";
+		"Then /rehash the IRCd.";
+		"For usage information, refer to the module's documentation found at: https://gottem.nl/unreal/man/reportlol";
+	}
+}
+*** <<<MODULE MANAGER END>>>
 */
 
 // One include for all cross-platform compatibility thangs
@@ -11,55 +27,46 @@
 #define MSG_REPORT "REPORT"
 
 // Dem macros yo
-CMD_FUNC(m_reportlol); // Register command function
+CMD_FUNC(reportlol); // Register command function
 
-// Muh globals
-static ModuleInfo *reportlolMI = NULL; // Store ModuleInfo so we can use it to check for errors in MOD_LOAD
-Command *reportlolCmd; // Pointer(s) to the command(s) we're gonna add
+#define CheckAPIError(apistr, apiobj) \
+	do { \
+		if(!(apiobj)) { \
+			config_error("A critical error occurred on %s for %s: %s", (apistr), MOD_HEADER.name, ModuleGetErrorStr(modinfo->handle)); \
+			return MOD_FAILED; \
+		} \
+	} while(0)
 
 // Dat dere module header
-ModuleHeader MOD_HEADER(m_reportlol) = {
-	"m_reportlol", // Module name
-	"$Id: v1.0 2018/09/24 Gottem$", // Version
+ModuleHeader MOD_HEADER = {
+	"third/reportlol", // Module name
+	"2.0", // Version
 	"Dankass /report command lol", // Description
-	"3.2-b8-1", // Modversion, not sure wat do
-	NULL
+	"Gottem", // Author
+	"unrealircd-5", // Modversion
 };
 
 // Initialisation routine (register hooks, commands and modes or create structs etc)
-MOD_INIT(m_reportlol) {
-	// If command already exists for some reason, bail out
-	if(CommandExists(MSG_REPORT)) {
-		config_error("Command %s already exists", MSG_REPORT);
-		return MOD_FAILED;
-	}
+MOD_INIT() {
+	CheckAPIError("CommandAdd(REPORT)", CommandAdd(modinfo->handle, MSG_REPORT, reportlol, 1, CMD_USER));
 
-	reportlolCmd = CommandAdd(modinfo->handle, MSG_REPORT, m_reportlol, MAXPARA, M_USER);
-	reportlolMI = modinfo; // Store module info yo
-	return MOD_SUCCESS; // Let MOD_LOAD handle errors
+	MARK_AS_GLOBAL_MODULE(modinfo);
+	return MOD_SUCCESS;
 }
 
 // Actually load the module here (also command overrides as they may not exist in MOD_INIT yet)
-MOD_LOAD(m_reportlol) {
-	// Did the module throw an error during initialisation, or is reportlolCmd null even?
-	if(ModuleGetError(reportlolMI->handle) != MODERR_NOERROR || !reportlolCmd) {
-		// Display error string kek
-		config_error("A critical error occurred when loading module %s: %s", MOD_HEADER(m_reportlol).name, ModuleGetErrorStr(reportlolMI->handle));
-		return MOD_FAILED; // No good
-	}
-
+MOD_LOAD() {
 	return MOD_SUCCESS; // We good
 }
 
 // Called on unload/rehash obv
-MOD_UNLOAD(m_reportlol) {
+MOD_UNLOAD() {
 	// Clean up any structs and other shit
 	return MOD_SUCCESS; // We good
 }
 
-CMD_FUNC(m_reportlol) {
-	if(!IsPerson(sptr) || BadPtr(parv[1])) // Need at least 1 word kek
-		return 0; // We good
-	sendnotice(sptr, "ayyy ur report will not be read so may as well kys lol");
-	return 0;
+CMD_FUNC(reportlol) {
+	if(!IsUser(client) || BadPtr(parv[1])) // Need at least 1 word kek
+		return; // We good
+	sendnotice(client, "ayyy ur report will not be read so may as well kys lol");
 }

+ 53 - 49
malv/sajoin_chan.c

@@ -1,7 +1,23 @@
 /* Copyright (C) All Rights Reserved
 ** Written by Gottem <support@gottem.nl>
-** Website: https://gitgud.malvager.net/Wazakindjes/unrealircd_mods
-** License: https://gitgud.malvager.net/Wazakindjes/unrealircd_mods/raw/master/LICENSE
+** Website: https://gottem.nl/unreal
+** License: https://gottem.nl/unreal/license
+*/
+
+/*** <<<MODULE MANAGER START>>>
+module {
+	documentation "https://gottem.nl/unreal/man/sajoin_chan";
+	troubleshooting "In case of problems, check the FAQ at https://gottem.nl/unreal/halp or e-mail me at support@gottem.nl";
+	min-unrealircd-version "5.*";
+	//max-unrealircd-version "5.*";
+	post-install-text {
+		"The module is installed, now all you need to do is add a 'loadmodule' line to your config file:";
+		"loadmodule \"third/sajoin_chan\";";
+		"Then /rehash the IRCd.";
+		"For usage information, refer to the module's documentation found at: https://gottem.nl/unreal/man/sajoin_chan";
+	}
+}
+*** <<<MODULE MANAGER END>>>
 */
 
 // One include for all cross-platform compatibility thangs
@@ -10,79 +26,67 @@
 // Commands to override
 #define OVR_SAJOIN "SAJOIN"
 
-// Quality fowod declarations
-static int sajoin_chan_override(Cmdoverride *ovr, aClient *cptr, aClient *sptr, int parc, char *parv[]);
+#define CheckAPIError(apistr, apiobj) \
+	do { \
+		if(!(apiobj)) { \
+			config_error("A critical error occurred on %s for %s: %s", (apistr), MOD_HEADER.name, ModuleGetErrorStr(modinfo->handle)); \
+			return MOD_FAILED; \
+		} \
+	} while(0)
 
-// Muh globals
-static ModuleInfo *sajoin_chanMI = NULL; // Store ModuleInfo so we can use it to check for errors in MOD_LOAD
-Cmdoverride *sajoin_chanOVR; // Pointer to the override we're gonna add
+// Quality fowod declarations
+CMD_OVERRIDE_FUNC(sajoin_chan_override);
 
 // Dat dere module header
-ModuleHeader MOD_HEADER(m_sajoin_chan) = {
-	"m_sajoin_chan", // Module name
-	"$Id: v1.0 2017/06/17 Gottem$", // Version
+ModuleHeader MOD_HEADER = {
+	"third/sajoin_chan", // Module name
+	"2.0", // Version
 	"Sajoin entire channels into another =]]", // Description
-	"3.2-b8-1", // Modversion, not sure wat do
-	NULL
+	"Gottem", // Author
+	"unrealircd-5", // Modversion
 };
 
 // Initialisation routine (register hooks, commands and modes or create structs etc)
-MOD_INIT(m_sajoin_chan) {
-	sajoin_chanMI = modinfo; // Store module info yo
-	return MOD_SUCCESS; // Let MOD_LOAD handle errors and registering of overrides
+MOD_INIT() {
+	MARK_AS_GLOBAL_MODULE(modinfo);
+	return MOD_SUCCESS;
 }
 
 // Actually load the module here (also command overrides as they may not exist in MOD_INIT yet)
-MOD_LOAD(m_sajoin_chan) {
-	sajoin_chanOVR = CmdoverrideAdd(sajoin_chanMI->handle, OVR_SAJOIN, sajoin_chan_override); // Attempt to add command override
-
-	// Did the module throw an error when adding override(s), or is one of the override pointers null even?
-	if(ModuleGetError(sajoin_chanMI->handle) != MODERR_NOERROR || !sajoin_chanOVR) {
-		// Display error string kek
-		config_error("A critical error occurred when loading module %s: %s", MOD_HEADER(m_sajoin_chan).name, ModuleGetErrorStr(sajoin_chanMI->handle));
-		return MOD_FAILED; // No good
-	}
-
+MOD_LOAD() {
+	CheckAPIError("CommandOverrideAdd(SAJOIN)", CommandOverrideAdd(modinfo->handle, OVR_SAJOIN, sajoin_chan_override));
 	return MOD_SUCCESS; // We good
 }
 
 // Called on unload/rehash obv
-MOD_UNLOAD(m_sajoin_chan) {
+MOD_UNLOAD() {
 	return MOD_SUCCESS; // We good
 }
 
 // Now for the actual override
-static int sajoin_chan_override(Cmdoverride *ovr, aClient *cptr, aClient *sptr, int parc, char *parv[]) {
-	/* Gets args: Cmdoverride *ovr, aClient *cptr, aClient *sptr, int parc, char *parv[]
-	**
-	** ovr: Pointer to the override we're attached to
-	** cptr: Pointer to directly attached client -- if remote user this is the remote server instead
-	** sptr: Pointer to user executing command
-	** parc: Amount of arguments (also includes the command in the count)
-	** parv: Contains the actual args, first one starts at parv[1]
-	**
-	** So "SAJOIN test" would result in parc = 2 and parv[1] = "test"
-	** Also, parv[0] seems to always be NULL, so better not rely on it fam
-	*/
+CMD_OVERRIDE_FUNC(sajoin_chan_override) {
+	// Gets args: CommandOverride *ovr, Client *client, MessageTag *recv_mtags, int parc, char *parv[]
 	char *victimchan;
 	char *targets;
-	aChannel *chptr; // Pointer for victim channel
-	aClient *acptr; // Client pointer from the victim channel
+	Channel *channel; // Pointer for victim channel
+	Client *acptr; // Client pointer from the victim channel
 	Member *member; // Channels work internally with "members" and "memberships" ;];]
 
-	if(BadPtr(parv[1]) || BadPtr(parv[2]) || parv[1][0] != '#' || !MyConnect(sptr) || !IsPerson(sptr) || !ValidatePermissionsForPath("sajoin", sptr, NULL, NULL, NULL))
-		return CallCmdoverride(ovr, cptr, sptr, parc, parv); // Run original function yo
+	if(BadPtr(parv[1]) || BadPtr(parv[2]) || parv[1][0] != '#' || !MyUser(client) || !ValidatePermissionsForPath("sajoin", client, NULL, NULL, NULL)) {
+		CallCommandOverride(ovr, client, recv_mtags, parc, parv); // Run original function yo
+		return;
+	}
 
 	victimchan = parv[1];
 	targets = parv[2];
 
-	if(!(chptr = find_channel(victimchan, NULL))) {
-		sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL), me.name, sptr->name, victimchan);
-		return 0;
+	if(!(channel = find_channel(victimchan, NULL))) {
+		sendnumeric(client, ERR_NOSUCHCHANNEL, victimchan);
+		return;
 	}
 
-	for(member = chptr->members; member; member = member->next) {
-		acptr = member->cptr;
+	for(member = channel->members; member; member = member->next) {
+		acptr = member->client;
 		if(IsULine(acptr)) // Let's skip these ;];]
 			continue;
 
@@ -92,8 +96,8 @@ static int sajoin_chan_override(Cmdoverride *ovr, aClient *cptr, aClient *sptr,
 		newparv[2] = targets;
 		newparv[3] = NULL;
 
-		int suppresshack = do_cmd(sptr, sptr, OVR_SAJOIN, 3, newparv);
+		do_cmd(client, NULL, OVR_SAJOIN, 3, newparv);
 	}
 
-	return 0; // Stop processing yo
+	return; // Stop processing yo
 }

+ 86 - 91
malv/saprivmsg.c

@@ -1,7 +1,23 @@
 /* Copyright (C) All Rights Reserved
 ** Written by Gottem <support@gottem.nl>
-** Website: https://gitgud.malvager.net/Wazakindjes/unrealircd_mods
-** License: https://gitgud.malvager.net/Wazakindjes/unrealircd_mods/raw/master/LICENSE
+** Website: https://gottem.nl/unreal
+** License: https://gottem.nl/unreal/license
+*/
+
+/*** <<<MODULE MANAGER START>>>
+module {
+	documentation "https://gottem.nl/unreal/man/saprivmsg";
+	troubleshooting "In case of problems, check the FAQ at https://gottem.nl/unreal/halp or e-mail me at support@gottem.nl";
+	min-unrealircd-version "5.*";
+	//max-unrealircd-version "5.*";
+	post-install-text {
+		"The module is installed, now all you need to do is add a 'loadmodule' line to your config file:";
+		"loadmodule \"third/saprivmsg\";";
+		"Then /rehash the IRCd.";
+		"For usage information, refer to the module's documentation found at: https://gottem.nl/unreal/man/saprivmsg";
+	}
+}
+*** <<<MODULE MANAGER END>>>
 */
 
 // One include for all cross-platform compatibility thangs
@@ -12,14 +28,18 @@
 #define MSG_SAPRIVMSG2 "SASAY"
 
 // Dem macros yo
-CMD_FUNC(m_saprivmsg); // Register command function
+CMD_FUNC(cmd_saprivmsg); // Register command function
 
-// Quality fowod declarations
-static int dumpit(aClient *sptr, char **p);
+#define CheckAPIError(apistr, apiobj) \
+	do { \
+		if(!(apiobj)) { \
+			config_error("A critical error occurred on %s for %s: %s", (apistr), MOD_HEADER.name, ModuleGetErrorStr(modinfo->handle)); \
+			return MOD_FAILED; \
+		} \
+	} while(0)
 
-// Muh globals
-static ModuleInfo *privmsgMI = NULL; // Store ModuleInfo so we can use it to check for errors in MOD_LOAD
-Command *saCmd, *saCmd2; // Pointers to the commands we're gonna add
+// Quality fowod declarations
+static void dumpit(Client *client, char **p);
 
 // Help string in case someone does just /SAPRIVMSG
 static char *halpstr[] = {
@@ -38,141 +58,118 @@ static char *halpstr[] = {
 };
 
 // Dat dere module header
-ModuleHeader MOD_HEADER(m_saprivmsg) = {
-	"m_saprivmsg", // Module name
-	"$Id: v1.12 2017/11/09 Gottem$", // Version
+ModuleHeader MOD_HEADER = {
+	"third/saprivmsg", // Module name
+	"2.0", // Version
 	"Similar to SAJOIN etc, but instead make people say shit", // Description
-	"3.2-b8-1", // Modversion, not sure wat do
-	NULL
+	"Gottem", // Author
+	"unrealircd-5", // Modversion
 };
 
 // Initialisation routine (register hooks, commands and modes or create structs etc)
-MOD_INIT(m_saprivmsg) {
-	// If command already exists for some reason, bail out
-	if(CommandExists(MSG_SAPRIVMSG)) {
-		config_error("Command %s already exists", MSG_SAPRIVMSG);
-		return MOD_FAILED;
-	}
-	if(CommandExists(MSG_SAPRIVMSG2)) {
-		config_error("Command %s already exists", MSG_SAPRIVMSG2);
-		return MOD_FAILED;
-	}
+MOD_INIT() {
+	CheckAPIError("CommandAdd(SAPRIVMSG)", CommandAdd(modinfo->handle, MSG_SAPRIVMSG, cmd_saprivmsg, MAXPARA, CMD_USER));
+	CheckAPIError("CommandAdd(SASAY)", CommandAdd(modinfo->handle, MSG_SAPRIVMSG2, cmd_saprivmsg, MAXPARA, CMD_USER));
 
-	saCmd = CommandAdd(modinfo->handle, MSG_SAPRIVMSG, m_saprivmsg, MAXPARA, M_USER);
-	saCmd2 = CommandAdd(modinfo->handle, MSG_SAPRIVMSG2, m_saprivmsg, MAXPARA, M_USER);
-	privmsgMI = modinfo; // Store module info yo
-	return MOD_SUCCESS; // Let MOD_LOAD handle errors
+	MARK_AS_GLOBAL_MODULE(modinfo);
+	return MOD_SUCCESS;
 }
 
 // Actually load the module here (also command overrides as they may not exist in MOD_INIT yet)
-MOD_LOAD(m_saprivmsg) {
-	// Did the module throw an error during initialisation, or is saCmd(2) null even?
-	if(ModuleGetError(privmsgMI->handle) != MODERR_NOERROR || !saCmd || !saCmd2) {
-		// Display error string kek
-		config_error("A critical error occurred when loading module %s: %s", MOD_HEADER(m_saprivmsg).name, ModuleGetErrorStr(privmsgMI->handle));
-		return MOD_FAILED; // No good
-	}
-
+MOD_LOAD() {
 	return MOD_SUCCESS; // We good
 }
 
 // Called on unload/rehash obv
-MOD_UNLOAD(m_saprivmsg) {
+MOD_UNLOAD() {
 	return MOD_SUCCESS; // We good
 }
 
-// Dump a NULL-terminated array of strings to user sptr using the numeric rplnum, and then return 0 (taken from DarkFire IRCd)
-static int dumpit(aClient *sptr, char **p) {
-	if(IsServer(sptr)) // Bail out early and silently if it's a server =]
-		return 0;
+// Dump a NULL-terminated array of strings to the user (taken from DarkFire IRCd)
+static void dumpit(Client *client, char **p) {
+	if(IsServer(client)) // Bail out early and silently if it's a server =]
+		return;
 
+	// Using sendto_one() instead of sendnumericfmt() because the latter strips indentation and stuff ;]
 	for(; *p != NULL; p++)
-		sendto_one(sptr, ":%s %03d %s :%s", me.name, RPL_TEXT, sptr->name, *p);
+		sendto_one(client, NULL, ":%s %03d %s :%s", me.name, RPL_TEXT, client->name, *p);
 
 	// Let user take 8 seconds to read it
-	sptr->local->since += 8;
-	return 0;
+	client->local->since += 8;
 }
 
-CMD_FUNC(m_saprivmsg) {
-	/* Gets args: aClient *cptr, aClient *sptr, int parc, char *parv[]
-	**
-	** cptr: Pointer to directly attached client -- if remote user this is the remote server instead
-	** sptr: Pointer to user executing command
-	** parc: Amount of arguments (also includes the command in the count)
-	** parv: Contains the actual args, first one starts at parv[1]
-	**
-	** So "SAPRIVMSG test" would result in parc = 2 and parv[1] = "test"
-	** Also, parv[0] seems to always be NULL, so better not rely on it fam
-	*/
+CMD_FUNC(cmd_saprivmsg) {
+	// Gets args: Client *client, MessageTag *recv_mtags, int parc, char *parv[]
 	char *msg; // We'll just let Unreal handle the limit for this one
 	char *target; // Get either the target channel or client's name for quikk axx
-	aClient *victim; // Client pointer for the "sayer"
-	aClient *acptr; // Muh target client
-	aChannel *chptr; // Muh target channel
-	Membership *lp; // Verify channel membership lol
+	Client *victim; // Client pointer for the "sayer"
+	Client *acptr; // Muh target client
+	Channel *channel; // Muh target channel
 	int i; // iter8or
 	size_t len; // Message length kek
 
-	if(!ValidatePermissionsForPath("saprivmsg", sptr, NULL, NULL, NULL)) {
-		sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, sptr->name); // lmao no privlelgdges
-		return -1; // No good
+	if(!ValidatePermissionsForPath("saprivmsg", client, NULL, NULL, NULL)) {
+		sendnumeric(client, ERR_NOPRIVILEGES); // Check ur privilege fam
+		return; // No good
 	}
 
-	if(BadPtr(parv[1])) // If first argument is a bad pointer, don't proceed and return halp instead
-		return dumpit(sptr, halpstr); // Return help string instead
+	if(BadPtr(parv[1])) { // If first argument is a bad pointer, don't proceed and return halp instead
+		dumpit(client, halpstr); // Return help string instead
+		return;
+	}
 
 	// Need more args lol
 	if(BadPtr(parv[2]) || BadPtr(parv[3]) || !strlen(parv[3])) {
-		sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, sptr->name, MSG_SAPRIVMSG); // Show "needs more parameters" error string
-		return -1; // "Critical" error
+		sendnumeric(client, ERR_NEEDMOREPARAMS, MSG_SAPRIVMSG); // Show "needs more parameters" error string
+		return; // "Critical" error
 	}
 
 	// Attempt to find da target chanul/nick
 	acptr = NULL;
-	chptr = NULL;
+	channel = NULL;
 	if(*parv[1] != '#') {
 		// Attempt to find da niqq
 		if(!(acptr = find_person(parv[1], NULL))) {
-			sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, sptr->name, parv[1]);
-			return -1; // Nope
+			sendnumeric(client, ERR_NOSUCHNICK, parv[1]);
+			return; // Nope
 		}
 		if(!IsULine(acptr)) {
-			sendnotice(sptr, "*** [%s] No can do, %s must be U:Lined", MSG_SAPRIVMSG, acptr->name);
-			return -1; // Nope
+			sendnotice(client, "*** [%s] No can do, target nick %s must be U-Lined", MSG_SAPRIVMSG, acptr->name);
+			return; // Nope
 		}
 	}
 	else {
-		if(!(chptr = find_channel(parv[1], NULL))) {
-			sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL), me.name, sptr->name, parv[1]);
-			return -1; // Nope
+		if(!(channel = find_channel(parv[1], NULL))) {
+			sendnumeric(client, ERR_NOSUCHCHANNEL, parv[1]);
+			return; // Nope
 		}
 	}
-	target = (chptr ? chptr->chname : acptr->name);
+	target = (channel ? channel->chname : acptr->name);
 
 	// Attempt to find da niqq
 	if(!(victim = find_person(parv[2], NULL))) {
-		sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, sptr->name, parv[2]);
-		return -1; // Nope
+		sendnumeric(client, ERR_NOSUCHNICK, parv[2]);
+		return; // Nope
 	}
 
-	// Disallow cab00sing of opers and ulines lol
+	// Disallow cab00sing of opers and U-Lines lol
 	if(IsOper(victim) || IsULine(victim)) {
-		sendnotice(sptr, "*** [%s] No can do, %s is U:Lined or an IRC oper", MSG_SAPRIVMSG, victim->name);
-		return -1; // Kbai
+		sendnotice(client, "*** [%s] No can do, victim nick %s is U-Lined or an IRC oper", MSG_SAPRIVMSG, victim->name);
+		return; // Kbai
 	}
 
 	// Victim on channel?
-	if(chptr && !(lp = find_membership_link(victim->user->channel, chptr))) {
-		sendto_one(sptr, err_str(ERR_USERNOTINCHANNEL), me.name, sptr->name, victim->name, chptr->chname);
-		return -1; // Nope
+	if(channel && !find_membership_link(victim->user->channel, channel)) {
+		sendnumeric(client, ERR_USERNOTINCHANNEL, victim->name, channel->chname);
+		return; // Nope
 	}
 
 	// Create one pointer from parv[] args kek
+	msg = NULL;
 	for(i = 3, len = 0; i < parc; i++) {
 		len += strlen(parv[i]);
 		if(i == 3) {
-			msg = malloc((len + 1) * sizeof(char));
+			msg = safe_alloc((len + 1) * sizeof(char));
 			strncpy(msg, parv[i], len);
 		}
 		else {
@@ -184,20 +181,18 @@ CMD_FUNC(m_saprivmsg) {
 	}
 
 	// If not our local client, pass it on to the "home server"
-	if(!MyConnect(victim)) {
-		sendto_one(victim->srvptr, ":%s %s %s %s %s", sptr->name, MSG_SAPRIVMSG, target, victim->name, msg);
-	}
+	if(!MyConnect(victim))
+		sendto_one(victim->srvptr, NULL, ":%s %s %s %s %s", client->name, MSG_SAPRIVMSG, target, victim->name, msg);
 
 	// Is een loqal client, proceed
 	else {
 		// Fix up parv[] array
 		parv[2] = msg; // Msg is just one arg due to a magic colon (PRIVMSG #chan :this is a message)
 		parv[3] = NULL; // Required
-		int suppresshack = do_cmd(victim, victim, "PRIVMSG", 3, parv); // Dirty shit cuz I cbf having warnings at all =]
-		sendto_one(victim, ":%s PRIVMSG %s :%s", victim->name, target, msg); // Send PRIVMSG back to target, required so they can see it too
-		sendto_snomask_global(SNO_EYES, "*** %s (%s@%s) used %s %s %s :%s", sptr->name, sptr->user->username, sptr->user->realhost, MSG_SAPRIVMSG, target, victim->name, msg);
+		do_cmd(victim, NULL, "PRIVMSG", 3, parv);
+		sendto_one(victim, NULL, ":%s PRIVMSG %s :%s", victim->name, target, msg); // Send PRIVMSG back to target, required so they can see it too
+		sendto_snomask_global(SNO_EYES, "*** %s (%s@%s) used %s %s %s :%s", client->name, client->user->username, client->user->realhost, MSG_SAPRIVMSG, target, victim->name, msg);
 	}
 
-	free(msg); // Ayyyy
-	return 0; // All good
+	safe_free(msg); // Ayyyy
 }

+ 53 - 45
spec/block_notlsident.c

@@ -1,73 +1,80 @@
 /* Copyright (C) All Rights Reserved
 ** Written by Gottem <support@gottem.nl>
-** Website: https://gitgud.malvager.net/Wazakindjes/unrealircd_mods
-** License: https://gitgud.malvager.net/Wazakindjes/unrealircd_mods/raw/master/LICENSE
+** Website: https://gottem.nl/unreal
+** License: https://gottem.nl/unreal/license
+*/
+
+/*** <<<MODULE MANAGER START>>>
+module {
+	documentation "https://gottem.nl/unreal/man/block_notlsident";
+	troubleshooting "In case of problems, check the FAQ at https://gottem.nl/unreal/halp or e-mail me at support@gottem.nl";
+	min-unrealircd-version "5.*";
+	//max-unrealircd-version "5.*";
+	post-install-text {
+		"The module is installed, now all you need to do is add a 'loadmodule' line to your config file:";
+		"loadmodule \"third/block_notlsident\";";
+		"Then /rehash the IRCd.";
+		"For usage information, refer to the module's documentation found at: https://gottem.nl/unreal/man/block_notlsident";
+	}
+}
+*** <<<MODULE MANAGER END>>>
 */
 
 // One include for all cross-platform compatibility thangs
 #include "unrealircd.h"
 
 // Config bl0ck
-#define MYCONF "block_nosslident"
+#define MYCONF "block_notlsident"
 
 // Quality fowod declarations
 int find_bident(char *ident);
-int block_nosslident_configtest(ConfigFile *cf, ConfigEntry *ce, int type, int *errs);
-int block_nosslident_configposttest(int *errs); // You may not need this
-int block_nosslident_configrun(ConfigFile *cf, ConfigEntry *ce, int type);
-int block_nosslident_prelocalconnect(aClient *sptr);
-
-// Muh globals
-static ModuleInfo *bnosIdentMI = NULL; // Store ModuleInfo so we can use it to check for errors in MOD_LOAD
+int block_notlsident_configtest(ConfigFile *cf, ConfigEntry *ce, int type, int *errs);
+int block_notlsident_configposttest(int *errs); // You may not need this
+int block_notlsident_configrun(ConfigFile *cf, ConfigEntry *ce, int type);
+int block_notlsident_prelocalconnect(Client *client);
 
 // Config vars
 char bicount = 0;
 char **blockedIdents; // Dynamic array ;]
 
 // Dat dere module header
-ModuleHeader MOD_HEADER(m_block_nosslident) = {
-	"m_block_nosslident", // Module name
-	"$Id: v1.0 2017/06/15 Gottem$", // Version
+ModuleHeader MOD_HEADER = {
+	"third/block_notlsident", // Module name
+	"2.0", // Version
 	"Restrict certain idents to SSL connections only", // Description
-	"3.2-b8-1", // Modversion, not sure wat do
-	NULL
+	"Gottem", // Author
+	"unrealircd-5", // Modversion
 };
 
 // Configuration testing-related hewks go in testing phase obv
-MOD_TEST(m_block_nosslident) {
+MOD_TEST() {
 	// We have our own config block so we need to checkem config obv m9
 	// Priorities don't really matter here
-	HookAdd(modinfo->handle, HOOKTYPE_CONFIGTEST, 0, block_nosslident_configtest);
-	HookAdd(modinfo->handle, HOOKTYPE_CONFIGPOSTTEST, 0, block_nosslident_configposttest);
+	HookAdd(modinfo->handle, HOOKTYPE_CONFIGTEST, 0, block_notlsident_configtest);
+	HookAdd(modinfo->handle, HOOKTYPE_CONFIGPOSTTEST, 0, block_notlsident_configposttest);
 	return MOD_SUCCESS;
 }
 
 // Initialisation routine (register hooks, commands and modes or create structs etc)
-MOD_INIT(m_block_nosslident) {
-	HookAdd(modinfo->handle, HOOKTYPE_CONFIGRUN, 0, block_nosslident_configrun);
-	HookAdd(modinfo->handle, HOOKTYPE_PRE_LOCAL_CONNECT, 0, block_nosslident_prelocalconnect);
+MOD_INIT() {
+	MARK_AS_GLOBAL_MODULE(modinfo);
 
-	bnosIdentMI = modinfo; // Store module info yo
-	return MOD_SUCCESS; // Let MOD_LOAD handle errors and registering of overrides
+	HookAdd(modinfo->handle, HOOKTYPE_CONFIGRUN, 0, block_notlsident_configrun);
+	HookAdd(modinfo->handle, HOOKTYPE_PRE_LOCAL_CONNECT, 0, block_notlsident_prelocalconnect);
+	return MOD_SUCCESS;
 }
 
-MOD_LOAD(m_block_nosslident) {
-	// Check if module handle is available, also check for overrides/commands that weren't added for some raisin
-	if(ModuleGetError(bnosIdentMI->handle) != MODERR_NOERROR) {
-		// Display error string kek
-		config_error("A critical error occurred when loading module %s: %s", MOD_HEADER(m_block_nosslident).name, ModuleGetErrorStr(bnosIdentMI->handle));
-		return MOD_FAILED; // No good
-	}
+MOD_LOAD() {
 	return MOD_SUCCESS; // We good
 }
 
 // Called on unload/rehash obv
-MOD_UNLOAD(m_block_nosslident) {
+MOD_UNLOAD() {
 	int i;
 	for(i = 0; i < bicount && blockedIdents[i]; i++) // Iter8 em
-		free(blockedIdents[i]); // Kbye
+		safe_free(blockedIdents[i]); // Kbye
 	if(bicount)
-		free(blockedIdents);
+		safe_free(blockedIdents);
 	bicount = 0;
 	return MOD_SUCCESS; // We good
 }
@@ -75,13 +82,13 @@ MOD_UNLOAD(m_block_nosslident) {
 int find_bident(char *ident) {
 	int i;
 	for(i = 0; i < bicount; i++) { // Iterate em lol
-		if(!match(blockedIdents[i], ident))
+		if(match_simple(blockedIdents[i], ident))
 			return 1; // We gottem
 	}
 	return 0; // Nope
 }
 
-int block_nosslident_configtest(ConfigFile *cf, ConfigEntry *ce, int type, int *errs) {
+int block_notlsident_configtest(ConfigFile *cf, ConfigEntry *ce, int type, int *errs) {
 	int errors = 0; // Error count
 	ConfigEntry *cep; // To store the current variable/value pair etc
 
@@ -118,18 +125,18 @@ int block_nosslident_configtest(ConfigFile *cf, ConfigEntry *ce, int type, int *
 	return errors ? -1 : 1; // Returning 1 means "all good", -1 means we shat our panties
 }
 
-int block_nosslident_configposttest(int *errs) {
+int block_notlsident_configposttest(int *errs) {
 	int errors = 0;
 
 	if(!bicount)
-		config_warn("Module %s was loaded but there are no idents specified", MOD_HEADER(m_block_nosslident).name);
+		config_warn("Module %s was loaded but there are no idents specified in the %s { } block", MOD_HEADER.name, MYCONF);
 
 	*errs = errors;
 	return errors ? -1 : 1;
 }
 
 // "Run" the config (everything should be valid at this point)
-int block_nosslident_configrun(ConfigFile *cf, ConfigEntry *ce, int type) {
+int block_notlsident_configrun(ConfigFile *cf, ConfigEntry *ce, int type) {
 	ConfigEntry *cep; // To store the current variable/value pair etc, nested
 	int i; // Array index =]
 
@@ -144,13 +151,13 @@ int block_nosslident_configrun(ConfigFile *cf, ConfigEntry *ce, int type) {
 	if(!ce || !ce->ce_varname)
 		return 0;
 
-	// If it isn't block_nosslident, idc
+	// If it isn't block_notlsident, idc
 	if(strcmp(ce->ce_varname, MYCONF))
 		return 0;
 
 	// Loop dat shyte fam
 	i = 0;
-	blockedIdents = malloc(bicount * sizeof(char *));
+	blockedIdents = safe_alloc(bicount * sizeof(char *));
 	for(cep = ce->ce_entries; cep; cep = cep->ce_next) {
 		// Do we even have a valid entry l0l?
 		if(!cep->ce_varname || !cep->ce_vardata)
@@ -165,10 +172,11 @@ int block_nosslident_configrun(ConfigFile *cf, ConfigEntry *ce, int type) {
 	return 1; // We good
 }
 
-int block_nosslident_prelocalconnect(aClient *sptr) {
-	if(!(sptr->local->listener->options & LISTENER_SSL) && find_bident(sptr->user->username)) {
-		sendto_snomask_global(SNO_KILLS, "*** [block_nosslident] Ident %s (%s@%s) just tried to connect without SSL", sptr->user->username, sptr->name, sptr->user->realhost);
-		return exit_client(sptr, sptr, sptr, "Illegal ident"); // Kbye