]>
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; | |
36 | char *parv[MAXPARA]; | |
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 AC |
80 | } |
81 | } | |
82 | ||
83 | /* skip any whitespace between tags and origin */ | |
84 | for (; *ch && *ch == ' '; ch++) | |
85 | ; | |
86 | ||
87 | if (*ch == ':') | |
88 | { | |
89 | ch++; | |
90 | msgbuf->origin = ch; | |
91 | ||
92 | char *end = strchr(ch, ' '); | |
93 | if (end == NULL) | |
94 | return 1; | |
95 | ||
96 | *end = '\0'; | |
97 | ||
98 | for (ch = end + 1; *ch && *ch == ' '; ch++) | |
99 | ; | |
100 | } | |
101 | ||
102 | if (*ch == '\0') | |
103 | return 1; | |
104 | ||
105 | n_para = rb_string_to_array(ch, parv, MAXPARA); | |
106 | if (n_para == 0) | |
107 | return 1; | |
108 | ||
109 | msgbuf->cmd = parv[0]; | |
66769bc1 | 110 | for (size_t i = 0; i < n_para; i++) |
a8e69f5d AC |
111 | msgbuf_append_para(msgbuf, parv[i]); |
112 | ||
113 | return 0; | |
114 | } | |
4a13e3f1 | 115 | |
4d2f2030 AC |
116 | static int |
117 | msgbuf_has_matching_tags(struct MsgBuf *msgbuf, unsigned int capmask) | |
118 | { | |
66769bc1 | 119 | for (size_t i = 0; i < msgbuf->n_tags; i++) |
4d2f2030 AC |
120 | { |
121 | if ((msgbuf->tags[i].capmask & capmask) != 0) | |
122 | return 1; | |
123 | } | |
124 | ||
125 | return 0; | |
126 | } | |
127 | ||
4a13e3f1 AC |
128 | static void |
129 | msgbuf_unparse_tags(char *buf, size_t buflen, struct MsgBuf *msgbuf, unsigned int capmask) | |
130 | { | |
4d2f2030 AC |
131 | if (!msgbuf_has_matching_tags(msgbuf, capmask)) |
132 | return; | |
133 | ||
4a13e3f1 AC |
134 | *buf = '@'; |
135 | ||
66769bc1 | 136 | for (size_t i = 0; i < msgbuf->n_tags; i++) |
4a13e3f1 AC |
137 | { |
138 | if ((msgbuf->tags[i].capmask & capmask) == 0) | |
139 | continue; | |
140 | ||
141 | if (i != 0) | |
142 | rb_strlcat(buf, ";", buflen); | |
143 | ||
144 | rb_strlcat(buf, msgbuf->tags[i].key, buflen); | |
145 | ||
146 | /* XXX properly handle escaping */ | |
147 | if (msgbuf->tags[i].value) | |
148 | { | |
149 | rb_strlcat(buf, "=", buflen); | |
150 | rb_strlcat(buf, msgbuf->tags[i].value, buflen); | |
151 | } | |
152 | } | |
153 | ||
154 | rb_strlcat(buf, " ", buflen); | |
155 | } | |
156 | ||
33085472 | 157 | void |
4a13e3f1 AC |
158 | msgbuf_unparse_prefix(char *buf, size_t buflen, struct MsgBuf *msgbuf, unsigned int capmask) |
159 | { | |
4a13e3f1 AC |
160 | memset(buf, 0, buflen); |
161 | ||
162 | if (msgbuf->n_tags > 0) | |
163 | msgbuf_unparse_tags(buf, buflen, msgbuf, capmask); | |
164 | ||
691adddd | 165 | rb_snprintf_append(buf, buflen, ":%s ", msgbuf->origin != NULL ? msgbuf->origin : me.name); |
5559c3cf AC |
166 | |
167 | if (msgbuf->cmd != NULL) | |
168 | rb_snprintf_append(buf, buflen, "%s ", msgbuf->cmd); | |
71c875fb AC |
169 | |
170 | if (msgbuf->target != NULL) | |
171 | rb_snprintf_append(buf, buflen, "%s ", msgbuf->target); | |
4a13e3f1 AC |
172 | } |
173 | ||
174 | /* | |
175 | * unparse a pure MsgBuf into a buffer. | |
176 | * if origin is NULL, me.name will be used. | |
177 | * cmd may not be NULL. | |
178 | * returns 0 on success, 1 on error. | |
179 | */ | |
180 | int | |
181 | msgbuf_unparse(char *buf, size_t buflen, struct MsgBuf *msgbuf, unsigned int capmask) | |
182 | { | |
4a13e3f1 AC |
183 | msgbuf_unparse_prefix(buf, buflen, msgbuf, capmask); |
184 | ||
66769bc1 | 185 | for (size_t i = msgbuf->cmd != NULL ? 0 : 1; i < msgbuf->n_para; i++) |
4a13e3f1 AC |
186 | { |
187 | if (i == (msgbuf->n_para - 1)) | |
188 | { | |
189 | if (strchr(msgbuf->para[i], ' ') != NULL) | |
190 | rb_snprintf_append(buf, buflen, ":%s", msgbuf->para[i]); | |
191 | else | |
192 | rb_strlcat(buf, msgbuf->para[i], buflen); | |
193 | } | |
194 | else | |
195 | rb_strlcat(buf, msgbuf->para[i], buflen); | |
196 | } | |
197 | ||
198 | return 0; | |
199 | } | |
8f64d325 AC |
200 | |
201 | /* | |
202 | * unparse a MsgBuf stem + format string into a buffer | |
203 | * if origin is NULL, me.name will be used. | |
204 | * cmd may not be NULL. | |
205 | * returns 0 on success, 1 on error. | |
206 | */ | |
207 | int | |
208 | msgbuf_vunparse_fmt(char *buf, size_t buflen, struct MsgBuf *head, unsigned int capmask, const char *fmt, va_list va) | |
209 | { | |
210 | char *ws; | |
211 | size_t prefixlen; | |
212 | ||
213 | msgbuf_unparse_prefix(buf, buflen, head, capmask); | |
214 | prefixlen = strlen(buf); | |
215 | ||
216 | ws = buf + prefixlen; | |
217 | vsnprintf(ws, buflen - prefixlen, fmt, va); | |
218 | ||
219 | return 0; | |
220 | } | |
221 | ||
222 | /* | |
223 | * unparse a MsgBuf stem + format string into a buffer (with va_list handling) | |
224 | * if origin is NULL, me.name will be used. | |
225 | * cmd may not be NULL. | |
226 | * returns 0 on success, 1 on error. | |
227 | */ | |
228 | int | |
229 | msgbuf_unparse_fmt(char *buf, size_t buflen, struct MsgBuf *head, unsigned int capmask, const char *fmt, ...) | |
230 | { | |
231 | va_list va; | |
232 | int res; | |
233 | ||
234 | va_start(va, fmt); | |
235 | res = msgbuf_vunparse_fmt(buf, buflen, head, capmask, fmt, va); | |
236 | va_end(va); | |
237 | ||
238 | return res; | |
239 | } |