User commands: handle nested substitution blocks when escaping message.
The UCMD specification doesn't mention nested blocks, and LinuxDC++ (and therefore presumably any other client based off the DC++ core) doesn't support them. But for future-proofing / clients that do support them, make sure the ucmd_escape_msg() function can handle nested blocks properly.
This commit is contained in:
parent
4cb80427fe
commit
1520026168
@ -32,7 +32,7 @@
|
|||||||
* terminator. Since unused bytes are set to zero, there should always be a
|
* terminator. Since unused bytes are set to zero, there should always be a
|
||||||
* terminator.
|
* terminator.
|
||||||
*/
|
*/
|
||||||
int ucmd_expand_tt(struct plugin_ucmd* ucmd, size_t size)
|
static int ucmd_expand_tt(struct plugin_ucmd* ucmd, size_t size)
|
||||||
{
|
{
|
||||||
if(size < ucmd->capacity) return 1;
|
if(size < ucmd->capacity) return 1;
|
||||||
|
|
||||||
@ -55,31 +55,44 @@ int ucmd_expand_tt(struct plugin_ucmd* ucmd, size_t size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Calculate the number of characters needed to store the escaped message. */
|
/* Calculate the number of characters needed to store the escaped message. */
|
||||||
size_t ucmd_msg_escape_length(const char* message)
|
static size_t ucmd_msg_escape_length(const char* message)
|
||||||
{
|
{
|
||||||
size_t extra = 0;
|
|
||||||
size_t i;
|
size_t i;
|
||||||
int insub = 0;
|
size_t extra = 0;
|
||||||
|
|
||||||
|
/* Keep track of substitution blocks. */
|
||||||
|
int substart = 0; /* Possible start of a block. */
|
||||||
|
int sublevel = 0; /* Number of nested blocks we are in. */
|
||||||
|
|
||||||
for(i = 0; message[i]; i++)
|
for(i = 0; message[i]; i++)
|
||||||
{
|
{
|
||||||
/* In a substitution block, no escaping needed. */
|
switch(message[i])
|
||||||
if(insub == 2)
|
|
||||||
{
|
{
|
||||||
if(message[i] == ']') insub = 0;
|
/* Character to escape. */
|
||||||
}
|
case ' ':
|
||||||
|
case '\n':
|
||||||
|
case '\\':
|
||||||
|
if(!sublevel) extra++;
|
||||||
|
substart = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
/* Not in a substitution block. */
|
/* Heading into a substitution block. */
|
||||||
else{
|
case '%':
|
||||||
/* A character that needs escaping. */
|
substart = 1;
|
||||||
if(message[i] == ' ' || message[i] == '\n' || message[i] == '\\'){
|
break;
|
||||||
extra++;
|
case '[':
|
||||||
insub = 0;
|
if(substart) sublevel++;
|
||||||
}
|
substart = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
/* See if we're heading into a substitution block. */
|
/* Coming out of a substitution block. */
|
||||||
else if(message[i] == '%') insub = 1;
|
case ']':
|
||||||
else if(message[i] == '[' && insub == 1) insub = 2;
|
substart = 0;
|
||||||
else insub = 0;
|
if(sublevel) sublevel --;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,63 +103,78 @@ size_t ucmd_msg_escape_length(const char* message)
|
|||||||
/* Escape a message that is being put into a user command. We cannot use
|
/* Escape a message that is being put into a user command. We cannot use
|
||||||
* adc_msg_escape for this as keyword substitutions should not be escaped while
|
* adc_msg_escape for this as keyword substitutions should not be escaped while
|
||||||
* general text should be. */
|
* general text should be. */
|
||||||
char* ucmd_msg_escape(const char* message)
|
static char* ucmd_msg_escape(const char* message)
|
||||||
{
|
{
|
||||||
/* Allocate the memory we need. */
|
/* Allocate the memory we need. */
|
||||||
size_t esclen = ucmd_msg_escape_length(message);
|
size_t esclen = ucmd_msg_escape_length(message);
|
||||||
char *escaped = hub_malloc(esclen + 1);
|
char *escaped = hub_malloc(esclen + 1);
|
||||||
|
if(escaped == NULL) return NULL;
|
||||||
|
|
||||||
|
/* Keep track of substitution blocks. */
|
||||||
|
int substart = 0; /* Possible start of a block. */
|
||||||
|
int sublevel = 0; /* Number of nested blocks we are in. */
|
||||||
|
|
||||||
int insub = 0;
|
|
||||||
size_t i;
|
size_t i;
|
||||||
size_t n = 0;
|
size_t n = 0;
|
||||||
|
|
||||||
for(i = 0; message[i]; i++)
|
for(i = 0; message[i]; i++)
|
||||||
{
|
|
||||||
/* In a substitution block, no escaping needed. */
|
|
||||||
if(insub == 2)
|
|
||||||
{
|
|
||||||
if(message[i] == ']') insub = 0;
|
|
||||||
escaped[n++] = message[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Not in a substitution block. */
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
switch(message[i])
|
switch(message[i])
|
||||||
{
|
{
|
||||||
/* Deal with characters that need escaping. */
|
/* Characters to escape provided we are *outside*
|
||||||
case '\\':
|
* any substitution blocks. */
|
||||||
escaped[n++] = '\\';
|
|
||||||
escaped[n++] = '\\';
|
|
||||||
insub = 0;
|
|
||||||
break;
|
|
||||||
case '\n':
|
|
||||||
escaped[n++] = '\\';
|
|
||||||
escaped[n++] = 'n';
|
|
||||||
insub = 0;
|
|
||||||
break;
|
|
||||||
case ' ':
|
case ' ':
|
||||||
|
if(sublevel)
|
||||||
|
{
|
||||||
|
escaped[n++] = ' ';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
escaped[n++] = '\\';
|
escaped[n++] = '\\';
|
||||||
escaped[n++] = 's';
|
escaped[n++] = 's';
|
||||||
insub = 0;
|
}
|
||||||
|
substart = 0;
|
||||||
break;
|
break;
|
||||||
|
case '\n':
|
||||||
/* Characters that start a substitution block. */
|
if(sublevel)
|
||||||
case '%':
|
{
|
||||||
escaped[n++] = message[i];
|
escaped[n++] = '\n';
|
||||||
insub = 1;
|
}
|
||||||
break;
|
else
|
||||||
case '[':
|
{
|
||||||
escaped[n++] = message[i];
|
escaped[n++] = '\\';
|
||||||
if(insub == 1) insub = 2;
|
escaped[n++] = 'n';
|
||||||
break;
|
substart = 0;
|
||||||
|
|
||||||
/* Standard character. */
|
|
||||||
default:
|
|
||||||
escaped[n++] = message[i];
|
|
||||||
insub = 0;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case '\\':
|
||||||
|
escaped[n++] = '\\';
|
||||||
|
if(!sublevel) escaped[n++] = '\\';
|
||||||
|
substart = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Heading into a substitution block. */
|
||||||
|
case '%':
|
||||||
|
escaped[n++] = '%';
|
||||||
|
substart = 1;
|
||||||
|
break;
|
||||||
|
case '[':
|
||||||
|
escaped[n++] = '[';
|
||||||
|
if(substart) sublevel++;
|
||||||
|
substart = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Coming out of a substitution block. */
|
||||||
|
case ']':
|
||||||
|
escaped[n++] = ']';
|
||||||
|
if(sublevel) sublevel--;
|
||||||
|
substart = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Normal character. */
|
||||||
|
default:
|
||||||
|
escaped[n++] = message[i];
|
||||||
|
substart = 0;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user