server: truncate slurp'd files correctly
[rb-79.git] / rb79-view-thread.c
blobe4f56a31dc22825bbf7bfbbe504df7ad6ed11aad
1 /*
2 * Copyright (c) 2017-2018, 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 usage(void)
40 size_t len = strlen(program_name);
42 printf("Usage: %s -b board-name\n", program_name);
43 printf(" %*s -t thread-id\n", (int) len, "");
44 printf(" %*s [ -C ] # Do not use color\n", (int) len, "");
47 /* Print out enough of a post to give the mod information */
48 int print_post(struct prepared_post *p, FILE *f, uint_fast8_t is_op,
49 uint_fast8_t is_summary, uint_fast8_t is_recent, const
50 char *board_name,
51 uintmax_t in_thread, uintmax_t total_posts_in_thread,
52 uint_fast8_t hr_before)
54 char *time_str = util_iso8601_from_time_t(p->now);
55 unsigned char out_hash[9] = { 0 };
57 UNUSED(is_summary);
58 UNUSED(is_recent);
59 UNUSED(hr_before);
60 UNUSED(board_name);
61 UNUSED(in_thread);
62 UNUSED(total_posts_in_thread);
64 if (crypto_generichash(out_hash, 9, (const unsigned char *) p->ip,
65 p->ip_len, 0, 0)) {
66 PERROR_MESSAGE("crypto_generichash_init");
67 goto done;
70 if (is_op) {
71 fprintf(f, "--------------------------------------\n");
74 fprintf(f, " ");
76 if (use_color) {
77 fprintf(f, "\033[48;2;%d;%d;%dm ", 0xff & out_hash[0], 0xff &
78 out_hash[1], 0xff & out_hash[2]);
79 fprintf(f, "\033[48;2;%d;%d;%dm ", 0xff & out_hash[3], 0xff &
80 out_hash[4], 0xff & out_hash[5]);
81 fprintf(f, "\033[48;2;%d;%d;%dm ", 0xff & out_hash[6], 0xff &
82 out_hash[7], 0xff & out_hash[8]);
83 fprintf(f, "\033[0m");
84 } else {
85 fprintf(f, " ");
88 fprintf(f, " %s%*s", p->ip, (int) (20 > p->ip_len ? 20 - p->ip_len : 1),
89 " ");
90 fprintf(f, "%s ", UBSAFES(time_str));
91 fprintf(f, "No. %ju\n", p->id);
93 if (p->file_name) {
94 fprintf(f, " [ File: %s ]\n", p->file_name);
97 fprintf(f, " ");
99 if (p->comment_len > 40) {
100 fprintf(f, "%.*s...", 37, p->comment);
101 } else if (p->comment_len) {
102 fprintf(f, "%s", p->comment);
105 fprintf(f, "\n");
106 fprintf(f, "--------------------------------------\n");
107 done:
108 free(time_str);
110 return 0;
113 /* Do the thing */
114 int main(int argc, char **argv)
116 int ret = EINVAL;
117 struct configuration conf = { 0 };
118 int opt = 0;
119 const char *b_arg = 0;
120 size_t board_idx = 0;
121 const char *t_arg = 0;
122 uintmax_t thread_id = 0;
124 setlocale(LC_ALL, "");
126 /* Parse options */
127 while ((opt = getopt(argc, argv, "b:t:C")) != -1) {
128 switch (opt) {
129 case 'b':
131 if (b_arg) {
132 ERROR_MESSAGE("-b already specified");
133 goto done;
136 b_arg = optarg;
137 break;
138 case 't':
140 if (t_arg) {
141 ERROR_MESSAGE("-t already specified");
142 goto done;
145 t_arg = optarg;
146 break;
147 case 'C':
148 use_color = 0;
149 break;
150 default:
151 usage();
152 goto done;
156 if (!b_arg ||
157 !t_arg) {
158 usage();
159 goto done;
162 conf = (struct configuration) {
163 /* */
164 .static_www_folder = static_www_folder, /* */
165 .work_path = work_path, /* */
166 .trip_salt = trip_salt, /* */
167 .trip_salt_len = strlen(trip_salt), /* */
168 .boards = boards, /* */
169 .boards_num = NUM_OF(boards), /* */
170 .max_form_data_size = max_form_data_size, /* */
171 .max_file_size = max_file_size, /* */
172 .max_text_len = max_text_len, /* */
173 .filetypes = filetypes, /* */
174 .filetypes_num = NUM_OF(filetypes), /* */
175 .file_description_prog = file_description_prog, /* */
176 .headers = headers, /* */
177 .headers_num = NUM_OF(headers), /* */
178 .challenges = challenges, /* */
179 .challenges_num = NUM_OF(challenges), /* */
180 .wordfilter_inputs = wordfilter_inputs, /* */
181 .wordfilter_inputs_num = NUM_OF(wordfilter_inputs), /* */
184 /* Interpret board */
185 board_idx = (size_t) -1;
187 for (size_t j = 0; j < conf.boards_num; ++j) {
188 if (!strcmp(conf.boards[j].name, b_arg)) {
189 board_idx = j;
193 if (board_idx == (size_t) -1) {
194 ERROR_MESSAGE("No board \"%s\" known", b_arg);
195 goto done;
198 /* Interpret thread */
199 errno = 0;
200 thread_id = strtoull(t_arg, 0, 0);
202 if (errno) {
203 ret = errno;
204 PERROR_MESSAGE("strtoull");
205 goto done;
208 /* Set up a minimal part of the system */
209 if (setup_locks(&conf) < 0) {
210 goto done;
213 if (setup_dbs(&conf) < 0) {
214 goto done;
217 if (setup_write_thread(&conf) < 0) {
218 goto done;
221 ret = db_writeback_posts_in_thread(board_idx, thread_id, stdout,
222 print_post);
223 done:
224 clean_locks();
225 clean_dbs();
226 clean_write_thread();
228 return ret;