server: implement -s bans
[rb-79.git] / rb79-moderate-post.c
blobbaadb9a65f862a6bfabf778c48f4f98fac801590
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 <errno.h>
19 #include <locale.h>
20 #include <stdint.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <unistd.h>
25 #include <sodium.h>
27 #include "macros.h"
28 #include "rb79.h"
30 #include "config.h"
32 const char *program_name = "rb79-moderate-post";
34 /* Show usage message, do not exit */
35 void
36 usage(void)
38 size_t len = strlen(program_name);
40 printf("Usage: %s -b board-name\n", program_name);
41 printf(" %*s -p post-id\n", (int) len, "");
42 printf(" %*s [ -a message ]\n", (int) len, "");
43 printf(" %*s [ -s | -S ] # Sticky or unsticky\n", (int) len,
44 "");
45 printf(" %*s [ -c | -C ] # Close or unclose\n", (int) len, "");
48 /* Do the thing */
49 int
50 main(int argc, char **argv)
52 int ret = EINVAL;
53 struct configuration conf = { 0 };
54 int opt = 0;
55 const char *b_arg = 0;
56 size_t board_idx = 0;
57 const char *p_arg = 0;
58 uintmax_t post_id = 0;
59 const char *a_arg = 0;
60 uint_fast8_t must_sticky = 0;
61 uint_fast8_t must_unsticky = 0;
62 uint_fast8_t must_close = 0;
63 uint_fast8_t must_unclose = 0;
64 uint_fast8_t actually_is_op = 0;
66 setlocale(LC_ALL, "");
68 /* Parse options */
69 while ((opt = getopt(argc, argv, "b:p:a:sScC")) != -1) {
70 switch (opt) {
71 case 'b':
73 if (b_arg) {
74 ERROR_MESSAGE("-b already specified");
75 goto done;
78 b_arg = optarg;
79 break;
80 case 'p':
82 if (p_arg) {
83 ERROR_MESSAGE("-p already specified");
84 goto done;
87 p_arg = optarg;
88 break;
89 case 'a':
91 if (a_arg) {
92 ERROR_MESSAGE("-a already specified");
93 goto done;
96 a_arg = optarg;
97 break;
98 case 's':
99 must_sticky = 1;
100 break;
101 case 'S':
102 must_unsticky = 1;
103 break;
104 case 'c':
105 must_close = 1;
106 break;
107 case 'C':
108 must_unclose = 1;
109 break;
110 default:
111 usage();
112 goto done;
116 if (!b_arg ||
117 !p_arg) {
118 usage();
119 goto done;
122 if (must_unsticky &&
123 must_sticky) {
124 ERROR_MESSAGE("-s and -S are mutually exclusive");
125 goto done;
128 if (must_unclose &&
129 must_close) {
130 ERROR_MESSAGE("-c and -C are mutually exclusive");
131 goto done;
134 conf = (struct configuration) {
135 /* */
136 .static_www_folder = static_www_folder, /* */
137 .work_path = work_path, /* */
138 .temp_dir_template = temp_dir_template, /* */
139 .trip_salt = trip_salt, /* */
140 .trip_salt_len = strlen(trip_salt), /* */
141 .boards = boards, /* */
142 .boards_num = NUM_OF(boards), /* */
143 .max_form_data_size = max_form_data_size, /* */
144 .max_file_size = max_file_size, /* */
145 .max_text_len = max_text_len, /* */
146 .filetypes = filetypes, /* */
147 .filetypes_num = NUM_OF(filetypes), /* */
148 .file_description_prog = file_description_prog, /* */
149 .headers = headers, /* */
150 .headers_num = NUM_OF(headers), /* */
151 .challenges = challenges, /* */
152 .challenges_num = NUM_OF(challenges), /* */
153 .wordfilter_inputs = wordfilter_inputs, /* */
154 .wordfilter_inputs_num = NUM_OF(wordfilter_inputs), /* */
155 .forbidden_inputs = forbidden_inputs, /* */
156 .forbidden_inputs_num = NUM_OF(forbidden_inputs), /* */
159 /* Interpret board */
160 board_idx = (size_t) -1;
162 for (size_t j = 0; j < conf.boards_num; ++j) {
163 if (!strcmp(conf.boards[j].name, b_arg)) {
164 board_idx = j;
168 if (board_idx == (size_t) -1) {
169 ERROR_MESSAGE("No board \"%s\" known", b_arg);
170 goto done;
173 /* Interpret post */
174 errno = 0;
175 post_id = strtoull(p_arg, 0, 0);
177 if (errno) {
178 ret = errno;
179 PERROR_MESSAGE("strtoull");
180 goto done;
183 /* Set up a minimal part of the system */
184 if (setup_locks(&conf) < 0) {
185 goto done;
188 if (setup_dbs(&conf) < 0) {
189 goto done;
192 if (setup_write_thread(&conf) < 0) {
193 goto done;
196 if (db_is_op(board_idx, post_id, &actually_is_op) < 0) {
197 goto done;
200 if (!actually_is_op &&
201 (must_sticky ||
202 must_unsticky ||
203 must_close ||
204 must_unclose)) {
205 ERROR_MESSAGE("Board /%s/, post %ju is not an OP, "
206 "cannot apply -s, -S, -C, -c",
207 conf.boards[board_idx].name,
208 post_id);
209 goto done;
212 if (db_moderate_post(board_idx, post_id, a_arg, (must_sticky ||
213 must_unsticky),
214 must_sticky, (must_close ||
215 must_unclose),
216 must_close) < 0) {
217 goto done;
220 util_rebuild(&conf);
221 ret = 0;
222 done:
223 clean_locks();
224 clean_dbs();
225 clean_write_thread();
227 return ret;