core/ChatTriggers.cpp
author Matt Woodrow <pred@alliedmods.net>
Fri Aug 08 00:17:37 2008 +0000 (2008-08-08)
changeset 2224 676c3b826f13
parent 2042 4a2faafca477
child 2276 50d05c18e62a
permissions -rw-r--r--
Initial Import of beta structs extension.
ds@1952
     1
/**
ds@1952
     2
 * vim: set ts=4 :
ds@1952
     3
 * =============================================================================
ds@1952
     4
 * SourceMod
ds@1952
     5
 * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
ds@1952
     6
 * =============================================================================
ds@1952
     7
 *
ds@1952
     8
 * This program is free software; you can redistribute it and/or modify it under
ds@1952
     9
 * the terms of the GNU General Public License, version 3.0, as published by the
ds@1952
    10
 * Free Software Foundation.
ds@1952
    11
 * 
ds@1952
    12
 * This program is distributed in the hope that it will be useful, but WITHOUT
ds@1952
    13
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
ds@1952
    14
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
ds@1952
    15
 * details.
ds@1952
    16
 *
ds@1952
    17
 * You should have received a copy of the GNU General Public License along with
ds@1952
    18
 * this program.  If not, see <http://www.gnu.org/licenses/>.
ds@1952
    19
 *
ds@1952
    20
 * As a special exception, AlliedModders LLC gives you permission to link the
ds@1952
    21
 * code of this program (as well as its derivative works) to "Half-Life 2," the
ds@1952
    22
 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
ds@1952
    23
 * by the Valve Corporation.  You must obey the GNU General Public License in
ds@1952
    24
 * all respects for all other code used.  Additionally, AlliedModders LLC grants
ds@1952
    25
 * this exception to all derivative works.  AlliedModders LLC defines further
ds@1952
    26
 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
ds@1952
    27
 * or <http://www.sourcemod.net/license.php>.
ds@1952
    28
 *
ds@1952
    29
 * Version: $Id$
ds@1952
    30
 */
ds@1952
    31
ds@1952
    32
#include <ITextParsers.h>
ds@1952
    33
#include "ChatTriggers.h"
ds@1952
    34
#include "sm_stringutil.h"
ds@1952
    35
#include "ConCmdManager.h"
ds@1952
    36
#include "PlayerManager.h"
ds@1952
    37
#include "Translator.h"
ds@1952
    38
#include "HalfLife2.h"
ds@1952
    39
ds@1952
    40
/* :HACKHACK: We can't SH_DECL here because ConCmdManager.cpp does.
ds@1952
    41
 * While the OB build only runs on MM:S 1.6.0+ (SH 5+), the older one 
ds@1952
    42
 * can technically be compiled against any MM:S version after 1.4.2.
ds@1952
    43
 */
ds@1952
    44
#if defined ORANGEBOX_BUILD
ds@1952
    45
extern bool __SourceHook_FHRemoveConCommandDispatch(void *, bool, class fastdelegate::FastDelegate1<const CCommand &, void>);
ds@1952
    46
extern int __SourceHook_FHAddConCommandDispatch(void *, ISourceHook::AddHookMode, bool, class fastdelegate::FastDelegate1<const CCommand &, void>);
ds@1952
    47
#else
ds@1952
    48
extern bool __SourceHook_FHRemoveConCommandDispatch(void *, bool, class fastdelegate::FastDelegate0<void>);
ds@1952
    49
#if SH_IMPL_VERSION >= 5
ds@1952
    50
extern int __SourceHook_FHAddConCommandDispatch(void *, ISourceHook::AddHookMode, bool, class fastdelegate::FastDelegate0<void>);
ds@1952
    51
#elif SH_IMPL_VERSION == 4
ds@1952
    52
extern int __SourceHook_FHAddConCommandDispatch(void *, bool, class fastdelegate::FastDelegate0<void>);
ds@1952
    53
#elif SH_IMPL_VERSION == 3
ds@1952
    54
extern bool __SourceHook_FHAddConCommandDispatch(void *, bool, class fastdelegate::FastDelegate0<void>);
ds@1952
    55
#endif //SH_IMPL_VERSION
ds@1952
    56
#endif //ORANGEBOX_BUILD
ds@1952
    57
ds@1952
    58
ChatTriggers g_ChatTriggers;
ds@1952
    59
bool g_bSupressSilentFails = false;
ds@1952
    60
CPhraseFile *g_pFloodPhrases = NULL;
ds@1952
    61
ds@1952
    62
ChatTriggers::ChatTriggers() : m_pSayCmd(NULL), m_bWillProcessInPost(false), 
ds@1952
    63
	m_bTriggerWasSilent(false), m_ReplyTo(SM_REPLY_CONSOLE)
ds@1952
    64
{
ds@1952
    65
	m_PubTrigger = sm_strdup("!");
ds@1952
    66
	m_PrivTrigger = sm_strdup("/");
ds@1952
    67
	m_PubTriggerSize = 1;
ds@1952
    68
	m_PrivTriggerSize = 1;
ds@1952
    69
	m_bIsChatTrigger = false;
ds@1952
    70
}
ds@1952
    71
ds@1952
    72
ChatTriggers::~ChatTriggers()
ds@1952
    73
{
ds@1952
    74
	delete [] m_PubTrigger;
ds@1952
    75
	m_PubTrigger = NULL;
ds@1952
    76
	delete [] m_PrivTrigger;
ds@1952
    77
	m_PrivTrigger = NULL;
ds@1952
    78
}
ds@1952
    79
ds@1952
    80
ConfigResult ChatTriggers::OnSourceModConfigChanged(const char *key, 
ds@1952
    81
													const char *value, 
ds@1952
    82
													ConfigSource source,
ds@1952
    83
													char *error, 
ds@1952
    84
													size_t maxlength)
ds@1952
    85
{
ds@1952
    86
	if (strcmp(key, "PublicChatTrigger") == 0)
ds@1952
    87
	{
ds@1952
    88
		delete [] m_PubTrigger;
ds@1952
    89
		m_PubTrigger = sm_strdup(value);
ds@1952
    90
		m_PubTriggerSize = strlen(m_PubTrigger);
ds@1952
    91
		return ConfigResult_Accept;
ds@1952
    92
	}
ds@1952
    93
	else if (strcmp(key, "SilentChatTrigger") == 0)
ds@1952
    94
	{
ds@1952
    95
		delete [] m_PrivTrigger;
ds@1952
    96
		m_PrivTrigger = sm_strdup(value);
ds@1952
    97
		m_PrivTriggerSize = strlen(m_PrivTrigger);
ds@1952
    98
		return ConfigResult_Accept;
ds@1952
    99
	}
ds@1952
   100
	else if (strcmp(key, "SilentFailSuppress") == 0)
ds@1952
   101
	{
ds@1952
   102
		g_bSupressSilentFails = strcmp(value, "yes") == 0;
ds@1952
   103
		return ConfigResult_Accept;
ds@1952
   104
	}
ds@1952
   105
ds@1952
   106
	return ConfigResult_Ignore;
ds@1952
   107
}
ds@1952
   108
ds@1952
   109
void ChatTriggers::OnSourceModAllInitialized()
ds@1952
   110
{
ds@1952
   111
	m_pShouldFloodBlock = g_Forwards.CreateForward("OnClientFloodCheck", ET_Event, 1, NULL, Param_Cell);
ds@1952
   112
	m_pDidFloodBlock = g_Forwards.CreateForward("OnClientFloodResult", ET_Event, 2, NULL, Param_Cell, Param_Cell);
ds@1952
   113
}
ds@1952
   114
ds@1952
   115
void ChatTriggers::OnSourceModAllInitialized_Post()
ds@1952
   116
{
ds@1952
   117
	unsigned int file_id;
ds@1952
   118
	
ds@1952
   119
	file_id = g_Translator.FindOrAddPhraseFile("antiflood.phrases.txt");
ds@1952
   120
	g_pFloodPhrases = g_Translator.GetFileByIndex(file_id);
ds@1952
   121
}
ds@1952
   122
ds@1952
   123
void ChatTriggers::OnSourceModGameInitialized()
ds@1952
   124
{
ds@1952
   125
	unsigned int total = 2;
ds@1952
   126
	ConCommandBase *pCmd = icvar->GetCommands();
ds@1952
   127
	const char *name;
ds@1952
   128
	while (pCmd)
ds@1952
   129
	{
ds@1952
   130
		if (pCmd->IsCommand())
ds@1952
   131
		{
ds@1952
   132
			name = pCmd->GetName();
ds@1952
   133
			if (!m_pSayCmd && strcmp(name, "say") == 0)
ds@1952
   134
			{
ds@1952
   135
				m_pSayCmd = (ConCommand *)pCmd;
ds@1952
   136
				if (--total == 0)
ds@1952
   137
				{
ds@1952
   138
					break;
ds@1952
   139
				}
ds@1952
   140
			} else if (!m_pSayTeamCmd && strcmp(name, "say_team") == 0) {
ds@1952
   141
				m_pSayTeamCmd = (ConCommand *)pCmd;
ds@1952
   142
				if (--total == 0)
ds@1952
   143
				{
ds@1952
   144
					break;
ds@1952
   145
				}
ds@1952
   146
			}
ds@1952
   147
		}
ds@1952
   148
		pCmd = const_cast<ConCommandBase *>(pCmd->GetNext());
ds@1952
   149
	}
ds@1952
   150
ds@1952
   151
	if (m_pSayCmd)
ds@1952
   152
	{
ds@1952
   153
		SH_ADD_HOOK_MEMFUNC(ConCommand, Dispatch, m_pSayCmd, this, &ChatTriggers::OnSayCommand_Pre, false);
ds@1952
   154
		SH_ADD_HOOK_MEMFUNC(ConCommand, Dispatch, m_pSayCmd, this, &ChatTriggers::OnSayCommand_Post, true);
ds@1952
   155
	}
ds@1952
   156
	if (m_pSayTeamCmd)
ds@1952
   157
	{
ds@1952
   158
		SH_ADD_HOOK_MEMFUNC(ConCommand, Dispatch, m_pSayTeamCmd, this, &ChatTriggers::OnSayCommand_Pre, false);
ds@1952
   159
		SH_ADD_HOOK_MEMFUNC(ConCommand, Dispatch, m_pSayTeamCmd, this, &ChatTriggers::OnSayCommand_Post, true);
ds@1952
   160
	}
ds@1952
   161
}
ds@1952
   162
ds@1952
   163
void ChatTriggers::OnSourceModShutdown()
ds@1952
   164
{
ds@1952
   165
	if (m_pSayTeamCmd)
ds@1952
   166
	{
ds@1952
   167
		SH_REMOVE_HOOK_MEMFUNC(ConCommand, Dispatch, m_pSayTeamCmd, this, &ChatTriggers::OnSayCommand_Post, true);
ds@1952
   168
		SH_REMOVE_HOOK_MEMFUNC(ConCommand, Dispatch, m_pSayTeamCmd, this, &ChatTriggers::OnSayCommand_Pre, false);
ds@1952
   169
	}
ds@1952
   170
	if (m_pSayCmd)
ds@1952
   171
	{
ds@1952
   172
		SH_REMOVE_HOOK_MEMFUNC(ConCommand, Dispatch, m_pSayCmd, this, &ChatTriggers::OnSayCommand_Post, true);
ds@1952
   173
		SH_REMOVE_HOOK_MEMFUNC(ConCommand, Dispatch, m_pSayCmd, this, &ChatTriggers::OnSayCommand_Pre, false);
ds@1952
   174
	}
ds@1952
   175
ds@1952
   176
	g_Forwards.ReleaseForward(m_pShouldFloodBlock);
ds@1952
   177
	g_Forwards.ReleaseForward(m_pDidFloodBlock);
ds@1952
   178
}
ds@1952
   179
ds@1952
   180
#if defined ORANGEBOX_BUILD
ds@1952
   181
void ChatTriggers::OnSayCommand_Pre(const CCommand &command)
ds@1952
   182
{
ds@1952
   183
#else
ds@1952
   184
void ChatTriggers::OnSayCommand_Pre()
ds@1952
   185
{
ds@1952
   186
	CCommand command;
ds@1952
   187
#endif
ds@1952
   188
	int client;
ds@1952
   189
	CPlayer *pPlayer;
ds@1952
   190
	
ds@1952
   191
	client = g_ConCmds.GetCommandClient();
ds@1952
   192
	m_bIsChatTrigger = false;
ds@1952
   193
	m_bWasFloodedMessage = false;
ds@1952
   194
ds@1952
   195
	/* The server console cannot do this */
ds@1952
   196
	if (client == 0 || (pPlayer = g_Players.GetPlayerByIndex(client)) == NULL)
ds@1952
   197
	{
ds@1952
   198
		RETURN_META(MRES_IGNORED);
ds@1952
   199
	}
ds@1952
   200
ds@1952
   201
	/* We guarantee the client is connected */
ds@1952
   202
	if (!pPlayer->IsConnected())
ds@1952
   203
	{
ds@1952
   204
		RETURN_META(MRES_IGNORED);
ds@1952
   205
	}
ds@1952
   206
ds@1952
   207
	const char *args = command.ArgS();
ds@1952
   208
	
ds@1952
   209
	if (!args)
ds@1952
   210
	{
ds@1952
   211
		RETURN_META(MRES_IGNORED);
ds@1952
   212
	}
ds@1952
   213
ds@1952
   214
	/* Check if we need to block this message from being sent */
ds@1952
   215
	if (ClientIsFlooding(client))
ds@1952
   216
	{
ds@1952
   217
		char buffer[128];
ds@1952
   218
dvander@2042
   219
		if (!CoreTranslate(
dvander@2042
   220
			buffer,
ds@1952
   221
			sizeof(buffer),
dvander@2042
   222
			"%T",
dvander@2042
   223
			2,
ds@1952
   224
			NULL,
dvander@2042
   225
			"Flooding the server",
dvander@2042
   226
			&client))
ds@1952
   227
		{
ds@1952
   228
			UTIL_Format(buffer, sizeof(buffer), "You are flooding the server!");
ds@1952
   229
		}
ds@1952
   230
ds@1952
   231
		/* :TODO: we should probably kick people who spam too much. */
ds@1952
   232
ds@1952
   233
		char fullbuffer[192];
ds@1952
   234
		UTIL_Format(fullbuffer, sizeof(fullbuffer), "[SM] %s", buffer);
ds@1952
   235
		g_HL2.TextMsg(client, HUD_PRINTTALK, fullbuffer);
ds@1952
   236
ds@1952
   237
		m_bWasFloodedMessage = true;
ds@1952
   238
ds@1952
   239
		RETURN_META(MRES_SUPERCEDE);
ds@1952
   240
	}
ds@1952
   241
ds@1952
   242
	/* Handle quoted string sets */
ds@1952
   243
	bool is_quoted = false;
ds@1952
   244
	if (args[0] == '"')
ds@1952
   245
	{
ds@1952
   246
		args++;
ds@1952
   247
		is_quoted = true;
ds@1952
   248
	}
ds@1952
   249
ds@1952
   250
	bool is_trigger = false;
ds@1952
   251
	bool is_silent = false;
ds@1952
   252
ds@1952
   253
	/* Check for either trigger */
ds@1952
   254
	if (m_PubTriggerSize && strncmp(args, m_PubTrigger, m_PubTriggerSize) == 0)
ds@1952
   255
	{
ds@1952
   256
		is_trigger = true;
ds@1952
   257
		args = &args[m_PubTriggerSize];
ds@1952
   258
	} 
ds@1952
   259
	else if (m_PrivTriggerSize && strncmp(args, m_PrivTrigger, m_PrivTriggerSize) == 0) 
ds@1952
   260
	{
ds@1952
   261
		is_trigger = true;
ds@1952
   262
		is_silent = true;
ds@1952
   263
		args = &args[m_PrivTriggerSize];
ds@1952
   264
	}
ds@1952
   265
ds@1952
   266
	if (!is_trigger)
ds@1952
   267
	{
ds@1952
   268
		RETURN_META(MRES_IGNORED);
ds@1952
   269
	}
ds@1952
   270
ds@1952
   271
	/**
ds@1952
   272
	 * Test if this is actually a command!
ds@1952
   273
	 */
ds@1952
   274
	if (!PreProcessTrigger(engine->PEntityOfEntIndex(client), args, is_quoted))
ds@1952
   275
	{
ds@1952
   276
		CPlayer *pPlayer;
ds@1952
   277
		if (is_silent 
ds@1952
   278
			&& g_bSupressSilentFails 
ds@1952
   279
			&& client != 0
ds@1952
   280
			&& (pPlayer = g_Players.GetPlayerByIndex(client)) != NULL
ds@1952
   281
			&& pPlayer->GetAdminId() != INVALID_ADMIN_ID)
ds@1952
   282
		{
ds@1952
   283
			RETURN_META(MRES_SUPERCEDE);
ds@1952
   284
		}
ds@1952
   285
		RETURN_META(MRES_IGNORED);
ds@1952
   286
	}
ds@1952
   287
ds@1952
   288
	m_bIsChatTrigger = true;
ds@1952
   289
ds@1952
   290
	/**
ds@1952
   291
	 * We'll execute it in post.
ds@1952
   292
	 */
ds@1952
   293
	m_bWillProcessInPost = true;
ds@1952
   294
	m_bTriggerWasSilent = is_silent;
ds@1952
   295
ds@1952
   296
	/* If we're silent, block */
ds@1952
   297
	if (is_silent)
ds@1952
   298
	{
ds@1952
   299
		RETURN_META(MRES_SUPERCEDE);
ds@1952
   300
	}
ds@1952
   301
ds@1952
   302
	/* Otherwise, let the command continue */
ds@1952
   303
	RETURN_META(MRES_IGNORED);
ds@1952
   304
}
ds@1952
   305
ds@1952
   306
#if defined ORANGEBOX_BUILD
ds@1952
   307
void ChatTriggers::OnSayCommand_Post(const CCommand &command)
ds@1952
   308
#else
ds@1952
   309
void ChatTriggers::OnSayCommand_Post()
ds@1952
   310
#endif
ds@1952
   311
{
ds@1952
   312
	m_bIsChatTrigger = false;
ds@1952
   313
	m_bWasFloodedMessage = false;
ds@1952
   314
	if (m_bWillProcessInPost)
ds@1952
   315
	{
ds@1952
   316
		/* Reset this for re-entrancy */
ds@1952
   317
		m_bWillProcessInPost = false;
ds@1952
   318
		
ds@1952
   319
		/* Execute the cached command */
ds@1952
   320
		int client = g_ConCmds.GetCommandClient();
ds@1952
   321
		unsigned int old = SetReplyTo(SM_REPLY_CHAT);
ds@1952
   322
		serverpluginhelpers->ClientCommand(engine->PEntityOfEntIndex(client), m_ToExecute);
ds@1952
   323
		SetReplyTo(old);
ds@1952
   324
	}
ds@1952
   325
}
ds@1952
   326
ds@1952
   327
bool ChatTriggers::PreProcessTrigger(edict_t *pEdict, const char *args, bool is_quoted)
ds@1952
   328
{
ds@1952
   329
	/* Extract a command.  This is kind of sloppy. */
ds@1952
   330
	char cmd_buf[64];
ds@1952
   331
	size_t cmd_len = 0;
ds@1952
   332
	const char *inptr = args;
ds@1952
   333
	while (*inptr != '\0' 
ds@1952
   334
			&& !textparsers->IsWhitespace(inptr) 
ds@1952
   335
			&& *inptr != '"'
ds@1952
   336
			&& cmd_len < sizeof(cmd_buf) - 1)
ds@1952
   337
	{
ds@1952
   338
		cmd_buf[cmd_len++] = *inptr++;
ds@1952
   339
	}
ds@1952
   340
	cmd_buf[cmd_len] = '\0';
ds@1952
   341
ds@1952
   342
	if (cmd_len == 0)
ds@1952
   343
	{
ds@1952
   344
		return false;
ds@1952
   345
	}
ds@1952
   346
ds@1952
   347
	/* See if we have this registered */
ds@1952
   348
	bool prepended = false;
ds@1952
   349
	if (!g_ConCmds.LookForSourceModCommand(cmd_buf))
ds@1952
   350
	{
ds@1952
   351
		/* Check if we had an "sm_" prefix */
ds@1952
   352
		if (strncmp(cmd_buf, "sm_", 3) == 0)
ds@1952
   353
		{
ds@1952
   354
			return false;
ds@1952
   355
		}
ds@1952
   356
ds@1952
   357
		/* Now, prepend.  Don't worry about the buffers.  This will 
ds@1952
   358
		 * work because the sizes are limited from earlier.
ds@1952
   359
		 */
ds@1952
   360
		char new_buf[80];
ds@1952
   361
		strcpy(new_buf, "sm_");
ds@1952
   362
		strncopy(&new_buf[3], cmd_buf, sizeof(new_buf)-3);
ds@1952
   363
ds@1952
   364
		/* Recheck */
ds@1952
   365
		if (!g_ConCmds.LookForSourceModCommand(new_buf))
ds@1952
   366
		{
ds@1952
   367
			return false;
ds@1952
   368
		}
ds@1952
   369
		
ds@1952
   370
		prepended = true;
ds@1952
   371
	}
ds@1952
   372
ds@1952
   373
	/* See if we need to do extra string manipulation */
ds@1952
   374
	if (is_quoted || prepended)
ds@1952
   375
	{
ds@1952
   376
		size_t len;
ds@1952
   377
ds@1952
   378
		/* Check if we need to prepend sm_ */
ds@1952
   379
		if (prepended)
ds@1952
   380
		{
ds@1952
   381
			len = UTIL_Format(m_ToExecute, sizeof(m_ToExecute), "sm_%s", args);
ds@1952
   382
		} else {
ds@1952
   383
			len = strncopy(m_ToExecute, args, sizeof(m_ToExecute));
ds@1952
   384
		}
ds@1952
   385
		
ds@1952
   386
		/* Check if we need to strip a quote */
ds@1952
   387
		if (is_quoted)
ds@1952
   388
		{
ds@1952
   389
			if (m_ToExecute[len-1] == '"')
ds@1952
   390
			{
ds@1952
   391
				m_ToExecute[--len] = '\0';
ds@1952
   392
			}
ds@1952
   393
		}
ds@1952
   394
	} else {
ds@1952
   395
		strncopy(m_ToExecute, args, sizeof(m_ToExecute));
ds@1952
   396
	}
ds@1952
   397
ds@1952
   398
	return true;
ds@1952
   399
}
ds@1952
   400
ds@1952
   401
unsigned int ChatTriggers::SetReplyTo(unsigned int reply)
ds@1952
   402
{
ds@1952
   403
	unsigned int old = m_ReplyTo;
ds@1952
   404
ds@1952
   405
	m_ReplyTo = reply;
ds@1952
   406
ds@1952
   407
	return old;
ds@1952
   408
}
ds@1952
   409
ds@1952
   410
unsigned int ChatTriggers::GetReplyTo()
ds@1952
   411
{
ds@1952
   412
	return m_ReplyTo;
ds@1952
   413
}
ds@1952
   414
ds@1952
   415
bool ChatTriggers::IsChatTrigger()
ds@1952
   416
{
ds@1952
   417
	return m_bIsChatTrigger;
ds@1952
   418
}
ds@1952
   419
ds@1952
   420
bool ChatTriggers::ClientIsFlooding(int client)
ds@1952
   421
{
ds@1952
   422
	bool is_flooding = false;
ds@1952
   423
ds@1952
   424
	if (m_pShouldFloodBlock->GetFunctionCount() != 0)
ds@1952
   425
	{
ds@1952
   426
		cell_t res = 0;
ds@1952
   427
ds@1952
   428
		m_pShouldFloodBlock->PushCell(client);
ds@1952
   429
		m_pShouldFloodBlock->Execute(&res);
ds@1952
   430
ds@1952
   431
		if (res != 0)
ds@1952
   432
		{
ds@1952
   433
			is_flooding = true;
ds@1952
   434
		}
ds@1952
   435
	}
ds@1952
   436
ds@1952
   437
	if (m_pDidFloodBlock->GetFunctionCount() != 0)
ds@1952
   438
	{
ds@1952
   439
		m_pDidFloodBlock->PushCell(client);
ds@1952
   440
		m_pDidFloodBlock->PushCell(is_flooding ? 1 : 0);
ds@1952
   441
		m_pDidFloodBlock->Execute(NULL);
ds@1952
   442
	}
ds@1952
   443
ds@1952
   444
	return is_flooding;
ds@1952
   445
}
ds@1952
   446
ds@1952
   447
bool ChatTriggers::WasFloodedMessage()
ds@1952
   448
{
ds@1952
   449
	return m_bWasFloodedMessage;
ds@1952
   450
}