server: let some boards be exempt from /recent
[rb-79.git] / rb79-view-thread.c
blobef941ce7ee1365f5f70351460946e20bff7e176d
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-view-thread";
34 /* Options */
35 static uint_fast8_t use_color = 1;
37 /* Show usage message, do not exit */
38 void
39 usage(void)
41 size_t len = strlen(program_name);
43 printf("Usage: %s -b board-name\n", program_name);
44 printf(" %*s -t thread-id\n", (int) len, "");
45 printf(" %*s [ -C ] # Do not use color\n", (int) len, "");
48 /* Print out enough of a post to give the mod information */
49 int
50 print_post(struct prepared_post *p, FILE *f, uint_fast8_t is_op, uint_fast8_t
51 is_summary, uint_fast8_t is_recent, const char *board_name, uintmax_t
52 in_thread,
53 uintmax_t total_posts_in_thread, uint_fast8_t hr_before)
55 char *time_str = util_iso8601_from_time_t(p->now);
56 unsigned char out_hash[9] = { 0 };
58 UNUSED(is_summary);
59 UNUSED(is_recent);
60 UNUSED(hr_before);
61 UNUSED(board_name);
62 UNUSED(in_thread);
63 UNUSED(total_posts_in_thread);
65 if (crypto_generichash(out_hash, 9, (const unsigned char *) p->ip,
66 p->ip_len, 0, 0)) {
67 PERROR_MESSAGE("crypto_generichash_init");
68 goto done;
71 if (is_op) {
72 fprintf(f, "--------------------------------------\n");
75 fprintf(f, " ");
77 if (use_color) {
78 fprintf(f, "\033[48;2;%d;%d;%dm ", 0xff & out_hash[0], 0xff &
79 out_hash[1], 0xff & out_hash[2]);
80 fprintf(f, "\033[48;2;%d;%d;%dm ", 0xff & out_hash[3], 0xff &
81 out_hash[4], 0xff & out_hash[5]);
82 fprintf(f, "\033[48;2;%d;%d;%dm ", 0xff & out_hash[6], 0xff &
83 out_hash[7], 0xff & out_hash[8]);
84 fprintf(f, "\033[0m");
85 } else {
86 fprintf(f, " ");
89 fprintf(f, " %s%*s", p->ip, (int) (20 > p->ip_len ? 20 - p->ip_len : 1),
90 " ");
91 fprintf(f, "%s ", UBSAFES(time_str));
92 fprintf(f, "No. %ju\n", p->id);
94 if (p->file_name) {
95 fprintf(f, " [ File: %s ]\n", p->file_name);
98 fprintf(f, " ");
100 if (p->comment_len > 40) {
101 fprintf(f, "%.*s...", 37, p->comment);
102 } else if (p->comment_len) {
103 fprintf(f, "%s", p->comment);
106 fprintf(f, "\n");
107 fprintf(f, "--------------------------------------\n");
108 done:
109 free(time_str);
111 return 0;
114 /* Do the thing */
116 main(int argc, char **argv)
118 int ret = EINVAL;
119 struct configuration conf = { 0 };
120 int opt = 0;
121 const char *b_arg = 0;
122 size_t board_idx = 0;
123 const char *t_arg = 0;
124 uintmax_t thread_id = 0;
126 setlocale(LC_ALL, "");
128 /* Parse options */
129 while ((opt = getopt(argc, argv, "b:t:C")) != -1) {
130 switch (opt) {
131 case 'b':
133 if (b_arg) {
134 ERROR_MESSAGE("-b already specified");
135 goto done;
138 b_arg = optarg;
139 break;
140 case 't':
142 if (t_arg) {
143 ERROR_MESSAGE("-t already specified");
144 goto done;
147 t_arg = optarg;
148 break;
149 case 'C':
150 use_color = 0;
151 break;
152 default:
153 usage();
154 goto done;
158 if (!b_arg ||
159 !t_arg) {
160 usage();
161 goto done;
164 conf = (struct configuration) {
165 /* */
166 .static_www_folder = static_www_folder, /* */
167 .work_path = work_path, /* */
168 .temp_dir_template = temp_dir_template, /* */
169 .trip_salt = trip_salt, /* */
170 .trip_salt_len = strlen(trip_salt), /* */
171 .boards = boards, /* */
172 .boards_num = NUM_OF(boards), /* */
173 .max_form_data_size = max_form_data_size, /* */
174 .max_file_size = max_file_size, /* */
175 .max_text_len = max_text_len, /* */
176 .filetypes = filetypes, /* */
177 .filetypes_num = NUM_OF(filetypes), /* */
178 .file_description_prog = file_description_prog, /* */
179 .headers = headers, /* */
180 .headers_num = NUM_OF(headers), /* */
181 .challenges = challenges, /* */
182 .challenges_num = NUM_OF(challenges), /* */
183 .wordfilter_inputs = wordfilter_inputs, /* */
184 .wordfilter_inputs_num = NUM_OF(wordfilter_inputs), /* */
185 .forbidden_inputs = forbidden_inputs, /* */
186 .forbidden_inputs_num = NUM_OF(forbidden_inputs), /* */
189 /* Interpret board */
190 board_idx = (size_t) -1;
192 for (size_t j = 0; j < conf.boards_num; ++j) {
193 if (!strcmp(conf.boards[j].name, b_arg)) {
194 board_idx = j;
198 if (board_idx == (size_t) -1) {
199 ERROR_MESSAGE("No board \"%s\" known", b_arg);
200 goto done;
203 /* Interpret thread */
204 errno = 0;
205 thread_id = strtoull(t_arg, 0, 0);
207 if (errno) {
208 ret = errno;
209 PERROR_MESSAGE("strtoull");
210 goto done;
213 /* Set up a minimal part of the system */
214 if (setup_locks(&conf) < 0) {
215 goto done;
218 if (setup_dbs(&conf) < 0) {
219 goto done;
222 if (setup_write_thread(&conf) < 0) {
223 goto done;
226 ret = db_writeback_posts_in_thread(board_idx, thread_id, stdout,
227 print_post);
228 done:
229 clean_locks();
230 clean_dbs();
231 clean_write_thread();
233 return ret;