commit - 9f74492aafebdbfa02f5abd1aa25e283211fe297
commit + 9e97090d644b51c0cb6e049e8c777139b18457fa
blob - f7631998b7a0f5abf1fc2d827c8610be026c3ff0
blob + 3d7a767702543a6d9cd2ab23a78ee3b5f600f7a1
--- fs.c
+++ fs.c
static void handle_session_tab(struct imsg*, size_t);
static void handle_session_tab_hist(struct imsg*, size_t);
static void handle_session_end(struct imsg*, size_t);
+static void handle_hist(struct imsg *, size_t);
static void handle_dispatch_imsg(int, short, void*);
static int fs_send_ui(int, uint32_t, int, const void *, uint16_t);
static size_t join_path(char*, const char*, const char*, size_t);
static void mkdirs(const char*, mode_t);
static void init_paths(void);
static void load_last_session(void);
+static void load_hist(void);
static int last_time_crashed(void);
static void load_certs(void);
char known_hosts_file[PATH_MAX], known_hosts_tmp[PATH_MAX];
char crashed_file[PATH_MAX];
char session_file[PATH_MAX];
+static char history_file[PATH_MAX];
static imsg_handlerfn *handlers[] = {
[IMSG_GET] = handle_get,
[IMSG_SESSION_TAB] = handle_session_tab,
[IMSG_SESSION_TAB_HIST] = handle_session_tab_hist,
[IMSG_SESSION_END] = handle_session_end,
+ [IMSG_HIST_ITEM] = handle_hist,
+ [IMSG_HIST_END] = handle_hist,
};
static void __attribute__((__noreturn__))
switch (imsg->hdr.type) {
case IMSG_INIT:
load_certs();
+ load_hist();
load_last_session();
break;
die();
fclose(session);
session = NULL;
+}
+
+static void
+handle_hist(struct imsg *imsg, size_t datalen)
+{
+ static FILE *hist;
+ struct histitem hi;
+
+ switch (imsg->hdr.type) {
+ case IMSG_HIST_ITEM:
+ if (hist == NULL) {
+ if ((hist = fopen(history_file, "a")) == NULL)
+ return;
+ }
+ if (datalen != sizeof(hi))
+ abort();
+ memcpy(&hi, imsg->data, sizeof(hi));
+ fprintf(hist, "%lld %s\n", (long long)hi.ts, hi.uri);
+ break;
+
+ case IMSG_HIST_END:
+ if (hist == NULL)
+ return;
+ fclose(hist);
+ hist = NULL;
+ break;
+
+ default:
+ abort();
+ }
}
static void
"/known_hosts.tmp.XXXXXXXXXX", sizeof(known_hosts_tmp));
join_path(session_file, cache_path_base, "/session",
sizeof(session_file));
+ join_path(history_file, cache_path_base, "/history",
+ sizeof(history_file));
join_path(crashed_file, cache_path_base, "/crashed",
sizeof(crashed_file));
fs_send_ui(IMSG_SESSION_END, 0, -1, &first_time, sizeof(first_time));
}
+static void
+load_hist(void)
+{
+ FILE *hist;
+ size_t linesize = 0;
+ ssize_t linelen;
+ char *nl, *spc, *line = NULL;
+ const char *errstr;
+ struct histitem hi;
+
+ if ((hist = fopen(history_file, "r")) == NULL)
+ goto end;
+
+ while ((linelen = getline(&line, &linesize, hist)) != -1) {
+ if ((nl = strchr(line, '\n')) != NULL)
+ *nl = '\0';
+ if ((spc = strchr(line, ' ')) == NULL)
+ continue;
+ *spc = '\0';
+ spc++;
+
+ memset(&hi, 0, sizeof(hi));
+ hi.ts = strtonum(line, INT64_MIN, INT64_MAX, &errstr);
+ if (errstr != NULL)
+ continue;
+ if (strlcpy(hi.uri, spc, sizeof(hi.uri)) >= sizeof(hi.uri))
+ continue;
+
+ fs_send_ui(IMSG_HIST_ITEM, 0, -1, &hi, sizeof(hi));
+ }
+
+ fclose(hist);
+ free(line);
+end:
+ fs_send_ui(IMSG_HIST_END, 0, -1, NULL, 0);
+}
+
int
fs_main(void)
{
blob - 43a69b8fbf331f85f67f3c290166e110e243b5c4
blob + fcb02e901a04e7942b801206c5e170627e7cc97b
--- include/session.h
+++ include/session.h
int future;
};
+struct histitem {
+ time_t ts;
+ char uri[GEMINI_URL_LEN];
+};
+
+struct history_item {
+ time_t ts;
+ char *uri;
+ int dirty;
+};
+
+#define HISTORY_CAP 1000
+struct history {
+ struct history_item items[HISTORY_CAP];
+ size_t len;
+ size_t dirty;
+};
+extern struct history history;
+
void switch_to_tab(struct tab *);
unsigned int tab_new_id(void);
struct tab *new_tab(const char *, const char *base, struct tab *);
void save_session(void);
+void history_push(struct histitem *);
+void history_sort(void);
+void history_add(const char *);
+
void autosave_init(void);
void autosave_timer(int, short, void *);
void autosave_hook(void);
blob - 66bad0bf2f576e29b0f3724503635a7823945e35
blob + 35d62cdf65eb32eb35a51fc8c3c7316463038e83
--- include/telescope.h
+++ include/telescope.h
IMSG_SESSION_TAB_HIST,
IMSG_SESSION_END,
+ IMSG_HIST_ITEM, /* struct histitem */
+ IMSG_HIST_END, /* empty */
+
IMSG_CTL_OPEN_URL,
};
blob - 11f78f41d23c9d31050427b6be0874cd8fe71180
blob + d5cdb78eff0b21b41f3eaaab0448c30f63689e41
--- session.c
+++ session.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <time.h>
#include <unistd.h>
#include "defaults.h"
#include "session.h"
#include "ui.h"
+struct history history;
+
static struct event autosaveev;
void
save_session(void)
{
struct tab *tab;
+ struct histitem hi;
+ size_t i;
if (safe_mode)
return;
sendtab(tab, 1);
ui_send_fs(IMSG_SESSION_END, 0, NULL, 0);
+
+ if (history.dirty) {
+ for (i = 0; i < history.len && history.dirty > 0; ++i) {
+ if (!history.items[i].dirty)
+ continue;
+ history.dirty--;
+ history.items[i].dirty = 0;
+
+ memset(&hi, 0, sizeof(hi));
+ hi.ts = history.items[i].ts;
+ strlcpy(hi.uri, history.items[i].uri, sizeof(hi.uri));
+ ui_send_fs(IMSG_HIST_ITEM, 0, &hi, sizeof(hi));
+ }
+ ui_send_fs(IMSG_HIST_END, 0, NULL, 0);
+ history.dirty = 0;
+ }
+}
+
+void
+history_push(struct histitem *hi)
+{
+ size_t i, oldest = 0;
+ char *uri;
+
+ for (i = 0; i < history.len; ++i) {
+ if (history.items[i].ts < history.items[oldest].ts)
+ oldest = i;
+
+ /* remove duplicates */
+ if (!strcmp(history.items[i].uri, hi->uri))
+ return;
+ }
+
+ if ((uri = strdup(hi->uri)) == NULL)
+ abort();
+
+ /* don't grow too much; replace the oldest */
+ if (history.len == HISTORY_CAP) {
+ history.items[oldest].ts = hi->ts;
+ free(history.items[oldest].uri);
+ history.items[oldest].uri = uri;
+ return;
+ }
+
+ history.items[history.len].ts = hi->ts;
+ history.items[history.len].uri = uri;
+ history.len++;
+}
+
+static int
+history_cmp(const void *a, const void *b)
+{
+ const struct history_item *i = a, *j = b;
+ return strcmp(i->uri, j->uri);
+}
+
+void
+history_sort(void)
+{
+ qsort(history.items, history.len, sizeof(history.items[0]),
+ history_cmp);
}
void
+history_add(const char *uri)
+{
+ size_t i, j, insert = 0, oldest = 0;
+ char *u;
+ int c;
+
+ for (i = 0; i < history.len; ++i) {
+ if (history.items[i].ts < history.items[oldest].ts)
+ oldest = i;
+
+ if (insert != 0 && insert < i)
+ continue;
+
+ c = strcmp(uri, history.items[i].uri);
+ if (c == 0) {
+ history.items[i].ts = time(NULL);
+ history.items[i].dirty = 1;
+ history.dirty++;
+ autosave_hook();
+ return;
+ }
+
+ if (c > 0)
+ insert = i;
+ }
+
+ if ((u = strdup(uri)) == NULL)
+ return;
+
+ /* if history is full, replace the oldest one */
+ if (history.len == HISTORY_CAP) {
+ free(history.items[oldest].uri);
+ history.items[oldest].uri = u;
+ history.items[oldest].ts = time(NULL);
+ history.items[oldest].dirty = 1;
+ history.dirty++;
+ history_sort();
+ autosave_hook();
+ return;
+ }
+
+ /* otherwise just insert in the right spot */
+
+ for (j = history.len; j > insert; --j)
+ memcpy(&history.items[j], &history.items[j-1],
+ sizeof(history.items[j]));
+
+ history.items[insert].ts = time(NULL);
+ history.items[insert].uri = u;
+ history.items[insert].dirty = 1;
+ history.dirty++;
+ history.len++;
+ autosave_hook();
+}
+
+void
autosave_init(void)
{
evtimer_set(&autosaveev, autosave_timer, NULL);
blob - 57eae92163eb02e3d31328a530e52eb16e554360
blob + 06cfcc999fdf902c64b2202a599a30d781459224
--- telescope.c
+++ telescope.c
static void handle_imsg_save_cert_ok(struct imsg *, size_t);
static void handle_imsg_update_cert_ok(struct imsg *, size_t);
static void handle_imsg_session(struct imsg *, size_t);
+static void handle_imsg_history(struct imsg *, size_t);
static void handle_dispatch_imsg(int, short, void *);
static int load_about_url(struct tab *, const char *);
static int load_file_url(struct tab *, const char *);
[IMSG_SESSION_TAB] = handle_imsg_session,
[IMSG_SESSION_TAB_HIST] = handle_imsg_session,
[IMSG_SESSION_END] = handle_imsg_session,
+ [IMSG_HIST_ITEM] = handle_imsg_history,
+ [IMSG_HIST_END] = handle_imsg_history,
};
static struct ohash certs;
load_page_from_str(tab, err_pages[tab->code]);
ui_require_input(tab, tab->code == 11, ir_select_gemini);
} else if (tab->code == 20) {
+ history_add(tab->hist_cur->h);
if (setup_parser_for(tab)) {
ui_send_net(IMSG_PROCEED, tab->id, NULL, 0);
} else if (safe_mode) {
}
static void
+handle_imsg_history(struct imsg *imsg, size_t datalen)
+{
+ struct histitem hi;
+
+ /*
+ * The fs process tried to send history item after it
+ * has announced that it's done. Something fishy is
+ * going on, better die
+ */
+ if (operating)
+ die();
+
+ switch (imsg->hdr.type) {
+ case IMSG_HIST_ITEM:
+ if (datalen != sizeof(hi))
+ die();
+
+ memcpy(&hi, imsg->data, sizeof(hi));
+ history_push(&hi);
+ break;
+
+ case IMSG_HIST_END:
+ history_sort();
+ break;
+
+ default:
+ die();
+ }
+}
+
+static void
handle_imsg_buf(struct imsg *imsg, size_t datalen)
{
struct tab *tab = NULL;