diff --git a/include/msgbuf.h b/include/msgbuf.h index 9bc34bf7..085569ab 100644 --- a/include/msgbuf.h +++ b/include/msgbuf.h @@ -38,6 +38,7 @@ struct MsgBuf { const char *origin; /* the origin of the message (or NULL) */ const char *target; /* the target of the message (either NULL, or custom defined) */ const char *cmd; /* the cmd/verb of the message (either NULL, or para[0]) */ + char *endp; /* one past the end of the original array */ size_t n_para; /* the number of parameters (always at least 1 if a full message) */ const char *para[MAXPARA]; /* parameters vector (starting with cmd as para[0]) */ @@ -76,6 +77,12 @@ struct MsgBuf_cache { */ int msgbuf_parse(struct MsgBuf *msgbuf, char *line); +/* + * Unparse the tail of a msgbuf perfectly, preserving framing details + * msgbuf->para[n] will reach to the end of the line + */ +void msgbuf_reconstruct_tail(struct MsgBuf *msgbuf, size_t n); + /* * unparse a pure MsgBuf into a buffer. * if origin is NULL, me.name will be used. diff --git a/ircd/msgbuf.c b/ircd/msgbuf.c index a92c07f2..fe4e8e25 100644 --- a/ircd/msgbuf.c +++ b/ircd/msgbuf.c @@ -154,6 +154,7 @@ msgbuf_parse(struct MsgBuf *msgbuf, char *line) if (*ch == '\0') return 2; + msgbuf->endp = &ch[strlen(ch)]; msgbuf->n_para = rb_string_to_array(ch, (char **)msgbuf->para, MAXPARA); if (msgbuf->n_para == 0) return 3; @@ -162,6 +163,40 @@ msgbuf_parse(struct MsgBuf *msgbuf, char *line) return 0; } +/* + * Unparse the tail of a msgbuf perfectly, preserving framing details + * msgbuf->para[n] will reach to the end of the line + */ + +void +msgbuf_reconstruct_tail(struct MsgBuf *msgbuf, size_t n) +{ + if (msgbuf->endp == NULL || n > msgbuf->n_para) + return; + + char *c; + const char *c_; + + if (n == 0) + c_ = msgbuf->para[n]; + else + c_ = msgbuf->para[n-1] + strlen(msgbuf->para[n-1]) + 1; + + if (n == msgbuf->n_para && c_ == msgbuf->endp) + return; + + msgbuf->para[n] = c_; + /* promote to non-const. msgbuf->endp witnesses that this is allowed */ + c = msgbuf->endp - (msgbuf->endp - c_); + + for ( ; c < msgbuf->endp; c++) + { + if (*c == '\0') + *c = ' '; + } +} + + /* * Unparse msgbuf tags into a buffer * returns the length of the tags written diff --git a/modules/m_alias.c b/modules/m_alias.c index fdc2a8f1..b8f1b035 100644 --- a/modules/m_alias.c +++ b/modules/m_alias.c @@ -114,7 +114,7 @@ m_alias(struct MsgBuf *msgbuf, struct Client *client_p, struct Client *source_p, { struct Client *target_p; struct alias_entry *aptr = rb_dictionary_retrieve(alias_dict, msgbuf->cmd); - char *p, *str; + char *p; if(aptr == NULL) { @@ -151,8 +151,8 @@ m_alias(struct MsgBuf *msgbuf, struct Client *client_p, struct Client *source_p, return; } - str = reconstruct_parv(parc - 1, &parv[1]); - if(EmptyString(str)) + msgbuf_reconstruct_tail(msgbuf, 1); + if(EmptyString(parv[1])) { sendto_one(client_p, form_str(ERR_NOTEXTTOSEND), me.name, target_p->name); return; @@ -161,5 +161,5 @@ m_alias(struct MsgBuf *msgbuf, struct Client *client_p, struct Client *source_p, sendto_one(target_p, ":%s PRIVMSG %s :%s", get_id(client_p, target_p), p != NULL ? aptr->target : get_id(target_p, target_p), - str); + parv[1]); } diff --git a/tests/msgbuf_parse1.c b/tests/msgbuf_parse1.c index 7712c6a1..b10b338f 100644 --- a/tests/msgbuf_parse1.c +++ b/tests/msgbuf_parse1.c @@ -3297,6 +3297,49 @@ static void unescape_8bit(void) } } +static struct MsgBuf *reconstruct_tail_prep(char *line, size_t n) +{ + static struct MsgBuf msgbuf; + msgbuf_init(&msgbuf); + msgbuf_parse(&msgbuf, line); + msgbuf_reconstruct_tail(&msgbuf, n); + return &msgbuf; +} + +static void reconstruct_tail(void) +{ + struct MsgBuf *mb; + mb = reconstruct_tail_prep((char[]){"CMD P1"}, 2); + is_string("CMD", mb->para[0], MSG); + is_string("P1", mb->para[1], MSG); + + mb = reconstruct_tail_prep((char[]){"CMD P1 P2"}, 2); + is_string("CMD", mb->para[0], MSG); + is_string("P1", mb->para[1], MSG); + is_string("P2", mb->para[2], MSG); + + mb = reconstruct_tail_prep((char[]){" CMD P1 P2 :P3"}, 0); + is_string("CMD P1 P2 :P3", mb->para[0], MSG); + + mb = reconstruct_tail_prep((char[]){"CMD P1 P2 :P3"}, 1); + is_string(" P1 P2 :P3", mb->para[1], MSG); + + mb = reconstruct_tail_prep((char[]){"CMD P1 P2"}, 1); + is_string("P1 P2", mb->para[1], MSG); + + mb = reconstruct_tail_prep((char[]){"CMD P1 P2 "}, 2); + is_string(" P2 ", mb->para[2], MSG); + + mb = reconstruct_tail_prep((char[]){"CMD P1 "}, 2); + is_string(" ", mb->para[2], MSG); + + mb = reconstruct_tail_prep((char[]){"CMD P1 :"}, 2); + is_string(":", mb->para[2], MSG); + + mb = reconstruct_tail_prep((char[]){"CMD P1 :"}, 2); + is_string(" :", mb->para[2], MSG); +} + int main(int argc, char *argv[]) { memset(&me, 0, sizeof(me)); @@ -3411,5 +3454,7 @@ int main(int argc, char *argv[]) unescape_8bit(); + reconstruct_tail(); + return 0; }