]>
Commit | Line | Data |
---|---|---|
a8e69f5d AC |
1 | /* |
2 | * charybdis - an advanced ircd. | |
3 | * Copyright (c) 2016 William Pitcock <nenolod@dereferenced.org>. | |
4 | * | |
5 | * Permission to use, copy, modify, and/or distribute this software for any | |
6 | * purpose with or without fee is hereby granted, provided that the above | |
7 | * copyright notice and this permission notice is present in all copies. | |
8 | * | |
9 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |
10 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
11 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
12 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, | |
13 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
14 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
15 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
16 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
17 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | |
18 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
19 | * POSSIBILITY OF SUCH DAMAGE. | |
20 | */ | |
21 | ||
22 | #include "stdinc.h" | |
23 | #include "ircd_defs.h" | |
24 | #include "msgbuf.h" | |
691adddd AC |
25 | #include "client.h" |
26 | #include "ircd.h" | |
a8e69f5d AC |
27 | |
28 | /* | |
29 | * parse a message into a MsgBuf. | |
30 | * returns 0 on success, 1 on error. | |
31 | */ | |
32 | int | |
33 | msgbuf_parse(struct MsgBuf *msgbuf, char *line) | |
34 | { | |
35 | char *ch; | |
3656fa83 | 36 | char *parv[MAXPARA + 1]; |
a8e69f5d | 37 | size_t n_para; |
a8e69f5d AC |
38 | |
39 | /* skip any leading spaces */ | |
40 | for (ch = line; *ch && *ch == ' '; ch++) | |
41 | ; | |
42 | ||
43 | msgbuf_init(msgbuf); | |
44 | ||
45 | if (*ch == '@') | |
46 | { | |
08006c16 | 47 | char *t = ch + 1; |
a8e69f5d AC |
48 | |
49 | ch = strchr(ch, ' '); | |
50 | if (ch != NULL) | |
51 | { | |
269dd686 | 52 | while (1) |
a8e69f5d AC |
53 | { |
54 | char *next = strchr(t, ';'); | |
55 | char *eq = strchr(t, '='); | |
56 | ||
57 | if (next != NULL) | |
08006c16 | 58 | { |
a8e69f5d AC |
59 | *next = '\0'; |
60 | ||
08006c16 AC |
61 | if (eq > next) |
62 | eq = NULL; | |
63 | } | |
a8e69f5d AC |
64 | |
65 | if (eq != NULL) | |
08006c16 | 66 | *eq++ = '\0'; |
a8e69f5d | 67 | |
08006c16 | 68 | if (*t && *t != ' ') |
d670fe52 | 69 | msgbuf_append_tag(msgbuf, t, eq, 0); |
08006c16 AC |
70 | else |
71 | break; | |
269dd686 AC |
72 | |
73 | if (next != NULL) | |
74 | t = next + 1; | |
75 | else | |
76 | break; | |
a8e69f5d | 77 | } |
08006c16 AC |
78 | |
79 | *ch++ = '\0'; | |
a8e69f5d | 80 | } |
6d16f66b AJ |
81 | else |
82 | ch = t; | |
a8e69f5d AC |
83 | } |
84 | ||
85 | /* skip any whitespace between tags and origin */ | |
86 | for (; *ch && *ch == ' '; ch++) | |
87 | ; | |
88 | ||
89 | if (*ch == ':') | |
90 | { | |
91 | ch++; | |
92 | msgbuf->origin = ch; | |
93 | ||
94 | char *end = strchr(ch, ' '); | |
95 | if (end == NULL) | |
96 | return 1; | |
97 | ||
98 | *end = '\0'; | |
99 | ||
100 | for (ch = end + 1; *ch && *ch == ' '; ch++) | |
101 | ; | |
102 | } | |
103 | ||
104 | if (*ch == '\0') | |
105 | return 1; | |
106 | ||
107 | n_para = rb_string_to_array(ch, parv, MAXPARA); | |
108 | if (n_para == 0) | |
109 | return 1; | |
110 | ||
111 | msgbuf->cmd = parv[0]; | |
66769bc1 | 112 | for (size_t i = 0; i < n_para; i++) |
a8e69f5d AC |
113 | msgbuf_append_para(msgbuf, parv[i]); |
114 | ||
115 | return 0; | |
116 | } | |
4a13e3f1 AC |
117 | |
118 | static void | |
119 | msgbuf_unparse_tags(char *buf, size_t buflen, struct MsgBuf *msgbuf, unsigned int capmask) | |
120 | { | |
57dd2c6a | 121 | bool has_tags = false; |
4a13e3f1 | 122 | |
66769bc1 | 123 | for (size_t i = 0; i < msgbuf->n_tags; i++) |
4a13e3f1 AC |
124 | { |
125 | if ((msgbuf->tags[i].capmask & capmask) == 0) | |
126 | continue; | |
127 | ||
57dd2c6a | 128 | if (has_tags) { |
4a13e3f1 | 129 | rb_strlcat(buf, ";", buflen); |
57dd2c6a SA |
130 | } else { |
131 | *buf = '@'; | |
132 | has_tags = true; | |
133 | } | |
4a13e3f1 AC |
134 | |
135 | rb_strlcat(buf, msgbuf->tags[i].key, buflen); | |
136 | ||
137 | /* XXX properly handle escaping */ | |
138 | if (msgbuf->tags[i].value) | |
139 | { | |
140 | rb_strlcat(buf, "=", buflen); | |
141 | rb_strlcat(buf, msgbuf->tags[i].value, buflen); | |
142 | } | |
143 | } | |
144 | ||
57dd2c6a SA |
145 | if (has_tags) |
146 | rb_strlcat(buf, " ", buflen); | |
4a13e3f1 AC |
147 | } |
148 | ||
33085472 | 149 | void |
4a13e3f1 AC |
150 | msgbuf_unparse_prefix(char *buf, size_t buflen, struct MsgBuf *msgbuf, unsigned int capmask) |
151 | { | |
4a13e3f1 AC |
152 | memset(buf, 0, buflen); |
153 | ||
154 | if (msgbuf->n_tags > 0) | |
155 | msgbuf_unparse_tags(buf, buflen, msgbuf, capmask); | |
156 | ||
691adddd | 157 | rb_snprintf_append(buf, buflen, ":%s ", msgbuf->origin != NULL ? msgbuf->origin : me.name); |
5559c3cf AC |
158 | |
159 | if (msgbuf->cmd != NULL) | |
160 | rb_snprintf_append(buf, buflen, "%s ", msgbuf->cmd); | |
71c875fb AC |
161 | |
162 | if (msgbuf->target != NULL) | |
163 | rb_snprintf_append(buf, buflen, "%s ", msgbuf->target); | |
4a13e3f1 AC |
164 | } |
165 | ||
166 | /* | |
167 | * unparse a pure MsgBuf into a buffer. | |
168 | * if origin is NULL, me.name will be used. | |
169 | * cmd may not be NULL. | |
170 | * returns 0 on success, 1 on error. | |
171 | */ | |
172 | int | |
173 | msgbuf_unparse(char *buf, size_t buflen, struct MsgBuf *msgbuf, unsigned int capmask) | |
174 | { | |
4a13e3f1 AC |
175 | msgbuf_unparse_prefix(buf, buflen, msgbuf, capmask); |
176 | ||
66769bc1 | 177 | for (size_t i = msgbuf->cmd != NULL ? 0 : 1; i < msgbuf->n_para; i++) |
4a13e3f1 AC |
178 | { |
179 | if (i == (msgbuf->n_para - 1)) | |
180 | { | |
181 | if (strchr(msgbuf->para[i], ' ') != NULL) | |
182 | rb_snprintf_append(buf, buflen, ":%s", msgbuf->para[i]); | |
183 | else | |
184 | rb_strlcat(buf, msgbuf->para[i], buflen); | |
185 | } | |
186 | else | |
187 | rb_strlcat(buf, msgbuf->para[i], buflen); | |
188 | } | |
189 | ||
190 | return 0; | |
191 | } | |
8f64d325 AC |
192 | |
193 | /* | |
194 | * unparse a MsgBuf stem + format string into a buffer | |
195 | * if origin is NULL, me.name will be used. | |
196 | * cmd may not be NULL. | |
197 | * returns 0 on success, 1 on error. | |
198 | */ | |
199 | int | |
200 | msgbuf_vunparse_fmt(char *buf, size_t buflen, struct MsgBuf *head, unsigned int capmask, const char *fmt, va_list va) | |
201 | { | |
202 | char *ws; | |
203 | size_t prefixlen; | |
204 | ||
205 | msgbuf_unparse_prefix(buf, buflen, head, capmask); | |
206 | prefixlen = strlen(buf); | |
207 | ||
208 | ws = buf + prefixlen; | |
209 | vsnprintf(ws, buflen - prefixlen, fmt, va); | |
210 | ||
211 | return 0; | |
212 | } | |
213 | ||
214 | /* | |
215 | * unparse a MsgBuf stem + format string into a buffer (with va_list handling) | |
216 | * if origin is NULL, me.name will be used. | |
217 | * cmd may not be NULL. | |
218 | * returns 0 on success, 1 on error. | |
219 | */ | |
220 | int | |
221 | msgbuf_unparse_fmt(char *buf, size_t buflen, struct MsgBuf *head, unsigned int capmask, const char *fmt, ...) | |
222 | { | |
223 | va_list va; | |
224 | int res; | |
225 | ||
226 | va_start(va, fmt); | |
227 | res = msgbuf_vunparse_fmt(buf, buflen, head, capmask, fmt, va); | |
228 | va_end(va); | |
229 | ||
230 | return res; | |
231 | } |