Blame


1 35e1f40a 2021-03-14 op /*
2 35e1f40a 2021-03-14 op * Copyright (c) 2021 Omar Polo <op@omarpolo.com>
3 35e1f40a 2021-03-14 op *
4 35e1f40a 2021-03-14 op * Permission to use, copy, modify, and distribute this software for any
5 35e1f40a 2021-03-14 op * purpose with or without fee is hereby granted, provided that the above
6 35e1f40a 2021-03-14 op * copyright notice and this permission notice appear in all copies.
7 35e1f40a 2021-03-14 op *
8 35e1f40a 2021-03-14 op * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 35e1f40a 2021-03-14 op * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 35e1f40a 2021-03-14 op * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 35e1f40a 2021-03-14 op * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 35e1f40a 2021-03-14 op * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 35e1f40a 2021-03-14 op * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 35e1f40a 2021-03-14 op * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 35e1f40a 2021-03-14 op */
16 35e1f40a 2021-03-14 op
17 740f578b 2021-03-15 op /*
18 eb2ed626 2021-10-07 op * Handles config and runtime files
19 740f578b 2021-03-15 op */
20 786e6deb 2021-07-21 op
21 786e6deb 2021-07-21 op #include "compat.h"
22 35e1f40a 2021-03-14 op
23 6cd6a9e1 2021-03-20 op #include <sys/stat.h>
24 65124267 2021-08-13 op #include <sys/types.h>
25 6cd6a9e1 2021-03-20 op
26 65124267 2021-08-13 op #include <dirent.h>
27 35e1f40a 2021-03-14 op #include <errno.h>
28 de2a69bb 2021-05-17 op #include <fcntl.h>
29 35e1f40a 2021-03-14 op #include <limits.h>
30 eb2ed626 2021-10-07 op #include <libgen.h>
31 35e1f40a 2021-03-14 op #include <stdio.h>
32 35e1f40a 2021-03-14 op #include <stdlib.h>
33 35e1f40a 2021-03-14 op #include <string.h>
34 35e1f40a 2021-03-14 op #include <unistd.h>
35 4913b479 2021-07-12 op
36 5a824be4 2021-07-13 op #include "pages.h"
37 f63b8f73 2022-04-24 op #include "parser.h"
38 eb9cbcba 2022-01-03 op #include "session.h"
39 f63b8f73 2022-04-24 op #include "telescope.h"
40 9d65b1d9 2022-01-11 op #include "utils.h"
41 35e1f40a 2021-03-14 op
42 f63b8f73 2022-04-24 op #include "fs.h"
43 f63b8f73 2022-04-24 op
44 f63b8f73 2022-04-24 op #ifndef nitems
45 f63b8f73 2022-04-24 op #define nitems(x) (sizeof(x) / sizeof(x[0]))
46 f63b8f73 2022-04-24 op #endif
47 f63b8f73 2022-04-24 op
48 35e1f40a 2021-03-14 op static void die(void) __attribute__((__noreturn__));
49 5cbe1763 2021-08-13 op static int select_non_dot(const struct dirent *);
50 5cbe1763 2021-08-13 op static int select_non_dotdot(const struct dirent *);
51 eb2ed626 2021-10-07 op static size_t join_path(char*, const char*, const char*, size_t);
52 eb2ed626 2021-10-07 op static void getenv_default(char*, const char*, const char*, size_t);
53 eb2ed626 2021-10-07 op static void mkdirs(const char*, mode_t);
54 6c8ddace 2022-01-03 op static void init_paths(void);
55 50f03682 2022-01-03 op static void load_last_session(void);
56 9e97090d 2022-02-26 op static void load_hist(void);
57 83ed72f1 2022-01-03 op static int last_time_crashed(void);
58 f63b8f73 2022-04-24 op static void load_certs(struct ohash *);
59 35e1f40a 2021-03-14 op
60 f88fbabc 2021-11-27 op /*
61 f88fbabc 2021-11-27 op * Where to store user data. These are all equal to ~/.telescope if
62 f88fbabc 2021-11-27 op * it exists.
63 f88fbabc 2021-11-27 op */
64 fb3d08c1 2021-10-07 op char config_path_base[PATH_MAX];
65 fb3d08c1 2021-10-07 op char data_path_base[PATH_MAX];
66 fb3d08c1 2021-10-07 op char cache_path_base[PATH_MAX];
67 eb2ed626 2021-10-07 op
68 4cf6ba13 2022-02-11 op char ctlsock_path[PATH_MAX];
69 eb2ed626 2021-10-07 op char config_path[PATH_MAX];
70 fb3d08c1 2021-10-07 op char lockfile_path[PATH_MAX];
71 fb3d08c1 2021-10-07 op char bookmark_file[PATH_MAX];
72 fb3d08c1 2021-10-07 op char known_hosts_file[PATH_MAX], known_hosts_tmp[PATH_MAX];
73 fb3d08c1 2021-10-07 op char crashed_file[PATH_MAX];
74 de6a6a40 2022-04-24 op char session_file[PATH_MAX], session_file_tmp[PATH_MAX];
75 de6a6a40 2022-04-24 op char history_file[PATH_MAX], history_file_tmp[PATH_MAX];
76 740f578b 2021-03-15 op
77 35e1f40a 2021-03-14 op static void __attribute__((__noreturn__))
78 35e1f40a 2021-03-14 op die(void)
79 35e1f40a 2021-03-14 op {
80 35e1f40a 2021-03-14 op abort(); /* TODO */
81 35e1f40a 2021-03-14 op }
82 35e1f40a 2021-03-14 op
83 f63b8f73 2022-04-24 op static int
84 f63b8f73 2022-04-24 op select_non_dot(const struct dirent *d)
85 fb4dc49f 2021-08-13 op {
86 f63b8f73 2022-04-24 op return strcmp(d->d_name, ".");
87 f63b8f73 2022-04-24 op }
88 fb4dc49f 2021-08-13 op
89 f63b8f73 2022-04-24 op static int
90 f63b8f73 2022-04-24 op select_non_dotdot(const struct dirent *d)
91 f63b8f73 2022-04-24 op {
92 f63b8f73 2022-04-24 op return strcmp(d->d_name, ".") && strcmp(d->d_name, "..");
93 fb4dc49f 2021-08-13 op }
94 fb4dc49f 2021-08-13 op
95 fb4dc49f 2021-08-13 op static void
96 f63b8f73 2022-04-24 op send_dir(struct tab *tab, const char *path)
97 35e1f40a 2021-03-14 op {
98 f63b8f73 2022-04-24 op struct dirent **names;
99 f63b8f73 2022-04-24 op int (*selector)(const struct dirent *) = select_non_dot;
100 f63b8f73 2022-04-24 op int i, len;
101 35e1f40a 2021-03-14 op
102 f63b8f73 2022-04-24 op #if notyet
103 f63b8f73 2022-04-24 op /*
104 f63b8f73 2022-04-24 op * need something to fake a redirect
105 f63b8f73 2022-04-24 op */
106 35e1f40a 2021-03-14 op
107 f63b8f73 2022-04-24 op if (!has_suffix(path, "/")) {
108 f63b8f73 2022-04-24 op if (asprintf(&s, "%s/", path) == -1)
109 f63b8f73 2022-04-24 op die();
110 f63b8f73 2022-04-24 op send_hdr(peerid, 30, s);
111 f63b8f73 2022-04-24 op free(s);
112 f63b8f73 2022-04-24 op return;
113 56e7efb4 2021-07-21 op }
114 f63b8f73 2022-04-24 op #endif
115 56e7efb4 2021-07-21 op
116 f63b8f73 2022-04-24 op if (!strcmp(path, "/"))
117 f63b8f73 2022-04-24 op selector = select_non_dotdot;
118 f63b8f73 2022-04-24 op
119 f63b8f73 2022-04-24 op if ((len = scandir(path, &names, selector, alphasort)) == -1) {
120 f63b8f73 2022-04-24 op load_page_from_str(tab, "# failure reading the directory\n");
121 a2728733 2021-07-18 op return;
122 35e1f40a 2021-03-14 op }
123 a2728733 2021-07-18 op
124 f63b8f73 2022-04-24 op parser_init(tab, gemtext_initparser);
125 f63b8f73 2022-04-24 op parser_parsef(tab, "# Index of %s\n\n", path);
126 56e7efb4 2021-07-21 op
127 f63b8f73 2022-04-24 op for (i = 0; i < len; ++i) {
128 f63b8f73 2022-04-24 op const char *sufx = "";
129 fb4dc49f 2021-08-13 op
130 f63b8f73 2022-04-24 op if (names[i]->d_type == DT_DIR)
131 f63b8f73 2022-04-24 op sufx = "/";
132 f63b8f73 2022-04-24 op
133 f63b8f73 2022-04-24 op parser_parsef(tab, "=> %s%s\n", names[i]->d_name, sufx);
134 f63b8f73 2022-04-24 op }
135 f63b8f73 2022-04-24 op
136 f63b8f73 2022-04-24 op parser_free(tab);
137 f63b8f73 2022-04-24 op free(names);
138 fb4dc49f 2021-08-13 op }
139 fb4dc49f 2021-08-13 op
140 f63b8f73 2022-04-24 op static int
141 f63b8f73 2022-04-24 op is_dir(FILE *fp)
142 24a68158 2021-08-13 op {
143 f63b8f73 2022-04-24 op struct stat sb;
144 24a68158 2021-08-13 op
145 f63b8f73 2022-04-24 op if (fstat(fileno(fp), &sb) == -1)
146 f63b8f73 2022-04-24 op return 0;
147 24a68158 2021-08-13 op
148 f63b8f73 2022-04-24 op return S_ISDIR(sb.st_mode);
149 24a68158 2021-08-13 op }
150 24a68158 2021-08-13 op
151 f63b8f73 2022-04-24 op static parserinit
152 65124267 2021-08-13 op file_type(const char *path)
153 fb4dc49f 2021-08-13 op {
154 fb4dc49f 2021-08-13 op struct mapping {
155 fb4dc49f 2021-08-13 op const char *ext;
156 f63b8f73 2022-04-24 op parserinit fn;
157 fb4dc49f 2021-08-13 op } ms[] = {
158 f63b8f73 2022-04-24 op {"diff", textpatch_initparser},
159 f63b8f73 2022-04-24 op {"gemini", gemtext_initparser},
160 f63b8f73 2022-04-24 op {"gmi", gemtext_initparser},
161 f63b8f73 2022-04-24 op {"markdown", textplain_initparser},
162 f63b8f73 2022-04-24 op {"md", textplain_initparser},
163 f63b8f73 2022-04-24 op {"patch", gemtext_initparser},
164 fb4dc49f 2021-08-13 op {NULL, NULL},
165 65124267 2021-08-13 op }, *m;
166 65124267 2021-08-13 op char *dot;
167 65124267 2021-08-13 op
168 65124267 2021-08-13 op if ((dot = strrchr(path, '.')) == NULL)
169 f63b8f73 2022-04-24 op return textplain_initparser;
170 65124267 2021-08-13 op
171 65124267 2021-08-13 op dot++;
172 65124267 2021-08-13 op
173 65124267 2021-08-13 op for (m = ms; m->ext != NULL; ++m)
174 65124267 2021-08-13 op if (!strcmp(m->ext, dot))
175 f63b8f73 2022-04-24 op return m->fn;
176 65124267 2021-08-13 op
177 f63b8f73 2022-04-24 op return textplain_initparser;
178 5cbe1763 2021-08-13 op }
179 5cbe1763 2021-08-13 op
180 f63b8f73 2022-04-24 op void
181 f63b8f73 2022-04-24 op fs_load_url(struct tab *tab, const char *url)
182 5cbe1763 2021-08-13 op {
183 f63b8f73 2022-04-24 op const char *bpath = "bookmarks.gmi", *fallback = "# Not found\n";
184 f63b8f73 2022-04-24 op parserinit initfn = gemtext_initparser;
185 f63b8f73 2022-04-24 op char path[PATH_MAX];
186 f63b8f73 2022-04-24 op FILE *fp = NULL;
187 f63b8f73 2022-04-24 op size_t i;
188 f63b8f73 2022-04-24 op char buf[BUFSIZ];
189 f63b8f73 2022-04-24 op struct page {
190 f63b8f73 2022-04-24 op const char *name;
191 f63b8f73 2022-04-24 op const char *path;
192 f63b8f73 2022-04-24 op const uint8_t *data;
193 f63b8f73 2022-04-24 op size_t len;
194 f63b8f73 2022-04-24 op } pages[] = {
195 f63b8f73 2022-04-24 op {"about", NULL, about_about, about_about_len},
196 f63b8f73 2022-04-24 op {"blank", NULL, about_blank, about_blank_len},
197 f63b8f73 2022-04-24 op {"bookmarks", bpath, bookmarks, bookmarks_len},
198 f63b8f73 2022-04-24 op {"crash", NULL, about_crash, about_crash_len},
199 f63b8f73 2022-04-24 op {"help", NULL, about_help, about_help_len},
200 f63b8f73 2022-04-24 op {"license", NULL, about_license, about_license_len},
201 f63b8f73 2022-04-24 op {"new", NULL, about_new, about_new_len},
202 f63b8f73 2022-04-24 op }, *page = NULL;
203 65124267 2021-08-13 op
204 f63b8f73 2022-04-24 op if (!strncmp(url, "about:", 6)) {
205 f63b8f73 2022-04-24 op url += 6;
206 65124267 2021-08-13 op
207 f63b8f73 2022-04-24 op for (i = 0; page == NULL && i < nitems(pages); ++i) {
208 f63b8f73 2022-04-24 op if (!strcmp(url, pages[i].name))
209 f63b8f73 2022-04-24 op page = &pages[i];
210 f63b8f73 2022-04-24 op }
211 5d43215b 2021-08-13 op
212 f63b8f73 2022-04-24 op if (page == NULL)
213 f63b8f73 2022-04-24 op goto done;
214 5cbe1763 2021-08-13 op
215 f63b8f73 2022-04-24 op strlcpy(path, data_path_base, sizeof(path));
216 f63b8f73 2022-04-24 op strlcat(path, "/", sizeof(path));
217 f63b8f73 2022-04-24 op if (page->path != NULL)
218 f63b8f73 2022-04-24 op strlcat(path, page->path, sizeof(path));
219 f63b8f73 2022-04-24 op else {
220 f63b8f73 2022-04-24 op strlcat(path, "page/about_", sizeof(path));
221 f63b8f73 2022-04-24 op strlcat(path, page->name, sizeof(path));
222 f63b8f73 2022-04-24 op strlcat(path, ".gmi", sizeof(path));
223 f63b8f73 2022-04-24 op }
224 65124267 2021-08-13 op
225 f63b8f73 2022-04-24 op fallback = page->data;
226 f63b8f73 2022-04-24 op } else if (!strncmp(url, "file://", 7)) {
227 f63b8f73 2022-04-24 op url += 7;
228 f63b8f73 2022-04-24 op strlcpy(path, url, sizeof(path));
229 f63b8f73 2022-04-24 op initfn = file_type(url);
230 f63b8f73 2022-04-24 op } else
231 f63b8f73 2022-04-24 op goto done;
232 65124267 2021-08-13 op
233 f63b8f73 2022-04-24 op if ((fp = fopen(path, "r")) == NULL)
234 f63b8f73 2022-04-24 op goto done;
235 65124267 2021-08-13 op
236 f63b8f73 2022-04-24 op if (is_dir(fp)) {
237 f63b8f73 2022-04-24 op fclose(fp);
238 f63b8f73 2022-04-24 op send_dir(tab, path);
239 f63b8f73 2022-04-24 op goto done;
240 fb4dc49f 2021-08-13 op }
241 fb4dc49f 2021-08-13 op
242 f63b8f73 2022-04-24 op parser_init(tab, initfn);
243 f63b8f73 2022-04-24 op for (;;) {
244 f63b8f73 2022-04-24 op size_t r;
245 fb4dc49f 2021-08-13 op
246 f63b8f73 2022-04-24 op r = fread(buf, 1, sizeof(buf), fp);
247 f63b8f73 2022-04-24 op if (!parser_parse(tab, buf, r))
248 f63b8f73 2022-04-24 op break;
249 f63b8f73 2022-04-24 op if (r != sizeof(buf))
250 f63b8f73 2022-04-24 op break;
251 fb4dc49f 2021-08-13 op }
252 f63b8f73 2022-04-24 op parser_free(tab);
253 fb4dc49f 2021-08-13 op
254 f63b8f73 2022-04-24 op done:
255 f63b8f73 2022-04-24 op if (fp != NULL)
256 f63b8f73 2022-04-24 op fclose(fp);
257 f63b8f73 2022-04-24 op else
258 f63b8f73 2022-04-24 op load_page_from_str(tab, fallback);
259 35e1f40a 2021-03-14 op }
260 35e1f40a 2021-03-14 op
261 f63b8f73 2022-04-24 op int
262 f63b8f73 2022-04-24 op bookmark_page(const char *url)
263 50f03682 2022-01-03 op {
264 f63b8f73 2022-04-24 op FILE *f;
265 be97d6e6 2021-08-15 op
266 f63b8f73 2022-04-24 op if ((f = fopen(bookmark_file, "a")) == NULL)
267 f63b8f73 2022-04-24 op return -1;
268 f63b8f73 2022-04-24 op fprintf(f, "=> %s\n", url);
269 f63b8f73 2022-04-24 op fclose(f);
270 f63b8f73 2022-04-24 op return 0;
271 35e1f40a 2021-03-14 op }
272 35e1f40a 2021-03-14 op
273 f63b8f73 2022-04-24 op int
274 f63b8f73 2022-04-24 op save_cert(const struct tofu_entry *e)
275 740f578b 2021-03-15 op {
276 f63b8f73 2022-04-24 op FILE *f;
277 740f578b 2021-03-15 op
278 f63b8f73 2022-04-24 op if ((f = fopen(known_hosts_file, "a")) == NULL)
279 f63b8f73 2022-04-24 op return -1;
280 f63b8f73 2022-04-24 op fprintf(f, "%s %s %d\n", e->domain, e->hash, e->verified);
281 740f578b 2021-03-15 op fclose(f);
282 f63b8f73 2022-04-24 op return 0;
283 740f578b 2021-03-15 op }
284 740f578b 2021-03-15 op
285 f63b8f73 2022-04-24 op int
286 f63b8f73 2022-04-24 op update_cert(const struct tofu_entry *e)
287 3a227e9a 2021-03-18 op {
288 288fd238 2021-04-25 op FILE *tmp, *f;
289 288fd238 2021-04-25 op char sfn[PATH_MAX], *line = NULL, *t;
290 288fd238 2021-04-25 op size_t l, linesize = 0;
291 288fd238 2021-04-25 op ssize_t linelen;
292 f63b8f73 2022-04-24 op int fd, err;
293 288fd238 2021-04-25 op
294 288fd238 2021-04-25 op strlcpy(sfn, known_hosts_tmp, sizeof(sfn));
295 288fd238 2021-04-25 op if ((fd = mkstemp(sfn)) == -1 ||
296 288fd238 2021-04-25 op (tmp = fdopen(fd, "w")) == NULL) {
297 288fd238 2021-04-25 op if (fd != -1) {
298 288fd238 2021-04-25 op unlink(sfn);
299 288fd238 2021-04-25 op close(fd);
300 288fd238 2021-04-25 op }
301 f63b8f73 2022-04-24 op return -1;
302 288fd238 2021-04-25 op }
303 288fd238 2021-04-25 op
304 288fd238 2021-04-25 op if ((f = fopen(known_hosts_file, "r")) == NULL) {
305 288fd238 2021-04-25 op unlink(sfn);
306 288fd238 2021-04-25 op fclose(tmp);
307 f63b8f73 2022-04-24 op return -1;
308 288fd238 2021-04-25 op }
309 288fd238 2021-04-25 op
310 f63b8f73 2022-04-24 op l = strlen(e->domain);
311 288fd238 2021-04-25 op while ((linelen = getline(&line, &linesize, f)) != -1) {
312 f63b8f73 2022-04-24 op if ((t = strstr(line, e->domain)) != NULL &&
313 288fd238 2021-04-25 op (line[l] == ' ' || line[l] == '\t'))
314 288fd238 2021-04-25 op continue;
315 288fd238 2021-04-25 op /* line has a trailing \n */
316 288fd238 2021-04-25 op fprintf(tmp, "%s", line);
317 288fd238 2021-04-25 op }
318 f63b8f73 2022-04-24 op fprintf(tmp, "%s %s %d\n", e->domain, e->hash, e->verified);
319 288fd238 2021-04-25 op
320 288fd238 2021-04-25 op free(line);
321 f63b8f73 2022-04-24 op err = ferror(tmp);
322 288fd238 2021-04-25 op
323 288fd238 2021-04-25 op fclose(tmp);
324 288fd238 2021-04-25 op fclose(f);
325 288fd238 2021-04-25 op
326 f63b8f73 2022-04-24 op if (err) {
327 288fd238 2021-04-25 op unlink(sfn);
328 f63b8f73 2022-04-24 op return -1;
329 288fd238 2021-04-25 op }
330 288fd238 2021-04-25 op
331 f63b8f73 2022-04-24 op if (rename(sfn, known_hosts_file))
332 f63b8f73 2022-04-24 op return -1;
333 f63b8f73 2022-04-24 op return 0;
334 35e1f40a 2021-03-14 op }
335 35e1f40a 2021-03-14 op
336 eb2ed626 2021-10-07 op static size_t
337 eb2ed626 2021-10-07 op join_path(char *buf, const char *lhs, const char *rhs, size_t buflen)
338 35e1f40a 2021-03-14 op {
339 eb2ed626 2021-10-07 op strlcpy(buf, lhs, buflen);
340 eb2ed626 2021-10-07 op return strlcat(buf, rhs, buflen);
341 eb2ed626 2021-10-07 op }
342 d0fd368a 2021-07-15 op
343 eb2ed626 2021-10-07 op static void
344 eb2ed626 2021-10-07 op getenv_default(char *buf, const char *name, const char *def, size_t buflen)
345 eb2ed626 2021-10-07 op {
346 eb2ed626 2021-10-07 op size_t ret;
347 eb2ed626 2021-10-07 op char *home, *env;
348 740f578b 2021-03-15 op
349 eb2ed626 2021-10-07 op if ((home = getenv("HOME")) == NULL)
350 eb2ed626 2021-10-07 op errx(1, "HOME is not defined");
351 3a227e9a 2021-03-18 op
352 eb2ed626 2021-10-07 op if ((env = getenv(name)) != NULL)
353 eb2ed626 2021-10-07 op ret = strlcpy(buf, env, buflen);
354 eb2ed626 2021-10-07 op else
355 eb2ed626 2021-10-07 op ret = join_path(buf, home, def, buflen);
356 288fd238 2021-04-25 op
357 eb2ed626 2021-10-07 op if (ret >= buflen)
358 eb2ed626 2021-10-07 op errx(1, "buffer too small for %s", name);
359 eb2ed626 2021-10-07 op }
360 c7107cec 2021-04-01 op
361 eb2ed626 2021-10-07 op static void
362 eb2ed626 2021-10-07 op mkdirs(const char *path, mode_t mode)
363 eb2ed626 2021-10-07 op {
364 444dad86 2021-10-07 op char copy[PATH_MAX+1], orig[PATH_MAX+1], *parent;
365 ea080950 2021-07-20 op
366 eb2ed626 2021-10-07 op strlcpy(copy, path, sizeof(copy));
367 444dad86 2021-10-07 op strlcpy(orig, path, sizeof(orig));
368 eb2ed626 2021-10-07 op parent = dirname(copy);
369 eb2ed626 2021-10-07 op if (!strcmp(parent, "/"))
370 eb2ed626 2021-10-07 op return;
371 eb2ed626 2021-10-07 op mkdirs(parent, mode);
372 eb2ed626 2021-10-07 op
373 444dad86 2021-10-07 op if (mkdir(orig, mode) != 0) {
374 eb2ed626 2021-10-07 op if (errno == EEXIST)
375 eb2ed626 2021-10-07 op return;
376 444dad86 2021-10-07 op err(1, "can't mkdir %s", orig);
377 eb2ed626 2021-10-07 op }
378 eb2ed626 2021-10-07 op }
379 eb2ed626 2021-10-07 op
380 eb2ed626 2021-10-07 op static void
381 6c8ddace 2022-01-03 op init_paths(void)
382 eb2ed626 2021-10-07 op {
383 7e60a21a 2022-01-03 op char xdg_config_base[PATH_MAX];
384 7e60a21a 2022-01-03 op char xdg_data_base[PATH_MAX];
385 7e60a21a 2022-01-03 op char xdg_cache_base[PATH_MAX];
386 7e60a21a 2022-01-03 op char old_path[PATH_MAX];
387 7e60a21a 2022-01-03 op char *home;
388 7e60a21a 2022-01-03 op struct stat info;
389 eb2ed626 2021-10-07 op
390 eb2ed626 2021-10-07 op /* old path */
391 eb2ed626 2021-10-07 op if ((home = getenv("HOME")) == NULL)
392 eb2ed626 2021-10-07 op errx(1, "HOME is not defined");
393 eb2ed626 2021-10-07 op join_path(old_path, home, "/.telescope", sizeof(old_path));
394 eb2ed626 2021-10-07 op
395 eb2ed626 2021-10-07 op /* if ~/.telescope exists, use that instead of xdg dirs */
396 eb2ed626 2021-10-07 op if (stat(old_path, &info) == 0 && S_ISDIR(info.st_mode)) {
397 eb2ed626 2021-10-07 op join_path(config_path_base, home, "/.telescope",
398 eb2ed626 2021-10-07 op sizeof(config_path_base));
399 eb2ed626 2021-10-07 op join_path(data_path_base, home, "/.telescope",
400 eb2ed626 2021-10-07 op sizeof(data_path_base));
401 eb2ed626 2021-10-07 op join_path(cache_path_base, home, "/.telescope",
402 eb2ed626 2021-10-07 op sizeof(cache_path_base));
403 eb2ed626 2021-10-07 op return;
404 eb2ed626 2021-10-07 op }
405 eb2ed626 2021-10-07 op
406 eb2ed626 2021-10-07 op /* xdg paths */
407 eb2ed626 2021-10-07 op getenv_default(xdg_config_base, "XDG_CONFIG_HOME", "/.config",
408 eb2ed626 2021-10-07 op sizeof(xdg_config_base));
409 eb2ed626 2021-10-07 op getenv_default(xdg_data_base, "XDG_DATA_HOME", "/.local/share",
410 eb2ed626 2021-10-07 op sizeof(xdg_data_base));
411 eb2ed626 2021-10-07 op getenv_default(xdg_cache_base, "XDG_CACHE_HOME", "/.cache",
412 eb2ed626 2021-10-07 op sizeof(xdg_cache_base));
413 eb2ed626 2021-10-07 op
414 eb2ed626 2021-10-07 op join_path(config_path_base, xdg_config_base, "/telescope",
415 eb2ed626 2021-10-07 op sizeof(config_path_base));
416 eb2ed626 2021-10-07 op join_path(data_path_base, xdg_data_base, "/telescope",
417 eb2ed626 2021-10-07 op sizeof(data_path_base));
418 eb2ed626 2021-10-07 op join_path(cache_path_base, xdg_cache_base, "/telescope",
419 eb2ed626 2021-10-07 op sizeof(cache_path_base));
420 eb2ed626 2021-10-07 op
421 eb2ed626 2021-10-07 op mkdirs(xdg_config_base, S_IRWXU);
422 eb2ed626 2021-10-07 op mkdirs(xdg_data_base, S_IRWXU);
423 eb2ed626 2021-10-07 op mkdirs(xdg_cache_base, S_IRWXU);
424 eb2ed626 2021-10-07 op
425 eb2ed626 2021-10-07 op mkdirs(config_path_base, S_IRWXU);
426 eb2ed626 2021-10-07 op mkdirs(data_path_base, S_IRWXU);
427 eb2ed626 2021-10-07 op mkdirs(cache_path_base, S_IRWXU);
428 eb2ed626 2021-10-07 op }
429 eb2ed626 2021-10-07 op
430 eb2ed626 2021-10-07 op int
431 eb2ed626 2021-10-07 op fs_init(void)
432 eb2ed626 2021-10-07 op {
433 6c8ddace 2022-01-03 op init_paths();
434 eb2ed626 2021-10-07 op
435 4cf6ba13 2022-02-11 op join_path(ctlsock_path, cache_path_base, "/ctl",
436 4cf6ba13 2022-02-11 op sizeof(ctlsock_path));
437 eb2ed626 2021-10-07 op join_path(config_path, config_path_base, "/config",
438 eb2ed626 2021-10-07 op sizeof(config_path));
439 eb2ed626 2021-10-07 op join_path(lockfile_path, cache_path_base, "/lock",
440 eb2ed626 2021-10-07 op sizeof(lockfile_path));
441 eb2ed626 2021-10-07 op join_path(bookmark_file, data_path_base, "/bookmarks.gmi",
442 eb2ed626 2021-10-07 op sizeof(bookmark_file));
443 eb2ed626 2021-10-07 op join_path(known_hosts_file, data_path_base, "/known_hosts",
444 eb2ed626 2021-10-07 op sizeof(known_hosts_file));
445 eb2ed626 2021-10-07 op join_path(known_hosts_tmp, cache_path_base,
446 eb2ed626 2021-10-07 op "/known_hosts.tmp.XXXXXXXXXX", sizeof(known_hosts_tmp));
447 eb2ed626 2021-10-07 op join_path(session_file, cache_path_base, "/session",
448 de6a6a40 2022-04-24 op sizeof(session_file));
449 de6a6a40 2022-04-24 op join_path(session_file_tmp, cache_path_base, "/session.XXXXXXXXXX",
450 eb2ed626 2021-10-07 op sizeof(session_file));
451 9e97090d 2022-02-26 op join_path(history_file, cache_path_base, "/history",
452 de6a6a40 2022-04-24 op sizeof(history_file));
453 de6a6a40 2022-04-24 op join_path(history_file_tmp, cache_path_base, "/history.XXXXXXXXXX",
454 9e97090d 2022-02-26 op sizeof(history_file));
455 eb2ed626 2021-10-07 op join_path(crashed_file, cache_path_base, "/crashed",
456 eb2ed626 2021-10-07 op sizeof(crashed_file));
457 eb2ed626 2021-10-07 op
458 3a227e9a 2021-03-18 op return 1;
459 3a227e9a 2021-03-18 op }
460 bb28f1c2 2021-12-30 op
461 bb28f1c2 2021-12-30 op /*
462 f63b8f73 2022-04-24 op * Parse a line of the session file and restores it. The format is:
463 bb28f1c2 2021-12-30 op *
464 bb28f1c2 2021-12-30 op * URL [flags,...] [title]\n
465 bb28f1c2 2021-12-30 op */
466 f63b8f73 2022-04-24 op static inline struct tab *
467 f63b8f73 2022-04-24 op parse_session_line(char *line, struct tab **ct)
468 bb28f1c2 2021-12-30 op {
469 f63b8f73 2022-04-24 op struct tab *tab;
470 bb28f1c2 2021-12-30 op char *s, *t, *ap;
471 f63b8f73 2022-04-24 op const char *uri, *title = "";
472 f63b8f73 2022-04-24 op int current = 0, killed = 0;
473 f63b8f73 2022-04-24 op size_t top_line = 0, current_line = 0;
474 bb28f1c2 2021-12-30 op
475 f63b8f73 2022-04-24 op uri = line;
476 bb28f1c2 2021-12-30 op if ((s = strchr(line, ' ')) == NULL)
477 f63b8f73 2022-04-24 op return NULL;
478 3a227e9a 2021-03-18 op
479 bb28f1c2 2021-12-30 op *s++ = '\0';
480 bb28f1c2 2021-12-30 op
481 bb28f1c2 2021-12-30 op if ((t = strchr(s, ' ')) != NULL) {
482 bb28f1c2 2021-12-30 op *t++ = '\0';
483 f63b8f73 2022-04-24 op title = t;
484 bb28f1c2 2021-12-30 op }
485 bb28f1c2 2021-12-30 op
486 bb28f1c2 2021-12-30 op while ((ap = strsep(&s, ",")) != NULL) {
487 bb28f1c2 2021-12-30 op if (!strcmp(ap, "current"))
488 f63b8f73 2022-04-24 op current = 1;
489 6c74799d 2022-01-05 op else if (!strcmp(ap, "killed"))
490 f63b8f73 2022-04-24 op killed = 1;
491 e795e935 2022-01-18 op else if (has_prefix(ap, "top="))
492 f63b8f73 2022-04-24 op top_line = strtonum(ap+4, 0, UINT32_MAX, NULL);
493 e795e935 2022-01-18 op else if (has_prefix(ap, "cur="))
494 f63b8f73 2022-04-24 op current_line = strtonum(ap+4, 0, UINT32_MAX, NULL);
495 bb28f1c2 2021-12-30 op }
496 bb28f1c2 2021-12-30 op
497 f63b8f73 2022-04-24 op if (top_line > current_line) {
498 f63b8f73 2022-04-24 op top_line = 0;
499 f63b8f73 2022-04-24 op current_line = 0;
500 e795e935 2022-01-18 op }
501 e795e935 2022-01-18 op
502 f63b8f73 2022-04-24 op if ((tab = new_tab(uri, NULL, NULL)) == NULL)
503 f63b8f73 2022-04-24 op die();
504 f63b8f73 2022-04-24 op tab->hist_cur->line_off = top_line;
505 f63b8f73 2022-04-24 op tab->hist_cur->current_off = current_line;
506 f63b8f73 2022-04-24 op strlcpy(tab->buffer.page.title, title, sizeof(tab->buffer.page.title));
507 f63b8f73 2022-04-24 op
508 f63b8f73 2022-04-24 op if (current)
509 f63b8f73 2022-04-24 op *ct = tab;
510 f63b8f73 2022-04-24 op else if (killed)
511 f63b8f73 2022-04-24 op kill_tab(tab, 1);
512 f63b8f73 2022-04-24 op
513 f63b8f73 2022-04-24 op return tab;
514 1040cc7f 2021-01-02 op }
515 1040cc7f 2021-01-02 op
516 1040cc7f 2021-01-02 op static inline void
517 f63b8f73 2022-04-24 op sendhist(struct tab *tab, const char *uri, int future)
518 1040cc7f 2021-01-02 op {
519 f63b8f73 2022-04-24 op struct hist *h;
520 1040cc7f 2021-01-02 op
521 f63b8f73 2022-04-24 op if ((h = calloc(1, sizeof(*h))) == NULL)
522 f63b8f73 2022-04-24 op die();
523 f63b8f73 2022-04-24 op strlcpy(h->h, uri, sizeof(h->h));
524 1040cc7f 2021-01-02 op
525 f63b8f73 2022-04-24 op if (future)
526 f63b8f73 2022-04-24 op hist_push(&tab->hist, h);
527 f63b8f73 2022-04-24 op else
528 f63b8f73 2022-04-24 op hist_add_before(&tab->hist, tab->hist_cur, h);
529 bb28f1c2 2021-12-30 op }
530 bb28f1c2 2021-12-30 op
531 bb28f1c2 2021-12-30 op static void
532 50f03682 2022-01-03 op load_last_session(void)
533 bb28f1c2 2021-12-30 op {
534 f63b8f73 2022-04-24 op struct tab *tab = NULL, *ct = NULL;
535 bb28f1c2 2021-12-30 op FILE *session;
536 bb28f1c2 2021-12-30 op size_t linesize = 0;
537 bb28f1c2 2021-12-30 op ssize_t linelen;
538 1040cc7f 2021-01-02 op int future;
539 1040cc7f 2021-01-02 op char *nl, *s, *line = NULL;
540 bb28f1c2 2021-12-30 op
541 bb28f1c2 2021-12-30 op if ((session = fopen(session_file, "r")) == NULL) {
542 f63b8f73 2022-04-24 op new_tab("about:new", NULL, NULL);
543 f63b8f73 2022-04-24 op switch_to_tab(new_tab("about:help", NULL, NULL));
544 f63b8f73 2022-04-24 op return;
545 bb28f1c2 2021-12-30 op }
546 bb28f1c2 2021-12-30 op
547 bb28f1c2 2021-12-30 op while ((linelen = getline(&line, &linesize, session)) != -1) {
548 bb28f1c2 2021-12-30 op if ((nl = strchr(line, '\n')) != NULL)
549 bb28f1c2 2021-12-30 op *nl = '\0';
550 1040cc7f 2021-01-02 op
551 1040cc7f 2021-01-02 op if (*line == '<' || *line == '>') {
552 1040cc7f 2021-01-02 op future = *line == '>';
553 1040cc7f 2021-01-02 op s = line+1;
554 f63b8f73 2022-04-24 op if (*s != ' ' || tab == NULL)
555 1040cc7f 2021-01-02 op continue;
556 f63b8f73 2022-04-24 op sendhist(tab, ++s, future);
557 1040cc7f 2021-01-02 op } else {
558 f63b8f73 2022-04-24 op tab = parse_session_line(line, &ct);
559 1040cc7f 2021-01-02 op }
560 bb28f1c2 2021-12-30 op }
561 bb28f1c2 2021-12-30 op
562 bb28f1c2 2021-12-30 op fclose(session);
563 bb28f1c2 2021-12-30 op free(line);
564 bb28f1c2 2021-12-30 op
565 f63b8f73 2022-04-24 op if (ct != NULL)
566 f63b8f73 2022-04-24 op switch_to_tab(ct);
567 bb28f1c2 2021-12-30 op
568 f63b8f73 2022-04-24 op if (last_time_crashed())
569 f63b8f73 2022-04-24 op switch_to_tab(new_tab("about:crash", NULL, NULL));
570 bb28f1c2 2021-12-30 op }
571 bb28f1c2 2021-12-30 op
572 9e97090d 2022-02-26 op static void
573 9e97090d 2022-02-26 op load_hist(void)
574 9e97090d 2022-02-26 op {
575 9e97090d 2022-02-26 op FILE *hist;
576 9e97090d 2022-02-26 op size_t linesize = 0;
577 9e97090d 2022-02-26 op ssize_t linelen;
578 9e97090d 2022-02-26 op char *nl, *spc, *line = NULL;
579 9e97090d 2022-02-26 op const char *errstr;
580 9e97090d 2022-02-26 op struct histitem hi;
581 9e97090d 2022-02-26 op
582 9e97090d 2022-02-26 op if ((hist = fopen(history_file, "r")) == NULL)
583 f63b8f73 2022-04-24 op return;
584 9e97090d 2022-02-26 op
585 9e97090d 2022-02-26 op while ((linelen = getline(&line, &linesize, hist)) != -1) {
586 9e97090d 2022-02-26 op if ((nl = strchr(line, '\n')) != NULL)
587 9e97090d 2022-02-26 op *nl = '\0';
588 9e97090d 2022-02-26 op if ((spc = strchr(line, ' ')) == NULL)
589 9e97090d 2022-02-26 op continue;
590 9e97090d 2022-02-26 op *spc = '\0';
591 9e97090d 2022-02-26 op spc++;
592 9e97090d 2022-02-26 op
593 9e97090d 2022-02-26 op memset(&hi, 0, sizeof(hi));
594 9e97090d 2022-02-26 op hi.ts = strtonum(line, INT64_MIN, INT64_MAX, &errstr);
595 9e97090d 2022-02-26 op if (errstr != NULL)
596 9e97090d 2022-02-26 op continue;
597 9e97090d 2022-02-26 op if (strlcpy(hi.uri, spc, sizeof(hi.uri)) >= sizeof(hi.uri))
598 9e97090d 2022-02-26 op continue;
599 9e97090d 2022-02-26 op
600 f63b8f73 2022-04-24 op history_push(&hi);
601 9e97090d 2022-02-26 op }
602 9e97090d 2022-02-26 op
603 9e97090d 2022-02-26 op fclose(hist);
604 9e97090d 2022-02-26 op free(line);
605 f63b8f73 2022-04-24 op
606 f63b8f73 2022-04-24 op history_sort();
607 9e97090d 2022-02-26 op }
608 9e97090d 2022-02-26 op
609 3a227e9a 2021-03-18 op int
610 f63b8f73 2022-04-24 op fs_load_state(struct ohash *certs)
611 3a227e9a 2021-03-18 op {
612 f63b8f73 2022-04-24 op load_certs(certs);
613 f63b8f73 2022-04-24 op load_hist();
614 f63b8f73 2022-04-24 op load_last_session();
615 35e1f40a 2021-03-14 op return 0;
616 35e1f40a 2021-03-14 op }
617 3a227e9a 2021-03-18 op
618 be97d6e6 2021-08-15 op /*
619 be97d6e6 2021-08-15 op * Check if the last time telescope crashed. The check is done by
620 be97d6e6 2021-08-15 op * looking at `crashed_file': if it exists then last time we crashed.
621 be97d6e6 2021-08-15 op * Then, while here, touch the file too. During IMSG_QUIT we'll
622 be97d6e6 2021-08-15 op * remove it.
623 be97d6e6 2021-08-15 op */
624 83ed72f1 2022-01-03 op static int
625 b6171794 2021-07-20 op last_time_crashed(void)
626 b6171794 2021-07-20 op {
627 be97d6e6 2021-08-15 op int fd, crashed = 1;
628 b6171794 2021-07-20 op
629 2b409042 2021-09-15 op if (safe_mode)
630 2b409042 2021-09-15 op return 0;
631 2b409042 2021-09-15 op
632 be97d6e6 2021-08-15 op if (unlink(crashed_file) == -1 && errno == ENOENT)
633 be97d6e6 2021-08-15 op crashed = 0;
634 be97d6e6 2021-08-15 op
635 be97d6e6 2021-08-15 op if ((fd = open(crashed_file, O_CREAT|O_WRONLY, 0600)) == -1)
636 be97d6e6 2021-08-15 op return crashed;
637 b6171794 2021-07-20 op close(fd);
638 be97d6e6 2021-08-15 op
639 be97d6e6 2021-08-15 op return crashed;
640 b6171794 2021-07-20 op }
641 b6171794 2021-07-20 op
642 b6171794 2021-07-20 op int
643 d0fd368a 2021-07-15 op lock_session(void)
644 d0fd368a 2021-07-15 op {
645 d0fd368a 2021-07-15 op struct flock lock;
646 d0fd368a 2021-07-15 op int fd;
647 d0fd368a 2021-07-15 op
648 d0fd368a 2021-07-15 op if ((fd = open(lockfile_path, O_WRONLY|O_CREAT, 0600)) == -1)
649 d0fd368a 2021-07-15 op return -1;
650 d0fd368a 2021-07-15 op
651 d0fd368a 2021-07-15 op lock.l_start = 0;
652 d0fd368a 2021-07-15 op lock.l_len = 0;
653 d0fd368a 2021-07-15 op lock.l_type = F_WRLCK;
654 d0fd368a 2021-07-15 op lock.l_whence = SEEK_SET;
655 c6d03cf5 2021-04-25 op
656 d0fd368a 2021-07-15 op if (fcntl(fd, F_SETLK, &lock) == -1) {
657 d0fd368a 2021-07-15 op close(fd);
658 d0fd368a 2021-07-15 op return -1;
659 d0fd368a 2021-07-15 op }
660 d0fd368a 2021-07-15 op
661 d0fd368a 2021-07-15 op return fd;
662 d0fd368a 2021-07-15 op }
663 d0fd368a 2021-07-15 op
664 6400962b 2022-01-03 op static inline int
665 c6d03cf5 2021-04-25 op parse_khost_line(char *line, char *tmp[3])
666 c6d03cf5 2021-04-25 op {
667 c6d03cf5 2021-04-25 op char **ap;
668 c6d03cf5 2021-04-25 op
669 c6d03cf5 2021-04-25 op for (ap = tmp; ap < &tmp[3] &&
670 c6d03cf5 2021-04-25 op (*ap = strsep(&line, " \t\n")) != NULL;) {
671 c6d03cf5 2021-04-25 op if (**ap != '\0')
672 c6d03cf5 2021-04-25 op ap++;
673 c6d03cf5 2021-04-25 op }
674 3a227e9a 2021-03-18 op
675 c6d03cf5 2021-04-25 op return ap == &tmp[3] && *line == '\0';
676 c6d03cf5 2021-04-25 op }
677 c6d03cf5 2021-04-25 op
678 eb722b50 2022-01-03 op static void
679 f63b8f73 2022-04-24 op load_certs(struct ohash *certs)
680 3a227e9a 2021-03-18 op {
681 c6d03cf5 2021-04-25 op char *tmp[3], *line = NULL;
682 6cd6a9e1 2021-03-20 op const char *errstr;
683 ec1fa0b0 2021-04-25 op size_t lineno = 0, linesize = 0;
684 3a227e9a 2021-03-18 op ssize_t linelen;
685 3a227e9a 2021-03-18 op FILE *f;
686 f63b8f73 2022-04-24 op struct tofu_entry *e;
687 3a227e9a 2021-03-18 op
688 3a227e9a 2021-03-18 op if ((f = fopen(known_hosts_file, "r")) == NULL)
689 eb722b50 2022-01-03 op return;
690 3a227e9a 2021-03-18 op
691 f63b8f73 2022-04-24 op if ((e = calloc(1, sizeof(*e))) == NULL) {
692 f63b8f73 2022-04-24 op fclose(f);
693 f63b8f73 2022-04-24 op return;
694 f63b8f73 2022-04-24 op }
695 f63b8f73 2022-04-24 op
696 3a227e9a 2021-03-18 op while ((linelen = getline(&line, &linesize, f)) != -1) {
697 ec1fa0b0 2021-04-25 op lineno++;
698 3a227e9a 2021-03-18 op
699 eb722b50 2022-01-03 op if (parse_khost_line(line, tmp)) {
700 f63b8f73 2022-04-24 op strlcpy(e->domain, tmp[0], sizeof(e->domain));
701 f63b8f73 2022-04-24 op strlcpy(e->hash, tmp[1], sizeof(e->hash));
702 3a227e9a 2021-03-18 op
703 f63b8f73 2022-04-24 op e->verified = strtonum(tmp[2], 0, 1, &errstr);
704 c6d03cf5 2021-04-25 op if (errstr != NULL)
705 c6d03cf5 2021-04-25 op errx(1, "%s:%zu verification for %s is %s: %s",
706 c6d03cf5 2021-04-25 op known_hosts_file, lineno,
707 f63b8f73 2022-04-24 op e->domain, errstr, tmp[2]);
708 eb722b50 2022-01-03 op
709 f63b8f73 2022-04-24 op tofu_add(certs, e);
710 c6d03cf5 2021-04-25 op } else {
711 ec1fa0b0 2021-04-25 op warnx("%s:%zu invalid entry",
712 ec1fa0b0 2021-04-25 op known_hosts_file, lineno);
713 c6d03cf5 2021-04-25 op }
714 3a227e9a 2021-03-18 op }
715 3a227e9a 2021-03-18 op
716 3a227e9a 2021-03-18 op free(line);
717 eb722b50 2022-01-03 op fclose(f);
718 eb722b50 2022-01-03 op return;
719 3a227e9a 2021-03-18 op }