2 * Copyright (c) 2010, 2011 Marco Peereboom <marco@peereboom.us>
3 * Copyright (c) 2011 Stevan Andjelkovic <stevan@student.chalmers.se>
4 * Copyright (c) 2010, 2011 Edd Barrett <vext01@gmail.com>
5 * Copyright (c) 2011 Todd T. Fries <todd@fries.net>
6 * Copyright (c) 2011 Raphael Graf <r@undefined.ch>
7 * Copyright (c) 2011 Michal Mazurek <akfaew@jasminek.net>
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24 #define XT_HISTORY_FILE ("history")
25 #define XT_MAX_HL_PURGE_COUNT (1000) /* Purge the history for every
26 * MAX_HL_PURGE_COUNT items inserted into
27 * history and delete all items older
28 * than MAX_HISTORY_AGE. */
29 #define XT_MAX_HISTORY_AGE (60.0 * 60.0 * 24 * 14) /* 14 days */
34 struct history
*h
, *next
;
37 DNPRINTF(XT_D_HISTORY
, "%s: hl_purge_count = %d (%d is max)\n",
38 __func__
, hl_purge_count
, XT_MAX_HL_PURGE_COUNT
);
40 if (hl_purge_count
== XT_MAX_HL_PURGE_COUNT
) {
43 for (h
= RB_MIN(history_list
, &hl
); h
!= NULL
; h
= next
) {
45 next
= RB_NEXT(history_list
, &hl
, h
);
47 age
= difftime(time(NULL
), h
->time
);
49 if (age
> XT_MAX_HISTORY_AGE
) {
50 DNPRINTF(XT_D_HISTORY
, "%s: removing %s (age %.1f)\n",
51 __func__
, h
->uri
, age
);
53 RB_REMOVE(history_list
, &hl
, h
);
58 DNPRINTF(XT_D_HISTORY
, "%s: keeping %s (age %.1f)\n",
59 __func__
, h
->uri
, age
);
68 insert_history_item(const gchar
*uri
, const gchar
*title
, time_t time
)
72 if (!(uri
&& strlen(uri
) && title
&& strlen(title
)))
75 h
= g_malloc(sizeof(struct history
));
76 h
->uri
= g_strdup(uri
);
77 h
->title
= g_strdup(title
);
80 DNPRINTF(XT_D_HISTORY
, "%s: adding %s\n", __func__
, h
->uri
);
82 RB_INSERT(history_list
, &hl
, h
);
83 completion_add_uri(h
->uri
);
87 update_history_tabs(NULL
);
93 restore_global_history(void)
97 gchar
*uri
, *title
, *stime
, *err
= NULL
;
100 const char delim
[3] = {'\\', '\\', '\0'};
102 snprintf(file
, sizeof file
, "%s" PS
"%s", work_dir
, XT_HISTORY_FILE
);
104 if ((f
= fopen(file
, "r")) == NULL
) {
105 warnx("%s: fopen", __func__
);
110 if ((uri
= fparseln(f
, NULL
, NULL
, delim
, 0)) == NULL
)
111 if (feof(f
) || ferror(f
))
114 if ((title
= fparseln(f
, NULL
, NULL
, delim
, 0)) == NULL
)
115 if (feof(f
) || ferror(f
)) {
116 err
= "broken history file (title)";
120 if ((stime
= fparseln(f
, NULL
, NULL
, delim
, 0)) == NULL
)
121 if (feof(f
) || ferror(f
)) {
122 err
= "broken history file (time)";
126 if (strptime(stime
, "%a %b %d %H:%M:%S %Y", &tm
) == NULL
) {
127 err
= "strptime failed to parse time";
133 if (insert_history_item(uri
, title
, time
)) {
134 err
= "failed to insert item";
147 if (err
&& strlen(err
)) {
148 warnx("%s: %s\n", __func__
, err
);
160 save_global_history_to_disk(struct tab
*t
)
166 snprintf(file
, sizeof file
, "%s" PS
"%s", work_dir
, XT_HISTORY_FILE
);
168 if ((f
= fopen(file
, "w")) == NULL
) {
169 show_oops(t
, "%s: global history file: %s",
170 __func__
, strerror(errno
));
174 RB_FOREACH_REVERSE(h
, history_list
, &hl
) {
175 if (h
->uri
&& h
->title
&& h
->time
)
176 fprintf(f
, "%s\n%s\n%s", h
->uri
, h
->title
,
185 /* Marshall the internal record of visited URIs into a Javascript hash table in
188 color_visited_helper(void)
193 RB_FOREACH_REVERSE(h
, history_list
, &hl
) {
195 s
= g_strdup_printf("'%s':'dummy'", h
->uri
);
197 s
= g_strjoin(",", s
,
198 g_strdup_printf("'%s':'dummy'", h
->uri
), NULL
);
201 s
= g_strdup_printf("{%s}", s
);
203 DNPRINTF(XT_D_VISITED
, "%s: s = %s\n", __func__
, s
);
209 color_visited(struct tab
*t
, char *visited
)
213 if (t
== NULL
|| visited
== NULL
) {
214 show_oops(NULL
, "%s: invalid parameters", __func__
);
218 /* Create a string representing an annonymous Javascript function, which
219 * takes a hash table of visited URIs as an argument, goes through the
220 * links at the current web page and colors them if they indeed been
224 "(function(visitedUris) {",
225 " for (var i = 0; i < document.links.length; i++)",
226 " if (visitedUris[document.links[i].href])",
227 " document.links[i].style.color = 'purple';",
229 /* Apply the annonymous function to the hash table containing
231 g_strdup_printf("(%s);", visited
),