--- m_listrestrict.c_orig	2018-11-03 17:34:57.072296369 -0000
+++ m_listrestrict.c	2018-11-03 23:18:32.997177692 -0000
@@ -18,6 +18,14 @@
 	restrictExcept *next;
 };
 
+typedef struct t_fakechans fakeChannel;
+struct t_fakechans {
+	char *name;
+	int users;
+	char *topic;
+	fakeChannel *next;
+};
+
 // Quality fowod declarations
 static int listrestrict_override(Cmdoverride *ovr, aClient *cptr, aClient *sptr, int parc, char *parv[]);
 int listrestrict_configtest(ConfigFile *cf, ConfigEntry *ce, int type, int *errs);
@@ -28,15 +36,18 @@
 static ModuleInfo *lrestrictMI = NULL; // Store ModuleInfo so we can use it to check for errors in MOD_LOAD
 Cmdoverride *lrestrictOVR; // Pointer to the override we're gonna add
 restrictExcept *exceptList = NULL; // Stores exceptions yo
+fakeChannel *fakeChanList = NULL;
 
 // Deez defaults
 int muhDelay = 0; // Default to off yo
 unsigned short needAuth = 0; // Must be identified w/ NickServ
+unsigned short fakeChans = 0;
+unsigned short authIsEnough = 0;
 
 // Dat dere module header
 ModuleHeader MOD_HEADER(m_listrestrict) = {
 	"m_listrestrict", // Module name
-	"$Id: v1.02 2017/09/02 Gottem$", // Version
+	"$Id: v1.03 2018/11/03 Gottem/k4be$", // Version
 	"Impose certain restrictions on /LIST usage", // Description
 	"3.2-b8-1", // Modversion, not sure wat do
 	NULL
@@ -80,10 +91,23 @@
 		restrictExcept *exEntry;
 		while((exEntry = exceptList) != NULL) {
 			exceptList = exceptList->next;
+			if(exEntry->mask) free(exEntry->mask);
 			free(exEntry);
 		}
 		exceptList = NULL;
 	}
+	
+	if(fakeChanList) {
+		// This shit is a bit convoluted to prevent memory issues obv famalmalmalmlmalm
+		fakeChannel *fakeChanEntry;
+		while((fakeChanEntry = fakeChanList) != NULL) {
+			fakeChanList = fakeChanList->next;
+			if(fakeChanEntry->name) free(fakeChanEntry->name);
+			if(fakeChanEntry->topic) free(fakeChanEntry->topic);
+			free(fakeChanEntry);
+		}
+		fakeChanList = NULL;
+	}
 
 	return MOD_SUCCESS; // We good
 }
@@ -102,13 +126,16 @@
 	** Also, parv[0] seems to always be NULL, so better not rely on it fam
 	*/
 	restrictExcept *exEntry; // For iteration yo
+	fakeChannel *fakeChansEntry;
 	unsigned short except_connect = 0; // We gottem exception?
 	unsigned short except_auth = 0; // Ditt0
+	unsigned short except_fakelist = 0;
 
 	// Checkem exceptions bro
 	if(!MyConnect(sptr) || !IsPerson(sptr) || IsOper(sptr) || IsULine(sptr)) { // Default set lel
 		except_connect = 1;
 		except_auth = 1;
+		except_fakelist = 1;
 	}
 	else { // Not an oper/U:Line/server, checkem whitelist (if ne)
 		for(exEntry = exceptList; exEntry; exEntry = exEntry->next) {
@@ -124,6 +151,9 @@
 					case 'c':
 						except_connect = 1;
 						break;
+					case 'f':
+						except_fakelist = 1;
+						break;
 					default:
 						break;
 				}
@@ -131,16 +161,29 @@
 			}
 		}
 	}
+	
+	if(authIsEnough && IsLoggedIn(sptr)) except_connect = 1; // do not check time when user already identified
+
+	int delayF = !except_connect && muhDelay > 0 && (sptr->local && TStime() - sptr->local->firsttime < muhDelay); // Sanity check + delay check =]
+	int authF = !except_auth && needAuth && !IsLoggedIn(sptr); // Need identified check ;];;]
+
+	if(fakeChans && !except_fakelist && (delayF || authF)) {
+		sendto_one(sptr, rpl_str(RPL_LISTSTART), me.name, sptr->name);
+		for(fakeChansEntry = fakeChanList; fakeChansEntry; fakeChansEntry = fakeChansEntry->next){
+			sendto_one(cptr, rpl_str(RPL_LIST), me.name, cptr->name, fakeChansEntry->name, fakeChansEntry->users, "[+ntr]", fakeChansEntry->topic);
+		}
+		sendto_one(sptr, rpl_str(RPL_LISTEND), me.name, sptr->name);
+	}
 
-	// Sanity check + delay check =]
-	if(!except_connect && muhDelay > 0 && sptr->local && TStime() - sptr->local->firsttime < muhDelay) {
+	if(delayF) {
 		sendnotice(sptr, "You have to be connected for at least %d seconds before being able to /%s", muhDelay, OVR_LIST);
+		if(fakeChans && !except_fakelist) sendnotice(sptr, "Please ignore the fake /%s output above.", OVR_LIST);
 		return 0;
 	}
 
-	// Need identified check ;];;]
-	if(!except_auth && needAuth && !IsLoggedIn(sptr)) {
+	if(authF) {
 		sendnotice(sptr, "You have to be identified with services before being able to /%s", OVR_LIST);
+		if(fakeChans && !except_fakelist) sendnotice(sptr, "Please ignore the fake /%s output above.", OVR_LIST);
 		return 0;
 	}
 
@@ -201,6 +244,22 @@
 			}
 			continue;
 		}
+		
+		if(!strcmp(cep->ce_varname, "authisenough")) {
+			if(!cep->ce_vardata || (strcmp(cep->ce_vardata, "0") && strcmp(cep->ce_vardata, "1"))) {
+				config_error("%s:%i: %s::%s must be either 0 or 1 fam", cep->ce_fileptr->cf_filename, cep->ce_varlinenum, MYCONF, cep->ce_varname);
+				errors++; // Increment err0r count fam
+			}
+			continue;
+		}
+		
+		if(!strcmp(cep->ce_varname, "fakechans")) {
+			if(!cep->ce_vardata || (strcmp(cep->ce_vardata, "0") && strcmp(cep->ce_vardata, "1"))) {
+				config_error("%s:%i: %s::%s must be either 0 or 1 fam", cep->ce_fileptr->cf_filename, cep->ce_varlinenum, MYCONF, cep->ce_varname);
+				errors++; // Increment err0r count fam
+			}
+			continue;
+		}
 
 		// Here comes a nested block =]
 		if(!strcmp(cep->ce_varname, "exceptions")) {
@@ -212,8 +271,8 @@
 					continue; // Next iteration imo tbh
 				}
 
-				if(strcmp(cep2->ce_varname, "connect") && strcmp(cep2->ce_varname, "auth") && strcmp(cep2->ce_varname, "all")) {
-					config_error("%s:%i: invalid %s::exceptions type (must be one of: connect, auth, all)", cep2->ce_fileptr->cf_filename, cep2->ce_varlinenum, MYCONF); // Rep0t error
+				if(strcmp(cep2->ce_varname, "connect") && strcmp(cep2->ce_varname, "auth") && strcmp(cep2->ce_varname, "all") && strcmp(cep2->ce_varname, "fake")) {
+					config_error("%s:%i: invalid %s::exceptions type (must be one of: connect, auth, fake, all)", cep2->ce_fileptr->cf_filename, cep2->ce_varlinenum, MYCONF); // Rep0t error
 					errors++; // Increment err0r count fam
 					continue; // Next iteration imo tbh
 				}
@@ -227,10 +286,68 @@
 			continue;
 		}
 
+		// Here comes another nested block =]
+		if(!strcmp(cep->ce_varname, "fakechannel")) {
+			int have_name = 0;
+			// Loop 'em again
+			for(cep2 = cep->ce_entries; cep2; cep2 = cep2->ce_next) {
+				if(!cep2->ce_varname || !cep2->ce_vardata) {
+					config_error("%s:%i: blank/incomplete %s::fakechannel entry", cep2->ce_fileptr->cf_filename, cep2->ce_varlinenum, MYCONF); // Rep0t error
+					errors++; // Increment err0r count fam
+					continue; // Next iteration imo tbh
+				}
+
+				if(strcmp(cep2->ce_varname, "name") && strcmp(cep2->ce_varname, "users") && strcmp(cep2->ce_varname, "topic")) {
+					config_error("%s:%i: invalid %s::fakechannel entry (must be one of: name, users, topic)", cep2->ce_fileptr->cf_filename, cep2->ce_varlinenum, MYCONF); // Rep0t error
+					errors++; // Increment err0r count fam
+					continue; // Next iteration imo tbh
+				}
+
+				if(!strcmp(cep2->ce_varname, "name")){
+					have_name = 1;
+					if(cep2->ce_vardata[0] != '#'){
+						config_error("%s:%i: invalid %s::fakechannel::name (channel name must start with a #)", cep2->ce_fileptr->cf_filename, cep2->ce_varlinenum, MYCONF); // Rep0t error
+						errors++;
+						continue;
+					}
+					if(strchr(cep2->ce_vardata, ',') || strchr(cep2->ce_vardata, ' ')){
+						config_error("%s:%i: invalid %s::fakechannel::name (contains space or comma)", cep2->ce_fileptr->cf_filename, cep2->ce_varlinenum, MYCONF); // Rep0t error
+						errors++;
+						continue;
+					}
+					if(strlen(cep2->ce_vardata) > CHANNELLEN){
+						config_error("%s:%i: invalid %s::fakechannel::name (too long). Max length is %i characters.", cep2->ce_fileptr->cf_filename, cep2->ce_varlinenum, MYCONF, CHANNELLEN); // Rep0t error
+						errors++;
+						continue;
+					}
+				}
+				if(!strcmp(cep2->ce_varname, "users")) {
+					if(!cep2->ce_vardata) {
+						config_error("%s:%i: %s::%s must be an integer of >= 0", cep->ce_fileptr->cf_filename, cep->ce_varlinenum, MYCONF, cep->ce_varname);
+						errors++; // Increment err0r count fam
+					}
+					for(i = 0; cep2->ce_vardata[i]; i++) {
+						if(!isdigit(cep2->ce_vardata[i])) {
+							config_error("%s:%i: %s::%s must be an integer of >= 0", cep->ce_fileptr->cf_filename, cep->ce_varlinenum, MYCONF, cep->ce_varname);
+							errors++; // Increment err0r count fam
+							break;
+						}
+					}
+					continue;
+				}
+			}
+			if(have_name == 0){
+				config_error("%s:%i: invalid %s::fakechannel (must contain a channel name)", cep->ce_fileptr->cf_filename, cep->ce_varlinenum, MYCONF); // Rep0t error
+				errors++;
+				continue;
+			}
+			continue;
+		}
+		
 		// Anything else is unknown to us =]
 		config_warn("%s:%i: unknown item %s::%s", cep->ce_fileptr->cf_filename, cep->ce_varlinenum, MYCONF, cep->ce_varname); // So display just a warning
 	}
-
+	
 	*errs = errors;
 	return errors ? -1 : 1; // Returning 1 means "all good", -1 means we shat our panties
 }
@@ -240,6 +357,8 @@
 	ConfigEntry *cep, *cep2; // For looping through our bl0cc, nested
 	restrictExcept *last = NULL; // Initialise to NULL so the loop requires minimal l0gic
 	restrictExcept **exEntry = &exceptList; // Hecks so the ->next chain stays intact
+	fakeChannel **fakeChanEntry = &fakeChanList;
+	fakeChannel *fakeChanLast = NULL;
 
 	// Since we'll add a new top-level block to unrealircd.conf, need to filter on CONFIG_MAIN lmao
 	if(type != CONFIG_MAIN)
@@ -268,6 +387,16 @@
 			needAuth = atoi(cep->ce_vardata);
 			continue;
 		}
+		
+		if(cep->ce_vardata && !strcmp(cep->ce_varname, "authisenough")) {
+			authIsEnough = atoi(cep->ce_vardata);
+			continue;
+		}
+		
+		if(cep->ce_vardata && !strcmp(cep->ce_varname, "fakechans")) {
+			fakeChans = atoi(cep->ce_vardata);
+			continue;
+		}
 
 		if(!strcmp(cep->ce_varname, "exceptions")) {
 			// Loop 'em
@@ -275,7 +404,6 @@
 				if(!cep2->ce_varname || !cep2->ce_vardata) // Sanity checks imo
 					continue; // Next iteration imo tbh
 
-				size_t masklen = sizeof(char) * (strlen(cep2->ce_vardata) + 1); // Get size
 				char etype; // Wat type etc
 
 				if(!strcmp(cep2->ce_varname, "all"))
@@ -284,17 +412,18 @@
 					etype = 'a';
 				else if(!strcmp(cep2->ce_varname, "connect"))
 					etype = 'c';
+				else if(!strcmp(cep2->ce_varname, "fake"))
+					etype = 'f';
 
 				// Allocate mem0ry for the current entry
 				*exEntry = malloc(sizeof(restrictExcept));
 
 				// Allocate/initialise shit here
-				(*exEntry)->mask = malloc(masklen);
+				(*exEntry)->mask = strdup(cep2->ce_vardata);
 				(*exEntry)->next = NULL;
 
 				// Copy that shit fam
 				(*exEntry)->type = etype;
-				strncpy((*exEntry)->mask, cep2->ce_vardata, masklen);
 
 				// Premium linked list fam
 				if(last)
@@ -305,6 +434,53 @@
 			}
 			continue;
 		}
+		
+		if(!strcmp(cep->ce_varname, "fakechannel")) {
+			// Loop 'em
+			
+			// Allocate mem0ry for the current entry
+			*fakeChanEntry = malloc(sizeof(fakeChannel));
+			(*fakeChanEntry)->next = NULL;
+			(*fakeChanEntry)->users = 2; // let this be default
+			// Premium linked list fam
+			if(fakeChanLast)
+				fakeChanLast->next = *fakeChanEntry;
+
+			fakeChanLast = *fakeChanEntry;
+			fakeChanEntry = &(*fakeChanEntry)->next;
+				
+			for(cep2 = cep->ce_entries; cep2; cep2 = cep2->ce_next) { // loop through parameters of a single fakechan
+				
+				if(!cep2->ce_varname || !cep2->ce_vardata) // Sanity checks imo
+					continue; // Next iteration imo tbh
+					
+				if(!strcmp(cep2->ce_varname, "name")){
+					fakeChanLast->name = strdup(cep2->ce_vardata);
+					clean_channelname(fakeChanLast->name);
+					continue;
+				}
+				
+				if(!strcmp(cep2->ce_varname, "users")){
+					int users = atoi(cep2->ce_vardata);
+					if(users < 0) users = 2; //something funny happened
+					fakeChanLast->users = users;
+					continue;
+				}
+				
+				if(!strcmp(cep2->ce_varname, "topic")){
+					if(strlen(cep2->ce_vardata) <= 0) continue;
+					fakeChanLast->topic = strdup(cep2->ce_vardata);
+					continue;
+				}
+			}
+			if(!fakeChanLast->name){ // should not happen!!!!
+				//???
+			}
+			if(!fakeChanLast->topic){ // empty topic is allowed
+				fakeChanLast->topic = strdup("DO NOT JOIN");
+			}
+			continue;
+		}
 	}
 
 	return 1; // We good
@@ -316,3 +492,4 @@
 	needAuth = 0;
 	return HOOK_CONTINUE;
 }
+
