1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2025-05-09 12:37:13 +02:00

Implement methods to send messages with style formatting in the IRC module. Should close #7

Also remove duplicate code in raw squirrel functions by merging it into one function.
This commit is contained in:
Sandu Liviu Catalin 2016-08-16 21:38:04 +03:00
parent 0f2ac5679a
commit e770ac3405
6 changed files with 193 additions and 142 deletions

View File

@ -246,7 +246,7 @@ static int libirc_colorparser_colorlookup (const char * color)
/* /*
* [code] to IRC color conversion. * [code] to IRC color conversion.
*/ */
char * irc_color_convert_to_mirc (const char * source) char * irc_color_convert_to_mirc (const char * source, void * (*memory_allocator)(size_t))
{ {
unsigned int destlen = 0; unsigned int destlen = 0;
char * destline = 0, *d = 0; char * destline = 0, *d = 0;
@ -262,7 +262,7 @@ char * irc_color_convert_to_mirc (const char * source)
if ( destlen > 0 ) if ( destlen > 0 )
{ {
// This is the 2nd pass; allocate memory. // This is the 2nd pass; allocate memory.
if ( (destline = malloc (destlen)) == 0 ) if ( (destline = memory_allocator (destlen)) == 0 )
return 0; return 0;
d = destline; d = destline;

View File

@ -1490,7 +1490,7 @@ char * irc_color_convert_from_mirc (const char * message);
* \sa irc_color_strip_from_mirc irc_color_convert_from_mirc * \sa irc_color_strip_from_mirc irc_color_convert_from_mirc
* \ingroup colors * \ingroup colors
*/ */
char * irc_color_convert_to_mirc (const char * message); char * irc_color_convert_to_mirc (const char * message, void * (*memory_allocator)(size_t));
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -7,6 +7,28 @@
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
namespace SqMod { namespace SqMod {
// ------------------------------------------------------------------------------------------------
void * IrcAllocMem(size_t n)
{
// Does the requested size exceed the common shared buffer size?
if (n > GetTempBuffSize())
{
return std::malloc(n);
}
// Return the common shared buffer
return GetTempBuff();
}
// ------------------------------------------------------------------------------------------------
void IrcFreeMem(void * p)
{
// Only release if it's not the temporary buffer
if ((p < GetTempBuff()) || (p > (GetTempBuff() + GetTempBuffSize())))
{
std::free(p);
}
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
static SQInteger SqGetNick(HSQUIRRELVM vm) static SQInteger SqGetNick(HSQUIRRELVM vm)
{ {
@ -104,7 +126,7 @@ static SQInteger SqConvertColorToMIRC(HSQUIRRELVM vm)
return val.mRes; // Propagate the error! return val.mRes; // Propagate the error!
} }
// Attempt to convert the colors // Attempt to convert the colors
CStr str = irc_color_convert_to_mirc(val.mPtr); CStr str = irc_color_convert_to_mirc(val.mPtr, IrcAllocMem);
// Could the IRC library allocate memory? // Could the IRC library allocate memory?
if (!str) if (!str)
{ {
@ -113,7 +135,7 @@ static SQInteger SqConvertColorToMIRC(HSQUIRRELVM vm)
// Push the resulted value on the stack // Push the resulted value on the stack
sq_pushstring(vm, str, -1); sq_pushstring(vm, str, -1);
// Free the memory allocated by the IRC library // Free the memory allocated by the IRC library
std::free(str); IrcFreeMem(str);
// Specify that this function returned a value // Specify that this function returned a value
return 1; return 1;
} }

View File

@ -58,6 +58,16 @@ enum SessionEvent
*/ */
class Session; class Session;
/* ------------------------------------------------------------------------------------------------
* Used by IRC as proxy to allocate memory if the requested size is larger than the common buffer.
*/
void * IrcAllocMem(size_t n);
/* ------------------------------------------------------------------------------------------------
* Release memory previously allocated with IrcAllocMem, only if necessary. Nasty but we'll try.
*/
void IrcFreeMem(void * p);
/* ------------------------------------------------------------------------------------------------ /* ------------------------------------------------------------------------------------------------
* Extract the name from the specified origin. * Extract the name from the specified origin.
*/ */

View File

@ -8,6 +8,9 @@
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
namespace SqMod { namespace SqMod {
// ------------------------------------------------------------------------------------------------
typedef int (*SendIrcMessageFunc)(irc_session_t *, const char *, const char *);
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
irc_callbacks_t Session::s_Callbacks; irc_callbacks_t Session::s_Callbacks;
@ -397,7 +400,7 @@ void Session::SetNick(CSStr nick)
STHROWF("Invalid IRC nickname"); STHROWF("Invalid IRC nickname");
} }
// Do we have to issue a nickname command? // Do we have to issue a nickname command?
else if (Connected()) else if (IsConnected())
{ {
irc_cmd_nick(m_Session, nick); irc_cmd_nick(m_Session, nick);
} }
@ -657,7 +660,7 @@ Int32 Session::Connect6(CSStr server, Uint32 port, CSStr nick, CSStr passwd, CSS
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void Session::Disconnect() void Session::Disconnect()
{ {
if (Connected()) if (IsConnected())
{ {
// Update one last time to catch remaining events // Update one last time to catch remaining events
Update(); Update();
@ -990,7 +993,7 @@ void Session::OnDccSendReq(irc_session_t * session, CCStr nick, CCStr addr, CCSt
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
SQInteger Session::CmdMsgF(HSQUIRRELVM vm) static SQInteger FormattedIrcMessageCmd(HSQUIRRELVM vm, SendIrcMessageFunc send_func, bool colored)
{ {
// Obtain the initial stack size // Obtain the initial stack size
const Int32 top = sq_gettop(vm); const Int32 top = sq_gettop(vm);
@ -1004,6 +1007,7 @@ SQInteger Session::CmdMsgF(HSQUIRRELVM vm)
{ {
return sq_throwerror(vm, "Missing the message value"); return sq_throwerror(vm, "Missing the message value");
} }
// The session instance // The session instance
Session * session = nullptr; Session * session = nullptr;
// Attempt to extract the argument values // Attempt to extract the argument values
@ -1016,21 +1020,23 @@ SQInteger Session::CmdMsgF(HSQUIRRELVM vm)
// Propagate the error // Propagate the error
return sq_throwerror(vm, e.what()); return sq_throwerror(vm, e.what());
} }
// Do we have a valid session instance? // Do we have a valid session instance?
if (!session) if (!session)
{ {
return sq_throwerror(vm, "Invalid session instance"); return sq_throwerror(vm, "Invalid session instance");
} }
// Do we have a valid session? // Do we have a valid session?
else if (!session->m_Session) else if (!session->IsValid())
{ {
return sq_throwerror(vm, "Invalid IRC session"); return sq_throwerror(vm, "Invalid IRC session");
} }
// Is the session connected? // Is the session connected?
else if (!session->Connected()) else if (!session->IsConnected())
{ {
return sq_throwerror(vm, "Session is not connected"); return sq_throwerror(vm, "Session is not connected");
} }
// Attempt to retrieve the target from the stack as a string // Attempt to retrieve the target from the stack as a string
StackStrF target(vm, 2, false); StackStrF target(vm, 2, false);
// Have we failed to retrieve the string? // Have we failed to retrieve the string?
@ -1038,6 +1044,7 @@ SQInteger Session::CmdMsgF(HSQUIRRELVM vm)
{ {
return target.mRes; // Propagate the error! return target.mRes; // Propagate the error!
} }
// Attempt to retrieve the value from the stack as a string // Attempt to retrieve the value from the stack as a string
StackStrF message(vm, 3); StackStrF message(vm, 3);
// Have we failed to retrieve the string? // Have we failed to retrieve the string?
@ -1045,140 +1052,65 @@ SQInteger Session::CmdMsgF(HSQUIRRELVM vm)
{ {
return message.mRes; // Propagate the error! return message.mRes; // Propagate the error!
} }
// Forward the resulted string value and save the returned result code
const Int32 code = irc_cmd_msg(session->m_Session, target.mPtr, message.mPtr); // Should we format this string for colored messages?
// Push the obtained code onto the stack if (colored)
sq_pushinteger(vm, code); {
// Attempt to scan the specified message for color formatting
char * cmsg = irc_color_convert_to_mirc(message.mPtr, IrcAllocMem);
// Validate the message
if (!cmsg)
{
return sq_throwerror(vm, "Failed to convert the message colors");
}
// Send the resulted message and push the returned result code onto the stack
sq_pushinteger(vm, send_func(session->GetHandle(), target.mPtr, cmsg));
// Free the memory used to convert the message
IrcFreeMem(cmsg);
}
// Forward the resulted string value and push the returned result code onto the stack
else
{
sq_pushinteger(vm, send_func(session->GetHandle(), target.mPtr, message.mPtr));
}
// We have a value on the stack // We have a value on the stack
return 1; return 1;
} }
// ------------------------------------------------------------------------------------------------
SQInteger Session::CmdMsgF(HSQUIRRELVM vm)
{
return FormattedIrcMessageCmd(vm, irc_cmd_msg, false);
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
SQInteger Session::CmdMeF(HSQUIRRELVM vm) SQInteger Session::CmdMeF(HSQUIRRELVM vm)
{ {
// Obtain the initial stack size return FormattedIrcMessageCmd(vm, irc_cmd_me, false);
const Int32 top = sq_gettop(vm);
// Do we have a target value?
if (top <= 1)
{
return sq_throwerror(vm, "Missing the message target");
}
// Do we have a message value?
else if (top <= 2)
{
return sq_throwerror(vm, "Missing the message value");
}
// The session instance
Session * session = nullptr;
// Attempt to extract the argument values
try
{
session = Var< Session * >(vm, 1).value;
}
catch (const Sqrat::Exception & e)
{
// Propagate the error
return sq_throwerror(vm, e.what());
}
// Do we have a valid session instance?
if (!session)
{
return sq_throwerror(vm, "Invalid session instance");
}
// Do we have a valid session?
else if (!session->m_Session)
{
return sq_throwerror(vm, "Invalid IRC session");
}
// Is the session connected?
else if (!session->Connected())
{
return sq_throwerror(vm, "Session is not connected");
}
// Attempt to retrieve the target from the stack as a string
StackStrF target(vm, 2, false);
// Have we failed to retrieve the string?
if (SQ_FAILED(target.mRes))
{
return target.mRes; // Propagate the error!
}
// Attempt to retrieve the value from the stack as a string
StackStrF message(vm, 3);
// Have we failed to retrieve the string?
if (SQ_FAILED(message.mRes))
{
return message.mRes; // Propagate the error!
}
// Forward the resulted string value and save the returned result code
const Int32 code = irc_cmd_me(session->m_Session, target.mPtr, message.mPtr);
// Push the obtained code onto the stack
sq_pushinteger(vm, code);
// We have a value on the stack
return 1;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
SQInteger Session::CmdNoticeF(HSQUIRRELVM vm) SQInteger Session::CmdNoticeF(HSQUIRRELVM vm)
{ {
// Obtain the initial stack size return FormattedIrcMessageCmd(vm, irc_cmd_notice, false);
const Int32 top = sq_gettop(vm);
// Do we have a target value?
if (top <= 1)
{
return sq_throwerror(vm, "Missing the message target");
} }
// Do we have a message value?
else if (top <= 2) // ------------------------------------------------------------------------------------------------
SQInteger Session::CmdColoredMsgF(HSQUIRRELVM vm)
{ {
return sq_throwerror(vm, "Missing the message value"); return FormattedIrcMessageCmd(vm, irc_cmd_msg, true);
} }
// The session instance
Session * session = nullptr; // ------------------------------------------------------------------------------------------------
// Attempt to extract the argument values SQInteger Session::CmdColoredMeF(HSQUIRRELVM vm)
try
{ {
session = Var< Session * >(vm, 1).value; return FormattedIrcMessageCmd(vm, irc_cmd_me, true);
} }
catch (const Sqrat::Exception & e)
// ------------------------------------------------------------------------------------------------
SQInteger Session::CmdColoredNoticeF(HSQUIRRELVM vm)
{ {
// Propagate the error return FormattedIrcMessageCmd(vm, irc_cmd_notice, true);
return sq_throwerror(vm, e.what());
}
// Do we have a valid session instance?
if (!session)
{
return sq_throwerror(vm, "Invalid session instance");
}
// Do we have a valid session?
else if (!session->m_Session)
{
return sq_throwerror(vm, "Invalid IRC session");
}
// Is the session connected?
else if (!session->Connected())
{
return sq_throwerror(vm, "Session is not connected");
}
// Attempt to retrieve the target from the stack as a string
StackStrF target(vm, 2, false);
// Have we failed to retrieve the string?
if (SQ_FAILED(target.mRes))
{
return target.mRes; // Propagate the error!
}
// Attempt to retrieve the value from the stack as a string
StackStrF message(vm, 3);
// Have we failed to retrieve the string?
if (SQ_FAILED(message.mRes))
{
return message.mRes; // Propagate the error!
}
// Forward the resulted string value and save the returned result code
const Int32 code = irc_cmd_notice(session->m_Session, target.mPtr, message.mPtr);
// Push the obtained code onto the stack
sq_pushinteger(vm, code);
// We have a value on the stack
return 1;
} }
/* ----------------------------------------------------------------------------------------------- /* -----------------------------------------------------------------------------------------------
@ -1240,6 +1172,9 @@ void Register_Session(Table & ircns)
.Func(_SC("CmdMsg"), &Session::CmdMsg) .Func(_SC("CmdMsg"), &Session::CmdMsg)
.Func(_SC("CmdMe"), &Session::CmdMe) .Func(_SC("CmdMe"), &Session::CmdMe)
.Func(_SC("CmdNotice"), &Session::CmdNotice) .Func(_SC("CmdNotice"), &Session::CmdNotice)
.Func(_SC("CmdColoredMsg"), &Session::CmdColoredMsg)
.Func(_SC("CmdColoredMe"), &Session::CmdColoredMe)
.Func(_SC("CmdColoredNotice"), &Session::CmdColoredNotice)
.Func(_SC("CmdCtcpRequest"), &Session::CmdCtcpRequest) .Func(_SC("CmdCtcpRequest"), &Session::CmdCtcpRequest)
.Func(_SC("CmdCtcpReply"), &Session::CmdCtcpReply) .Func(_SC("CmdCtcpReply"), &Session::CmdCtcpReply)
.Func(_SC("CmdNick"), &Session::CmdNick) .Func(_SC("CmdNick"), &Session::CmdNick)
@ -1278,6 +1213,9 @@ void Register_Session(Table & ircns)
.SquirrelFunc(_SC("CmdMsgF"), &Session::CmdMsgF) .SquirrelFunc(_SC("CmdMsgF"), &Session::CmdMsgF)
.SquirrelFunc(_SC("CmdMeF"), &Session::CmdMeF) .SquirrelFunc(_SC("CmdMeF"), &Session::CmdMeF)
.SquirrelFunc(_SC("CmdNoticeF"), &Session::CmdNoticeF) .SquirrelFunc(_SC("CmdNoticeF"), &Session::CmdNoticeF)
.SquirrelFunc(_SC("CmdColoredMsgF"), &Session::CmdColoredMsgF)
.SquirrelFunc(_SC("CmdColoredMeF"), &Session::CmdColoredMeF)
.SquirrelFunc(_SC("CmdColoredNoticeF"), &Session::CmdColoredNoticeF)
); );
} }

View File

@ -89,14 +89,6 @@ protected:
*/ */
void IsNotConnected() const; void IsNotConnected() const;
/* --------------------------------------------------------------------------------------------
* See whether this session is connected to a server or not.
*/
bool Connected() const
{
return (m_Session && irc_is_connected(m_Session));
}
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Validate a session instance used by an event and log an error if it's invalid. * Validate a session instance used by an event and log an error if it's invalid.
*/ */
@ -227,6 +219,14 @@ public:
*/ */
static SQInteger Typename(HSQUIRRELVM vm); static SQInteger Typename(HSQUIRRELVM vm);
/* --------------------------------------------------------------------------------------------
* Retrieve the actual session handle.
*/
irc_session_t * GetHandle() const
{
return m_Session;
}
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* See whether this session is valid. * See whether this session is valid.
*/ */
@ -569,11 +569,11 @@ public:
void Disconnect(); void Disconnect();
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* See whether the session is connected to a server. * See whether this session is connected to a server or not.
*/ */
bool IsConnected() bool IsConnected()
{ {
return Connected(); return (m_Session && irc_is_connected(m_Session));
} }
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
@ -774,6 +774,72 @@ public:
return irc_cmd_notice(m_Session, nch, text); return irc_cmd_notice(m_Session, nch, text);
} }
/* --------------------------------------------------------------------------------------------
* Send a message to a specific channel or privately to another nick.
*/
Int32 CmdColoredMsg(CSStr nch, CSStr text)
{
// Validate the connection status
ValidateConnection();
// Attempt to scan the specified message for color formatting
char * cmsg = irc_color_convert_to_mirc(text, IrcAllocMem);
// Validate the message
if (!cmsg)
{
STHROWF("Failed to convert the message colors");
}
// Send the resulted message and grab the result code
const int ret = irc_cmd_msg(m_Session, nch, cmsg);
// Free the memory used to convert the message
IrcFreeMem(cmsg);
// Return the resulted code
return ret;
}
/* --------------------------------------------------------------------------------------------
* Send a /me message (CTCP ACTION) to a specific channel or privately to another nick.
*/
Int32 CmdColoredMe(CSStr nch, CSStr text)
{
// Validate the connection status
ValidateConnection();
// Attempt to scan the specified message for color formatting
char * cmsg = irc_color_convert_to_mirc(text, IrcAllocMem);
// Validate the message
if (!cmsg)
{
STHROWF("Failed to convert the message colors");
}
// Send the resulted message and grab the result code
const int ret = irc_cmd_me(m_Session, nch, cmsg);
// Free the memory used to convert the message
IrcFreeMem(cmsg);
// Return the resulted code
return ret;
}
/* --------------------------------------------------------------------------------------------
* Send a notice to a specific channel or privately to another nick.
*/
Int32 CmdColoredNotice(CSStr nch, CSStr text)
{
// Validate the connection status
ValidateConnection();
// Attempt to scan the specified message for color formatting
char * cmsg = irc_color_convert_to_mirc(text, IrcAllocMem);
// Validate the message
if (!cmsg)
{
STHROWF("Failed to convert the message colors");
}
// Send the resulted message and grab the result code
const int ret = irc_cmd_notice(m_Session, nch, cmsg);
// Free the memory used to convert the message
IrcFreeMem(cmsg);
// Return the resulted code
return ret;
}
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Send a CTCP request to the specified user on the connected server. * Send a CTCP request to the specified user on the connected server.
*/ */
@ -927,6 +993,21 @@ public:
*/ */
static SQInteger CmdNoticeF(HSQUIRRELVM vm); static SQInteger CmdNoticeF(HSQUIRRELVM vm);
/* --------------------------------------------------------------------------------------------
* Send a colored message to a specific channel or privately to another nick.
*/
static SQInteger CmdColoredMsgF(HSQUIRRELVM vm);
/* --------------------------------------------------------------------------------------------
* Send a colored /me message (CTCP ACTION) to a specific channel or privately to another nick.
*/
static SQInteger CmdColoredMeF(HSQUIRRELVM vm);
/* --------------------------------------------------------------------------------------------
* Send a colored notice to a specific channel or privately to another nick.
*/
static SQInteger CmdColoredNoticeF(HSQUIRRELVM vm);
protected: protected:
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------