Beispiel #1
0
void CMapLayers::BackgroundMapUpdate()
{
	if(m_Type == TYPE_BACKGROUND && m_pMenuMap)
	{
		// unload map
		m_pMenuMap->Unload();

		int HourOfTheDay = (time_timestamp()/3600)%24;

		char aBuf[128];
		str_format(aBuf, sizeof(aBuf), "ui/%s_%s.map", g_Config.m_ClMenuMap, (HourOfTheDay >= 6 && HourOfTheDay < 18) ? "day" : "night");
		if(!m_pMenuMap->Load(aBuf, m_pClient->Storage()))
		{
			str_format(aBuf, sizeof(aBuf), "map '%s' not found", g_Config.m_ClMenuMap);
			Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "client", aBuf);
			return;
		}

		str_format(aBuf, sizeof(aBuf), "loaded map '%s'", g_Config.m_ClMenuMap);
		Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "client", aBuf);

		m_pMenuLayers->Init(Kernel(), m_pMenuMap);
		RenderTools()->RenderTilemapGenerateSkip(m_pMenuLayers);
		m_pClient->m_pMapimages->OnMenuMapLoad(m_pMenuMap);
		LoadEnvPoints(m_pMenuLayers, m_lEnvPointsMenu);
	}
}
int CNetServer::Update()
{
	int Now = time_timestamp();
	for(int i = 0; i < MaxClients(); i++)
	{
		m_aSlots[i].m_Connection.Update();
		if(m_aSlots[i].m_Connection.State() == NET_CONNSTATE_ERROR)
			Drop(i, m_aSlots[i].m_Connection.ErrorString());
	}

	// remove expired bans
	while(m_BanPool_FirstUsed && m_BanPool_FirstUsed->m_Info.m_Expires > -1 && m_BanPool_FirstUsed->m_Info.m_Expires < Now)
	{
		CBan *pBan = m_BanPool_FirstUsed;
		BanRemoveByObject(pBan);
	}

	return 0;
}
Beispiel #3
0
void CNetBan::Update()
{
	int Now = time_timestamp();

	// remove expired bans
	char aBuf[256], aNetStr[256];
	while(m_BanAddrPool.First() && m_BanAddrPool.First()->m_Info.m_Expires != CBanInfo::EXPIRES_NEVER && m_BanAddrPool.First()->m_Info.m_Expires < Now)
	{
		str_format(aBuf, sizeof(aBuf), "ban %s expired", NetToString(&m_BanAddrPool.First()->m_Data, aNetStr, sizeof(aNetStr)));
		Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", aBuf);
		m_BanAddrPool.Remove(m_BanAddrPool.First());
	}
	while(m_BanRangePool.First() && m_BanRangePool.First()->m_Info.m_Expires != CBanInfo::EXPIRES_NEVER && m_BanRangePool.First()->m_Info.m_Expires < Now)
	{
		str_format(aBuf, sizeof(aBuf), "ban %s expired", NetToString(&m_BanRangePool.First()->m_Data, aNetStr, sizeof(aNetStr)));
		Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", aBuf);
		m_BanRangePool.Remove(m_BanRangePool.First());
	}
}
Beispiel #4
0
int CNetBan::Ban(T *pBanPool, const typename T::CDataType *pData, int Seconds, const char *pReason)
{
	// do not ban localhost
	if(NetMatch(pData, &m_LocalhostIPV4) || NetMatch(pData, &m_LocalhostIPV6))
	{
		Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", "ban failed (localhost)");
		return -1;
	}

	int Stamp = Seconds > 0 ? time_timestamp()+Seconds : CBanInfo::EXPIRES_NEVER;

	// set up info
	CBanInfo Info = {0};
	Info.m_Expires = Stamp;
	str_copy(Info.m_aReason, pReason, sizeof(Info.m_aReason));

	// check if it already exists
	CNetHash NetHash(pData);
	CBan<typename T::CDataType> *pBan = pBanPool->Find(pData, &NetHash);
	if(pBan)
	{
		// adjust the ban
		pBanPool->Update(pBan, &Info);
		char aBuf[128];
		MakeBanInfo(pBan, aBuf, sizeof(aBuf), MSGTYPE_LIST);
		Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", aBuf);
		return 1;
	}

	// add ban and print result
	pBan = pBanPool->Add(pData, &Info, &NetHash);
	if(pBan)
	{
		char aBuf[128];
		MakeBanInfo(pBan, aBuf, sizeof(aBuf), MSGTYPE_BANADD);
		Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", aBuf);
		return 0;
	}
	else
		Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", "ban failed (full banlist)");
	return -1;
}
Beispiel #5
0
void CNetBan::MakeBanInfo(const CBan<T> *pBan, char *pBuf, unsigned BuffSize, int Type) const
{
	if(pBan == 0 || pBuf == 0)
	{
		if(BuffSize > 0)
			pBuf[0] = 0;
		return;
	}
	
	// build type based part
	char aBuf[256];
	if(Type == MSGTYPE_PLAYER)
		str_copy(aBuf, "You have been banned", sizeof(aBuf));
	else
	{
		char aTemp[256];
		switch(Type)
		{
		case MSGTYPE_LIST:
			str_format(aBuf, sizeof(aBuf), "%s banned", NetToString(&pBan->m_Data, aTemp, sizeof(aTemp))); break;
		case MSGTYPE_BANADD:
			str_format(aBuf, sizeof(aBuf), "banned %s", NetToString(&pBan->m_Data, aTemp, sizeof(aTemp))); break;
		case MSGTYPE_BANREM:
			str_format(aBuf, sizeof(aBuf), "unbanned %s", NetToString(&pBan->m_Data, aTemp, sizeof(aTemp))); break;
		default:
			aBuf[0] = 0;
		}
	}

	// add info part
	if(pBan->m_Info.m_Expires != CBanInfo::EXPIRES_NEVER)
	{
		int Mins = ((pBan->m_Info.m_Expires-time_timestamp()) + 59) / 60;
		if(Mins <= 1)
			str_format(pBuf, BuffSize, "%s for 1 minute (%s)", aBuf, pBan->m_Info.m_aReason);
		else
			str_format(pBuf, BuffSize, "%s for %d minutes (%s)", aBuf, Mins, pBan->m_Info.m_aReason);
	}
	else
		str_format(pBuf, BuffSize, "%s for life (%s)", aBuf, pBan->m_Info.m_aReason);
}
Beispiel #6
0
int netserver_update(NETSERVER *s)
{
	unsigned now = time_timestamp();
	
	int i;
	for(i = 0; i < s->max_clients; i++)
	{
		conn_update(&s->slots[i].conn);
		if(s->slots[i].conn.state == NET_CONNSTATE_ERROR)
			netserver_drop(s, i, conn_error(&s->slots[i].conn));
	}
	
	/* remove expired bans */
	while(s->banpool_firstused && s->banpool_firstused->info.expires < now)
	{
		NETBAN *ban = s->banpool_firstused;
		netserver_ban_remove_by_object(s, ban);
	}
	
	(void)now;
	
	return 0;
}
Beispiel #7
0
void CNetBan::ConBansSave(IConsole::IResult *pResult, void *pUser)
{
	CNetBan *pThis = static_cast<CNetBan *>(pUser);

	char aBuf[256];
	IOHANDLE File = pThis->Storage()->OpenFile(pResult->GetString(0), IOFLAG_WRITE, IStorage::TYPE_SAVE);
	if(!File)
	{
		str_format(aBuf, sizeof(aBuf), "failed to save banlist to '%s'", pResult->GetString(0));
		pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", aBuf);
		return;
	}

	int Now = time_timestamp();
	char aAddrStr1[NETADDR_MAXSTRSIZE], aAddrStr2[NETADDR_MAXSTRSIZE];
	for(CBanAddr *pBan = pThis->m_BanAddrPool.First(); pBan; pBan = pBan->m_pNext)
	{
		int Min = pBan->m_Info.m_Expires>-1 ? (pBan->m_Info.m_Expires-Now+59)/60 : -1;
		net_addr_str(&pBan->m_Data, aAddrStr1, sizeof(aAddrStr1), false);
		str_format(aBuf, sizeof(aBuf), "ban %s %i %s", aAddrStr1, Min, pBan->m_Info.m_aReason);
		io_write(File, aBuf, str_length(aBuf));
		io_write_newline(File);
	}
	for(CBanRange *pBan = pThis->m_BanRangePool.First(); pBan; pBan = pBan->m_pNext)
	{
		int Min = pBan->m_Info.m_Expires>-1 ? (pBan->m_Info.m_Expires-Now+59)/60 : -1;
		net_addr_str(&pBan->m_Data.m_LB, aAddrStr1, sizeof(aAddrStr1), false);
		net_addr_str(&pBan->m_Data.m_UB, aAddrStr2, sizeof(aAddrStr2), false);
		str_format(aBuf, sizeof(aBuf), "ban_range %s %s %i %s", aAddrStr1, aAddrStr2, Min, pBan->m_Info.m_aReason);
		io_write(File, aBuf, str_length(aBuf));
		io_write_newline(File);
	}

	io_close(File);
	str_format(aBuf, sizeof(aBuf), "saved banlist to '%s'", pResult->GetString(0));
	pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", aBuf);
}
Beispiel #8
0
/*
	TODO: chopp up this function into smaller working parts
*/
int netserver_recv(NETSERVER *s, NETCHUNK *chunk)
{
	unsigned now = time_timestamp();
	
	while(1)
	{
		NETADDR addr;
		int i, bytes, found;
			
		/* check for a chunk */
		if(recvinfo_fetch_chunk(&s->recv, chunk))
			return 1;
		
		/* TODO: empty the recvinfo */
		bytes = net_udp_recv(s->socket, &addr, s->recv.buffer, NET_MAX_PACKETSIZE);

		/* no more packets for now */
		if(bytes <= 0)
			break;
		
		if(unpack_packet(s->recv.buffer, bytes, &s->recv.data) == 0)
		{
			NETBAN *ban = 0;
			NETADDR banaddr = addr;
			int iphash = (addr.ip[0]+addr.ip[1]+addr.ip[2]+addr.ip[3])&0xff;
			found = 0;
			banaddr.port = 0;
			
			/* search a ban */
			for(ban = s->bans[iphash]; ban; ban = ban->hashnext)
			{
				if(net_addr_comp(&ban->info.addr, &banaddr) == 0)
					break;
			}
			
			/* check if we just should drop the packet */
			if(ban)
			{
				// banned, reply with a message
				char banstr[128];
				if(ban->info.expires)
				{
					int mins = ((ban->info.expires - now)+59)/60;
					if(mins == 1)
						str_format(banstr, sizeof(banstr), "banned for %d minute", mins);
					else
						str_format(banstr, sizeof(banstr), "banned for %d minutes", mins);
				}
				else
					str_format(banstr, sizeof(banstr), "banned for life");
				send_controlmsg(s->socket, &addr, 0, NET_CTRLMSG_CLOSE, banstr, str_length(banstr)+1);
				continue;
			}
			
			if(s->recv.data.flags&NET_PACKETFLAG_CONNLESS)
			{
				chunk->flags = NETSENDFLAG_CONNLESS;
				chunk->client_id = -1;
				chunk->address = addr;
				chunk->data_size = s->recv.data.data_size;
				chunk->data = s->recv.data.chunk_data;
				return 1;
			}
			else
			{			
				/* TODO: check size here */
				if(s->recv.data.flags&NET_PACKETFLAG_CONTROL && s->recv.data.chunk_data[0] == NET_CTRLMSG_CONNECT)
				{
					found = 0;
				
					/* check if we already got this client */
					for(i = 0; i < s->max_clients; i++)
					{
						if(s->slots[i].conn.state != NET_CONNSTATE_OFFLINE &&
							net_addr_comp(&s->slots[i].conn.peeraddr, &addr) == 0)
						{
							found = 1; /* silent ignore.. we got this client already */
							break;
						}
					}
					
					/* client that wants to connect */
					if(!found)
					{
						for(i = 0; i < s->max_clients; i++)
						{
							if(s->slots[i].conn.state == NET_CONNSTATE_OFFLINE)
							{
								found = 1;
								conn_feed(&s->slots[i].conn, &s->recv.data, &addr);
								if(s->new_client)
									s->new_client(i, s->user_ptr);
								break;
							}
						}
						
						if(!found)
						{
							const char fullmsg[] = "server is full";
							send_controlmsg(s->socket, &addr, 0, NET_CTRLMSG_CLOSE, fullmsg, sizeof(fullmsg));
						}
					}
				}
				else
				{
					/* normal packet, find matching slot */
					for(i = 0; i < s->max_clients; i++)
					{
						if(net_addr_comp(&s->slots[i].conn.peeraddr, &addr) == 0)
						{
							if(conn_feed(&s->slots[i].conn, &s->recv.data, &addr))
							{
								if(s->recv.data.data_size)
									recvinfo_start(&s->recv, &addr, &s->slots[i].conn, i);
							}
						}
					}
				}
			}
		}
	}
	return 0;
}
Beispiel #9
0
int netserver_ban_add(NETSERVER *s, NETADDR addr, int seconds)
{
	int iphash = (addr.ip[0]+addr.ip[1]+addr.ip[2]+addr.ip[3])&0xff;
	unsigned stamp = 0xffffffff;
	NETBAN *ban;
	
	/* remove the port */
	addr.port = 0;
	
	if(seconds)
		stamp = time_timestamp() + seconds;
		
	/* search to see if it already exists */
	ban = s->bans[iphash];
	MACRO_LIST_FIND(ban, hashnext, net_addr_comp(&ban->info.addr, &addr) == 0);
	if(ban)
	{
		/* adjust the ban */
		ban->info.expires = stamp;
		return 0;
	}
	
	if(!s->banpool_firstfree)
		return -1;

	/* fetch and clear the new ban */
	ban = s->banpool_firstfree;
	MACRO_LIST_UNLINK(ban, s->banpool_firstfree, prev, next);
	
	/* setup the ban info */
	ban->info.expires = stamp;
	ban->info.addr = addr;
	
	/* add it to the ban hash */
	MACRO_LIST_LINK_FIRST(ban, s->bans[iphash], hashprev, hashnext);
	
	/* insert it into the used list */
	{
		if(s->banpool_firstused)
		{
			NETBAN *insert_after = s->banpool_firstused;
			MACRO_LIST_FIND(insert_after, next, stamp < insert_after->info.expires);
			
			if(insert_after)
				insert_after = insert_after->prev;
			else
			{
				/* add to last */
				insert_after = s->banpool_firstused;
				while(insert_after->next)
					insert_after = insert_after->next;
			}
			
			if(insert_after)
			{
				MACRO_LIST_LINK_AFTER(ban, insert_after, prev, next);
			}
			else
			{
				MACRO_LIST_LINK_FIRST(ban, s->banpool_firstused, prev, next);
			}
		}
		else
		{
			MACRO_LIST_LINK_FIRST(ban, s->banpool_firstused, prev, next);
		}
	}

	/* drop banned clients */	
	{
		char buf[128];
		int i;
		NETADDR banaddr;
		
		if(seconds)
			str_format(buf, sizeof(buf), "you have been banned for %d minutes", seconds/60);
		else
			str_format(buf, sizeof(buf), "you have been banned for life");
		
		for(i = 0; i < s->max_clients; i++)
		{
			banaddr = s->slots[i].conn.peeraddr;
			banaddr.port = 0;
			
			if(net_addr_comp(&addr, &banaddr) == 0)
				netserver_drop(s, i, buf);
		}
	}
	return 0;
}
/*
	TODO: chopp up this function into smaller working parts
*/
int CNetServer::Recv(CNetChunk *pChunk)
{
	unsigned Now = time_timestamp();

	while(1)
	{
		NETADDR Addr;

		// check for a chunk
		if(m_RecvUnpacker.FetchChunk(pChunk))
			return 1;

		// TODO: empty the recvinfo
		int Bytes = net_udp_recv(m_Socket, &Addr, m_RecvUnpacker.m_aBuffer, NET_MAX_PACKETSIZE);

		// no more packets for now
		if(Bytes <= 0)
			break;

		if(CNetBase::UnpackPacket(m_RecvUnpacker.m_aBuffer, Bytes, &m_RecvUnpacker.m_Data) == 0)
		{
			CBan *pBan = 0;
			NETADDR BanAddr = Addr;
			int IpHash = (BanAddr.ip[0]+BanAddr.ip[1]+BanAddr.ip[2]+BanAddr.ip[3]+BanAddr.ip[4]+BanAddr.ip[5]+BanAddr.ip[6]+BanAddr.ip[7]+
							BanAddr.ip[8]+BanAddr.ip[9]+BanAddr.ip[10]+BanAddr.ip[11]+BanAddr.ip[12]+BanAddr.ip[13]+BanAddr.ip[14]+BanAddr.ip[15])&0xff;
			int Found = 0;
			BanAddr.port = 0;

			// search a ban
			for(pBan = m_aBans[IpHash]; pBan; pBan = pBan->m_pHashNext)
			{
				if(net_addr_comp(&pBan->m_Info.m_Addr, &BanAddr) == 0)
					break;
			}

			// check if we just should drop the packet
			if(pBan)
			{
				// banned, reply with a message
				char BanStr[128];
				if(pBan->m_Info.m_Expires > -1)
				{
					int Mins = ((pBan->m_Info.m_Expires - Now)+59)/60;
					if(Mins <= 1)
						str_format(BanStr, sizeof(BanStr), "Banned for 1 minute (%s)", pBan->m_Info.m_Reason);
					else
						str_format(BanStr, sizeof(BanStr), "Banned for %d minutes (%s)", Mins, pBan->m_Info.m_Reason);
				}
				else
					str_format(BanStr, sizeof(BanStr), "Banned for life (%s)", pBan->m_Info.m_Reason);
				CNetBase::SendControlMsg(m_Socket, &Addr, 0, NET_CTRLMSG_CLOSE, BanStr, str_length(BanStr)+1);
				continue;
			}

			if(m_RecvUnpacker.m_Data.m_Flags&NET_PACKETFLAG_CONNLESS)
			{
				pChunk->m_Flags = NETSENDFLAG_CONNLESS;
				pChunk->m_ClientID = -1;
				pChunk->m_Address = Addr;
				pChunk->m_DataSize = m_RecvUnpacker.m_Data.m_DataSize;
				pChunk->m_pData = m_RecvUnpacker.m_Data.m_aChunkData;
				return 1;
			}
			else
			{
				// TODO: check size here
				if(m_RecvUnpacker.m_Data.m_Flags&NET_PACKETFLAG_CONTROL && m_RecvUnpacker.m_Data.m_aChunkData[0] == NET_CTRLMSG_CONNECT)
				{
					Found = 0;

					// check if we already got this client
					for(int i = 0; i < MaxClients(); i++)
					{
						NETADDR PeerAddr = m_aSlots[i].m_Connection.PeerAddress();
						if(m_aSlots[i].m_Connection.State() != NET_CONNSTATE_OFFLINE &&
							net_addr_comp(&PeerAddr, &Addr) == 0)
						{
							Found = 1; // silent ignore.. we got this client already
							break;
						}
					}

					// client that wants to connect
					if(!Found)
					{
						// only allow a specific number of players with the same ip
						NETADDR ThisAddr = Addr, OtherAddr;
						int FoundAddr = 1;
						ThisAddr.port = 0;
						for(int i = 0; i < MaxClients(); ++i)
						{
							if(m_aSlots[i].m_Connection.State() == NET_CONNSTATE_OFFLINE)
								continue;

							OtherAddr = m_aSlots[i].m_Connection.PeerAddress();
							OtherAddr.port = 0;
							if(!net_addr_comp(&ThisAddr, &OtherAddr))
							{
								if(FoundAddr++ >= m_MaxClientsPerIP)
								{
									char aBuf[128];
									str_format(aBuf, sizeof(aBuf), "Only %d players with the same IP are allowed", m_MaxClientsPerIP);
									CNetBase::SendControlMsg(m_Socket, &Addr, 0, NET_CTRLMSG_CLOSE, aBuf, sizeof(aBuf));
									return 0;
								}
							}
						}

						for(int i = 0; i < MaxClients(); i++)
						{
							if(m_aSlots[i].m_Connection.State() == NET_CONNSTATE_OFFLINE)
							{
								Found = 1;
								m_aSlots[i].m_Connection.Feed(&m_RecvUnpacker.m_Data, &Addr);
								if(m_pfnNewClient)
									m_pfnNewClient(i, m_UserPtr);
								break;
							}
						}

						if(!Found)
						{
							const char FullMsg[] = "This server is full";
							CNetBase::SendControlMsg(m_Socket, &Addr, 0, NET_CTRLMSG_CLOSE, FullMsg, sizeof(FullMsg));
						}
					}
				}
				else
				{
					// normal packet, find matching slot
					for(int i = 0; i < MaxClients(); i++)
					{
						NETADDR PeerAddr = m_aSlots[i].m_Connection.PeerAddress();
						if(net_addr_comp(&PeerAddr, &Addr) == 0)
						{
							if(m_aSlots[i].m_Connection.Feed(&m_RecvUnpacker.m_Data, &Addr))
							{
								if(m_RecvUnpacker.m_Data.m_DataSize)
									m_RecvUnpacker.Start(&Addr, &m_aSlots[i].m_Connection, i);
							}
						}
					}
				}
			}
		}
	}
	return 0;
}
int CNetServer::BanAdd(NETADDR Addr, int Seconds, const char *pReason)
{
	int IpHash = (Addr.ip[0]+Addr.ip[1]+Addr.ip[2]+Addr.ip[3]+Addr.ip[4]+Addr.ip[5]+Addr.ip[6]+Addr.ip[7]+
					Addr.ip[8]+Addr.ip[9]+Addr.ip[10]+Addr.ip[11]+Addr.ip[12]+Addr.ip[13]+Addr.ip[14]+Addr.ip[15])&0xff;
	int Stamp = -1;
	CBan *pBan;

	// remove the port
	Addr.port = 0;

	if(Seconds)
		Stamp = time_timestamp() + Seconds;

	// search to see if it already exists
	pBan = m_aBans[IpHash];
	MACRO_LIST_FIND(pBan, m_pHashNext, net_addr_comp(&pBan->m_Info.m_Addr, &Addr) == 0);
	if(pBan)
	{
		// adjust the ban
		pBan->m_Info.m_Expires = Stamp;
		return 0;
	}

	if(!m_BanPool_FirstFree)
		return -1;

	// fetch and clear the new ban
	pBan = m_BanPool_FirstFree;
	MACRO_LIST_UNLINK(pBan, m_BanPool_FirstFree, m_pPrev, m_pNext);

	// setup the ban info
	pBan->m_Info.m_Expires = Stamp;
	pBan->m_Info.m_Addr = Addr;
	str_copy(pBan->m_Info.m_Reason, pReason, sizeof(pBan->m_Info.m_Reason));

	// add it to the ban hash
	MACRO_LIST_LINK_FIRST(pBan, m_aBans[IpHash], m_pHashPrev, m_pHashNext);

	// insert it into the used list
	{
		if(m_BanPool_FirstUsed)
		{
			CBan *pInsertAfter = m_BanPool_FirstUsed;
			MACRO_LIST_FIND(pInsertAfter, m_pNext, Stamp < pInsertAfter->m_Info.m_Expires);

			if(pInsertAfter)
				pInsertAfter = pInsertAfter->m_pPrev;
			else
			{
				// add to last
				pInsertAfter = m_BanPool_FirstUsed;
				while(pInsertAfter->m_pNext)
					pInsertAfter = pInsertAfter->m_pNext;
			}

			if(pInsertAfter)
			{
				MACRO_LIST_LINK_AFTER(pBan, pInsertAfter, m_pPrev, m_pNext);
			}
			else
			{
				MACRO_LIST_LINK_FIRST(pBan, m_BanPool_FirstUsed, m_pPrev, m_pNext);
			}
		}
		else
		{
			MACRO_LIST_LINK_FIRST(pBan, m_BanPool_FirstUsed, m_pPrev, m_pNext);
		}
	}

	// drop banned clients
	{
		char Buf[128];
		NETADDR BanAddr;

		if(Stamp > -1)
		{
			int Mins = (Seconds + 59) / 60;
			if(Mins <= 1)
				str_format(Buf, sizeof(Buf), "You have been banned for 1 minute (%s)", pReason);
			else
				str_format(Buf, sizeof(Buf), "You have been banned for %d minutes (%s)", Mins, pReason);
		}
		else
			str_format(Buf, sizeof(Buf), "You have been banned for life (%s)", pReason);

		for(int i = 0; i < MaxClients(); i++)
		{
			BanAddr = m_aSlots[i].m_Connection.PeerAddress();
			BanAddr.port = 0;

			if(net_addr_comp(&Addr, &BanAddr) == 0)
				Drop(i, Buf);
		}
	}
	return 0;
}