]>
Commit | Line | Data |
---|---|---|
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" | |
25 | #include "client.h" | |
26 | #include "ircd.h" | |
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 | { | |
48 | char *t = ch + 1; | |
49 | ||
50 | ch = strchr(ch, ' '); | |
51 | if (ch != NULL) | |
52 | { | |
53 | while (1) | |
54 | { | |
55 | char *next = strchr(t, ';'); | |
56 | char *eq = strchr(t, '='); | |
57 | ||
58 | if (next != NULL) | |
59 | { | |
60 | *next = '\0'; | |
61 | ||
62 | if (eq > next) | |
63 | eq = NULL; | |
64 | } | |
65 | ||
66 | if (eq != NULL) | |
67 | *eq++ = '\0'; | |
68 | ||
69 | if (*t && *t != ' ') | |
70 | msgbuf_append_tag(msgbuf, t, eq, 0); | |
71 | else | |
72 | break; | |
73 | ||
74 | if (next != NULL) | |
75 | t = next + 1; | |
76 | else | |
77 | break; | |
78 | } | |
79 | ||
80 | *ch++ = '\0'; | |
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]; | |
111 | for (i = 0; i < n_para; i++) | |
112 | msgbuf_append_para(msgbuf, parv[i]); | |
113 | ||
114 | return 0; | |
115 | } | |
116 | ||
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 | ||
131 | static void | |
132 | msgbuf_unparse_tags(char *buf, size_t buflen, struct MsgBuf *msgbuf, unsigned int capmask) | |
133 | { | |
134 | int i; | |
135 | ||
136 | if (!msgbuf_has_matching_tags(msgbuf, capmask)) | |
137 | return; | |
138 | ||
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 | ||
162 | void | |
163 | msgbuf_unparse_prefix(char *buf, size_t buflen, struct MsgBuf *msgbuf, unsigned int capmask) | |
164 | { | |
165 | memset(buf, 0, buflen); | |
166 | ||
167 | if (msgbuf->n_tags > 0) | |
168 | msgbuf_unparse_tags(buf, buflen, msgbuf, capmask); | |
169 | ||
170 | rb_snprintf_append(buf, buflen, ":%s ", msgbuf->origin != NULL ? msgbuf->origin : me.name); | |
171 | ||
172 | if (msgbuf->cmd != NULL) | |
173 | rb_snprintf_append(buf, buflen, "%s ", msgbuf->cmd); | |
174 | ||
175 | if (msgbuf->target != NULL) | |
176 | rb_snprintf_append(buf, buflen, "%s ", msgbuf->target); | |
177 | } | |
178 | ||
179 | /* | |
180 | * unparse a pure MsgBuf into a buffer. | |
181 | * if origin is NULL, me.name will be used. | |
182 | * cmd may not be NULL. | |
183 | * returns 0 on success, 1 on error. | |
184 | */ | |
185 | int | |
186 | msgbuf_unparse(char *buf, size_t buflen, struct MsgBuf *msgbuf, unsigned int capmask) | |
187 | { | |
188 | int i; | |
189 | ||
190 | msgbuf_unparse_prefix(buf, buflen, msgbuf, capmask); | |
191 | ||
192 | for (i = msgbuf->cmd != NULL ? 0 : 1; i < msgbuf->n_para; i++) | |
193 | { | |
194 | if (i == (msgbuf->n_para - 1)) | |
195 | { | |
196 | if (strchr(msgbuf->para[i], ' ') != NULL) | |
197 | rb_snprintf_append(buf, buflen, ":%s", msgbuf->para[i]); | |
198 | else | |
199 | rb_strlcat(buf, msgbuf->para[i], buflen); | |
200 | } | |
201 | else | |
202 | rb_strlcat(buf, msgbuf->para[i], buflen); | |
203 | } | |
204 | ||
205 | return 0; | |
206 | } | |
207 | ||
208 | /* | |
209 | * unparse a MsgBuf stem + format string into a buffer | |
210 | * if origin is NULL, me.name will be used. | |
211 | * cmd may not be NULL. | |
212 | * returns 0 on success, 1 on error. | |
213 | */ | |
214 | int | |
215 | msgbuf_vunparse_fmt(char *buf, size_t buflen, struct MsgBuf *head, unsigned int capmask, const char *fmt, va_list va) | |
216 | { | |
217 | char *ws; | |
218 | size_t prefixlen; | |
219 | ||
220 | msgbuf_unparse_prefix(buf, buflen, head, capmask); | |
221 | prefixlen = strlen(buf); | |
222 | ||
223 | ws = buf + prefixlen; | |
224 | vsnprintf(ws, buflen - prefixlen, fmt, va); | |
225 | ||
226 | return 0; | |
227 | } | |
228 | ||
229 | /* | |
230 | * unparse a MsgBuf stem + format string into a buffer (with va_list handling) | |
231 | * if origin is NULL, me.name will be used. | |
232 | * cmd may not be NULL. | |
233 | * returns 0 on success, 1 on error. | |
234 | */ | |
235 | int | |
236 | msgbuf_unparse_fmt(char *buf, size_t buflen, struct MsgBuf *head, unsigned int capmask, const char *fmt, ...) | |
237 | { | |
238 | va_list va; | |
239 | int res; | |
240 | ||
241 | va_start(va, fmt); | |
242 | res = msgbuf_vunparse_fmt(buf, buflen, head, capmask, fmt, va); | |
243 | va_end(va); | |
244 | ||
245 | return res; | |
246 | } |