]> jfr.im git - solanum.git/blobdiff - ircd/msgbuf.c
ircd: attach_conf: avoid clang static analysis warning
[solanum.git] / ircd / msgbuf.c
index e3f5389246fe09dd0b6c142830dd46586b5671a7..9d63d109fa3c66bef846a628f62eb1d04e4c8443 100644 (file)
@@ -22,6 +22,8 @@
 #include "stdinc.h"
 #include "ircd_defs.h"
 #include "msgbuf.h"
+#include "client.h"
+#include "ircd.h"
 
 /*
  * parse a message into a MsgBuf.
@@ -31,9 +33,8 @@ int
 msgbuf_parse(struct MsgBuf *msgbuf, char *line)
 {
        char *ch;
-       char *parv[MAXPARA];
+       char *parv[MAXPARA + 1];
        size_t n_para;
-       int i;
 
        /* skip any leading spaces */
        for (ch = line; *ch && *ch == ' '; ch++)
@@ -43,7 +44,7 @@ msgbuf_parse(struct MsgBuf *msgbuf, char *line)
 
        if (*ch == '@')
        {
-               char *t = ch++;
+               char *t = ch + 1;
 
                ch = strchr(ch, ' ');
                if (ch != NULL)
@@ -54,22 +55,31 @@ msgbuf_parse(struct MsgBuf *msgbuf, char *line)
                                char *eq = strchr(t, '=');
 
                                if (next != NULL)
+                               {
                                        *next = '\0';
 
-                               if (eq > next)
-                                       eq = NULL;
+                                       if (eq > next)
+                                               eq = NULL;
+                               }
 
                                if (eq != NULL)
-                                       *eq = '\0';
+                                       *eq++ = '\0';
 
-                               msgbuf_append_tag(msgbuf, t, eq);
+                               if (*t && *t != ' ')
+                                       msgbuf_append_tag(msgbuf, t, eq, 0);
+                               else
+                                       break;
 
                                if (next != NULL)
                                        t = next + 1;
                                else
                                        break;
                        }
+
+                       *ch++ = '\0';
                }
+               else
+                       ch = t;
        }
 
        /* skip any whitespace between tags and origin */
@@ -99,8 +109,123 @@ msgbuf_parse(struct MsgBuf *msgbuf, char *line)
                return 1;
 
        msgbuf->cmd = parv[0];
-       for (i = 0; i < n_para; i++)
+       for (size_t i = 0; i < n_para; i++)
                msgbuf_append_para(msgbuf, parv[i]);
 
        return 0;
 }
+
+static void
+msgbuf_unparse_tags(char *buf, size_t buflen, struct MsgBuf *msgbuf, unsigned int capmask)
+{
+       bool has_tags = false;
+
+       for (size_t i = 0; i < msgbuf->n_tags; i++)
+       {
+               if ((msgbuf->tags[i].capmask & capmask) == 0)
+                       continue;
+
+               if (has_tags) {
+                       rb_strlcat(buf, ";", buflen);
+               } else {
+                       *buf = '@';
+                       has_tags = true;
+               }
+
+               rb_strlcat(buf, msgbuf->tags[i].key, buflen);
+
+               /* XXX properly handle escaping */
+               if (msgbuf->tags[i].value)
+               {
+                       rb_strlcat(buf, "=", buflen);
+                       rb_strlcat(buf, msgbuf->tags[i].value, buflen);
+               }
+       }
+
+       if (has_tags)
+               rb_strlcat(buf, " ", buflen);
+}
+
+void
+msgbuf_unparse_prefix(char *buf, size_t buflen, struct MsgBuf *msgbuf, unsigned int capmask)
+{
+       memset(buf, 0, buflen);
+
+       if (msgbuf->n_tags > 0)
+               msgbuf_unparse_tags(buf, buflen, msgbuf, capmask);
+
+       rb_snprintf_append(buf, buflen, ":%s ", msgbuf->origin != NULL ? msgbuf->origin : me.name);
+
+       if (msgbuf->cmd != NULL)
+               rb_snprintf_append(buf, buflen, "%s ", msgbuf->cmd);
+
+       if (msgbuf->target != NULL)
+               rb_snprintf_append(buf, buflen, "%s ", msgbuf->target);
+}
+
+/*
+ * unparse a pure MsgBuf into a buffer.
+ * if origin is NULL, me.name will be used.
+ * cmd may not be NULL.
+ * returns 0 on success, 1 on error.
+ */
+int
+msgbuf_unparse(char *buf, size_t buflen, struct MsgBuf *msgbuf, unsigned int capmask)
+{
+       msgbuf_unparse_prefix(buf, buflen, msgbuf, capmask);
+
+       for (size_t i = msgbuf->cmd != NULL ? 0 : 1; i < msgbuf->n_para; i++)
+       {
+               if (i == (msgbuf->n_para - 1))
+               {
+                       if (strchr(msgbuf->para[i], ' ') != NULL)
+                               rb_snprintf_append(buf, buflen, ":%s", msgbuf->para[i]);
+                       else
+                               rb_strlcat(buf, msgbuf->para[i], buflen);
+               }
+               else
+                       rb_strlcat(buf, msgbuf->para[i], buflen);
+       }
+
+       return 0;
+}
+
+/*
+ * unparse a MsgBuf stem + format string into a buffer
+ * if origin is NULL, me.name will be used.
+ * cmd may not be NULL.
+ * returns 0 on success, 1 on error.
+ */
+int
+msgbuf_vunparse_fmt(char *buf, size_t buflen, struct MsgBuf *head, unsigned int capmask, const char *fmt, va_list va)
+{
+       char *ws;
+       size_t prefixlen;
+
+       msgbuf_unparse_prefix(buf, buflen, head, capmask);
+       prefixlen = strlen(buf);
+
+       ws = buf + prefixlen;
+       vsnprintf(ws, buflen - prefixlen, fmt, va);
+
+       return 0;
+}
+
+/*
+ * unparse a MsgBuf stem + format string into a buffer (with va_list handling)
+ * if origin is NULL, me.name will be used.
+ * cmd may not be NULL.
+ * returns 0 on success, 1 on error.
+ */
+int
+msgbuf_unparse_fmt(char *buf, size_t buflen, struct MsgBuf *head, unsigned int capmask, const char *fmt, ...)
+{
+       va_list va;
+       int res;
+
+       va_start(va, fmt);
+       res = msgbuf_vunparse_fmt(buf, buflen, head, capmask, fmt, va);
+       va_end(va);
+
+       return res;
+}