server: early return on ban detection
[rb-79.git] / multipart.c
blob7186480ea0bf713b5b746bbe0393be599d1eac78
1 /*
2 * Copyright (c) 2017-2020, De Rais <derais@cock.li>
4 * Permission to use, copy, modify, and/or distribute this software for
5 * any purpose with or without fee is hereby granted, provided that the
6 * above copyright notice and this permission notice appear in all
7 * copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16 * PERFORMANCE OF THIS SOFTWARE.
18 #include <stdint.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <time.h>
23 #include <gmime/gmime.h>
25 #include "macros.h"
26 #include "rb79.h"
28 /* User data for callback */
29 struct gmime_cb_data {
30 /* */
31 struct post_cmd pc;
32 int had_error;
35 /* Initialize GMime */
36 int
37 setup_multipart(void)
39 g_mime_init(0);
41 return 0;
44 /* Callback to add things - get stuff out of mime so we can strcmp() it */
45 static void
46 record_argument(GMimeObject *parent, GMimeObject *part, gpointer user_data)
48 UNUSED(parent);
49 struct gmime_cb_data *d = (struct gmime_cb_data *) user_data;
51 if (!(GMIME_IS_PART(part))) {
52 return;
55 if (GMIME_IS_MESSAGE_PART(part)) {
56 GMimeMessage *m = g_mime_message_part_get_message(
57 (GMimeMessagePart *) part);
59 g_mime_message_foreach(m, record_argument, user_data);
62 GMimePart *p = (GMimePart *) part;
63 const char *name = g_mime_object_get_content_disposition_parameter(part,
64 "name");
66 if (!name) {
67 return;
70 char **set_this = 0;
71 size_t *set_this_len = 0;
73 if (!strcmp(name, "action")) {
74 set_this = &d->pc.raw.action;
75 set_this_len = &d->pc.raw.action_len;
76 } else if (!strcmp(name, "board")) {
77 set_this = &d->pc.raw.board;
78 set_this_len = &d->pc.raw.board_len;
79 } else if (!strcmp(name, "thread")) {
80 set_this = &d->pc.raw.thread;
81 set_this_len = &d->pc.raw.thread_len;
82 } else if (!strcmp(name, "post")) {
83 set_this = &d->pc.raw.post;
84 set_this_len = &d->pc.raw.post_len;
85 } else if (!strcmp(name, "name")) {
86 set_this = &d->pc.raw.name;
87 set_this_len = &d->pc.raw.name_len;
88 } else if (!strcmp(name, "email")) {
89 set_this = &d->pc.raw.email;
90 set_this_len = &d->pc.raw.email_len;
91 } else if (!strcmp(name, "subject")) {
92 set_this = &d->pc.raw.subject;
93 set_this_len = &d->pc.raw.subject_len;
94 } else if (!strcmp(name, "comment")) {
95 set_this = &d->pc.raw.comment;
96 set_this_len = &d->pc.raw.comment_len;
97 } else if (!strcmp(name, "comment")) {
98 set_this = &d->pc.raw.comment;
99 set_this_len = &d->pc.raw.comment_len;
100 } else if (!strcmp(name, "challengeid")) {
101 set_this = &d->pc.raw.challenge_id;
102 set_this_len = &d->pc.raw.challenge_id_len;
103 } else if (!strcmp(name, "challengeresponse")) {
104 set_this = &d->pc.raw.challenge_response;
105 set_this_len = &d->pc.raw.challenge_response_len;
106 } else if (!strcmp(name, "file")) {
107 set_this = &d->pc.raw.file_contents;
108 set_this_len = &d->pc.raw.file_contents_len;
109 free(d->pc.raw.file_name);
110 d->pc.raw.file_name = 0;
111 d->pc.raw.file_name_len = 0;
112 const char *file_name = g_mime_part_get_filename(p);
114 if (!file_name) {
115 file_name = "[No filename provided]";
118 if (!(d->pc.raw.file_name = strdup(file_name))) {
119 ERROR_MESSAGE("strdup");
120 d->had_error = 1;
122 return;
125 d->pc.raw.file_name_len = strlen(d->pc.raw.file_name);
128 if (!set_this) {
129 return;
132 GMimeDataWrapper *w = 0;
133 GMimeStream *s = 0;
134 size_t l = 0;
135 char *buf = 0;
137 if (!(w = g_mime_part_get_content_object(p))) {
138 d->had_error = 1;
140 return;
143 if (!(s = g_mime_data_wrapper_get_stream(w))) {
144 d->had_error = 1;
146 return;
149 l = g_mime_stream_length(s);
151 if (l + 1 < l) {
152 ERROR_MESSAGE("overflow");
153 d->had_error = 1;
155 return;
158 if (!(buf = malloc(l + 1))) {
159 PERROR_MESSAGE("malloc");
160 d->had_error = 1;
162 return;
165 g_mime_stream_read(s, buf, l);
166 buf[l] = '\0';
167 free(*set_this);
168 *set_this = buf;
169 *set_this_len = l;
171 /* Don't g_object_unref here. I think. */
175 * This is segmented off because, one day, I want to go full NIH.
176 * No pre/postconditions until then.
179 multipart_decompose(const char *full_data, size_t full_data_len, struct
180 post_cmd *post_cmd)
182 GMimeStream *s = 0;
183 GMimeParser *p = 0;
184 GMimeMessage *m = 0;
185 int had_error = 0;
186 int ret = -1;
187 struct gmime_cb_data d = { 0 };
189 memcpy(&d, post_cmd, sizeof *post_cmd);
191 if (!(s = g_mime_stream_mem_new_with_buffer(full_data,
192 full_data_len))) {
193 ERROR_MESSAGE("Some kind of GMime error");
194 goto done;
197 if (!(p = g_mime_parser_new_with_stream(s))) {
198 ERROR_MESSAGE("Some kind of GMime error");
199 goto done;
202 if (!(m = g_mime_parser_construct_message(p))) {
203 ERROR_MESSAGE("Some kind of GMime error");
204 goto done;
207 g_mime_message_foreach(m, record_argument, (gpointer) & d);
209 if (had_error) {
210 ERROR_MESSAGE("Some kind of GMime error");
211 goto done;
214 memcpy(post_cmd, &d.pc, sizeof *post_cmd);
215 ret = 0;
216 done:
218 if (s) {
219 g_object_unref(s);
222 if (p) {
223 g_object_unref(p);
226 if (m) {
227 g_object_unref(m);
230 return ret;
233 /* Tear down GMime */
235 clean_multipart(void)
237 g_mime_shutdown();
239 return 0;