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